summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bincompat-backward.whitelist.conf4
-rw-r--r--bincompat-forward.whitelist.conf41
-rw-r--r--build-ant-macros.xml5
-rw-r--r--build.number2
-rwxr-xr-xbuild.xml34
-rw-r--r--src/asm/README30
-rw-r--r--src/asm/scala/tools/asm/AnnotationVisitor.java8
-rw-r--r--src/asm/scala/tools/asm/AnnotationWriter.java55
-rw-r--r--src/asm/scala/tools/asm/ByteVector.java99
-rw-r--r--src/asm/scala/tools/asm/ClassReader.java366
-rw-r--r--src/asm/scala/tools/asm/ClassVisitor.java46
-rw-r--r--src/asm/scala/tools/asm/ClassWriter.java124
-rw-r--r--src/asm/scala/tools/asm/Context.java35
-rw-r--r--src/asm/scala/tools/asm/CustomAttr.java2
-rw-r--r--src/asm/scala/tools/asm/FieldVisitor.java41
-rw-r--r--src/asm/scala/tools/asm/FieldWriter.java58
-rw-r--r--src/asm/scala/tools/asm/Frame.java23
-rw-r--r--src/asm/scala/tools/asm/Handle.java13
-rw-r--r--src/asm/scala/tools/asm/Item.java3
-rw-r--r--src/asm/scala/tools/asm/MethodVisitor.java254
-rw-r--r--src/asm/scala/tools/asm/MethodWriter.java338
-rw-r--r--src/asm/scala/tools/asm/Opcodes.java7
-rw-r--r--src/asm/scala/tools/asm/Type.java11
-rw-r--r--src/asm/scala/tools/asm/TypePath.java193
-rw-r--r--src/asm/scala/tools/asm/TypeReference.java452
-rw-r--r--src/asm/scala/tools/asm/signature/SignatureVisitor.java7
-rw-r--r--src/asm/scala/tools/asm/signature/SignatureWriter.java2
-rw-r--r--src/asm/scala/tools/asm/tree/AbstractInsnNode.java78
-rw-r--r--src/asm/scala/tools/asm/tree/AnnotationNode.java14
-rw-r--r--src/asm/scala/tools/asm/tree/ClassNode.java80
-rw-r--r--src/asm/scala/tools/asm/tree/FieldInsnNode.java8
-rw-r--r--src/asm/scala/tools/asm/tree/FieldNode.java76
-rw-r--r--src/asm/scala/tools/asm/tree/IincInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/InsnList.java20
-rw-r--r--src/asm/scala/tools/asm/tree/InsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/IntInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/InvokeDynamicInsnNode.java4
-rw-r--r--src/asm/scala/tools/asm/tree/JumpInsnNode.java4
-rw-r--r--src/asm/scala/tools/asm/tree/LdcInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/LocalVariableAnnotationNode.java157
-rw-r--r--src/asm/scala/tools/asm/tree/LookupSwitchInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/MethodInsnNode.java35
-rw-r--r--src/asm/scala/tools/asm/tree/MethodNode.java260
-rw-r--r--src/asm/scala/tools/asm/tree/MultiANewArrayInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/ParameterNode.java76
-rw-r--r--src/asm/scala/tools/asm/tree/TableSwitchInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/TryCatchBlockNode.java59
-rw-r--r--src/asm/scala/tools/asm/tree/TypeAnnotationNode.java100
-rw-r--r--src/asm/scala/tools/asm/tree/TypeInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/VarInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/analysis/AnalyzerException.java1
-rw-r--r--src/asm/scala/tools/asm/tree/analysis/BasicInterpreter.java2
-rw-r--r--src/asm/scala/tools/asm/tree/analysis/BasicVerifier.java2
-rw-r--r--src/asm/scala/tools/asm/tree/analysis/Frame.java9
-rw-r--r--src/asm/scala/tools/asm/tree/analysis/SimpleVerifier.java2
-rw-r--r--src/asm/scala/tools/asm/tree/analysis/SourceInterpreter.java2
-rw-r--r--src/asm/scala/tools/asm/util/ASMifier.java141
-rw-r--r--src/asm/scala/tools/asm/util/CheckAnnotationAdapter.java4
-rw-r--r--src/asm/scala/tools/asm/util/CheckClassAdapter.java119
-rw-r--r--src/asm/scala/tools/asm/util/CheckFieldAdapter.java26
-rw-r--r--src/asm/scala/tools/asm/util/CheckMethodAdapter.java159
-rw-r--r--src/asm/scala/tools/asm/util/CheckSignatureAdapter.java4
-rw-r--r--src/asm/scala/tools/asm/util/Printer.java95
-rw-r--r--src/asm/scala/tools/asm/util/Textifier.java279
-rw-r--r--src/asm/scala/tools/asm/util/TraceAnnotationVisitor.java2
-rw-r--r--src/asm/scala/tools/asm/util/TraceClassVisitor.java13
-rw-r--r--src/asm/scala/tools/asm/util/TraceFieldVisitor.java13
-rw-r--r--src/asm/scala/tools/asm/util/TraceMethodVisitor.java77
-rw-r--r--src/asm/scala/tools/asm/util/TraceSignatureVisitor.java4
-rw-r--r--src/build/bnd/scala-actors.bnd2
-rw-r--r--src/build/bnd/scala-compiler-doc.bnd3
-rw-r--r--src/build/bnd/scala-compiler-interactive.bnd3
-rw-r--r--src/build/bnd/scala-compiler.bnd4
-rw-r--r--src/build/bnd/scala-continuations-library.bnd4
-rw-r--r--src/build/bnd/scala-continuations-plugin.bnd4
-rw-r--r--src/build/bnd/scala-library.bnd1
-rw-r--r--src/build/bnd/scala-parser-combinators.bnd4
-rw-r--r--src/build/bnd/scala-reflect.bnd5
-rw-r--r--src/build/bnd/scala-swing.bnd4
-rw-r--r--src/build/bnd/scala-xml.bnd4
-rw-r--r--src/build/maven/scala-dist-pom.xml5
-rw-r--r--src/compiler/scala/reflect/macros/contexts/Parsers.scala17
-rw-r--r--src/compiler/scala/tools/nsc/CompilationUnits.scala40
-rw-r--r--src/compiler/scala/tools/nsc/CompileServer.scala4
-rw-r--r--src/compiler/scala/tools/nsc/CompilerCommand.scala11
-rw-r--r--src/compiler/scala/tools/nsc/Driver.scala21
-rw-r--r--src/compiler/scala/tools/nsc/GenericRunnerCommand.scala27
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala179
-rw-r--r--src/compiler/scala/tools/nsc/Reporting.scala123
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala10
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala6
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala15
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala100
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala718
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala101
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala147
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala33
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala17
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala171
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala417
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala34
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala13
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala7
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala9
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala2
-rw-r--r--src/compiler/scala/tools/nsc/javac/JavaParsers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/javac/JavaScanners.scala6
-rw-r--r--src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala11
-rw-r--r--src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala3
-rw-r--r--src/compiler/scala/tools/nsc/reporters/Reporter.scala100
-rw-r--r--src/compiler/scala/tools/nsc/reporters/StoreReporter.scala3
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala48
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala13
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala8
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala20
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala1
-rw-r--r--src/compiler/scala/tools/nsc/transform/TailCalls.scala13
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala10
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/Logic.scala25
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala22
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchWarnings.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Adaptations.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala18
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Checkable.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala20
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala16
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala26
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala49
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala84
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala58
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala20
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala108
-rw-r--r--src/compiler/scala/tools/reflect/FormatInterpolator.scala20
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala1
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala13
-rw-r--r--src/interactive/scala/tools/nsc/interactive/Main.scala7
-rw-r--r--src/library/scala/StringContext.scala97
-rwxr-xr-xsrc/library/scala/collection/IndexedSeqOptimized.scala2
-rw-r--r--src/library/scala/collection/Iterable.scala2
-rw-r--r--src/library/scala/collection/Iterator.scala17
-rw-r--r--src/library/scala/collection/Searching.scala12
-rw-r--r--src/library/scala/collection/SetLike.scala7
-rw-r--r--src/library/scala/collection/Traversable.scala2
-rw-r--r--src/library/scala/collection/TraversableLike.scala8
-rw-r--r--src/library/scala/collection/TraversableOnce.scala7
-rw-r--r--src/library/scala/collection/convert/DecorateAsScala.scala6
-rw-r--r--src/library/scala/collection/convert/WrapAsScala.scala8
-rw-r--r--src/library/scala/collection/convert/Wrappers.scala11
-rw-r--r--src/library/scala/collection/immutable/HashSet.scala7
-rw-r--r--src/library/scala/collection/immutable/Iterable.scala1
-rw-r--r--src/library/scala/collection/immutable/List.scala6
-rw-r--r--src/library/scala/collection/immutable/ListSet.scala7
-rw-r--r--src/library/scala/collection/immutable/Set.scala16
-rw-r--r--src/library/scala/collection/immutable/Stream.scala8
-rw-r--r--src/library/scala/collection/immutable/Traversable.scala2
-rw-r--r--src/library/scala/collection/mutable/AVLTree.scala2
-rw-r--r--src/library/scala/collection/mutable/SetLike.scala17
-rw-r--r--src/library/scala/collection/mutable/UnrolledBuffer.scala48
-rw-r--r--src/library/scala/concurrent/Channel.scala17
-rw-r--r--src/library/scala/concurrent/ExecutionContext.scala72
-rw-r--r--src/library/scala/concurrent/Lock.scala2
-rw-r--r--src/library/scala/concurrent/SyncVar.scala16
-rw-r--r--src/library/scala/concurrent/duration/Duration.scala2
-rw-r--r--src/library/scala/concurrent/package.scala5
-rw-r--r--src/library/scala/io/BufferedSource.scala2
-rw-r--r--src/library/scala/reflect/ClassTag.scala48
-rw-r--r--src/library/scala/util/Properties.scala7
-rw-r--r--src/library/scala/util/matching/Regex.scala10
-rw-r--r--src/partest-javaagent/scala/tools/partest/javaagent/ProfilerVisitor.java2
-rw-r--r--src/reflect/scala/reflect/api/Exprs.scala23
-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/Internals.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Names.scala106
-rw-r--r--src/reflect/scala/reflect/internal/Positions.scala11
-rw-r--r--src/reflect/scala/reflect/internal/Printers.scala41
-rw-r--r--src/reflect/scala/reflect/internal/ReificationSupport.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Reporting.scala113
-rw-r--r--src/reflect/scala/reflect/internal/Scopes.scala24
-rw-r--r--src/reflect/scala/reflect/internal/SymbolTable.scala9
-rw-r--r--src/reflect/scala/reflect/internal/TreeGen.scala4
-rw-r--r--src/reflect/scala/reflect/internal/Variances.scala2
-rw-r--r--src/reflect/scala/reflect/internal/pickling/UnPickler.scala42
-rw-r--r--src/reflect/scala/reflect/internal/util/SourceFile.scala2
-rw-r--r--src/reflect/scala/reflect/macros/Attachments.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverse.scala18
-rw-r--r--src/reflect/scala/reflect/runtime/SymbolLoaders.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedOps.scala3
-rw-r--r--src/reflect/scala/reflect/runtime/package.scala3
-rw-r--r--src/repl/scala/tools/nsc/MainGenericRunner.scala128
-rw-r--r--src/repl/scala/tools/nsc/interpreter/IMain.scala8
-rw-r--r--src/repl/scala/tools/nsc/interpreter/JavapClass.scala96
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ReplReporter.scala19
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/DocFactory.scala6
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala6
-rwxr-xr-xsrc/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala12
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.css1
-rw-r--r--test/files/jvm/deprecation.check2
-rw-r--r--test/files/jvm/duration-tck.scala5
-rw-r--r--test/files/jvm/future-spec.check2
-rw-r--r--test/files/jvm/interpreter.check4
-rw-r--r--test/files/jvm/serialization-new.check2
-rw-r--r--test/files/jvm/serialization.check2
-rw-r--r--test/files/neg/aladdin1055.check7
-rw-r--r--test/files/neg/aladdin1055.flags1
-rw-r--r--test/files/neg/aladdin1055/A.scala6
-rw-r--r--test/files/neg/aladdin1055/Test_1.scala5
-rw-r--r--test/files/neg/checksensible.check3
-rw-r--r--test/files/neg/double-def-top-level.check7
-rw-r--r--test/files/neg/double-def-top-level/A_1.scala4
-rw-r--r--test/files/neg/double-def-top-level/B_2.scala2
-rw-r--r--test/files/neg/double-def-top-level/C_3.scala2
-rw-r--r--test/files/neg/double-def-top-level/D_3.scala2
-rw-r--r--test/files/neg/overloaded-implicit.check3
-rw-r--r--test/files/neg/t1909-object.check4
-rw-r--r--test/files/neg/t5675.check4
-rw-r--r--test/files/neg/t6162-inheritance.check8
-rw-r--r--test/files/neg/t6289.check2
-rw-r--r--test/files/neg/t6567.check3
-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/t8630.check7
-rw-r--r--test/files/neg/t8630.scala1
-rw-r--r--test/files/neg/t8675.check11
-rw-r--r--test/files/neg/t8675.scala24
-rw-r--r--test/files/neg/t8675b.check6
-rw-r--r--test/files/neg/t8675b.scala22
-rw-r--r--test/files/neg/tailrec-4.check16
-rw-r--r--test/files/neg/tailrec-4.scala35
-rw-r--r--test/files/neg/unchecked-refinement.check3
-rw-r--r--test/files/neg/virtpatmat_exhaust_compound.check15
-rw-r--r--test/files/neg/virtpatmat_exhaust_compound.flags1
-rw-r--r--test/files/neg/virtpatmat_exhaust_compound.scala29
-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/t8596.flags1
-rw-r--r--test/files/pos/t8596.scala7
-rw-r--r--test/files/pos/t8617.flags1
-rw-r--r--test/files/pos/t8617.scala10
-rw-r--r--test/files/pos/t8625.scala5
-rw-r--r--test/files/pos/t8708/Either_1.scala6
-rw-r--r--test/files/pos/t8708/Test_2.scala13
-rw-r--r--test/files/presentation/ide-bug-1000531.check111
-rw-r--r--test/files/presentation/ide-bug-1000531/src/CrashOnLoad.scala15
-rw-r--r--test/files/presentation/ide-bug-1000531/src/TestIterable.java7
-rw-r--r--test/files/presentation/t7915.check20
-rw-r--r--test/files/presentation/t7915/src/Foo.scala4
-rw-r--r--test/files/run/abstypetags_serialize.check4
-rw-r--r--test/files/run/analyzerPlugins.check13
-rw-r--r--test/files/run/classfile-format-51.scala14
-rw-r--r--test/files/run/collection-stacks.check2
-rw-r--r--test/files/run/colltest.check2
-rw-r--r--test/files/run/colltest1.scala2
-rw-r--r--test/files/run/compiler-asSeenFrom.scala2
-rw-r--r--test/files/run/constrained-types.check8
-rw-r--r--test/files/run/delambdafy_t6028.check2
-rw-r--r--test/files/run/delay-bad.check2
-rw-r--r--test/files/run/eta-expand-star2.check2
-rw-r--r--test/files/run/existentials-in-compiler.scala2
-rw-r--r--test/files/run/exprs_serialize.check21
-rw-r--r--test/files/run/exprs_serialize.scala12
-rw-r--r--test/files/run/icode-reader-dead-code.check19
-rw-r--r--test/files/run/icode-reader-dead-code.scala82
-rw-r--r--test/files/run/inferred-type-constructors.check2
-rw-r--r--test/files/run/is-valid-num.scala2
-rw-r--r--test/files/run/iterator-from.scala2
-rw-r--r--test/files/run/large_class.check3
-rw-r--r--test/files/run/large_class.scala27
-rw-r--r--test/files/run/literals.check2
-rw-r--r--test/files/run/macro-rangepos-args.check1
-rw-r--r--test/files/run/macro-rangepos-args.flags1
-rw-r--r--test/files/run/macro-rangepos-args/Macros_1.scala10
-rw-r--r--test/files/run/macro-rangepos-args/Test_2.scala4
-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/macroPlugins-isBlackbox/Macros_2.scala11
-rw-r--r--test/files/run/macroPlugins-isBlackbox/Plugin_1.scala21
-rw-r--r--test/files/run/macroPlugins-isBlackbox/Test_3.flags1
-rw-r--r--test/files/run/macroPlugins-isBlackbox/Test_3.scala3
-rw-r--r--test/files/run/macroPlugins-isBlackbox/scalac-plugin.xml4
-rw-r--r--test/files/run/mapConserve.scala2
-rw-r--r--test/files/run/names-defaults.check3
-rw-r--r--test/files/run/names-defaults.scala4
-rw-r--r--test/files/run/pc-conversions.scala2
-rw-r--r--test/files/run/reflection-attachments.check0
-rw-r--r--test/files/run/reflection-java-annotations.check2
-rw-r--r--test/files/run/reflection-magicsymbols-repl.check2
-rw-r--r--test/files/run/repl-javap-app.check39
-rw-r--r--test/files/run/repl-javap-app.scala11
-rw-r--r--test/files/run/repl-power.check4
-rw-r--r--test/files/run/richs.check2
-rw-r--r--test/files/run/search.check4
-rw-r--r--test/files/run/stringinterpolation_macro-run.check4
-rw-r--r--test/files/run/stringinterpolation_macro-run.scala3
-rw-r--r--test/files/run/synchronized.check2
-rw-r--r--test/files/run/t2212.check2
-rw-r--r--test/files/run/t3361.check2
-rw-r--r--test/files/run/t3888.check2
-rw-r--r--test/files/run/t3970.check2
-rw-r--r--test/files/run/t3996.check2
-rw-r--r--test/files/run/t4080.check2
-rw-r--r--test/files/run/t4172.check2
-rw-r--r--test/files/run/t4396.check2
-rw-r--r--test/files/run/t4461.check2
-rw-r--r--test/files/run/t4594-repl-settings.scala2
-rw-r--r--test/files/run/t4680.check2
-rw-r--r--test/files/run/t4710.check2
-rw-r--r--test/files/run/t4813.check2
-rw-r--r--test/files/run/t5428.check2
-rw-r--r--test/files/run/t576.check2
-rw-r--r--test/files/run/t5905-features.scala8
-rw-r--r--test/files/run/t6028.check2
-rw-r--r--test/files/run/t6111.check2
-rw-r--r--test/files/run/t6292.check2
-rw-r--r--test/files/run/t6318_primitives.check54
-rw-r--r--test/files/run/t6318_primitives.scala40
-rw-r--r--test/files/run/t6329_repl.check8
-rw-r--r--test/files/run/t6329_repl_bug.check2
-rw-r--r--test/files/run/t6329_vanilla_bug.check2
-rw-r--r--test/files/run/t6481.check2
-rw-r--r--test/files/run/t6690.check2
-rw-r--r--test/files/run/t6863.check2
-rw-r--r--test/files/run/t6935.check2
-rw-r--r--test/files/run/t7096.scala2
-rw-r--r--test/files/run/t7319.check6
-rw-r--r--test/files/run/t7582.check2
-rw-r--r--test/files/run/t7582b.check2
-rw-r--r--test/files/run/t7932.check2
-rw-r--r--test/files/run/t7974.check29
-rw-r--r--test/files/run/t7974/Test.scala2
-rw-r--r--test/files/run/t8196.check2
-rw-r--r--test/files/run/t8346.check6
-rw-r--r--test/files/run/t8346.scala34
-rw-r--r--test/files/run/t8549.check2
-rw-r--r--test/files/run/t8574.scala27
-rw-r--r--test/files/run/t8601-closure-elim.flags1
-rw-r--r--test/files/run/t8601-closure-elim.scala26
-rw-r--r--test/files/run/t8601.flags1
-rw-r--r--test/files/run/t8601.scala15
-rw-r--r--test/files/run/t8601b.flags1
-rw-r--r--test/files/run/t8601b.scala14
-rw-r--r--test/files/run/t8601c.flags1
-rw-r--r--test/files/run/t8601c.scala12
-rw-r--r--test/files/run/t8601d.flags1
-rw-r--r--test/files/run/t8601d.scala8
-rw-r--r--test/files/run/t8601e.flags1
-rw-r--r--test/files/run/t8601e/StaticInit.classbin0 -> 417 bytes
-rw-r--r--test/files/run/t8601e/StaticInit.java8
-rw-r--r--test/files/run/t8601e/Test.scala12
-rw-r--r--test/files/run/t8607.scala36
-rw-r--r--test/files/run/t8608-no-format.scala15
-rw-r--r--test/files/run/t8611a.flags1
-rw-r--r--test/files/run/t8611a.scala16
-rw-r--r--test/files/run/t8611b.flags1
-rw-r--r--test/files/run/t8611b.scala54
-rw-r--r--test/files/run/t8611c.flags1
-rw-r--r--test/files/run/t8611c.scala21
-rw-r--r--test/files/run/t8637.check0
-rw-r--r--test/files/run/t8637.scala9
-rw-r--r--test/files/run/t8690.check2
-rw-r--r--test/files/run/t8690.scala12
-rw-r--r--test/files/run/t8708_b.check8
-rw-r--r--test/files/run/t8708_b/A_1.scala8
-rw-r--r--test/files/run/t8708_b/Test_2.scala21
-rw-r--r--test/files/run/tailcalls.check8
-rw-r--r--test/files/run/tailcalls.scala35
-rw-r--r--test/files/run/typetags_serialize.check5
-rw-r--r--test/files/run/typetags_serialize.scala5
-rw-r--r--test/files/run/unittest_collection.check2
-rw-r--r--test/files/run/virtpatmat_typetag.check4
-rw-r--r--test/files/scalacheck/quasiquotes/TermConstructionProps.scala12
-rw-r--r--test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala7
-rw-r--r--test/junit/scala/StringContextTest.scala51
-rw-r--r--test/junit/scala/collection/IndexedSeqOptimizedTest.scala16
-rw-r--r--test/junit/scala/collection/IteratorTest.scala28
-rw-r--r--test/junit/scala/reflect/internal/NamesTest.scala95
-rw-r--r--test/junit/scala/reflect/internal/PrintersTest.scala77
-rw-r--r--test/junit/scala/reflect/internal/ScopeTest.scala54
-rw-r--r--test/junit/scala/reflect/internal/TypesTest.scala35
-rw-r--r--test/junit/scala/reflect/internal/util/SourceFileTest.scala5
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala104
-rw-r--r--test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala12
-rw-r--r--test/junit/scala/tools/testing/AssertUtil.scala17
-rw-r--r--test/scaladoc/run/t8672.check4
-rw-r--r--test/scaladoc/run/t8672.scala32
-rw-r--r--versions.properties15
408 files changed, 7931 insertions, 2648 deletions
diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf
index 703c5add42..ffacbf0442 100644
--- a/bincompat-backward.whitelist.conf
+++ b/bincompat-backward.whitelist.conf
@@ -181,6 +181,10 @@ filter {
{
matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticExistentialType"
problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.reflect.runtime.SynchronizedOps.newNestedScope"
+ problemName=MissingMethodProblem
}
]
}
diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf
index ca8f7468eb..0b90cf4c8b 100644
--- a/bincompat-forward.whitelist.conf
+++ b/bincompat-forward.whitelist.conf
@@ -230,6 +230,47 @@ filter {
{
matchName="scala.reflect.runtime.JavaMirrors#JavaMirror.scala$reflect$runtime$JavaMirrors$JavaMirror$$followStatic"
problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.reflect.runtime.SynchronizedOps.newNestedScope"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.reflect.runtime.JavaUniverse"
+ problemName=MissingTypesProblem
+ },
+ {
+ matchName="scala.reflect.runtime.JavaUniverse.reporter"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.reflect.runtime.JavaUniverse$PerRunReporting"
+ problemName=MissingClassProblem
+ },
+ {
+ matchName="scala.reflect.runtime.JavaUniverse.currentRun"
+ problemName=MissingMethodProblem
+ },
+ {
+ 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
}
]
}
diff --git a/build-ant-macros.xml b/build-ant-macros.xml
index bd0e723b9b..609f106d09 100644
--- a/build-ant-macros.xml
+++ b/build-ant-macros.xml
@@ -467,6 +467,11 @@
<filter token="SCALA_FULL_VERSION" value="${scala.full.version}"/>
<filter token="SCALA_COMPILER_DOC_VERSION" value="${scala-compiler-doc.version.number}"/>
<filter token="SCALA_COMPILER_INTERACTIVE_VERSION" value="${scala-compiler-interactive.version.number}"/>
+ <filter token="XML_VERSION" value="${scala-xml.version.number}" />
+ <filter token="PARSER_COMBINATORS_VERSION" value="${scala-parser-combinators.version.number}" />
+ <filter token="CONTINUATIONS_PLUGIN_VERSION" value="${scala-continuations-plugin.version.number}" />
+ <filter token="CONTINUATIONS_LIBRARY_VERSION" value="${scala-continuations-library.version.number}" />
+ <filter token="SCALA_SWING_VERSION" value="${scala-swing.version.number}" />
</filterset>
</copy>
<bnd classpath="${@{project}.jar}" eclipse="false" failok="false" exceptions="true" files="${build-osgi.dir}/${@{project}.name}.bnd" output="${build-osgi.dir}"/>
diff --git a/build.number b/build.number
index 63a55339b9..4a0898529e 100644
--- a/build.number
+++ b/build.number
@@ -1,7 +1,7 @@
#Tue Sep 11 19:21:09 CEST 2007
version.major=2
version.minor=11
-version.patch=1
+version.patch=2
# This is the -N part of a version. if it's 0, it's dropped from maven versions.
version.bnum=0
diff --git a/build.xml b/build.xml
index ed12eb06d2..a89e694ac2 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"/>
@@ -1357,20 +1355,24 @@ TODO:
</target>
<target name="test.osgi" depends="test.osgi.comp">
- <stopwatch name="test.osgi.timer"/>
- <mkdir dir="${test.osgi.classes}"/>
-
- <echo message="Running OSGi JUnit tests. Output in ${build-osgi.dir}"/>
- <junit fork="yes" haltonfailure="yes">
- <classpath refid="test.osgi.compiler.build.path"/>
- <batchtest fork="yes" todir="${build-osgi.dir}">
- <fileset dir="${test.osgi.classes}">
- <include name="**/*Test.class"/>
- </fileset>
- </batchtest>
- <formatter type="xml" /> <!-- silenced by having it use a file; I tried for an hour to use other formatters but classpath issues drove me to this usefile="false" -->
- </junit>
- <stopwatch name="test.osgi.timer" action="total"/>
+ <if><isset property="has.java8"/><then>
+ <echo message="Skipping OSGi JUnit tests on Java 8. See SI-8642"/>
+ </then><else>
+ <echo message="Running OSGi JUnit tests. Output in ${build-osgi.dir}"/>
+ <stopwatch name="test.osgi.timer"/>
+ <mkdir dir="${test.osgi.classes}"/>
+
+ <junit fork="yes" haltonfailure="yes">
+ <classpath refid="test.osgi.compiler.build.path"/>
+ <batchtest fork="yes" todir="${build-osgi.dir}">
+ <fileset dir="${test.osgi.classes}">
+ <include name="**/*Test.class"/>
+ </fileset>
+ </batchtest>
+ <formatter type="xml" /> <!-- silenced by having it use a file; I tried for an hour to use other formatters but classpath issues drove me to this usefile="false" -->
+ </junit>
+ <stopwatch name="test.osgi.timer" action="total"/>
+ </else></if>
</target>
diff --git a/src/asm/README b/src/asm/README
new file mode 100644
index 0000000000..3ceac88098
--- /dev/null
+++ b/src/asm/README
@@ -0,0 +1,30 @@
+Version 5.0.2, SVN r1741, tags/ASM_5_0_2
+
+Git SVN repo: https://github.com/lrytz/asm
+ - git svn howto: https://github.com/lrytz/asm/issues/1
+
+Upgrading ASM
+-------------
+
+Start by deleting all source files in src/asm/ and copy the ones from the latest ASM release.
+
+Excluded Files (don't copy):
+ - package.html files
+ - org/objectweb/asm/commons
+ - org/objectweb/asm/optimizer
+ - org/objectweb/asm/xml
+
+Re-packaging and cosmetic changes:
+ - convert line endings (there are some CRLF)
+ find src/asm/scala/tools/asm -name '*.java' | xargs dos2unix
+ - change package clauses
+ find src/asm/scala/tools/asm -name '*.java' | xargs sed -i '' -e 's/package org\.objectweb\.asm/package scala.tools.asm/'
+ - update imports
+ find src/asm/scala/tools/asm -name '*.java' | xargs sed -i '' -e 's/import org\.objectweb\.asm/import scala.tools.asm/'
+ - update @links, @associates
+ find src/asm/scala/tools/asm -name '*.java' | xargs sed -i '' -e 's/@link org\.objectweb\.asm/@link scala.tools.asm/'
+ find src/asm/scala/tools/asm -name '*.java' | xargs sed -i '' -e 's/@associates org\.objectweb\.asm/@associates scala.tools.asm/'
+ - remove trailing whitespace
+ find src/asm/scala/tools/asm -name '*.java' | xargs sed -i '' -e 's/[ ]*$//'
+
+Actual changes: check the git log for [asm-cherry-pick] after the previous upgrade.
diff --git a/src/asm/scala/tools/asm/AnnotationVisitor.java b/src/asm/scala/tools/asm/AnnotationVisitor.java
index c806ca71e8..abcaf1d6d1 100644
--- a/src/asm/scala/tools/asm/AnnotationVisitor.java
+++ b/src/asm/scala/tools/asm/AnnotationVisitor.java
@@ -41,7 +41,7 @@ public abstract class AnnotationVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
- * must be one of {@link Opcodes#ASM4}.
+ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
protected final int api;
@@ -56,7 +56,7 @@ public abstract class AnnotationVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public AnnotationVisitor(final int api) {
this(api, null);
@@ -67,13 +67,13 @@ public abstract class AnnotationVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param av
* the annotation visitor to which this visitor must delegate
* method calls. May be null.
*/
public AnnotationVisitor(final int api, final AnnotationVisitor av) {
- if (api != Opcodes.ASM4) {
+ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
diff --git a/src/asm/scala/tools/asm/AnnotationWriter.java b/src/asm/scala/tools/asm/AnnotationWriter.java
index 8eb5b2ef48..6de74ce041 100644
--- a/src/asm/scala/tools/asm/AnnotationWriter.java
+++ b/src/asm/scala/tools/asm/AnnotationWriter.java
@@ -104,7 +104,7 @@ final class AnnotationWriter extends AnnotationVisitor {
*/
AnnotationWriter(final ClassWriter cw, final boolean named,
final ByteVector bv, final ByteVector parent, final int offset) {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
this.cw = cw;
this.named = named;
this.bv = bv;
@@ -315,4 +315,57 @@ final class AnnotationWriter extends AnnotationVisitor {
}
}
}
+
+ /**
+ * Puts the given type reference and type path into the given bytevector.
+ * LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
+ *
+ * @param typeRef
+ * a reference to the annotated type. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param out
+ * where the type reference and type path must be put.
+ */
+ static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
+ switch (typeRef >>> 24) {
+ case 0x00: // CLASS_TYPE_PARAMETER
+ case 0x01: // METHOD_TYPE_PARAMETER
+ case 0x16: // METHOD_FORMAL_PARAMETER
+ out.putShort(typeRef >>> 16);
+ break;
+ case 0x13: // FIELD
+ case 0x14: // METHOD_RETURN
+ case 0x15: // METHOD_RECEIVER
+ out.putByte(typeRef >>> 24);
+ break;
+ case 0x47: // CAST
+ case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
+ case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
+ out.putInt(typeRef);
+ break;
+ // case 0x10: // CLASS_EXTENDS
+ // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
+ // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
+ // case 0x17: // THROWS
+ // case 0x42: // EXCEPTION_PARAMETER
+ // case 0x43: // INSTANCEOF
+ // case 0x44: // NEW
+ // case 0x45: // CONSTRUCTOR_REFERENCE
+ // case 0x46: // METHOD_REFERENCE
+ default:
+ out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
+ break;
+ }
+ if (typePath == null) {
+ out.putByte(0);
+ } else {
+ int length = typePath.b[typePath.offset] * 2 + 1;
+ out.putByteArray(typePath.b, typePath.offset, length);
+ }
+ }
}
diff --git a/src/asm/scala/tools/asm/ByteVector.java b/src/asm/scala/tools/asm/ByteVector.java
index 2bc63eb384..3bca7af12a 100644
--- a/src/asm/scala/tools/asm/ByteVector.java
+++ b/src/asm/scala/tools/asm/ByteVector.java
@@ -204,11 +204,14 @@ public class ByteVector {
* automatically enlarged if necessary.
*
* @param s
- * a String.
+ * a String whose UTF8 encoded length must be less than 65536.
* @return this byte vector.
*/
public ByteVector putUTF8(final String s) {
int charLength = s.length();
+ if (charLength > 65535) {
+ throw new IllegalArgumentException();
+ }
int len = length;
if (len + 2 + charLength > data.length) {
enlarge(2 + charLength);
@@ -227,38 +230,68 @@ public class ByteVector {
if (c >= '\001' && c <= '\177') {
data[len++] = (byte) c;
} else {
- int byteLength = i;
- for (int j = i; j < charLength; ++j) {
- c = s.charAt(j);
- if (c >= '\001' && c <= '\177') {
- byteLength++;
- } else if (c > '\u07FF') {
- byteLength += 3;
- } else {
- byteLength += 2;
- }
- }
- data[length] = (byte) (byteLength >>> 8);
- data[length + 1] = (byte) byteLength;
- if (length + 2 + byteLength > data.length) {
- length = len;
- enlarge(2 + byteLength);
- data = this.data;
- }
- for (int j = i; j < charLength; ++j) {
- c = s.charAt(j);
- if (c >= '\001' && c <= '\177') {
- data[len++] = (byte) c;
- } else if (c > '\u07FF') {
- data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
- data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
- data[len++] = (byte) (0x80 | c & 0x3F);
- } else {
- data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
- data[len++] = (byte) (0x80 | c & 0x3F);
- }
- }
- break;
+ length = len;
+ return encodeUTF8(s, i, 65535);
+ }
+ }
+ length = len;
+ return this;
+ }
+
+ /**
+ * Puts an UTF8 string into this byte vector. The byte vector is
+ * automatically enlarged if necessary. The string length is encoded in two
+ * bytes before the encoded characters, if there is space for that (i.e. if
+ * this.length - i - 2 >= 0).
+ *
+ * @param s
+ * the String to encode.
+ * @param i
+ * the index of the first character to encode. The previous
+ * characters are supposed to have already been encoded, using
+ * only one byte per character.
+ * @param maxByteLength
+ * the maximum byte length of the encoded string, including the
+ * already encoded characters.
+ * @return this byte vector.
+ */
+ ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
+ int charLength = s.length();
+ int byteLength = i;
+ char c;
+ for (int j = i; j < charLength; ++j) {
+ c = s.charAt(j);
+ if (c >= '\001' && c <= '\177') {
+ byteLength++;
+ } else if (c > '\u07FF') {
+ byteLength += 3;
+ } else {
+ byteLength += 2;
+ }
+ }
+ if (byteLength > maxByteLength) {
+ throw new IllegalArgumentException();
+ }
+ int start = length - i - 2;
+ if (start >= 0) {
+ data[start] = (byte) (byteLength >>> 8);
+ data[start + 1] = (byte) byteLength;
+ }
+ if (length + byteLength - i > data.length) {
+ enlarge(byteLength - i);
+ }
+ int len = length;
+ for (int j = i; j < charLength; ++j) {
+ c = s.charAt(j);
+ if (c >= '\001' && c <= '\177') {
+ data[len++] = (byte) c;
+ } else if (c > '\u07FF') {
+ data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
+ data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
+ data[len++] = (byte) (0x80 | c & 0x3F);
+ } else {
+ data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
+ data[len++] = (byte) (0x80 | c & 0x3F);
}
}
length = len;
diff --git a/src/asm/scala/tools/asm/ClassReader.java b/src/asm/scala/tools/asm/ClassReader.java
index cc655c1b62..8b0e12cb04 100644
--- a/src/asm/scala/tools/asm/ClassReader.java
+++ b/src/asm/scala/tools/asm/ClassReader.java
@@ -166,7 +166,7 @@ public class ClassReader {
public ClassReader(final byte[] b, final int off, final int len) {
this.b = b;
// checks the class version
- if (readShort(off + 6) > Opcodes.V1_7) {
+ if (readShort(off + 6) > Opcodes.V1_8) {
throw new IllegalArgumentException();
}
// parses the constant pool
@@ -557,6 +557,8 @@ public class ClassReader {
String enclosingDesc = null;
int anns = 0;
int ianns = 0;
+ int tanns = 0;
+ int itanns = 0;
int innerClasses = 0;
Attribute attributes = null;
@@ -581,6 +583,9 @@ public class ClassReader {
} else if (ANNOTATIONS
&& "RuntimeVisibleAnnotations".equals(attrName)) {
anns = u + 8;
+ } else if (ANNOTATIONS
+ && "RuntimeVisibleTypeAnnotations".equals(attrName)) {
+ tanns = u + 8;
} else if ("Deprecated".equals(attrName)) {
access |= Opcodes.ACC_DEPRECATED;
} else if ("Synthetic".equals(attrName)) {
@@ -592,6 +597,9 @@ public class ClassReader {
} else if (ANNOTATIONS
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
ianns = u + 8;
+ } else if (ANNOTATIONS
+ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
+ itanns = u + 8;
} else if ("BootstrapMethods".equals(attrName)) {
int[] bootstrapMethods = new int[readUnsignedShort(u + 8)];
for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) {
@@ -626,7 +634,7 @@ public class ClassReader {
enclosingDesc);
}
- // visits the class annotations
+ // visits the class annotations and type annotations
if (ANNOTATIONS && anns != 0) {
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
@@ -639,6 +647,22 @@ public class ClassReader {
classVisitor.visitAnnotation(readUTF8(v, c), false));
}
}
+ if (ANNOTATIONS && tanns != 0) {
+ for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(v + 2, c, true,
+ classVisitor.visitTypeAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), true));
+ }
+ }
+ if (ANNOTATIONS && itanns != 0) {
+ for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(v + 2, c, true,
+ classVisitor.visitTypeAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), false));
+ }
+ }
// visits the attributes
while (attributes != null) {
@@ -697,6 +721,8 @@ public class ClassReader {
String signature = null;
int anns = 0;
int ianns = 0;
+ int tanns = 0;
+ int itanns = 0;
Object value = null;
Attribute attributes = null;
@@ -718,8 +744,14 @@ public class ClassReader {
&& "RuntimeVisibleAnnotations".equals(attrName)) {
anns = u + 8;
} else if (ANNOTATIONS
+ && "RuntimeVisibleTypeAnnotations".equals(attrName)) {
+ tanns = u + 8;
+ } else if (ANNOTATIONS
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
ianns = u + 8;
+ } else if (ANNOTATIONS
+ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
+ itanns = u + 8;
} else {
Attribute attr = readAttribute(context.attrs, attrName, u + 8,
readInt(u + 4), c, -1, null);
@@ -739,7 +771,7 @@ public class ClassReader {
return u;
}
- // visits the field annotations
+ // visits the field annotations and type annotations
if (ANNOTATIONS && anns != 0) {
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
@@ -752,6 +784,22 @@ public class ClassReader {
fv.visitAnnotation(readUTF8(v, c), false));
}
}
+ if (ANNOTATIONS && tanns != 0) {
+ for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(v + 2, c, true,
+ fv.visitTypeAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), true));
+ }
+ }
+ if (ANNOTATIONS && itanns != 0) {
+ for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(v + 2, c, true,
+ fv.visitTypeAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), false));
+ }
+ }
// visits the field attributes
while (attributes != null) {
@@ -782,9 +830,9 @@ public class ClassReader {
final Context context, int u) {
// reads the method declaration
char[] c = context.buffer;
- int access = readUnsignedShort(u);
- String name = readUTF8(u + 2, c);
- String desc = readUTF8(u + 4, c);
+ context.access = readUnsignedShort(u);
+ context.name = readUTF8(u + 2, c);
+ context.desc = readUTF8(u + 4, c);
u += 6;
// reads the method attributes
@@ -792,8 +840,11 @@ public class ClassReader {
int exception = 0;
String[] exceptions = null;
String signature = null;
+ int methodParameters = 0;
int anns = 0;
int ianns = 0;
+ int tanns = 0;
+ int itanns = 0;
int dann = 0;
int mpanns = 0;
int impanns = 0;
@@ -818,24 +869,32 @@ public class ClassReader {
} else if (SIGNATURES && "Signature".equals(attrName)) {
signature = readUTF8(u + 8, c);
} else if ("Deprecated".equals(attrName)) {
- access |= Opcodes.ACC_DEPRECATED;
+ context.access |= Opcodes.ACC_DEPRECATED;
} else if (ANNOTATIONS
&& "RuntimeVisibleAnnotations".equals(attrName)) {
anns = u + 8;
+ } else if (ANNOTATIONS
+ && "RuntimeVisibleTypeAnnotations".equals(attrName)) {
+ tanns = u + 8;
} else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) {
dann = u + 8;
} else if ("Synthetic".equals(attrName)) {
- access |= Opcodes.ACC_SYNTHETIC
+ context.access |= Opcodes.ACC_SYNTHETIC
| ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
} else if (ANNOTATIONS
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
ianns = u + 8;
} else if (ANNOTATIONS
+ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
+ itanns = u + 8;
+ } else if (ANNOTATIONS
&& "RuntimeVisibleParameterAnnotations".equals(attrName)) {
mpanns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeInvisibleParameterAnnotations".equals(attrName)) {
impanns = u + 8;
+ } else if ("MethodParameters".equals(attrName)) {
+ methodParameters = u + 8;
} else {
Attribute attr = readAttribute(context.attrs, attrName, u + 8,
readInt(u + 4), c, -1, null);
@@ -849,8 +908,8 @@ public class ClassReader {
u += 2;
// visits the method declaration
- MethodVisitor mv = classVisitor.visitMethod(access, name, desc,
- signature, exceptions);
+ MethodVisitor mv = classVisitor.visitMethod(context.access,
+ context.name, context.desc, signature, exceptions);
if (mv == null) {
return u;
}
@@ -894,6 +953,13 @@ public class ClassReader {
}
}
+ // visit the method parameters
+ if (methodParameters != 0) {
+ for (int i = b[methodParameters] & 0xFF, v = methodParameters + 1; i > 0; --i, v = v + 4) {
+ mv.visitParameter(readUTF8(v, c), readUnsignedShort(v + 2));
+ }
+ }
+
// visits the method annotations
if (ANNOTATIONS && dann != 0) {
AnnotationVisitor dv = mv.visitAnnotationDefault();
@@ -914,11 +980,27 @@ public class ClassReader {
mv.visitAnnotation(readUTF8(v, c), false));
}
}
+ if (ANNOTATIONS && tanns != 0) {
+ for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(v + 2, c, true,
+ mv.visitTypeAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), true));
+ }
+ }
+ if (ANNOTATIONS && itanns != 0) {
+ for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(v + 2, c, true,
+ mv.visitTypeAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), false));
+ }
+ }
if (ANNOTATIONS && mpanns != 0) {
- readParameterAnnotations(mpanns, desc, c, true, mv);
+ readParameterAnnotations(mv, context, mpanns, true);
}
if (ANNOTATIONS && impanns != 0) {
- readParameterAnnotations(impanns, desc, c, false, mv);
+ readParameterAnnotations(mv, context, impanns, false);
}
// visits the method attributes
@@ -931,9 +1013,6 @@ public class ClassReader {
// visits the method code
if (code != 0) {
- context.access = access;
- context.name = name;
- context.desc = desc;
mv.visitCode();
readCode(mv, context, code);
}
@@ -966,7 +1045,7 @@ public class ClassReader {
// reads the bytecode to find the labels
int codeStart = u;
int codeEnd = u + codeLength;
- Label[] labels = new Label[codeLength + 2];
+ Label[] labels = context.labels = new Label[codeLength + 2];
readLabel(codeLength + 1, labels);
while (u < codeEnd) {
int offset = u - codeStart;
@@ -1049,6 +1128,12 @@ public class ClassReader {
u += 2;
// reads the code attributes
+ int[] tanns = null; // start index of each visible type annotation
+ int[] itanns = null; // start index of each invisible type annotation
+ int tann = 0; // current index in tanns array
+ int itann = 0; // current index in itanns array
+ int ntoff = -1; // next visible type annotation code offset
+ int nitoff = -1; // next invisible type annotation code offset
int varTable = 0;
int varTypeTable = 0;
boolean zip = true;
@@ -1089,6 +1174,16 @@ public class ClassReader {
v += 4;
}
}
+ } else if (ANNOTATIONS
+ && "RuntimeVisibleTypeAnnotations".equals(attrName)) {
+ tanns = readTypeAnnotations(mv, context, u + 8, true);
+ ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1
+ : readUnsignedShort(tanns[0] + 1);
+ } else if (ANNOTATIONS
+ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
+ itanns = readTypeAnnotations(mv, context, u + 8, false);
+ nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1
+ : readUnsignedShort(itanns[0] + 1);
} else if (FRAMES && "StackMapTable".equals(attrName)) {
if ((context.flags & SKIP_FRAMES) == 0) {
stackMap = u + 10;
@@ -1211,7 +1306,7 @@ public class ClassReader {
}
}
if (frameCount > 0) {
- stackMap = readFrame(stackMap, zip, unzip, labels, frame);
+ stackMap = readFrame(stackMap, zip, unzip, frame);
--frameCount;
} else {
frame = null;
@@ -1310,6 +1405,7 @@ public class ClassReader {
case ClassWriter.FIELDORMETH_INSN:
case ClassWriter.ITFMETH_INSN: {
int cpIndex = items[readUnsignedShort(u + 1)];
+ boolean itf = b[cpIndex - 1] == ClassWriter.IMETH;
String iowner = readClass(cpIndex, c);
cpIndex = items[readUnsignedShort(cpIndex + 2)];
String iname = readUTF8(cpIndex, c);
@@ -1317,7 +1413,7 @@ public class ClassReader {
if (opcode < Opcodes.INVOKEVIRTUAL) {
mv.visitFieldInsn(opcode, iowner, iname, idesc);
} else {
- mv.visitMethodInsn(opcode, iowner, iname, idesc);
+ mv.visitMethodInsn(opcode, iowner, iname, idesc, itf);
}
if (opcode == Opcodes.INVOKEINTERFACE) {
u += 5;
@@ -1358,6 +1454,29 @@ public class ClassReader {
u += 4;
break;
}
+
+ // visit the instruction annotations, if any
+ while (tanns != null && tann < tanns.length && ntoff <= offset) {
+ if (ntoff == offset) {
+ int v = readAnnotationTarget(context, tanns[tann]);
+ readAnnotationValues(v + 2, c, true,
+ mv.visitInsnAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), true));
+ }
+ ntoff = ++tann >= tanns.length || readByte(tanns[tann]) < 0x43 ? -1
+ : readUnsignedShort(tanns[tann] + 1);
+ }
+ while (itanns != null && itann < itanns.length && nitoff <= offset) {
+ if (nitoff == offset) {
+ int v = readAnnotationTarget(context, itanns[itann]);
+ readAnnotationValues(v + 2, c, true,
+ mv.visitInsnAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), false));
+ }
+ nitoff = ++itann >= itanns.length
+ || readByte(itanns[itann]) < 0x43 ? -1
+ : readUnsignedShort(itanns[itann] + 1);
+ }
}
if (labels[codeLength] != null) {
mv.visitLabel(labels[codeLength]);
@@ -1397,6 +1516,32 @@ public class ClassReader {
}
}
+ // visits the local variables type annotations
+ if (tanns != null) {
+ for (int i = 0; i < tanns.length; ++i) {
+ if ((readByte(tanns[i]) >> 1) == (0x40 >> 1)) {
+ int v = readAnnotationTarget(context, tanns[i]);
+ v = readAnnotationValues(v + 2, c, true,
+ mv.visitLocalVariableAnnotation(context.typeRef,
+ context.typePath, context.start,
+ context.end, context.index, readUTF8(v, c),
+ true));
+ }
+ }
+ }
+ if (itanns != null) {
+ for (int i = 0; i < itanns.length; ++i) {
+ if ((readByte(itanns[i]) >> 1) == (0x40 >> 1)) {
+ int v = readAnnotationTarget(context, itanns[i]);
+ v = readAnnotationValues(v + 2, c, true,
+ mv.visitLocalVariableAnnotation(context.typeRef,
+ context.typePath, context.start,
+ context.end, context.index, readUTF8(v, c),
+ false));
+ }
+ }
+ }
+
// visits the code attributes
while (attributes != null) {
Attribute attr = attributes.next;
@@ -1410,24 +1555,175 @@ public class ClassReader {
}
/**
+ * Parses a type annotation table to find the labels, and to visit the try
+ * catch block annotations.
+ *
+ * @param u
+ * the start offset of a type annotation table.
+ * @param mv
+ * the method visitor to be used to visit the try catch block
+ * annotations.
+ * @param context
+ * information about the class being parsed.
+ * @param visible
+ * if the type annotation table to parse contains runtime visible
+ * annotations.
+ * @return the start offset of each type annotation in the parsed table.
+ */
+ private int[] readTypeAnnotations(final MethodVisitor mv,
+ final Context context, int u, boolean visible) {
+ char[] c = context.buffer;
+ int[] offsets = new int[readUnsignedShort(u)];
+ u += 2;
+ for (int i = 0; i < offsets.length; ++i) {
+ offsets[i] = u;
+ int target = readInt(u);
+ switch (target >>> 24) {
+ case 0x00: // CLASS_TYPE_PARAMETER
+ case 0x01: // METHOD_TYPE_PARAMETER
+ case 0x16: // METHOD_FORMAL_PARAMETER
+ u += 2;
+ break;
+ case 0x13: // FIELD
+ case 0x14: // METHOD_RETURN
+ case 0x15: // METHOD_RECEIVER
+ u += 1;
+ break;
+ case 0x40: // LOCAL_VARIABLE
+ case 0x41: // RESOURCE_VARIABLE
+ for (int j = readUnsignedShort(u + 1); j > 0; --j) {
+ int start = readUnsignedShort(u + 3);
+ int length = readUnsignedShort(u + 5);
+ readLabel(start, context.labels);
+ readLabel(start + length, context.labels);
+ u += 6;
+ }
+ u += 3;
+ break;
+ case 0x47: // CAST
+ case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
+ case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
+ u += 4;
+ break;
+ // case 0x10: // CLASS_EXTENDS
+ // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
+ // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
+ // case 0x17: // THROWS
+ // case 0x42: // EXCEPTION_PARAMETER
+ // case 0x43: // INSTANCEOF
+ // case 0x44: // NEW
+ // case 0x45: // CONSTRUCTOR_REFERENCE
+ // case 0x46: // METHOD_REFERENCE
+ default:
+ u += 3;
+ break;
+ }
+ int pathLength = readByte(u);
+ if ((target >>> 24) == 0x42) {
+ TypePath path = pathLength == 0 ? null : new TypePath(b, u);
+ u += 1 + 2 * pathLength;
+ u = readAnnotationValues(u + 2, c, true,
+ mv.visitTryCatchAnnotation(target, path,
+ readUTF8(u, c), visible));
+ } else {
+ u = readAnnotationValues(u + 3 + 2 * pathLength, c, true, null);
+ }
+ }
+ return offsets;
+ }
+
+ /**
+ * Parses the header of a type annotation to extract its target_type and
+ * target_path (the result is stored in the given context), and returns the
+ * start offset of the rest of the type_annotation structure (i.e. the
+ * offset to the type_index field, which is followed by
+ * num_element_value_pairs and then the name,value pairs).
+ *
+ * @param context
+ * information about the class being parsed. This is where the
+ * extracted target_type and target_path must be stored.
+ * @param u
+ * the start offset of a type_annotation structure.
+ * @return the start offset of the rest of the type_annotation structure.
+ */
+ private int readAnnotationTarget(final Context context, int u) {
+ int target = readInt(u);
+ switch (target >>> 24) {
+ case 0x00: // CLASS_TYPE_PARAMETER
+ case 0x01: // METHOD_TYPE_PARAMETER
+ case 0x16: // METHOD_FORMAL_PARAMETER
+ target &= 0xFFFF0000;
+ u += 2;
+ break;
+ case 0x13: // FIELD
+ case 0x14: // METHOD_RETURN
+ case 0x15: // METHOD_RECEIVER
+ target &= 0xFF000000;
+ u += 1;
+ break;
+ case 0x40: // LOCAL_VARIABLE
+ case 0x41: { // RESOURCE_VARIABLE
+ target &= 0xFF000000;
+ int n = readUnsignedShort(u + 1);
+ context.start = new Label[n];
+ context.end = new Label[n];
+ context.index = new int[n];
+ u += 3;
+ for (int i = 0; i < n; ++i) {
+ int start = readUnsignedShort(u);
+ int length = readUnsignedShort(u + 2);
+ context.start[i] = readLabel(start, context.labels);
+ context.end[i] = readLabel(start + length, context.labels);
+ context.index[i] = readUnsignedShort(u + 4);
+ u += 6;
+ }
+ break;
+ }
+ case 0x47: // CAST
+ case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
+ case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
+ target &= 0xFF0000FF;
+ u += 4;
+ break;
+ // case 0x10: // CLASS_EXTENDS
+ // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
+ // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
+ // case 0x17: // THROWS
+ // case 0x42: // EXCEPTION_PARAMETER
+ // case 0x43: // INSTANCEOF
+ // case 0x44: // NEW
+ // case 0x45: // CONSTRUCTOR_REFERENCE
+ // case 0x46: // METHOD_REFERENCE
+ default:
+ target &= (target >>> 24) < 0x43 ? 0xFFFFFF00 : 0xFF000000;
+ u += 3;
+ break;
+ }
+ int pathLength = readByte(u);
+ context.typeRef = target;
+ context.typePath = pathLength == 0 ? null : new TypePath(b, u);
+ return u + 1 + 2 * pathLength;
+ }
+
+ /**
* Reads parameter annotations and makes the given visitor visit them.
*
+ * @param mv
+ * the visitor that must visit the annotations.
+ * @param context
+ * information about the class being parsed.
* @param v
* start offset in {@link #b b} of the annotations to be read.
- * @param desc
- * the method descriptor.
- * @param buf
- * buffer to be used to call {@link #readUTF8 readUTF8},
- * {@link #readClass(int,char[]) readClass} or {@link #readConst
- * readConst}.
* @param visible
* <tt>true</tt> if the annotations to be read are visible at
* runtime.
- * @param mv
- * the visitor that must visit the annotations.
*/
- private void readParameterAnnotations(int v, final String desc,
- final char[] buf, final boolean visible, final MethodVisitor mv) {
+ private void readParameterAnnotations(final MethodVisitor mv,
+ final Context context, int v, final boolean visible) {
int i;
int n = b[v++] & 0xFF;
// workaround for a bug in javac (javac compiler generates a parameter
@@ -1436,7 +1732,7 @@ public class ClassReader {
// equal to the number of parameters in the method descriptor - which
// includes the synthetic parameters added by the compiler). This work-
// around supposes that the synthetic parameters are the first ones.
- int synthetics = Type.getArgumentTypes(desc).length - n;
+ int synthetics = Type.getArgumentTypes(context.desc).length - n;
AnnotationVisitor av;
for (i = 0; i < synthetics; ++i) {
// virtual annotation to detect synthetic parameters in MethodWriter
@@ -1445,12 +1741,13 @@ public class ClassReader {
av.visitEnd();
}
}
+ char[] c = context.buffer;
for (; i < n + synthetics; ++i) {
int j = readUnsignedShort(v);
v += 2;
for (; j > 0; --j) {
- av = mv.visitParameterAnnotation(i, readUTF8(v, buf), visible);
- v = readAnnotationValues(v + 2, buf, true, av);
+ av = mv.visitParameterAnnotation(i, readUTF8(v, c), visible);
+ v = readAnnotationValues(v + 2, c, true, av);
}
}
}
@@ -1729,17 +2026,14 @@ public class ClassReader {
* if the stack map frame at stackMap is compressed or not.
* @param unzip
* if the stack map frame must be uncompressed.
- * @param labels
- * the labels of the method currently being parsed, indexed by
- * their offset. A new label for the parsed stack map frame is
- * stored in this array if it does not already exist.
* @param frame
* where the parsed stack map frame must be stored.
* @return the offset of the first byte following the parsed frame.
*/
private int readFrame(int stackMap, boolean zip, boolean unzip,
- Label[] labels, Context frame) {
+ Context frame) {
char[] c = frame.buffer;
+ Label[] labels = frame.labels;
int tag;
int delta;
if (zip) {
diff --git a/src/asm/scala/tools/asm/ClassVisitor.java b/src/asm/scala/tools/asm/ClassVisitor.java
index 3fc364d5e5..48dc2ca6ae 100644
--- a/src/asm/scala/tools/asm/ClassVisitor.java
+++ b/src/asm/scala/tools/asm/ClassVisitor.java
@@ -33,8 +33,9 @@ package scala.tools.asm;
* A visitor to visit a Java class. The methods of this class must be called in
* the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [
* <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> |
- * <tt>visitAttribute</tt> )* ( <tt>visitInnerClass</tt> | <tt>visitField</tt> |
- * <tt>visitMethod</tt> )* <tt>visitEnd</tt>.
+ * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* (
+ * <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )*
+ * <tt>visitEnd</tt>.
*
* @author Eric Bruneton
*/
@@ -42,7 +43,7 @@ public abstract class ClassVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
- * must be one of {@link Opcodes#ASM4}.
+ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
protected final int api;
@@ -57,7 +58,7 @@ public abstract class ClassVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public ClassVisitor(final int api) {
this(api, null);
@@ -68,13 +69,13 @@ public abstract class ClassVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param cv
* the class visitor to which this visitor must delegate method
* calls. May be null.
*/
public ClassVisitor(final int api, final ClassVisitor cv) {
- if (api != Opcodes.ASM4) {
+ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
@@ -169,6 +170,39 @@ public abstract class ClassVisitor {
}
/**
+ * Visits an annotation on a type in the class signature.
+ *
+ * @param typeRef
+ * a reference to the annotated type. The sort of this type
+ * reference must be {@link TypeReference#CLASS_TYPE_PARAMETER
+ * CLASS_TYPE_PARAMETER},
+ * {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND
+ * CLASS_TYPE_PARAMETER_BOUND} or
+ * {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See
+ * {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if
+ * this visitor is not interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ if (api < Opcodes.ASM5) {
+ throw new RuntimeException();
+ }
+ if (cv != null) {
+ return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+ return null;
+ }
+
+ /**
* Visits a non standard attribute of the class.
*
* @param attr
diff --git a/src/asm/scala/tools/asm/ClassWriter.java b/src/asm/scala/tools/asm/ClassWriter.java
index 93ed7313c7..5c2de3f982 100644
--- a/src/asm/scala/tools/asm/ClassWriter.java
+++ b/src/asm/scala/tools/asm/ClassWriter.java
@@ -417,6 +417,16 @@ public class ClassWriter extends ClassVisitor {
private AnnotationWriter ianns;
/**
+ * The runtime visible type annotations of this class.
+ */
+ private AnnotationWriter tanns;
+
+ /**
+ * The runtime invisible type annotations of this class.
+ */
+ private AnnotationWriter itanns;
+
+ /**
* The non standard attributes of this class.
*/
private Attribute attrs;
@@ -477,12 +487,12 @@ public class ClassWriter extends ClassVisitor {
* <tt>true</tt> if the maximum stack size and number of local variables
* must be automatically computed.
*/
- private final boolean computeMaxs;
+ private boolean computeMaxs;
/**
* <tt>true</tt> if the stack map frames must be recomputed from scratch.
*/
- private final boolean computeFrames;
+ private boolean computeFrames;
/**
* <tt>true</tt> if the stack map tables of this class are invalid. The
@@ -595,7 +605,7 @@ public class ClassWriter extends ClassVisitor {
* {@link #COMPUTE_FRAMES}.
*/
public ClassWriter(final int flags) {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
index = 1;
pool = new ByteVector();
items = new Item[256];
@@ -677,7 +687,8 @@ public class ClassWriter extends ClassVisitor {
sourceFile = newUTF8(file);
}
if (debug != null) {
- sourceDebug = new ByteVector().putUTF8(debug);
+ sourceDebug = new ByteVector().encodeUTF8(debug, 0,
+ Integer.MAX_VALUE);
}
}
@@ -711,6 +722,29 @@ public class ClassWriter extends ClassVisitor {
}
@Override
+ public final AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, final String desc, final boolean visible) {
+ if (!ClassReader.ANNOTATIONS) {
+ return null;
+ }
+ ByteVector bv = new ByteVector();
+ // write target_type and target_info
+ AnnotationWriter.putTarget(typeRef, typePath, bv);
+ // write type, and reserve space for values count
+ bv.putShort(newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv,
+ bv.length - 2);
+ if (visible) {
+ aw.next = tanns;
+ tanns = aw;
+ } else {
+ aw.next = itanns;
+ itanns = aw;
+ }
+ return aw;
+ }
+
+ @Override
public final void visitAttribute(final Attribute attr) {
attr.next = attrs;
attrs = attr;
@@ -722,11 +756,29 @@ public class ClassWriter extends ClassVisitor {
if (innerClasses == null) {
innerClasses = new ByteVector();
}
- ++innerClassesCount;
- innerClasses.putShort(name == null ? 0 : newClass(name));
- innerClasses.putShort(outerName == null ? 0 : newClass(outerName));
- innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));
- innerClasses.putShort(access);
+ // Sec. 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the
+ // constant_pool table which represents a class or interface C that is
+ // not a package member must have exactly one corresponding entry in the
+ // classes array". To avoid duplicates we keep track in the intVal field
+ // of the Item of each CONSTANT_Class_info entry C whether an inner
+ // class entry has already been added for C (this field is unused for
+ // class entries, and changing its value does not change the hashcode
+ // and equality tests). If so we store the index of this inner class
+ // entry (plus one) in intVal. This hack allows duplicate detection in
+ // O(1) time.
+ Item nameItem = newClassItem(name);
+ if (nameItem.intVal == 0) {
+ ++innerClassesCount;
+ innerClasses.putShort(nameItem.index);
+ innerClasses.putShort(outerName == null ? 0 : newClass(outerName));
+ innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));
+ innerClasses.putShort(access);
+ nameItem.intVal = innerClassesCount;
+ } else {
+ // Compare the inner classes entry nameItem.intVal - 1 with the
+ // arguments of this method and throw an exception if there is a
+ // difference?
+ }
}
@Override
@@ -795,7 +847,7 @@ public class ClassWriter extends ClassVisitor {
}
if (sourceDebug != null) {
++attributeCount;
- size += sourceDebug.length + 4;
+ size += sourceDebug.length + 6;
newUTF8("SourceDebugExtension");
}
if (enclosingMethodOwner != 0) {
@@ -831,6 +883,16 @@ public class ClassWriter extends ClassVisitor {
size += 8 + ianns.getSize();
newUTF8("RuntimeInvisibleAnnotations");
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ ++attributeCount;
+ size += 8 + tanns.getSize();
+ newUTF8("RuntimeVisibleTypeAnnotations");
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ ++attributeCount;
+ size += 8 + itanns.getSize();
+ newUTF8("RuntimeInvisibleTypeAnnotations");
+ }
if (attrs != null) {
attributeCount += attrs.getCount();
size += attrs.getSize(this, null, 0, -1, -1);
@@ -874,9 +936,9 @@ public class ClassWriter extends ClassVisitor {
out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile);
}
if (sourceDebug != null) {
- int len = sourceDebug.length - 2;
+ int len = sourceDebug.length;
out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
- out.putByteArray(sourceDebug.data, 2, len);
+ out.putByteArray(sourceDebug.data, 0, len);
}
if (enclosingMethodOwner != 0) {
out.putShort(newUTF8("EnclosingMethod")).putInt(4);
@@ -904,13 +966,34 @@ public class ClassWriter extends ClassVisitor {
out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out);
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ out.putShort(newUTF8("RuntimeVisibleTypeAnnotations"));
+ tanns.put(out);
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations"));
+ itanns.put(out);
+ }
if (attrs != null) {
attrs.put(this, null, 0, -1, -1, out);
}
if (invalidFrames) {
- ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
- new ClassReader(out.data).accept(cw, ClassReader.SKIP_FRAMES);
- return cw.toByteArray();
+ anns = null;
+ ianns = null;
+ attrs = null;
+ innerClassesCount = 0;
+ innerClasses = null;
+ bootstrapMethodsCount = 0;
+ bootstrapMethods = null;
+ firstField = null;
+ lastField = null;
+ firstMethod = null;
+ lastMethod = null;
+ computeMaxs = false;
+ computeFrames = true;
+ invalidFrames = false;
+ new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES);
+ return toByteArray();
}
return out.data;
}
@@ -1577,7 +1660,7 @@ public class ClassWriter extends ClassVisitor {
/**
* Returns the common super type of the two given types. The default
- * implementation of this method <i>loads<i> the two given classes and uses
+ * implementation of this method <i>loads</i> the two given classes and uses
* the java.lang.Class methods to find the common super class. It can be
* overridden to compute this common super type in other ways, in particular
* without actually loading any class, or to take into account the class
@@ -1664,6 +1747,15 @@ public class ClassWriter extends ClassVisitor {
}
/**
+ * Find item that whose index is `index`.
+ */
+ public Item findItemByIndex(int index) {
+ int i = 0;
+ while (i < items.length && (items[i] == null || items[i].index != index)) i++;
+ return items[i];
+ }
+
+ /**
* Puts one byte and two shorts into the constant pool.
*
* @param b
diff --git a/src/asm/scala/tools/asm/Context.java b/src/asm/scala/tools/asm/Context.java
index 7b3a2ad9dd..24546969e3 100644
--- a/src/asm/scala/tools/asm/Context.java
+++ b/src/asm/scala/tools/asm/Context.java
@@ -73,11 +73,46 @@ class Context {
String desc;
/**
+ * The label objects, indexed by bytecode offset, of the method currently
+ * being parsed (only bytecode offsets for which a label is needed have a
+ * non null associated Label object).
+ */
+ Label[] labels;
+
+ /**
+ * The target of the type annotation currently being parsed.
+ */
+ int typeRef;
+
+ /**
+ * The path of the type annotation currently being parsed.
+ */
+ TypePath typePath;
+
+ /**
* The offset of the latest stack map frame that has been parsed.
*/
int offset;
/**
+ * The labels corresponding to the start of the local variable ranges in the
+ * local variable type annotation currently being parsed.
+ */
+ Label[] start;
+
+ /**
+ * The labels corresponding to the end of the local variable ranges in the
+ * local variable type annotation currently being parsed.
+ */
+ Label[] end;
+
+ /**
+ * The local variable indices for each local variable range in the local
+ * variable type annotation currently being parsed.
+ */
+ int[] index;
+
+ /**
* The encoding of the latest stack map frame that has been parsed.
*/
int mode;
diff --git a/src/asm/scala/tools/asm/CustomAttr.java b/src/asm/scala/tools/asm/CustomAttr.java
index 22b5d287b7..5ecfd283d0 100644
--- a/src/asm/scala/tools/asm/CustomAttr.java
+++ b/src/asm/scala/tools/asm/CustomAttr.java
@@ -1,5 +1,5 @@
/* NSC -- new Scala compiler
- * Copyright 2005-2013 LAMP/EPFL
+ * Copyright 2005-2012 LAMP/EPFL
*/
package scala.tools.asm;
diff --git a/src/asm/scala/tools/asm/FieldVisitor.java b/src/asm/scala/tools/asm/FieldVisitor.java
index 9171f331e5..708c1d322e 100644
--- a/src/asm/scala/tools/asm/FieldVisitor.java
+++ b/src/asm/scala/tools/asm/FieldVisitor.java
@@ -31,8 +31,8 @@ package scala.tools.asm;
/**
* A visitor to visit a Java field. The methods of this class must be called in
- * the following order: ( <tt>visitAnnotation</tt> | <tt>visitAttribute</tt> )*
- * <tt>visitEnd</tt>.
+ * the following order: ( <tt>visitAnnotation</tt> |
+ * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* <tt>visitEnd</tt>.
*
* @author Eric Bruneton
*/
@@ -40,7 +40,7 @@ public abstract class FieldVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
- * must be one of {@link Opcodes#ASM4}.
+ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
protected final int api;
@@ -55,7 +55,7 @@ public abstract class FieldVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public FieldVisitor(final int api) {
this(api, null);
@@ -66,13 +66,13 @@ public abstract class FieldVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param fv
* the field visitor to which this visitor must delegate method
* calls. May be null.
*/
public FieldVisitor(final int api, final FieldVisitor fv) {
- if (api != Opcodes.ASM4) {
+ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
@@ -97,6 +97,35 @@ public abstract class FieldVisitor {
}
/**
+ * Visits an annotation on the type of the field.
+ *
+ * @param typeRef
+ * a reference to the annotated type. The sort of this type
+ * reference must be {@link TypeReference#FIELD FIELD}. See
+ * {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if
+ * this visitor is not interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ if (api < Opcodes.ASM5) {
+ throw new RuntimeException();
+ }
+ if (fv != null) {
+ return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+ return null;
+ }
+
+ /**
* Visits a non standard attribute of the field.
*
* @param attr
diff --git a/src/asm/scala/tools/asm/FieldWriter.java b/src/asm/scala/tools/asm/FieldWriter.java
index 02c6059b91..e640a8d406 100644
--- a/src/asm/scala/tools/asm/FieldWriter.java
+++ b/src/asm/scala/tools/asm/FieldWriter.java
@@ -81,6 +81,17 @@ final class FieldWriter extends FieldVisitor {
private AnnotationWriter ianns;
/**
+ * The runtime visible type annotations of this field. May be <tt>null</tt>.
+ */
+ private AnnotationWriter tanns;
+
+ /**
+ * The runtime invisible type annotations of this field. May be
+ * <tt>null</tt>.
+ */
+ private AnnotationWriter itanns;
+
+ /**
* The non standard attributes of this field. May be <tt>null</tt>.
*/
private Attribute attrs;
@@ -107,7 +118,7 @@ final class FieldWriter extends FieldVisitor {
*/
FieldWriter(final ClassWriter cw, final int access, final String name,
final String desc, final String signature, final Object value) {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
if (cw.firstField == null) {
cw.firstField = this;
} else {
@@ -151,6 +162,29 @@ final class FieldWriter extends FieldVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ if (!ClassReader.ANNOTATIONS) {
+ return null;
+ }
+ ByteVector bv = new ByteVector();
+ // write target_type and target_info
+ AnnotationWriter.putTarget(typeRef, typePath, bv);
+ // write type, and reserve space for values count
+ bv.putShort(cw.newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
+ bv.length - 2);
+ if (visible) {
+ aw.next = tanns;
+ tanns = aw;
+ } else {
+ aw.next = itanns;
+ itanns = aw;
+ }
+ return aw;
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
attr.next = attrs;
attrs = attr;
@@ -198,6 +232,14 @@ final class FieldWriter extends FieldVisitor {
cw.newUTF8("RuntimeInvisibleAnnotations");
size += 8 + ianns.getSize();
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ cw.newUTF8("RuntimeVisibleTypeAnnotations");
+ size += 8 + tanns.getSize();
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ cw.newUTF8("RuntimeInvisibleTypeAnnotations");
+ size += 8 + itanns.getSize();
+ }
if (attrs != null) {
size += attrs.getSize(cw, null, 0, -1, -1);
}
@@ -237,6 +279,12 @@ final class FieldWriter extends FieldVisitor {
if (ClassReader.ANNOTATIONS && ianns != null) {
++attributeCount;
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ ++attributeCount;
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ ++attributeCount;
+ }
if (attrs != null) {
attributeCount += attrs.getCount();
}
@@ -266,6 +314,14 @@ final class FieldWriter extends FieldVisitor {
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out);
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
+ tanns.put(out);
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
+ itanns.put(out);
+ }
if (attrs != null) {
attrs.put(cw, null, 0, -1, -1, out);
}
diff --git a/src/asm/scala/tools/asm/Frame.java b/src/asm/scala/tools/asm/Frame.java
index bcc3e8450b..85ad3269ab 100644
--- a/src/asm/scala/tools/asm/Frame.java
+++ b/src/asm/scala/tools/asm/Frame.java
@@ -70,8 +70,8 @@ final class Frame {
* stack types. VALUE depends on KIND. For LOCAL types, it is an index in
* the input local variable types. For STACK types, it is a position
* relatively to the top of input frame stack. For BASE types, it is either
- * one of the constants defined in FrameVisitor, or for OBJECT and
- * UNINITIALIZED types, a tag and an index in the type table.
+ * one of the constants defined below, or for OBJECT and UNINITIALIZED
+ * types, a tag and an index in the type table.
*
* Output frames can contain types of any kind and with a positive or
* negative dimension (and even unassigned types, represented by 0 - which
@@ -1417,6 +1417,7 @@ final class Frame {
// if t is the NULL type, merge(u,t)=u, so there is no change
return false;
} else if ((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND))) {
+ // if t and u have the same dimension and same base kind
if ((u & BASE_KIND) == OBJECT) {
// if t is also a reference type, and if u and t have the
// same dimension merge(u,t) = dim(t) | common parent of the
@@ -1425,13 +1426,21 @@ final class Frame {
| cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE);
} else {
// if u and t are array types, but not with the same element
- // type, merge(u,t)=java/lang/Object
- v = OBJECT | cw.addType("java/lang/Object");
+ // type, merge(u,t) = dim(u) - 1 | java/lang/Object
+ int vdim = ELEMENT_OF + (u & DIM);
+ v = vdim | OBJECT | cw.addType("java/lang/Object");
}
} else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) {
- // if t is any other reference or array type,
- // merge(u,t)=java/lang/Object
- v = OBJECT | cw.addType("java/lang/Object");
+ // if t is any other reference or array type, the merged type
+ // is min(udim, tdim) | java/lang/Object, where udim is the
+ // array dimension of u, minus 1 if u is an array type with a
+ // primitive element type (and similarly for tdim).
+ int tdim = (((t & DIM) == 0 || (t & BASE_KIND) == OBJECT) ? 0
+ : ELEMENT_OF) + (t & DIM);
+ int udim = (((u & DIM) == 0 || (u & BASE_KIND) == OBJECT) ? 0
+ : ELEMENT_OF) + (u & DIM);
+ v = Math.min(tdim, udim) | OBJECT
+ | cw.addType("java/lang/Object");
} else {
// if t is any other type, merge(u,t)=TOP
v = TOP;
diff --git a/src/asm/scala/tools/asm/Handle.java b/src/asm/scala/tools/asm/Handle.java
index 5dd06a54b9..cf12bb7613 100644
--- a/src/asm/scala/tools/asm/Handle.java
+++ b/src/asm/scala/tools/asm/Handle.java
@@ -49,7 +49,8 @@ public final class Handle {
final int tag;
/**
- * The internal name of the field or method designed by this handle.
+ * The internal name of the class that owns the field or method designated
+ * by this handle.
*/
final String owner;
@@ -76,8 +77,8 @@ public final class Handle {
* {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner
- * the internal name of the field or method designed by this
- * handle.
+ * the internal name of the class that owns the field or method
+ * designated by this handle.
* @param name
* the name of the field or method designated by this handle.
* @param desc
@@ -106,9 +107,11 @@ public final class Handle {
}
/**
- * Returns the internal name of the field or method designed by this handle.
+ * Returns the internal name of the class that owns the field or method
+ * designated by this handle.
*
- * @return the internal name of the field or method designed by this handle.
+ * @return the internal name of the class that owns the field or method
+ * designated by this handle.
*/
public String getOwner() {
return owner;
diff --git a/src/asm/scala/tools/asm/Item.java b/src/asm/scala/tools/asm/Item.java
index 94195a1082..4693f5ae99 100644
--- a/src/asm/scala/tools/asm/Item.java
+++ b/src/asm/scala/tools/asm/Item.java
@@ -208,9 +208,10 @@ final class Item {
this.strVal2 = strVal2;
this.strVal3 = strVal3;
switch (type) {
+ case ClassWriter.CLASS:
+ this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
case ClassWriter.UTF8:
case ClassWriter.STR:
- case ClassWriter.CLASS:
case ClassWriter.MTYPE:
case ClassWriter.TYPE_NORMAL:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
diff --git a/src/asm/scala/tools/asm/MethodVisitor.java b/src/asm/scala/tools/asm/MethodVisitor.java
index e43ca97823..bddc325020 100644
--- a/src/asm/scala/tools/asm/MethodVisitor.java
+++ b/src/asm/scala/tools/asm/MethodVisitor.java
@@ -31,18 +31,24 @@ package scala.tools.asm;
/**
* A visitor to visit a Java method. The methods of this class must be called in
- * the following order: [ <tt>visitAnnotationDefault</tt> ] (
- * <tt>visitAnnotation</tt> | <tt>visitParameterAnnotation</tt> |
- * <tt>visitAttribute</tt> )* [ <tt>visitCode</tt> ( <tt>visitFrame</tt> |
- * <tt>visit</tt><i>X</i>Insn</tt> | <tt>visitLabel</tt> |
- * <tt>visitTryCatchBlock</tt> | <tt>visitLocalVariable</tt> |
+ * the following order: ( <tt>visitParameter</tt> )* [
+ * <tt>visitAnnotationDefault</tt> ] ( <tt>visitAnnotation</tt> |
+ * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* [
+ * <tt>visitCode</tt> ( <tt>visitFrame</tt> | <tt>visit<i>X</i>Insn</tt> |
+ * <tt>visitLabel</tt> | <tt>visitInsnAnnotation</tt> |
+ * <tt>visitTryCatchBlock</tt> | <tt>visitTryCatchBlockAnnotation</tt> |
+ * <tt>visitLocalVariable</tt> | <tt>visitLocalVariableAnnotation</tt> |
* <tt>visitLineNumber</tt> )* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In
- * addition, the <tt>visit</tt><i>X</i>Insn</tt> and <tt>visitLabel</tt> methods
- * must be called in the sequential order of the bytecode instructions of the
- * visited code, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the
- * labels passed as arguments have been visited, and the
- * <tt>visitLocalVariable</tt> and <tt>visitLineNumber</tt> methods must be
- * called <i>after</i> the labels passed as arguments have been visited.
+ * addition, the <tt>visit<i>X</i>Insn</tt> and <tt>visitLabel</tt> methods must
+ * be called in the sequential order of the bytecode instructions of the visited
+ * code, <tt>visitInsnAnnotation</tt> must be called <i>after</i> the annotated
+ * instruction, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the
+ * labels passed as arguments have been visited,
+ * <tt>visitTryCatchBlockAnnotation</tt> must be called <i>after</i> the
+ * corresponding try catch block has been visited, and the
+ * <tt>visitLocalVariable</tt>, <tt>visitLocalVariableAnnotation</tt> and
+ * <tt>visitLineNumber</tt> methods must be called <i>after</i> the labels
+ * passed as arguments have been visited.
*
* @author Eric Bruneton
*/
@@ -50,7 +56,7 @@ public abstract class MethodVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
- * must be one of {@link Opcodes#ASM4}.
+ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
protected final int api;
@@ -65,7 +71,7 @@ public abstract class MethodVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public MethodVisitor(final int api) {
this(api, null);
@@ -76,13 +82,13 @@ public abstract class MethodVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param mv
* the method visitor to which this visitor must delegate method
* calls. May be null.
*/
public MethodVisitor(final int api, final MethodVisitor mv) {
- if (api != Opcodes.ASM4) {
+ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
@@ -90,10 +96,29 @@ public abstract class MethodVisitor {
}
// -------------------------------------------------------------------------
- // Annotations and non standard attributes
+ // Parameters, annotations and non standard attributes
// -------------------------------------------------------------------------
/**
+ * Visits a parameter of this method.
+ *
+ * @param name
+ * parameter name or null if none is provided.
+ * @param access
+ * the parameter's access flags, only <tt>ACC_FINAL</tt>,
+ * <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are
+ * allowed (see {@link Opcodes}).
+ */
+ public void visitParameter(String name, int access) {
+ if (api < Opcodes.ASM5) {
+ throw new RuntimeException();
+ }
+ if (mv != null) {
+ mv.visitParameter(name, access);
+ }
+ }
+
+ /**
* Visits the default value of this annotation interface method.
*
* @return a visitor to the visit the actual default value of this
@@ -128,6 +153,42 @@ public abstract class MethodVisitor {
}
/**
+ * Visits an annotation on a type in the method signature.
+ *
+ * @param typeRef
+ * a reference to the annotated type. The sort of this type
+ * reference must be {@link TypeReference#METHOD_TYPE_PARAMETER
+ * METHOD_TYPE_PARAMETER},
+ * {@link TypeReference#METHOD_TYPE_PARAMETER_BOUND
+ * METHOD_TYPE_PARAMETER_BOUND},
+ * {@link TypeReference#METHOD_RETURN METHOD_RETURN},
+ * {@link TypeReference#METHOD_RECEIVER METHOD_RECEIVER},
+ * {@link TypeReference#METHOD_FORMAL_PARAMETER
+ * METHOD_FORMAL_PARAMETER} or {@link TypeReference#THROWS
+ * THROWS}. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if
+ * this visitor is not interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ if (api < Opcodes.ASM5) {
+ throw new RuntimeException();
+ }
+ if (mv != null) {
+ return mv.visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+ return null;
+ }
+
+ /**
* Visits an annotation of a parameter this method.
*
* @param parameter
@@ -201,9 +262,11 @@ public abstract class MethodVisitor {
* <li>{@link Opcodes#F_CHOP} representing frame with current locals are the
* same as the locals in the previous frame, except that the last 1-3 locals
* are absent and with the empty stack (<code>nLocals</code> is 1, 2 or 3).</li>
- * <li>{@link Opcodes#F_FULL} representing complete frame data.</li></li>
+ * <li>{@link Opcodes#F_FULL} representing complete frame data.</li>
+ * </ul>
+ * </li>
* </ul>
- * </ul> <br>
+ * <br>
* In both cases the first frame, corresponding to the method's parameters
* and access flags, is implicit and must not be visited. Also, it is
* illegal to visit two or more frames for the same code location (i.e., at
@@ -376,14 +439,53 @@ public abstract class MethodVisitor {
* @param desc
* the method's descriptor (see {@link Type Type}).
*/
+ @Deprecated
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
+ if (api >= Opcodes.ASM5) {
+ boolean itf = opcode == Opcodes.INVOKEINTERFACE;
+ visitMethodInsn(opcode, owner, name, desc, itf);
+ return;
+ }
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc);
}
}
/**
+ * Visits a method instruction. A method instruction is an instruction that
+ * invokes a method.
+ *
+ * @param opcode
+ * the opcode of the type instruction to be visited. This opcode
+ * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
+ * INVOKEINTERFACE.
+ * @param owner
+ * the internal name of the method's owner class (see
+ * {@link Type#getInternalName() getInternalName}).
+ * @param name
+ * the method's name.
+ * @param desc
+ * the method's descriptor (see {@link Type Type}).
+ * @param itf
+ * if the method's owner class is an interface.
+ */
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc, boolean itf) {
+ if (api < Opcodes.ASM5) {
+ if (itf != (opcode == Opcodes.INVOKEINTERFACE)) {
+ throw new IllegalArgumentException(
+ "INVOKESPECIAL/STATIC on interfaces require ASM 5");
+ }
+ visitMethodInsn(opcode, owner, name, desc);
+ return;
+ }
+ if (mv != null) {
+ mv.visitMethodInsn(opcode, owner, name, desc, itf);
+ }
+ }
+
+ /**
* Visits an invokedynamic instruction.
*
* @param name
@@ -558,6 +660,48 @@ public abstract class MethodVisitor {
}
}
+ /**
+ * Visits an annotation on an instruction. This method must be called just
+ * <i>after</i> the annotated instruction. It can be called several times
+ * for the same instruction.
+ *
+ * @param typeRef
+ * a reference to the annotated type. The sort of this type
+ * reference must be {@link TypeReference#INSTANCEOF INSTANCEOF},
+ * {@link TypeReference#NEW NEW},
+ * {@link TypeReference#CONSTRUCTOR_REFERENCE
+ * CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE
+ * METHOD_REFERENCE}, {@link TypeReference#CAST CAST},
+ * {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
+ * {@link TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT
+ * METHOD_INVOCATION_TYPE_ARGUMENT},
+ * {@link TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
+ * {@link TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT
+ * METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if
+ * this visitor is not interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitInsnAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ if (api < Opcodes.ASM5) {
+ throw new RuntimeException();
+ }
+ if (mv != null) {
+ return mv.visitInsnAnnotation(typeRef, typePath, desc, visible);
+ }
+ return null;
+ }
+
// -------------------------------------------------------------------------
// Exceptions table entries, debug information, max stack and max locals
// -------------------------------------------------------------------------
@@ -587,6 +731,38 @@ public abstract class MethodVisitor {
}
/**
+ * Visits an annotation on an exception handler type. This method must be
+ * called <i>after</i> the {@link #visitTryCatchBlock} for the annotated
+ * exception handler. It can be called several times for the same exception
+ * handler.
+ *
+ * @param typeRef
+ * a reference to the annotated type. The sort of this type
+ * reference must be {@link TypeReference#EXCEPTION_PARAMETER
+ * EXCEPTION_PARAMETER}. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if
+ * this visitor is not interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ if (api < Opcodes.ASM5) {
+ throw new RuntimeException();
+ }
+ if (mv != null) {
+ return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
+ }
+ return null;
+ }
+
+ /**
* Visits a local variable declaration.
*
* @param name
@@ -617,6 +793,48 @@ public abstract class MethodVisitor {
}
/**
+ * Visits an annotation on a local variable type.
+ *
+ * @param typeRef
+ * a reference to the annotated type. The sort of this type
+ * reference must be {@link TypeReference#LOCAL_VARIABLE
+ * LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE
+ * RESOURCE_VARIABLE}. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param start
+ * the fist instructions corresponding to the continuous ranges
+ * that make the scope of this local variable (inclusive).
+ * @param end
+ * the last instructions corresponding to the continuous ranges
+ * that make the scope of this local variable (exclusive). This
+ * array must have the same size as the 'start' array.
+ * @param index
+ * the local variable's index in each range. This array must have
+ * the same size as the 'start' array.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if
+ * this visitor is not interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
+ TypePath typePath, Label[] start, Label[] end, int[] index,
+ String desc, boolean visible) {
+ if (api < Opcodes.ASM5) {
+ throw new RuntimeException();
+ }
+ if (mv != null) {
+ return mv.visitLocalVariableAnnotation(typeRef, typePath, start,
+ end, index, desc, visible);
+ }
+ return null;
+ }
+
+ /**
* Visits a line number declaration.
*
* @param line
diff --git a/src/asm/scala/tools/asm/MethodWriter.java b/src/asm/scala/tools/asm/MethodWriter.java
index 87acab17c9..0c4130e499 100644
--- a/src/asm/scala/tools/asm/MethodWriter.java
+++ b/src/asm/scala/tools/asm/MethodWriter.java
@@ -192,6 +192,18 @@ class MethodWriter extends MethodVisitor {
private AnnotationWriter ianns;
/**
+ * The runtime visible type annotations of this method. May be <tt>null</tt>
+ * .
+ */
+ private AnnotationWriter tanns;
+
+ /**
+ * The runtime invisible type annotations of this method. May be
+ * <tt>null</tt>.
+ */
+ private AnnotationWriter itanns;
+
+ /**
* The runtime visible parameter annotations of this method. May be
* <tt>null</tt>.
*/
@@ -283,6 +295,16 @@ class MethodWriter extends MethodVisitor {
private Handler lastHandler;
/**
+ * Number of entries in the MethodParameters attribute.
+ */
+ private int methodParametersCount;
+
+ /**
+ * The MethodParameters attribute.
+ */
+ private ByteVector methodParameters;
+
+ /**
* Number of entries in the LocalVariableTable attribute.
*/
private int localVarCount;
@@ -313,6 +335,21 @@ class MethodWriter extends MethodVisitor {
private ByteVector lineNumber;
/**
+ * The start offset of the last visited instruction.
+ */
+ private int lastCodeOffset;
+
+ /**
+ * The runtime visible type annotations of the code. May be <tt>null</tt>.
+ */
+ private AnnotationWriter ctanns;
+
+ /**
+ * The runtime invisible type annotations of the code. May be <tt>null</tt>.
+ */
+ private AnnotationWriter ictanns;
+
+ /**
* The non standard attributes of the method's code.
*/
private Attribute cattrs;
@@ -416,7 +453,7 @@ class MethodWriter extends MethodVisitor {
final String desc, final String signature,
final String[] exceptions, final boolean computeMaxs,
final boolean computeFrames) {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
if (cw.firstMethod == null) {
cw.firstMethod = this;
} else {
@@ -462,6 +499,16 @@ class MethodWriter extends MethodVisitor {
// ------------------------------------------------------------------------
@Override
+ public void visitParameter(String name, int access) {
+ if (methodParameters == null) {
+ methodParameters = new ByteVector();
+ }
+ ++methodParametersCount;
+ methodParameters.putShort((name == null) ? 0 : cw.newUTF8(name))
+ .putShort(access);
+ }
+
+ @Override
public AnnotationVisitor visitAnnotationDefault() {
if (!ClassReader.ANNOTATIONS) {
return null;
@@ -491,6 +538,29 @@ class MethodWriter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ if (!ClassReader.ANNOTATIONS) {
+ return null;
+ }
+ ByteVector bv = new ByteVector();
+ // write target_type and target_info
+ AnnotationWriter.putTarget(typeRef, typePath, bv);
+ // write type, and reserve space for values count
+ bv.putShort(cw.newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
+ bv.length - 2);
+ if (visible) {
+ aw.next = tanns;
+ tanns = aw;
+ } else {
+ aw.next = itanns;
+ itanns = aw;
+ }
+ return aw;
+ }
+
+ @Override
public AnnotationVisitor visitParameterAnnotation(final int parameter,
final String desc, final boolean visible) {
if (!ClassReader.ANNOTATIONS) {
@@ -642,6 +712,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitInsn(final int opcode) {
+ lastCodeOffset = code.length;
// adds the instruction to the bytecode of the method
code.putByte(opcode);
// update currentBlock
@@ -667,6 +738,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitIntInsn(final int opcode, final int operand) {
+ lastCodeOffset = code.length;
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
if (compute == FRAMES) {
@@ -691,6 +763,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitVarInsn(final int opcode, final int var) {
+ lastCodeOffset = code.length;
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
if (compute == FRAMES) {
@@ -749,6 +822,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitTypeInsn(final int opcode, final String type) {
+ lastCodeOffset = code.length;
Item i = cw.newClassItem(type);
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
@@ -771,6 +845,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitFieldInsn(final int opcode, final String owner,
final String name, final String desc) {
+ lastCodeOffset = code.length;
Item i = cw.newFieldItem(owner, name, desc);
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
@@ -808,8 +883,8 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitMethodInsn(final int opcode, final String owner,
- final String name, final String desc) {
- boolean itf = opcode == Opcodes.INVOKEINTERFACE;
+ final String name, final String desc, final boolean itf) {
+ lastCodeOffset = code.length;
Item i = cw.newMethodItem(owner, name, desc, itf);
int argSize = i.intVal;
// Label currentBlock = this.currentBlock;
@@ -847,7 +922,7 @@ class MethodWriter extends MethodVisitor {
}
}
// adds the instruction to the bytecode of the method
- if (itf) {
+ if (opcode == Opcodes.INVOKEINTERFACE) {
if (argSize == 0) {
argSize = Type.getArgumentsAndReturnSizes(desc);
i.intVal = argSize;
@@ -861,6 +936,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitInvokeDynamicInsn(final String name, final String desc,
final Handle bsm, final Object... bsmArgs) {
+ lastCodeOffset = code.length;
Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs);
int argSize = i.intVal;
// Label currentBlock = this.currentBlock;
@@ -900,6 +976,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitJumpInsn(final int opcode, final Label label) {
+ lastCodeOffset = code.length;
Label nextInsn = null;
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
@@ -1045,6 +1122,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitLdcInsn(final Object cst) {
+ lastCodeOffset = code.length;
Item i = cw.newConstItem(cst);
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
@@ -1078,6 +1156,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitIincInsn(final int var, final int increment) {
+ lastCodeOffset = code.length;
if (currentBlock != null) {
if (compute == FRAMES) {
currentBlock.frame.execute(Opcodes.IINC, var, null, null);
@@ -1102,6 +1181,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitTableSwitchInsn(final int min, final int max,
final Label dflt, final Label... labels) {
+ lastCodeOffset = code.length;
// adds the instruction to the bytecode of the method
int source = code.length;
code.putByte(Opcodes.TABLESWITCH);
@@ -1118,6 +1198,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
final Label[] labels) {
+ lastCodeOffset = code.length;
// adds the instruction to the bytecode of the method
int source = code.length;
code.putByte(Opcodes.LOOKUPSWITCH);
@@ -1160,6 +1241,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
+ lastCodeOffset = code.length;
Item i = cw.newClassItem(desc);
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
@@ -1176,6 +1258,30 @@ class MethodWriter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitInsnAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ if (!ClassReader.ANNOTATIONS) {
+ return null;
+ }
+ ByteVector bv = new ByteVector();
+ // write target_type and target_info
+ typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8);
+ AnnotationWriter.putTarget(typeRef, typePath, bv);
+ // write type, and reserve space for values count
+ bv.putShort(cw.newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
+ bv.length - 2);
+ if (visible) {
+ aw.next = ctanns;
+ ctanns = aw;
+ } else {
+ aw.next = ictanns;
+ ictanns = aw;
+ }
+ return aw;
+ }
+
+ @Override
public void visitTryCatchBlock(final Label start, final Label end,
final Label handler, final String type) {
++handlerCount;
@@ -1194,6 +1300,29 @@ class MethodWriter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ if (!ClassReader.ANNOTATIONS) {
+ return null;
+ }
+ ByteVector bv = new ByteVector();
+ // write target_type and target_info
+ AnnotationWriter.putTarget(typeRef, typePath, bv);
+ // write type, and reserve space for values count
+ bv.putShort(cw.newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
+ bv.length - 2);
+ if (visible) {
+ aw.next = ctanns;
+ ctanns = aw;
+ } else {
+ aw.next = ictanns;
+ ictanns = aw;
+ }
+ return aw;
+ }
+
+ @Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
final int index) {
@@ -1226,6 +1355,41 @@ class MethodWriter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
+ TypePath typePath, Label[] start, Label[] end, int[] index,
+ String desc, boolean visible) {
+ if (!ClassReader.ANNOTATIONS) {
+ return null;
+ }
+ ByteVector bv = new ByteVector();
+ // write target_type and target_info
+ bv.putByte(typeRef >>> 24).putShort(start.length);
+ for (int i = 0; i < start.length; ++i) {
+ bv.putShort(start[i].position)
+ .putShort(end[i].position - start[i].position)
+ .putShort(index[i]);
+ }
+ if (typePath == null) {
+ bv.putByte(0);
+ } else {
+ int length = typePath.b[typePath.offset] * 2 + 1;
+ bv.putByteArray(typePath.b, typePath.offset, length);
+ }
+ // write type, and reserve space for values count
+ bv.putShort(cw.newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
+ bv.length - 2);
+ if (visible) {
+ aw.next = ctanns;
+ ctanns = aw;
+ } else {
+ aw.next = ictanns;
+ ictanns = aw;
+ }
+ return aw;
+ }
+
+ @Override
public void visitLineNumber(final int line, final Label start) {
if (lineNumber == null) {
lineNumber = new ByteVector();
@@ -1237,6 +1401,14 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitMaxs(final int maxStack, final int maxLocals) {
+ if (resize) {
+ // replaces the temporary jump opcodes introduced by Label.resolve.
+ if (ClassReader.RESIZE) {
+ resizeInstructions();
+ } else {
+ throw new RuntimeException("Method code too large!");
+ }
+ }
if (ClassReader.FRAMES && compute == FRAMES) {
// completes the control flow graph with exception handler blocks
Handler handler = firstHandler;
@@ -1858,22 +2030,12 @@ class MethodWriter extends MethodVisitor {
if (classReaderOffset != 0) {
return 6 + classReaderLength;
}
- if (resize) {
- // replaces the temporary jump opcodes introduced by Label.resolve.
- if (ClassReader.RESIZE) {
- resizeInstructions();
- } else {
- throw new RuntimeException("Method code too large!");
- }
- }
int size = 8;
if (code.length > 0) {
if (code.length > 65536) {
String nameString = "";
- int i = 0;
- // find item that corresponds to the index of our name
- while (i < cw.items.length && (cw.items[i] == null || cw.items[i].index != name)) i++;
- if (cw.items[i] != null) nameString = cw.items[i].strVal1 +"'s ";
+ Item nameItem = cw.findItemByIndex(name);
+ if (nameItem != null) nameString = nameItem.strVal1 +"'s ";
throw new RuntimeException("Method "+ nameString +"code too large!");
}
cw.newUTF8("Code");
@@ -1895,6 +2057,14 @@ class MethodWriter extends MethodVisitor {
cw.newUTF8(zip ? "StackMapTable" : "StackMap");
size += 8 + stackMap.length;
}
+ if (ClassReader.ANNOTATIONS && ctanns != null) {
+ cw.newUTF8("RuntimeVisibleTypeAnnotations");
+ size += 8 + ctanns.getSize();
+ }
+ if (ClassReader.ANNOTATIONS && ictanns != null) {
+ cw.newUTF8("RuntimeInvisibleTypeAnnotations");
+ size += 8 + ictanns.getSize();
+ }
if (cattrs != null) {
size += cattrs.getSize(cw, code.data, code.length, maxStack,
maxLocals);
@@ -1920,6 +2090,10 @@ class MethodWriter extends MethodVisitor {
cw.newUTF8(signature);
size += 8;
}
+ if (methodParameters != null) {
+ cw.newUTF8("MethodParameters");
+ size += 7 + methodParameters.length;
+ }
if (ClassReader.ANNOTATIONS && annd != null) {
cw.newUTF8("AnnotationDefault");
size += 6 + annd.length;
@@ -1932,6 +2106,14 @@ class MethodWriter extends MethodVisitor {
cw.newUTF8("RuntimeInvisibleAnnotations");
size += 8 + ianns.getSize();
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ cw.newUTF8("RuntimeVisibleTypeAnnotations");
+ size += 8 + tanns.getSize();
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ cw.newUTF8("RuntimeInvisibleTypeAnnotations");
+ size += 8 + itanns.getSize();
+ }
if (ClassReader.ANNOTATIONS && panns != null) {
cw.newUTF8("RuntimeVisibleParameterAnnotations");
size += 7 + 2 * (panns.length - synthetics);
@@ -1988,6 +2170,9 @@ class MethodWriter extends MethodVisitor {
if (ClassReader.SIGNATURES && signature != null) {
++attributeCount;
}
+ if (methodParameters != null) {
+ ++attributeCount;
+ }
if (ClassReader.ANNOTATIONS && annd != null) {
++attributeCount;
}
@@ -1997,6 +2182,12 @@ class MethodWriter extends MethodVisitor {
if (ClassReader.ANNOTATIONS && ianns != null) {
++attributeCount;
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ ++attributeCount;
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ ++attributeCount;
+ }
if (ClassReader.ANNOTATIONS && panns != null) {
++attributeCount;
}
@@ -2021,6 +2212,12 @@ class MethodWriter extends MethodVisitor {
if (stackMap != null) {
size += 8 + stackMap.length;
}
+ if (ClassReader.ANNOTATIONS && ctanns != null) {
+ size += 8 + ctanns.getSize();
+ }
+ if (ClassReader.ANNOTATIONS && ictanns != null) {
+ size += 8 + ictanns.getSize();
+ }
if (cattrs != null) {
size += cattrs.getSize(cw, code.data, code.length, maxStack,
maxLocals);
@@ -2050,6 +2247,12 @@ class MethodWriter extends MethodVisitor {
if (stackMap != null) {
++attributeCount;
}
+ if (ClassReader.ANNOTATIONS && ctanns != null) {
+ ++attributeCount;
+ }
+ if (ClassReader.ANNOTATIONS && ictanns != null) {
+ ++attributeCount;
+ }
if (cattrs != null) {
attributeCount += cattrs.getCount();
}
@@ -2075,6 +2278,14 @@ class MethodWriter extends MethodVisitor {
out.putInt(stackMap.length + 2).putShort(frameCount);
out.putByteArray(stackMap.data, 0, stackMap.length);
}
+ if (ClassReader.ANNOTATIONS && ctanns != null) {
+ out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
+ ctanns.put(out);
+ }
+ if (ClassReader.ANNOTATIONS && ictanns != null) {
+ out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
+ ictanns.put(out);
+ }
if (cattrs != null) {
cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
}
@@ -2100,6 +2311,12 @@ class MethodWriter extends MethodVisitor {
out.putShort(cw.newUTF8("Signature")).putInt(2)
.putShort(cw.newUTF8(signature));
}
+ if (methodParameters != null) {
+ out.putShort(cw.newUTF8("MethodParameters"));
+ out.putInt(methodParameters.length + 1).putByte(
+ methodParametersCount);
+ out.putByteArray(methodParameters.data, 0, methodParameters.length);
+ }
if (ClassReader.ANNOTATIONS && annd != null) {
out.putShort(cw.newUTF8("AnnotationDefault"));
out.putInt(annd.length);
@@ -2113,6 +2330,14 @@ class MethodWriter extends MethodVisitor {
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out);
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
+ tanns.put(out);
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
+ itanns.put(out);
+ }
if (ClassReader.ANNOTATIONS && panns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
AnnotationWriter.put(panns, synthetics, out);
@@ -2464,49 +2689,50 @@ class MethodWriter extends MethodVisitor {
}
}
- // recomputes the stack map frames
- if (frameCount > 0) {
- if (compute == FRAMES) {
- frameCount = 0;
- stackMap = null;
- previousFrame = null;
- frame = null;
- Frame f = new Frame();
- f.owner = labels;
- Type[] args = Type.getArgumentTypes(descriptor);
- f.initInputFrame(cw, access, args, maxLocals);
- visitFrame(f);
- Label l = labels;
- while (l != null) {
- /*
- * here we need the original label position. getNewOffset
- * must therefore never have been called for this label.
- */
- u = l.position - 3;
- if ((l.status & Label.STORE) != 0 || (u >= 0 && resize[u])) {
- getNewOffset(allIndexes, allSizes, l);
- // TODO update offsets in UNINITIALIZED values
- visitFrame(l.frame);
- }
- l = l.successor;
- }
- } else {
+ // updates the stack map frame labels
+ if (compute == FRAMES) {
+ Label l = labels;
+ while (l != null) {
/*
- * Resizing an existing stack map frame table is really hard.
- * Not only the table must be parsed to update the offets, but
- * new frames may be needed for jump instructions that were
- * inserted by this method. And updating the offsets or
- * inserting frames can change the format of the following
- * frames, in case of packed frames. In practice the whole table
- * must be recomputed. For this the frames are marked as
- * potentially invalid. This will cause the whole class to be
- * reread and rewritten with the COMPUTE_FRAMES option (see the
- * ClassWriter.toByteArray method). This is not very efficient
- * but is much easier and requires much less code than any other
- * method I can think of.
+ * Detects the labels that are just after an IF instruction that
+ * has been resized with the IFNOT GOTO_W pattern. These labels
+ * are now the target of a jump instruction (the IFNOT
+ * instruction). Note that we need the original label position
+ * here. getNewOffset must therefore never have been called for
+ * this label.
*/
- cw.invalidFrames = true;
+ u = l.position - 3;
+ if (u >= 0 && resize[u]) {
+ l.status |= Label.TARGET;
+ }
+ getNewOffset(allIndexes, allSizes, l);
+ l = l.successor;
}
+ // Update the offsets in the uninitialized types
+ for (i = 0; i < cw.typeTable.length; ++i) {
+ Item item = cw.typeTable[i];
+ if (item != null && item.type == ClassWriter.TYPE_UNINIT) {
+ item.intVal = getNewOffset(allIndexes, allSizes, 0,
+ item.intVal);
+ }
+ }
+ // The stack map frames are not serialized yet, so we don't need
+ // to update them. They will be serialized in visitMaxs.
+ } else if (frameCount > 0) {
+ /*
+ * Resizing an existing stack map frame table is really hard. Not
+ * only the table must be parsed to update the offets, but new
+ * frames may be needed for jump instructions that were inserted by
+ * this method. And updating the offsets or inserting frames can
+ * change the format of the following frames, in case of packed
+ * frames. In practice the whole table must be recomputed. For this
+ * the frames are marked as potentially invalid. This will cause the
+ * whole class to be reread and rewritten with the COMPUTE_FRAMES
+ * option (see the ClassWriter.toByteArray method). This is not very
+ * efficient but is much easier and requires much less code than any
+ * other method I can think of.
+ */
+ cw.invalidFrames = true;
}
// updates the exception handler block labels
Handler h = firstHandler;
diff --git a/src/asm/scala/tools/asm/Opcodes.java b/src/asm/scala/tools/asm/Opcodes.java
index 809e5ae590..24eaffa717 100644
--- a/src/asm/scala/tools/asm/Opcodes.java
+++ b/src/asm/scala/tools/asm/Opcodes.java
@@ -46,6 +46,7 @@ public interface Opcodes {
// ASM API versions
int ASM4 = 4 << 16 | 0 << 8 | 0;
+ int ASM5 = 5 << 16 | 0 << 8 | 0;
// versions
@@ -56,6 +57,7 @@ public interface Opcodes {
int V1_5 = 0 << 16 | 49;
int V1_6 = 0 << 16 | 50;
int V1_7 = 0 << 16 | 51;
+ int V1_8 = 0 << 16 | 52;
// access flags
@@ -63,7 +65,7 @@ public interface Opcodes {
int ACC_PRIVATE = 0x0002; // class, field, method
int ACC_PROTECTED = 0x0004; // class, field, method
int ACC_STATIC = 0x0008; // field, method
- int ACC_FINAL = 0x0010; // class, field, method
+ int ACC_FINAL = 0x0010; // class, field, method, parameter
int ACC_SUPER = 0x0020; // class
int ACC_SYNCHRONIZED = 0x0020; // method
int ACC_VOLATILE = 0x0040; // field
@@ -74,9 +76,10 @@ public interface Opcodes {
int ACC_INTERFACE = 0x0200; // class
int ACC_ABSTRACT = 0x0400; // class, method
int ACC_STRICT = 0x0800; // method
- int ACC_SYNTHETIC = 0x1000; // class, field, method
+ int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter
int ACC_ANNOTATION = 0x2000; // class
int ACC_ENUM = 0x4000; // class(?) field inner
+ int ACC_MANDATED = 0x8000; // parameter
// ASM specific pseudo access flags
diff --git a/src/asm/scala/tools/asm/Type.java b/src/asm/scala/tools/asm/Type.java
index 7821a492e6..7887080dee 100644
--- a/src/asm/scala/tools/asm/Type.java
+++ b/src/asm/scala/tools/asm/Type.java
@@ -401,8 +401,8 @@ public class Type {
* @return the size of the arguments of the method (plus one for the
* implicit this argument), argSize, and the size of its return
* value, retSize, packed into a single int i =
- * <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal to
- * <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>).
+ * <tt>(argSize &lt;&lt; 2) | retSize</tt> (argSize is therefore equal to
+ * <tt>i &gt;&gt; 2</tt>, and retSize to <tt>i &amp; 0x03</tt>).
*/
public static int getArgumentsAndReturnSizes(final String desc) {
int n = 1;
@@ -606,9 +606,10 @@ public class Type {
*
* @return the size of the arguments (plus one for the implicit this
* argument), argSize, and the size of the return value, retSize,
- * packed into a single int i = <tt>(argSize << 2) | retSize</tt>
- * (argSize is therefore equal to <tt>i >> 2</tt>, and retSize to
- * <tt>i & 0x03</tt>).
+ * packed into a single
+ * int i = <tt>(argSize &lt;&lt; 2) | retSize</tt>
+ * (argSize is therefore equal to <tt>i &gt;&gt; 2</tt>,
+ * and retSize to <tt>i &amp; 0x03</tt>).
*/
public int getArgumentsAndReturnSizes() {
return getArgumentsAndReturnSizes(getDescriptor());
diff --git a/src/asm/scala/tools/asm/TypePath.java b/src/asm/scala/tools/asm/TypePath.java
new file mode 100644
index 0000000000..d4c6f0d857
--- /dev/null
+++ b/src/asm/scala/tools/asm/TypePath.java
@@ -0,0 +1,193 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2013 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the copyright holders 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.
+ */
+
+package scala.tools.asm;
+
+/**
+ * The path to a type argument, wildcard bound, array element type, or static
+ * inner type within an enclosing type.
+ *
+ * @author Eric Bruneton
+ */
+public class TypePath {
+
+ /**
+ * A type path step that steps into the element type of an array type. See
+ * {@link #getStep getStep}.
+ */
+ public final static int ARRAY_ELEMENT = 0;
+
+ /**
+ * A type path step that steps into the nested type of a class type. See
+ * {@link #getStep getStep}.
+ */
+ public final static int INNER_TYPE = 1;
+
+ /**
+ * A type path step that steps into the bound of a wildcard type. See
+ * {@link #getStep getStep}.
+ */
+ public final static int WILDCARD_BOUND = 2;
+
+ /**
+ * A type path step that steps into a type argument of a generic type. See
+ * {@link #getStep getStep}.
+ */
+ public final static int TYPE_ARGUMENT = 3;
+
+ /**
+ * The byte array where the path is stored, in Java class file format.
+ */
+ byte[] b;
+
+ /**
+ * The offset of the first byte of the type path in 'b'.
+ */
+ int offset;
+
+ /**
+ * Creates a new type path.
+ *
+ * @param b
+ * the byte array containing the type path in Java class file
+ * format.
+ * @param offset
+ * the offset of the first byte of the type path in 'b'.
+ */
+ TypePath(byte[] b, int offset) {
+ this.b = b;
+ this.offset = offset;
+ }
+
+ /**
+ * Returns the length of this path.
+ *
+ * @return the length of this path.
+ */
+ public int getLength() {
+ return b[offset];
+ }
+
+ /**
+ * Returns the value of the given step of this path.
+ *
+ * @param index
+ * an index between 0 and {@link #getLength()}, exclusive.
+ * @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE
+ * INNER_TYPE}, {@link #WILDCARD_BOUND WILDCARD_BOUND}, or
+ * {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
+ */
+ public int getStep(int index) {
+ return b[offset + 2 * index + 1];
+ }
+
+ /**
+ * Returns the index of the type argument that the given step is stepping
+ * into. This method should only be used for steps whose value is
+ * {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
+ *
+ * @param index
+ * an index between 0 and {@link #getLength()}, exclusive.
+ * @return the index of the type argument that the given step is stepping
+ * into.
+ */
+ public int getStepArgument(int index) {
+ return b[offset + 2 * index + 2];
+ }
+
+ /**
+ * Converts a type path in string form, in the format used by
+ * {@link #toString()}, into a TypePath object.
+ *
+ * @param typePath
+ * a type path in string form, in the format used by
+ * {@link #toString()}. May be null or empty.
+ * @return the corresponding TypePath object, or null if the path is empty.
+ */
+ public static TypePath fromString(final String typePath) {
+ if (typePath == null || typePath.length() == 0) {
+ return null;
+ }
+ int n = typePath.length();
+ ByteVector out = new ByteVector(n);
+ out.putByte(0);
+ for (int i = 0; i < n;) {
+ char c = typePath.charAt(i++);
+ if (c == '[') {
+ out.put11(ARRAY_ELEMENT, 0);
+ } else if (c == '.') {
+ out.put11(INNER_TYPE, 0);
+ } else if (c == '*') {
+ out.put11(WILDCARD_BOUND, 0);
+ } else if (c >= '0' && c <= '9') {
+ int typeArg = c - '0';
+ while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') {
+ typeArg = typeArg * 10 + c - '0';
+ i += 1;
+ }
+ out.put11(TYPE_ARGUMENT, typeArg);
+ }
+ }
+ out.data[0] = (byte) (out.length / 2);
+ return new TypePath(out.data, 0);
+ }
+
+ /**
+ * Returns a string representation of this type path. {@link #ARRAY_ELEMENT
+ * ARRAY_ELEMENT} steps are represented with '[', {@link #INNER_TYPE
+ * INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps
+ * with '*' and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type
+ * argument index in decimal form.
+ */
+ @Override
+ public String toString() {
+ int length = getLength();
+ StringBuilder result = new StringBuilder(length * 2);
+ for (int i = 0; i < length; ++i) {
+ switch (getStep(i)) {
+ case ARRAY_ELEMENT:
+ result.append('[');
+ break;
+ case INNER_TYPE:
+ result.append('.');
+ break;
+ case WILDCARD_BOUND:
+ result.append('*');
+ break;
+ case TYPE_ARGUMENT:
+ result.append(getStepArgument(i));
+ break;
+ default:
+ result.append('_');
+ }
+ }
+ return result.toString();
+ }
+}
diff --git a/src/asm/scala/tools/asm/TypeReference.java b/src/asm/scala/tools/asm/TypeReference.java
new file mode 100644
index 0000000000..118b0f6529
--- /dev/null
+++ b/src/asm/scala/tools/asm/TypeReference.java
@@ -0,0 +1,452 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2013 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the copyright holders 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.
+ */
+
+package scala.tools.asm;
+
+/**
+ * A reference to a type appearing in a class, field or method declaration, or
+ * on an instruction. Such a reference designates the part of the class where
+ * the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws'
+ * clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable
+ * declaration, etc).
+ *
+ * @author Eric Bruneton
+ */
+public class TypeReference {
+
+ /**
+ * The sort of type references that target a type parameter of a generic
+ * class. See {@link #getSort getSort}.
+ */
+ public final static int CLASS_TYPE_PARAMETER = 0x00;
+
+ /**
+ * The sort of type references that target a type parameter of a generic
+ * method. See {@link #getSort getSort}.
+ */
+ public final static int METHOD_TYPE_PARAMETER = 0x01;
+
+ /**
+ * The sort of type references that target the super class of a class or one
+ * of the interfaces it implements. See {@link #getSort getSort}.
+ */
+ public final static int CLASS_EXTENDS = 0x10;
+
+ /**
+ * The sort of type references that target a bound of a type parameter of a
+ * generic class. See {@link #getSort getSort}.
+ */
+ public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11;
+
+ /**
+ * The sort of type references that target a bound of a type parameter of a
+ * generic method. See {@link #getSort getSort}.
+ */
+ public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12;
+
+ /**
+ * The sort of type references that target the type of a field. See
+ * {@link #getSort getSort}.
+ */
+ public final static int FIELD = 0x13;
+
+ /**
+ * The sort of type references that target the return type of a method. See
+ * {@link #getSort getSort}.
+ */
+ public final static int METHOD_RETURN = 0x14;
+
+ /**
+ * The sort of type references that target the receiver type of a method.
+ * See {@link #getSort getSort}.
+ */
+ public final static int METHOD_RECEIVER = 0x15;
+
+ /**
+ * The sort of type references that target the type of a formal parameter of
+ * a method. See {@link #getSort getSort}.
+ */
+ public final static int METHOD_FORMAL_PARAMETER = 0x16;
+
+ /**
+ * The sort of type references that target the type of an exception declared
+ * in the throws clause of a method. See {@link #getSort getSort}.
+ */
+ public final static int THROWS = 0x17;
+
+ /**
+ * The sort of type references that target the type of a local variable in a
+ * method. See {@link #getSort getSort}.
+ */
+ public final static int LOCAL_VARIABLE = 0x40;
+
+ /**
+ * The sort of type references that target the type of a resource variable
+ * in a method. See {@link #getSort getSort}.
+ */
+ public final static int RESOURCE_VARIABLE = 0x41;
+
+ /**
+ * The sort of type references that target the type of the exception of a
+ * 'catch' clause in a method. See {@link #getSort getSort}.
+ */
+ public final static int EXCEPTION_PARAMETER = 0x42;
+
+ /**
+ * The sort of type references that target the type declared in an
+ * 'instanceof' instruction. See {@link #getSort getSort}.
+ */
+ public final static int INSTANCEOF = 0x43;
+
+ /**
+ * The sort of type references that target the type of the object created by
+ * a 'new' instruction. See {@link #getSort getSort}.
+ */
+ public final static int NEW = 0x44;
+
+ /**
+ * The sort of type references that target the receiver type of a
+ * constructor reference. See {@link #getSort getSort}.
+ */
+ public final static int CONSTRUCTOR_REFERENCE = 0x45;
+
+ /**
+ * The sort of type references that target the receiver type of a method
+ * reference. See {@link #getSort getSort}.
+ */
+ public final static int METHOD_REFERENCE = 0x46;
+
+ /**
+ * The sort of type references that target the type declared in an explicit
+ * or implicit cast instruction. See {@link #getSort getSort}.
+ */
+ public final static int CAST = 0x47;
+
+ /**
+ * The sort of type references that target a type parameter of a generic
+ * constructor in a constructor call. See {@link #getSort getSort}.
+ */
+ public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
+
+ /**
+ * The sort of type references that target a type parameter of a generic
+ * method in a method call. See {@link #getSort getSort}.
+ */
+ public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
+
+ /**
+ * The sort of type references that target a type parameter of a generic
+ * constructor in a constructor reference. See {@link #getSort getSort}.
+ */
+ public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
+
+ /**
+ * The sort of type references that target a type parameter of a generic
+ * method in a method reference. See {@link #getSort getSort}.
+ */
+ public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
+
+ /**
+ * The type reference value in Java class file format.
+ */
+ private int value;
+
+ /**
+ * Creates a new TypeReference.
+ *
+ * @param typeRef
+ * the int encoded value of the type reference, as received in a
+ * visit method related to type annotations, like
+ * visitTypeAnnotation.
+ */
+ public TypeReference(int typeRef) {
+ this.value = typeRef;
+ }
+
+ /**
+ * Returns a type reference of the given sort.
+ *
+ * @param sort
+ * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
+ * {@link #METHOD_RECEIVER METHOD_RECEIVER},
+ * {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
+ * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
+ * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
+ * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or
+ * {@link #METHOD_REFERENCE METHOD_REFERENCE}.
+ * @return a type reference of the given sort.
+ */
+ public static TypeReference newTypeReference(int sort) {
+ return new TypeReference(sort << 24);
+ }
+
+ /**
+ * Returns a reference to a type parameter of a generic class or method.
+ *
+ * @param sort
+ * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
+ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
+ * @param paramIndex
+ * the type parameter index.
+ * @return a reference to the given generic class or method type parameter.
+ */
+ public static TypeReference newTypeParameterReference(int sort,
+ int paramIndex) {
+ return new TypeReference((sort << 24) | (paramIndex << 16));
+ }
+
+ /**
+ * Returns a reference to a type parameter bound of a generic class or
+ * method.
+ *
+ * @param sort
+ * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
+ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
+ * @param paramIndex
+ * the type parameter index.
+ * @param boundIndex
+ * the type bound index within the above type parameters.
+ * @return a reference to the given generic class or method type parameter
+ * bound.
+ */
+ public static TypeReference newTypeParameterBoundReference(int sort,
+ int paramIndex, int boundIndex) {
+ return new TypeReference((sort << 24) | (paramIndex << 16)
+ | (boundIndex << 8));
+ }
+
+ /**
+ * Returns a reference to the super class or to an interface of the
+ * 'implements' clause of a class.
+ *
+ * @param itfIndex
+ * the index of an interface in the 'implements' clause of a
+ * class, or -1 to reference the super class of the class.
+ * @return a reference to the given super type of a class.
+ */
+ public static TypeReference newSuperTypeReference(int itfIndex) {
+ itfIndex &= 0xFFFF;
+ return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));
+ }
+
+ /**
+ * Returns a reference to the type of a formal parameter of a method.
+ *
+ * @param paramIndex
+ * the formal parameter index.
+ *
+ * @return a reference to the type of the given method formal parameter.
+ */
+ public static TypeReference newFormalParameterReference(int paramIndex) {
+ return new TypeReference((METHOD_FORMAL_PARAMETER << 24)
+ | (paramIndex << 16));
+ }
+
+ /**
+ * Returns a reference to the type of an exception, in a 'throws' clause of
+ * a method.
+ *
+ * @param exceptionIndex
+ * the index of an exception in a 'throws' clause of a method.
+ *
+ * @return a reference to the type of the given exception.
+ */
+ public static TypeReference newExceptionReference(int exceptionIndex) {
+ return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
+ }
+
+ /**
+ * Returns a reference to the type of the exception declared in a 'catch'
+ * clause of a method.
+ *
+ * @param tryCatchBlockIndex
+ * the index of a try catch block (using the order in which they
+ * are visited with visitTryCatchBlock).
+ *
+ * @return a reference to the type of the given exception.
+ */
+ public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {
+ return new TypeReference((EXCEPTION_PARAMETER << 24)
+ | (tryCatchBlockIndex << 8));
+ }
+
+ /**
+ * Returns a reference to the type of a type argument in a constructor or
+ * method call or reference.
+ *
+ * @param sort
+ * {@link #CAST CAST},
+ * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
+ * {@link #METHOD_INVOCATION_TYPE_ARGUMENT
+ * METHOD_INVOCATION_TYPE_ARGUMENT},
+ * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
+ * {@link #METHOD_REFERENCE_TYPE_ARGUMENT
+ * METHOD_REFERENCE_TYPE_ARGUMENT}.
+ * @param argIndex
+ * the type argument index.
+ *
+ * @return a reference to the type of the given type argument.
+ */
+ public static TypeReference newTypeArgumentReference(int sort, int argIndex) {
+ return new TypeReference((sort << 24) | argIndex);
+ }
+
+ /**
+ * Returns the sort of this type reference.
+ *
+ * @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
+ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
+ * {@link #CLASS_EXTENDS CLASS_EXTENDS},
+ * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND},
+ * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND},
+ * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
+ * {@link #METHOD_RECEIVER METHOD_RECEIVER},
+ * {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER},
+ * {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
+ * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
+ * {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER},
+ * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
+ * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
+ * {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST},
+ * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
+ * {@link #METHOD_INVOCATION_TYPE_ARGUMENT
+ * METHOD_INVOCATION_TYPE_ARGUMENT},
+ * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
+ * {@link #METHOD_REFERENCE_TYPE_ARGUMENT
+ * METHOD_REFERENCE_TYPE_ARGUMENT}.
+ */
+ public int getSort() {
+ return value >>> 24;
+ }
+
+ /**
+ * Returns the index of the type parameter referenced by this type
+ * reference. This method must only be used for type references whose sort
+ * is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
+ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
+ * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
+ * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
+ *
+ * @return a type parameter index.
+ */
+ public int getTypeParameterIndex() {
+ return (value & 0x00FF0000) >> 16;
+ }
+
+ /**
+ * Returns the index of the type parameter bound, within the type parameter
+ * {@link #getTypeParameterIndex}, referenced by this type reference. This
+ * method must only be used for type references whose sort is
+ * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
+ * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
+ *
+ * @return a type parameter bound index.
+ */
+ public int getTypeParameterBoundIndex() {
+ return (value & 0x0000FF00) >> 8;
+ }
+
+ /**
+ * Returns the index of the "super type" of a class that is referenced by
+ * this type reference. This method must only be used for type references
+ * whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}.
+ *
+ * @return the index of an interface in the 'implements' clause of a class,
+ * or -1 if this type reference references the type of the super
+ * class.
+ */
+ public int getSuperTypeIndex() {
+ return (short) ((value & 0x00FFFF00) >> 8);
+ }
+
+ /**
+ * Returns the index of the formal parameter whose type is referenced by
+ * this type reference. This method must only be used for type references
+ * whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}.
+ *
+ * @return a formal parameter index.
+ */
+ public int getFormalParameterIndex() {
+ return (value & 0x00FF0000) >> 16;
+ }
+
+ /**
+ * Returns the index of the exception, in a 'throws' clause of a method,
+ * whose type is referenced by this type reference. This method must only be
+ * used for type references whose sort is {@link #THROWS THROWS}.
+ *
+ * @return the index of an exception in the 'throws' clause of a method.
+ */
+ public int getExceptionIndex() {
+ return (value & 0x00FFFF00) >> 8;
+ }
+
+ /**
+ * Returns the index of the try catch block (using the order in which they
+ * are visited with visitTryCatchBlock), whose 'catch' type is referenced by
+ * this type reference. This method must only be used for type references
+ * whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} .
+ *
+ * @return the index of an exception in the 'throws' clause of a method.
+ */
+ public int getTryCatchBlockIndex() {
+ return (value & 0x00FFFF00) >> 8;
+ }
+
+ /**
+ * Returns the index of the type argument referenced by this type reference.
+ * This method must only be used for type references whose sort is
+ * {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
+ * {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
+ * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
+ * {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
+ *
+ * @return a type parameter index.
+ */
+ public int getTypeArgumentIndex() {
+ return value & 0xFF;
+ }
+
+ /**
+ * Returns the int encoded value of this type reference, suitable for use in
+ * visit methods related to type annotations, like visitTypeAnnotation.
+ *
+ * @return the int encoded value of this type reference.
+ */
+ public int getValue() {
+ return value;
+ }
+}
diff --git a/src/asm/scala/tools/asm/signature/SignatureVisitor.java b/src/asm/scala/tools/asm/signature/SignatureVisitor.java
index f38f81f53b..1e16bd3f7c 100644
--- a/src/asm/scala/tools/asm/signature/SignatureVisitor.java
+++ b/src/asm/scala/tools/asm/signature/SignatureVisitor.java
@@ -73,7 +73,7 @@ public abstract class SignatureVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
- * must be one of {@link Opcodes#ASM4}.
+ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
protected final int api;
@@ -82,9 +82,12 @@ public abstract class SignatureVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public SignatureVisitor(final int api) {
+ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
+ throw new IllegalArgumentException();
+ }
this.api = api;
}
diff --git a/src/asm/scala/tools/asm/signature/SignatureWriter.java b/src/asm/scala/tools/asm/signature/SignatureWriter.java
index ebf4fe07b4..65756eee51 100644
--- a/src/asm/scala/tools/asm/signature/SignatureWriter.java
+++ b/src/asm/scala/tools/asm/signature/SignatureWriter.java
@@ -66,7 +66,7 @@ public class SignatureWriter extends SignatureVisitor {
* Constructs a new {@link SignatureWriter} object.
*/
public SignatureWriter() {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
}
// ------------------------------------------------------------------------
diff --git a/src/asm/scala/tools/asm/tree/AbstractInsnNode.java b/src/asm/scala/tools/asm/tree/AbstractInsnNode.java
index 411eead3c7..2ce0c8b6ee 100644
--- a/src/asm/scala/tools/asm/tree/AbstractInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/AbstractInsnNode.java
@@ -29,6 +29,7 @@
*/
package scala.tools.asm.tree;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -128,6 +129,28 @@ public abstract class AbstractInsnNode {
protected int opcode;
/**
+ * The runtime visible type annotations of this instruction. This field is
+ * only used for real instructions (i.e. not for labels, frames, or line
+ * number nodes). This list is a list of {@link TypeAnnotationNode} objects.
+ * May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label visible
+ */
+ public List<TypeAnnotationNode> visibleTypeAnnotations;
+
+ /**
+ * The runtime invisible type annotations of this instruction. This field is
+ * only used for real instructions (i.e. not for labels, frames, or line
+ * number nodes). This list is a list of {@link TypeAnnotationNode} objects.
+ * May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label invisible
+ */
+ public List<TypeAnnotationNode> invisibleTypeAnnotations;
+
+ /**
* Previous instruction in the list to which this instruction belongs.
*/
AbstractInsnNode prev;
@@ -204,6 +227,29 @@ public abstract class AbstractInsnNode {
public abstract void accept(final MethodVisitor cv);
/**
+ * Makes the given visitor visit the annotations of this instruction.
+ *
+ * @param mv
+ * a method visitor.
+ */
+ protected final void acceptAnnotations(final MethodVisitor mv) {
+ int n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations
+ .size();
+ for (int i = 0; i < n; ++i) {
+ TypeAnnotationNode an = visibleTypeAnnotations.get(i);
+ an.accept(mv.visitInsnAnnotation(an.typeRef, an.typePath, an.desc,
+ true));
+ }
+ n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
+ .size();
+ for (int i = 0; i < n; ++i) {
+ TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
+ an.accept(mv.visitInsnAnnotation(an.typeRef, an.typePath, an.desc,
+ false));
+ }
+ }
+
+ /**
* Returns a copy of this instruction.
*
* @param labels
@@ -245,4 +291,36 @@ public abstract class AbstractInsnNode {
}
return clones;
}
+
+ /**
+ * Clones the annotations of the given instruction into this instruction.
+ *
+ * @param insn
+ * the source instruction.
+ * @return this instruction.
+ */
+ protected final AbstractInsnNode cloneAnnotations(
+ final AbstractInsnNode insn) {
+ if (insn.visibleTypeAnnotations != null) {
+ this.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
+ for (int i = 0; i < insn.visibleTypeAnnotations.size(); ++i) {
+ TypeAnnotationNode src = insn.visibleTypeAnnotations.get(i);
+ TypeAnnotationNode ann = new TypeAnnotationNode(src.typeRef,
+ src.typePath, src.desc);
+ src.accept(ann);
+ this.visibleTypeAnnotations.add(ann);
+ }
+ }
+ if (insn.invisibleTypeAnnotations != null) {
+ this.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
+ for (int i = 0; i < insn.invisibleTypeAnnotations.size(); ++i) {
+ TypeAnnotationNode src = insn.invisibleTypeAnnotations.get(i);
+ TypeAnnotationNode ann = new TypeAnnotationNode(src.typeRef,
+ src.typePath, src.desc);
+ src.accept(ann);
+ this.invisibleTypeAnnotations.add(ann);
+ }
+ }
+ return this;
+ }
}
diff --git a/src/asm/scala/tools/asm/tree/AnnotationNode.java b/src/asm/scala/tools/asm/tree/AnnotationNode.java
index 1f4beef9f7..b8d5988066 100644
--- a/src/asm/scala/tools/asm/tree/AnnotationNode.java
+++ b/src/asm/scala/tools/asm/tree/AnnotationNode.java
@@ -67,9 +67,14 @@ public class AnnotationNode extends AnnotationVisitor {
*
* @param desc
* the class descriptor of the annotation class.
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public AnnotationNode(final String desc) {
- this(Opcodes.ASM4, desc);
+ this(Opcodes.ASM5, desc);
+ if (getClass() != AnnotationNode.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -77,7 +82,7 @@ public class AnnotationNode extends AnnotationVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param desc
* the class descriptor of the annotation class.
*/
@@ -93,7 +98,7 @@ public class AnnotationNode extends AnnotationVisitor {
* where the visited values must be stored.
*/
AnnotationNode(final List<Object> values) {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
this.values = values;
}
@@ -166,7 +171,8 @@ public class AnnotationNode extends AnnotationVisitor {
* versions of the ASM API than the given version.
*
* @param api
- * an ASM API version. Must be one of {@link Opcodes#ASM4}.
+ * an ASM API version. Must be one of {@link Opcodes#ASM4} or
+ * {@link Opcodes#ASM5}.
*/
public void check(final int api) {
// nothing to do
diff --git a/src/asm/scala/tools/asm/tree/ClassNode.java b/src/asm/scala/tools/asm/tree/ClassNode.java
index c3d999985a..304b4ec9f5 100644
--- a/src/asm/scala/tools/asm/tree/ClassNode.java
+++ b/src/asm/scala/tools/asm/tree/ClassNode.java
@@ -39,6 +39,7 @@ import scala.tools.asm.ClassVisitor;
import scala.tools.asm.FieldVisitor;
import scala.tools.asm.MethodVisitor;
import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
/**
* A node that represents a class.
@@ -133,6 +134,24 @@ public class ClassNode extends ClassVisitor {
public List<AnnotationNode> invisibleAnnotations;
/**
+ * The runtime visible type annotations of this class. This list is a list
+ * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label visible
+ */
+ public List<TypeAnnotationNode> visibleTypeAnnotations;
+
+ /**
+ * The runtime invisible type annotations of this class. This list is a list
+ * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label invisible
+ */
+ public List<TypeAnnotationNode> invisibleTypeAnnotations;
+
+ /**
* The non standard attributes of this class. This list is a list of
* {@link Attribute} objects. May be <tt>null</tt>.
*
@@ -168,9 +187,15 @@ public class ClassNode extends ClassVisitor {
* Constructs a new {@link ClassNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the {@link #ClassNode(int)}
* version.
+ *
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public ClassNode() {
- this(Opcodes.ASM4);
+ this(Opcodes.ASM5);
+ if (getClass() != ClassNode.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -178,7 +203,7 @@ public class ClassNode extends ClassVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public ClassNode(final int api) {
super(api);
@@ -239,6 +264,24 @@ public class ClassNode extends ClassVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
+ if (visible) {
+ if (visibleTypeAnnotations == null) {
+ visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+ }
+ visibleTypeAnnotations.add(an);
+ } else {
+ if (invisibleTypeAnnotations == null) {
+ invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+ }
+ invisibleTypeAnnotations.add(an);
+ }
+ return an;
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
if (attrs == null) {
attrs = new ArrayList<Attribute>(1);
@@ -286,10 +329,26 @@ public class ClassNode extends ClassVisitor {
* API than the given version.
*
* @param api
- * an ASM API version. Must be one of {@link Opcodes#ASM4}.
+ * an ASM API version. Must be one of {@link Opcodes#ASM4} or
+ * {@link Opcodes#ASM5}.
*/
public void check(final int api) {
- // nothing to do
+ if (api == Opcodes.ASM4) {
+ if (visibleTypeAnnotations != null
+ && visibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (invisibleTypeAnnotations != null
+ && invisibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ for (FieldNode f : fields) {
+ f.check(api);
+ }
+ for (MethodNode m : methods) {
+ m.check(api);
+ }
+ }
}
/**
@@ -323,6 +382,19 @@ public class ClassNode extends ClassVisitor {
AnnotationNode an = invisibleAnnotations.get(i);
an.accept(cv.visitAnnotation(an.desc, false));
}
+ n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
+ for (i = 0; i < n; ++i) {
+ TypeAnnotationNode an = visibleTypeAnnotations.get(i);
+ an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
+ true));
+ }
+ n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
+ .size();
+ for (i = 0; i < n; ++i) {
+ TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
+ an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
+ false));
+ }
n = attrs == null ? 0 : attrs.size();
for (i = 0; i < n; ++i) {
cv.visitAttribute(attrs.get(i));
diff --git a/src/asm/scala/tools/asm/tree/FieldInsnNode.java b/src/asm/scala/tools/asm/tree/FieldInsnNode.java
index 0c94f18adf..c027de109b 100644
--- a/src/asm/scala/tools/asm/tree/FieldInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/FieldInsnNode.java
@@ -97,12 +97,14 @@ public class FieldInsnNode extends AbstractInsnNode {
}
@Override
- public void accept(final MethodVisitor cv) {
- cv.visitFieldInsn(opcode, owner, name, desc);
+ public void accept(final MethodVisitor mv) {
+ mv.visitFieldInsn(opcode, owner, name, desc);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new FieldInsnNode(opcode, owner, name, desc);
+ return new FieldInsnNode(opcode, owner, name, desc)
+ .cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/FieldNode.java b/src/asm/scala/tools/asm/tree/FieldNode.java
index 61b614ec59..3fb14dac4f 100644
--- a/src/asm/scala/tools/asm/tree/FieldNode.java
+++ b/src/asm/scala/tools/asm/tree/FieldNode.java
@@ -37,6 +37,7 @@ import scala.tools.asm.Attribute;
import scala.tools.asm.ClassVisitor;
import scala.tools.asm.FieldVisitor;
import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
/**
* A node that represents a field.
@@ -92,6 +93,24 @@ public class FieldNode extends FieldVisitor {
public List<AnnotationNode> invisibleAnnotations;
/**
+ * The runtime visible type annotations of this field. This list is a list
+ * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label visible
+ */
+ public List<TypeAnnotationNode> visibleTypeAnnotations;
+
+ /**
+ * The runtime invisible type annotations of this field. This list is a list
+ * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label invisible
+ */
+ public List<TypeAnnotationNode> invisibleTypeAnnotations;
+
+ /**
* The non standard attributes of this field. This list is a list of
* {@link Attribute} objects. May be <tt>null</tt>.
*
@@ -120,20 +139,24 @@ public class FieldNode extends FieldVisitor {
* <tt>null</tt> if the field does not have an initial value,
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String}.
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public FieldNode(final int access, final String name, final String desc,
final String signature, final Object value) {
- this(Opcodes.ASM4, access, name, desc, signature, value);
+ this(Opcodes.ASM5, access, name, desc, signature, value);
+ if (getClass() != FieldNode.class) {
+ throw new IllegalStateException();
+ }
}
/**
* Constructs a new {@link FieldNode}. <i>Subclasses must not use this
- * constructor</i>. Instead, they must use the
- * {@link #FieldNode(int, int, String, String, String, Object)} version.
+ * constructor</i>.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param access
* the field's access flags (see
* {@link scala.tools.asm.Opcodes}). This parameter also
@@ -184,6 +207,24 @@ public class FieldNode extends FieldVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
+ if (visible) {
+ if (visibleTypeAnnotations == null) {
+ visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+ }
+ visibleTypeAnnotations.add(an);
+ } else {
+ if (invisibleTypeAnnotations == null) {
+ invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+ }
+ invisibleTypeAnnotations.add(an);
+ }
+ return an;
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
if (attrs == null) {
attrs = new ArrayList<Attribute>(1);
@@ -206,10 +247,20 @@ public class FieldNode extends FieldVisitor {
* API than the given version.
*
* @param api
- * an ASM API version. Must be one of {@link Opcodes#ASM4}.
+ * an ASM API version. Must be one of {@link Opcodes#ASM4} or
+ * {@link Opcodes#ASM5}.
*/
public void check(final int api) {
- // nothing to do
+ if (api == Opcodes.ASM4) {
+ if (visibleTypeAnnotations != null
+ && visibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (invisibleTypeAnnotations != null
+ && invisibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ }
}
/**
@@ -234,6 +285,19 @@ public class FieldNode extends FieldVisitor {
AnnotationNode an = invisibleAnnotations.get(i);
an.accept(fv.visitAnnotation(an.desc, false));
}
+ n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
+ for (i = 0; i < n; ++i) {
+ TypeAnnotationNode an = visibleTypeAnnotations.get(i);
+ an.accept(fv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
+ true));
+ }
+ n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
+ .size();
+ for (i = 0; i < n; ++i) {
+ TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
+ an.accept(fv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
+ false));
+ }
n = attrs == null ? 0 : attrs.size();
for (i = 0; i < n; ++i) {
fv.visitAttribute(attrs.get(i));
diff --git a/src/asm/scala/tools/asm/tree/IincInsnNode.java b/src/asm/scala/tools/asm/tree/IincInsnNode.java
index f9adf2e38c..c37ac91c27 100644
--- a/src/asm/scala/tools/asm/tree/IincInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/IincInsnNode.java
@@ -73,10 +73,11 @@ public class IincInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitIincInsn(var, incr);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new IincInsnNode(var, incr);
+ return new IincInsnNode(var, incr).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/InsnList.java b/src/asm/scala/tools/asm/tree/InsnList.java
index b1e2d97c6f..e808712e78 100644
--- a/src/asm/scala/tools/asm/tree/InsnList.java
+++ b/src/asm/scala/tools/asm/tree/InsnList.java
@@ -100,7 +100,7 @@ public class InsnList {
* the index of the instruction that must be returned.
* @return the instruction whose index is given.
* @throws IndexOutOfBoundsException
- * if (index < 0 || index >= size()).
+ * if (index &lt; 0 || index &gt;= size()).
*/
public AbstractInsnNode get(final int index) {
if (index < 0 || index >= size) {
@@ -535,6 +535,8 @@ public class InsnList {
AbstractInsnNode prev;
+ AbstractInsnNode remove;
+
InsnListIterator(int index) {
if (index == size()) {
next = null;
@@ -556,12 +558,22 @@ public class InsnList {
AbstractInsnNode result = next;
prev = result;
next = result.next;
+ remove = result;
return result;
}
public void remove() {
- InsnList.this.remove(prev);
- prev = prev.prev;
+ if (remove != null) {
+ if (remove == next) {
+ next = next.next;
+ } else {
+ prev = prev.prev;
+ }
+ InsnList.this.remove(remove);
+ remove = null;
+ } else {
+ throw new IllegalStateException();
+ }
}
public boolean hasPrevious() {
@@ -572,6 +584,7 @@ public class InsnList {
AbstractInsnNode result = prev;
next = result;
prev = result.prev;
+ remove = result;
return result;
}
@@ -598,6 +611,7 @@ public class InsnList {
public void add(Object o) {
InsnList.this.insertBefore(next, (AbstractInsnNode) o);
prev = (AbstractInsnNode) o;
+ remove = null;
}
public void set(Object o) {
diff --git a/src/asm/scala/tools/asm/tree/InsnNode.java b/src/asm/scala/tools/asm/tree/InsnNode.java
index 4d5288cafa..f5313929ee 100644
--- a/src/asm/scala/tools/asm/tree/InsnNode.java
+++ b/src/asm/scala/tools/asm/tree/InsnNode.java
@@ -78,10 +78,11 @@ public class InsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitInsn(opcode);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new InsnNode(opcode);
+ return new InsnNode(opcode).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/IntInsnNode.java b/src/asm/scala/tools/asm/tree/IntInsnNode.java
index e0aeed4bc8..6bbe8d845c 100644
--- a/src/asm/scala/tools/asm/tree/IntInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/IntInsnNode.java
@@ -78,10 +78,11 @@ public class IntInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitIntInsn(opcode, operand);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new IntInsnNode(opcode, operand);
+ return new IntInsnNode(opcode, operand).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/InvokeDynamicInsnNode.java b/src/asm/scala/tools/asm/tree/InvokeDynamicInsnNode.java
index 7ee84b875b..0f85e60291 100644
--- a/src/asm/scala/tools/asm/tree/InvokeDynamicInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/InvokeDynamicInsnNode.java
@@ -91,10 +91,12 @@ public class InvokeDynamicInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs);
+ return new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs)
+ .cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/JumpInsnNode.java b/src/asm/scala/tools/asm/tree/JumpInsnNode.java
index 81e1e09deb..8b8a769204 100644
--- a/src/asm/scala/tools/asm/tree/JumpInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/JumpInsnNode.java
@@ -86,10 +86,12 @@ public class JumpInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitJumpInsn(opcode, label.getLabel());
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new JumpInsnNode(opcode, clone(label, labels));
+ return new JumpInsnNode(opcode, clone(label, labels))
+ .cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/LdcInsnNode.java b/src/asm/scala/tools/asm/tree/LdcInsnNode.java
index 4e328f9b39..1cc850bb31 100644
--- a/src/asm/scala/tools/asm/tree/LdcInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/LdcInsnNode.java
@@ -69,10 +69,11 @@ public class LdcInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitLdcInsn(cst);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new LdcInsnNode(cst);
+ return new LdcInsnNode(cst).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/LocalVariableAnnotationNode.java b/src/asm/scala/tools/asm/tree/LocalVariableAnnotationNode.java
new file mode 100644
index 0000000000..d05b808171
--- /dev/null
+++ b/src/asm/scala/tools/asm/tree/LocalVariableAnnotationNode.java
@@ -0,0 +1,157 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the copyright holders 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.
+ */
+
+package scala.tools.asm.tree;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import scala.tools.asm.Label;
+import scala.tools.asm.MethodVisitor;
+import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
+import scala.tools.asm.TypeReference;
+
+/**
+ * A node that represents a type annotation on a local or resource variable.
+ *
+ * @author Eric Bruneton
+ */
+public class LocalVariableAnnotationNode extends TypeAnnotationNode {
+
+ /**
+ * The fist instructions corresponding to the continuous ranges that make
+ * the scope of this local variable (inclusive). Must not be <tt>null</tt>.
+ */
+ public List<LabelNode> start;
+
+ /**
+ * The last instructions corresponding to the continuous ranges that make
+ * the scope of this local variable (exclusive). This list must have the
+ * same size as the 'start' list. Must not be <tt>null</tt>.
+ */
+ public List<LabelNode> end;
+
+ /**
+ * The local variable's index in each range. This list must have the same
+ * size as the 'start' list. Must not be <tt>null</tt>.
+ */
+ public List<Integer> index;
+
+ /**
+ * Constructs a new {@link LocalVariableAnnotationNode}. <i>Subclasses must
+ * not use this constructor</i>. Instead, they must use the
+ * {@link #LocalVariableAnnotationNode(int, TypePath, LabelNode[], LabelNode[], int[], String)}
+ * version.
+ *
+ * @param typeRef
+ * a reference to the annotated type. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param start
+ * the fist instructions corresponding to the continuous ranges
+ * that make the scope of this local variable (inclusive).
+ * @param end
+ * the last instructions corresponding to the continuous ranges
+ * that make the scope of this local variable (exclusive). This
+ * array must have the same size as the 'start' array.
+ * @param index
+ * the local variable's index in each range. This array must have
+ * the same size as the 'start' array.
+ * @param desc
+ * the class descriptor of the annotation class.
+ */
+ public LocalVariableAnnotationNode(int typeRef, TypePath typePath,
+ LabelNode[] start, LabelNode[] end, int[] index, String desc) {
+ this(Opcodes.ASM5, typeRef, typePath, start, end, index, desc);
+ }
+
+ /**
+ * Constructs a new {@link LocalVariableAnnotationNode}.
+ *
+ * @param api
+ * the ASM API version implemented by this visitor. Must be one
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
+ * @param typeRef
+ * a reference to the annotated type. See {@link TypeReference}.
+ * @param start
+ * the fist instructions corresponding to the continuous ranges
+ * that make the scope of this local variable (inclusive).
+ * @param end
+ * the last instructions corresponding to the continuous ranges
+ * that make the scope of this local variable (exclusive). This
+ * array must have the same size as the 'start' array.
+ * @param index
+ * the local variable's index in each range. This array must have
+ * the same size as the 'start' array.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ */
+ public LocalVariableAnnotationNode(int api, int typeRef, TypePath typePath,
+ LabelNode[] start, LabelNode[] end, int[] index, String desc) {
+ super(api, typeRef, typePath, desc);
+ this.start = new ArrayList<LabelNode>(start.length);
+ this.start.addAll(Arrays.asList(start));
+ this.end = new ArrayList<LabelNode>(end.length);
+ this.end.addAll(Arrays.asList(end));
+ this.index = new ArrayList<Integer>(index.length);
+ for (int i : index) {
+ this.index.add(i);
+ }
+ }
+
+ /**
+ * Makes the given visitor visit this type annotation.
+ *
+ * @param mv
+ * the visitor that must visit this annotation.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ */
+ public void accept(final MethodVisitor mv, boolean visible) {
+ Label[] start = new Label[this.start.size()];
+ Label[] end = new Label[this.end.size()];
+ int[] index = new int[this.index.size()];
+ for (int i = 0; i < start.length; ++i) {
+ start[i] = this.start.get(i).getLabel();
+ end[i] = this.end.get(i).getLabel();
+ index[i] = this.index.get(i);
+ }
+ accept(mv.visitLocalVariableAnnotation(typeRef, typePath, start, end,
+ index, desc, true));
+ }
+}
diff --git a/src/asm/scala/tools/asm/tree/LookupSwitchInsnNode.java b/src/asm/scala/tools/asm/tree/LookupSwitchInsnNode.java
index d2479b4814..7db2f53ff4 100644
--- a/src/asm/scala/tools/asm/tree/LookupSwitchInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/LookupSwitchInsnNode.java
@@ -105,6 +105,7 @@ public class LookupSwitchInsnNode extends AbstractInsnNode {
labels[i] = this.labels.get(i).getLabel();
}
mv.visitLookupSwitchInsn(dflt.getLabel(), keys, labels);
+ acceptAnnotations(mv);
}
@Override
@@ -112,6 +113,6 @@ public class LookupSwitchInsnNode extends AbstractInsnNode {
LookupSwitchInsnNode clone = new LookupSwitchInsnNode(clone(dflt,
labels), null, clone(this.labels, labels));
clone.keys.addAll(keys);
- return clone;
+ return clone.cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/MethodInsnNode.java b/src/asm/scala/tools/asm/tree/MethodInsnNode.java
index bf09f556d8..1ec46d473d 100644
--- a/src/asm/scala/tools/asm/tree/MethodInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/MethodInsnNode.java
@@ -32,6 +32,7 @@ package scala.tools.asm.tree;
import java.util.Map;
import scala.tools.asm.MethodVisitor;
+import scala.tools.asm.Opcodes;
/**
* A node that represents a method instruction. A method instruction is an
@@ -58,6 +59,11 @@ public class MethodInsnNode extends AbstractInsnNode {
public String desc;
/**
+ * If the method's owner class if an interface.
+ */
+ public boolean itf;
+
+ /**
* Constructs a new {@link MethodInsnNode}.
*
* @param opcode
@@ -73,12 +79,37 @@ public class MethodInsnNode extends AbstractInsnNode {
* @param desc
* the method's descriptor (see {@link scala.tools.asm.Type}).
*/
+ @Deprecated
public MethodInsnNode(final int opcode, final String owner,
final String name, final String desc) {
+ this(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE);
+ }
+
+ /**
+ * Constructs a new {@link MethodInsnNode}.
+ *
+ * @param opcode
+ * the opcode of the type instruction to be constructed. This
+ * opcode must be INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
+ * INVOKEINTERFACE.
+ * @param owner
+ * the internal name of the method's owner class (see
+ * {@link scala.tools.asm.Type#getInternalName()
+ * getInternalName}).
+ * @param name
+ * the method's name.
+ * @param desc
+ * the method's descriptor (see {@link scala.tools.asm.Type}).
+ * @param itf
+ * if the method's owner class is an interface.
+ */
+ public MethodInsnNode(final int opcode, final String owner,
+ final String name, final String desc, final boolean itf) {
super(opcode);
this.owner = owner;
this.name = name;
this.desc = desc;
+ this.itf = itf;
}
/**
@@ -99,11 +130,11 @@ public class MethodInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
- mv.visitMethodInsn(opcode, owner, name, desc);
+ mv.visitMethodInsn(opcode, owner, name, desc, itf);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new MethodInsnNode(opcode, owner, name, desc);
+ return new MethodInsnNode(opcode, owner, name, desc, itf);
}
}
diff --git a/src/asm/scala/tools/asm/tree/MethodNode.java b/src/asm/scala/tools/asm/tree/MethodNode.java
index a161600edb..3dec50e02c 100644
--- a/src/asm/scala/tools/asm/tree/MethodNode.java
+++ b/src/asm/scala/tools/asm/tree/MethodNode.java
@@ -41,6 +41,7 @@ import scala.tools.asm.Label;
import scala.tools.asm.MethodVisitor;
import scala.tools.asm.Opcodes;
import scala.tools.asm.Type;
+import scala.tools.asm.TypePath;
/**
* A node that represents a method.
@@ -78,6 +79,11 @@ public class MethodNode extends MethodVisitor {
public List<String> exceptions;
/**
+ * The method parameter info (access flags and name)
+ */
+ public List<ParameterNode> parameters;
+
+ /**
* The runtime visible annotations of this method. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
@@ -96,6 +102,24 @@ public class MethodNode extends MethodVisitor {
public List<AnnotationNode> invisibleAnnotations;
/**
+ * The runtime visible type annotations of this method. This list is a list
+ * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label visible
+ */
+ public List<TypeAnnotationNode> visibleTypeAnnotations;
+
+ /**
+ * The runtime invisible type annotations of this method. This list is a
+ * list of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label invisible
+ */
+ public List<TypeAnnotationNode> invisibleTypeAnnotations;
+
+ /**
* The non standard attributes of this method. This list is a list of
* {@link Attribute} objects. May be <tt>null</tt>.
*
@@ -167,6 +191,22 @@ public class MethodNode extends MethodVisitor {
public List<LocalVariableNode> localVariables;
/**
+ * The visible local variable annotations of this method. This list is a
+ * list of {@link LocalVariableAnnotationNode} objects. May be <tt>null</tt>
+ *
+ * @associates scala.tools.asm.tree.LocalVariableAnnotationNode
+ */
+ public List<LocalVariableAnnotationNode> visibleLocalVariableAnnotations;
+
+ /**
+ * The invisible local variable annotations of this method. This list is a
+ * list of {@link LocalVariableAnnotationNode} objects. May be <tt>null</tt>
+ *
+ * @associates scala.tools.asm.tree.LocalVariableAnnotationNode
+ */
+ public List<LocalVariableAnnotationNode> invisibleLocalVariableAnnotations;
+
+ /**
* If the accept method has been called on this object.
*/
private boolean visited;
@@ -175,9 +215,15 @@ public class MethodNode extends MethodVisitor {
* Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not
* use this constructor</i>. Instead, they must use the
* {@link #MethodNode(int)} version.
+ *
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public MethodNode() {
- this(Opcodes.ASM4);
+ this(Opcodes.ASM5);
+ if (getClass() != MethodNode.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -185,7 +231,7 @@ public class MethodNode extends MethodVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public MethodNode(final int api) {
super(api);
@@ -211,10 +257,15 @@ public class MethodNode extends MethodVisitor {
* the internal names of the method's exception classes (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public MethodNode(final int access, final String name, final String desc,
final String signature, final String[] exceptions) {
- this(Opcodes.ASM4, access, name, desc, signature, exceptions);
+ this(Opcodes.ASM5, access, name, desc, signature, exceptions);
+ if (getClass() != MethodNode.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -222,7 +273,7 @@ public class MethodNode extends MethodVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param access
* the method's access flags (see {@link Opcodes}). This
* parameter also indicates if the method is synthetic and/or
@@ -263,6 +314,15 @@ public class MethodNode extends MethodVisitor {
// ------------------------------------------------------------------------
@Override
+ public void visitParameter(String name, int access) {
+ if (parameters == null) {
+ parameters = new ArrayList<ParameterNode>(5);
+ }
+ parameters.add(new ParameterNode(name, access));
+ }
+
+ @Override
+ @SuppressWarnings("serial")
public AnnotationVisitor visitAnnotationDefault() {
return new AnnotationNode(new ArrayList<Object>(0) {
@Override
@@ -292,6 +352,24 @@ public class MethodNode extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
+ if (visible) {
+ if (visibleTypeAnnotations == null) {
+ visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+ }
+ visibleTypeAnnotations.add(an);
+ } else {
+ if (invisibleTypeAnnotations == null) {
+ invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+ }
+ invisibleTypeAnnotations.add(an);
+ }
+ return an;
+ }
+
+ @Override
public AnnotationVisitor visitParameterAnnotation(final int parameter,
final String desc, final boolean visible) {
AnnotationNode an = new AnnotationNode(desc);
@@ -365,13 +443,28 @@ public class MethodNode extends MethodVisitor {
instructions.add(new FieldInsnNode(opcode, owner, name, desc));
}
+ @Deprecated
@Override
- public void visitMethodInsn(final int opcode, final String owner,
- final String name, final String desc) {
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc) {
+ if (api >= Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc);
+ return;
+ }
instructions.add(new MethodInsnNode(opcode, owner, name, desc));
}
@Override
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc, boolean itf) {
+ if (api < Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc, itf);
+ return;
+ }
+ instructions.add(new MethodInsnNode(opcode, owner, name, desc, itf));
+ }
+
+ @Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) {
instructions.add(new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs));
@@ -417,6 +510,33 @@ public class MethodNode extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitInsnAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ // Finds the last real instruction, i.e. the instruction targeted by
+ // this annotation.
+ AbstractInsnNode insn = instructions.getLast();
+ while (insn.getOpcode() == -1) {
+ insn = insn.getPrevious();
+ }
+ // Adds the annotation to this instruction.
+ TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
+ if (visible) {
+ if (insn.visibleTypeAnnotations == null) {
+ insn.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
+ 1);
+ }
+ insn.visibleTypeAnnotations.add(an);
+ } else {
+ if (insn.invisibleTypeAnnotations == null) {
+ insn.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
+ 1);
+ }
+ insn.invisibleTypeAnnotations.add(an);
+ }
+ return an;
+ }
+
+ @Override
public void visitTryCatchBlock(final Label start, final Label end,
final Label handler, final String type) {
tryCatchBlocks.add(new TryCatchBlockNode(getLabelNode(start),
@@ -424,6 +544,27 @@ public class MethodNode extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ TryCatchBlockNode tcb = tryCatchBlocks.get((typeRef & 0x00FFFF00) >> 8);
+ TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
+ if (visible) {
+ if (tcb.visibleTypeAnnotations == null) {
+ tcb.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
+ 1);
+ }
+ tcb.visibleTypeAnnotations.add(an);
+ } else {
+ if (tcb.invisibleTypeAnnotations == null) {
+ tcb.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
+ 1);
+ }
+ tcb.invisibleTypeAnnotations.add(an);
+ }
+ return an;
+ }
+
+ @Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
final int index) {
@@ -432,6 +573,29 @@ public class MethodNode extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
+ TypePath typePath, Label[] start, Label[] end, int[] index,
+ String desc, boolean visible) {
+ LocalVariableAnnotationNode an = new LocalVariableAnnotationNode(
+ typeRef, typePath, getLabelNodes(start), getLabelNodes(end),
+ index, desc);
+ if (visible) {
+ if (visibleLocalVariableAnnotations == null) {
+ visibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(
+ 1);
+ }
+ visibleLocalVariableAnnotations.add(an);
+ } else {
+ if (invisibleLocalVariableAnnotations == null) {
+ invisibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(
+ 1);
+ }
+ invisibleLocalVariableAnnotations.add(an);
+ }
+ return an;
+ }
+
+ @Override
public void visitLineNumber(final int line, final Label start) {
instructions.add(new LineNumberNode(line, getLabelNode(start)));
}
@@ -494,10 +658,57 @@ public class MethodNode extends MethodVisitor {
* versions of the ASM API than the given version.
*
* @param api
- * an ASM API version. Must be one of {@link Opcodes#ASM4}.
+ * an ASM API version. Must be one of {@link Opcodes#ASM4} or
+ * {@link Opcodes#ASM5}.
*/
public void check(final int api) {
- // nothing to do
+ if (api == Opcodes.ASM4) {
+ if (visibleTypeAnnotations != null
+ && visibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (invisibleTypeAnnotations != null
+ && invisibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ int n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size();
+ for (int i = 0; i < n; ++i) {
+ TryCatchBlockNode tcb = tryCatchBlocks.get(i);
+ if (tcb.visibleTypeAnnotations != null
+ && tcb.visibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (tcb.invisibleTypeAnnotations != null
+ && tcb.invisibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ }
+ for (int i = 0; i < instructions.size(); ++i) {
+ AbstractInsnNode insn = instructions.get(i);
+ if (insn.visibleTypeAnnotations != null
+ && insn.visibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (insn.invisibleTypeAnnotations != null
+ && insn.invisibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (insn instanceof MethodInsnNode) {
+ boolean itf = ((MethodInsnNode) insn).itf;
+ if (itf != (insn.opcode == Opcodes.INVOKEINTERFACE)) {
+ throw new RuntimeException();
+ }
+ }
+ }
+ if (visibleLocalVariableAnnotations != null
+ && visibleLocalVariableAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (invisibleLocalVariableAnnotations != null
+ && invisibleLocalVariableAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ }
}
/**
@@ -523,8 +734,14 @@ public class MethodNode extends MethodVisitor {
* a method visitor.
*/
public void accept(final MethodVisitor mv) {
- // visits the method attributes
+ // visits the method parameters
int i, j, n;
+ n = parameters == null ? 0 : parameters.size();
+ for (i = 0; i < n; i++) {
+ ParameterNode parameter = parameters.get(i);
+ mv.visitParameter(parameter.name, parameter.access);
+ }
+ // visits the method attributes
if (annotationDefault != null) {
AnnotationVisitor av = mv.visitAnnotationDefault();
AnnotationNode.accept(av, null, annotationDefault);
@@ -542,6 +759,19 @@ public class MethodNode extends MethodVisitor {
AnnotationNode an = invisibleAnnotations.get(i);
an.accept(mv.visitAnnotation(an.desc, false));
}
+ n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
+ for (i = 0; i < n; ++i) {
+ TypeAnnotationNode an = visibleTypeAnnotations.get(i);
+ an.accept(mv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
+ true));
+ }
+ n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
+ .size();
+ for (i = 0; i < n; ++i) {
+ TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
+ an.accept(mv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
+ false));
+ }
n = visibleParameterAnnotations == null ? 0
: visibleParameterAnnotations.length;
for (i = 0; i < n; ++i) {
@@ -579,6 +809,7 @@ public class MethodNode extends MethodVisitor {
// visits try catch blocks
n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size();
for (i = 0; i < n; ++i) {
+ tryCatchBlocks.get(i).updateIndex(i);
tryCatchBlocks.get(i).accept(mv);
}
// visits instructions
@@ -588,6 +819,17 @@ public class MethodNode extends MethodVisitor {
for (i = 0; i < n; ++i) {
localVariables.get(i).accept(mv);
}
+ // visits local variable annotations
+ n = visibleLocalVariableAnnotations == null ? 0
+ : visibleLocalVariableAnnotations.size();
+ for (i = 0; i < n; ++i) {
+ visibleLocalVariableAnnotations.get(i).accept(mv, true);
+ }
+ n = invisibleLocalVariableAnnotations == null ? 0
+ : invisibleLocalVariableAnnotations.size();
+ for (i = 0; i < n; ++i) {
+ invisibleLocalVariableAnnotations.get(i).accept(mv, false);
+ }
// visits maxs
mv.visitMaxs(maxStack, maxLocals);
visited = true;
diff --git a/src/asm/scala/tools/asm/tree/MultiANewArrayInsnNode.java b/src/asm/scala/tools/asm/tree/MultiANewArrayInsnNode.java
index fe5e8832b3..a8339a20b5 100644
--- a/src/asm/scala/tools/asm/tree/MultiANewArrayInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/MultiANewArrayInsnNode.java
@@ -73,11 +73,12 @@ public class MultiANewArrayInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitMultiANewArrayInsn(desc, dims);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new MultiANewArrayInsnNode(desc, dims);
+ return new MultiANewArrayInsnNode(desc, dims).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/ParameterNode.java b/src/asm/scala/tools/asm/tree/ParameterNode.java
new file mode 100644
index 0000000000..a3e55d5629
--- /dev/null
+++ b/src/asm/scala/tools/asm/tree/ParameterNode.java
@@ -0,0 +1,76 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the copyright holders 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.
+ */
+package scala.tools.asm.tree;
+
+import scala.tools.asm.MethodVisitor;
+
+/**
+ * A node that represents a parameter access and name.
+ *
+ * @author Remi Forax
+ */
+public class ParameterNode {
+ /**
+ * The parameter's name.
+ */
+ public String name;
+
+ /**
+ * The parameter's access flags (see {@link scala.tools.asm.Opcodes}).
+ * Valid values are <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt> and
+ * <tt>ACC_MANDATED</tt>.
+ */
+ public int access;
+
+ /**
+ * Constructs a new {@link ParameterNode}.
+ *
+ * @param access
+ * The parameter's access flags. Valid values are
+ * <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt> or/and
+ * <tt>ACC_MANDATED</tt> (see {@link scala.tools.asm.Opcodes}).
+ * @param name
+ * the parameter's name.
+ */
+ public ParameterNode(final String name, final int access) {
+ this.name = name;
+ this.access = access;
+ }
+
+ /**
+ * Makes the given visitor visit this parameter declaration.
+ *
+ * @param mv
+ * a method visitor.
+ */
+ public void accept(final MethodVisitor mv) {
+ mv.visitParameter(name, access);
+ }
+}
diff --git a/src/asm/scala/tools/asm/tree/TableSwitchInsnNode.java b/src/asm/scala/tools/asm/tree/TableSwitchInsnNode.java
index 9b3c2a3437..fb17b9e2e9 100644
--- a/src/asm/scala/tools/asm/tree/TableSwitchInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/TableSwitchInsnNode.java
@@ -103,11 +103,12 @@ public class TableSwitchInsnNode extends AbstractInsnNode {
labels[i] = this.labels.get(i).getLabel();
}
mv.visitTableSwitchInsn(min, max, dflt.getLabel(), labels);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new TableSwitchInsnNode(min, max, clone(dflt, labels), clone(
- this.labels, labels));
+ this.labels, labels)).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/TryCatchBlockNode.java b/src/asm/scala/tools/asm/tree/TryCatchBlockNode.java
index ab4fa97c34..c639b9aa8b 100644
--- a/src/asm/scala/tools/asm/tree/TryCatchBlockNode.java
+++ b/src/asm/scala/tools/asm/tree/TryCatchBlockNode.java
@@ -29,6 +29,8 @@
*/
package scala.tools.asm.tree;
+import java.util.List;
+
import scala.tools.asm.MethodVisitor;
/**
@@ -60,6 +62,26 @@ public class TryCatchBlockNode {
public String type;
/**
+ * The runtime visible type annotations on the exception handler type. This
+ * list is a list of {@link TypeAnnotationNode} objects. May be
+ * <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label visible
+ */
+ public List<TypeAnnotationNode> visibleTypeAnnotations;
+
+ /**
+ * The runtime invisible type annotations on the exception handler type.
+ * This list is a list of {@link TypeAnnotationNode} objects. May be
+ * <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label invisible
+ */
+ public List<TypeAnnotationNode> invisibleTypeAnnotations;
+
+ /**
* Constructs a new {@link TryCatchBlockNode}.
*
* @param start
@@ -82,6 +104,29 @@ public class TryCatchBlockNode {
}
/**
+ * Updates the index of this try catch block in the method's list of try
+ * catch block nodes. This index maybe stored in the 'target' field of the
+ * type annotations of this block.
+ *
+ * @param index
+ * the new index of this try catch block in the method's list of
+ * try catch block nodes.
+ */
+ public void updateIndex(final int index) {
+ int newTypeRef = 0x42000000 | (index << 8);
+ if (visibleTypeAnnotations != null) {
+ for (TypeAnnotationNode tan : visibleTypeAnnotations) {
+ tan.typeRef = newTypeRef;
+ }
+ }
+ if (invisibleTypeAnnotations != null) {
+ for (TypeAnnotationNode tan : invisibleTypeAnnotations) {
+ tan.typeRef = newTypeRef;
+ }
+ }
+ }
+
+ /**
* Makes the given visitor visit this try catch block.
*
* @param mv
@@ -90,5 +135,19 @@ public class TryCatchBlockNode {
public void accept(final MethodVisitor mv) {
mv.visitTryCatchBlock(start.getLabel(), end.getLabel(),
handler == null ? null : handler.getLabel(), type);
+ int n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations
+ .size();
+ for (int i = 0; i < n; ++i) {
+ TypeAnnotationNode an = visibleTypeAnnotations.get(i);
+ an.accept(mv.visitTryCatchAnnotation(an.typeRef, an.typePath,
+ an.desc, true));
+ }
+ n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
+ .size();
+ for (int i = 0; i < n; ++i) {
+ TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
+ an.accept(mv.visitTryCatchAnnotation(an.typeRef, an.typePath,
+ an.desc, false));
+ }
}
}
diff --git a/src/asm/scala/tools/asm/tree/TypeAnnotationNode.java b/src/asm/scala/tools/asm/tree/TypeAnnotationNode.java
new file mode 100644
index 0000000000..73b29624f7
--- /dev/null
+++ b/src/asm/scala/tools/asm/tree/TypeAnnotationNode.java
@@ -0,0 +1,100 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the copyright holders 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.
+ */
+package scala.tools.asm.tree;
+
+import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
+import scala.tools.asm.TypeReference;
+
+/**
+ * A node that represents a type annotationn.
+ *
+ * @author Eric Bruneton
+ */
+public class TypeAnnotationNode extends AnnotationNode {
+
+ /**
+ * A reference to the annotated type. See {@link TypeReference}.
+ */
+ public int typeRef;
+
+ /**
+ * The path to the annotated type argument, wildcard bound, array element
+ * type, or static outer type within the referenced type. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ */
+ public TypePath typePath;
+
+ /**
+ * Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this
+ * constructor</i>. Instead, they must use the
+ * {@link #TypeAnnotationNode(int, int, TypePath, String)} version.
+ *
+ * @param typeRef
+ * a reference to the annotated type. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
+ */
+ public TypeAnnotationNode(final int typeRef, final TypePath typePath,
+ final String desc) {
+ this(Opcodes.ASM5, typeRef, typePath, desc);
+ if (getClass() != TypeAnnotationNode.class) {
+ throw new IllegalStateException();
+ }
+ }
+
+ /**
+ * Constructs a new {@link AnnotationNode}.
+ *
+ * @param api
+ * the ASM API version implemented by this visitor. Must be one
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
+ * @param typeRef
+ * a reference to the annotated type. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ */
+ public TypeAnnotationNode(final int api, final int typeRef,
+ final TypePath typePath, final String desc) {
+ super(api, desc);
+ this.typeRef = typeRef;
+ this.typePath = typePath;
+ }
+}
diff --git a/src/asm/scala/tools/asm/tree/TypeInsnNode.java b/src/asm/scala/tools/asm/tree/TypeInsnNode.java
index 3210dd60e6..401400c3cb 100644
--- a/src/asm/scala/tools/asm/tree/TypeInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/TypeInsnNode.java
@@ -81,10 +81,11 @@ public class TypeInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitTypeInsn(opcode, desc);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new TypeInsnNode(opcode, desc);
+ return new TypeInsnNode(opcode, desc).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/VarInsnNode.java b/src/asm/scala/tools/asm/tree/VarInsnNode.java
index 5dd9ef6726..685e4fce2c 100644
--- a/src/asm/scala/tools/asm/tree/VarInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/VarInsnNode.java
@@ -84,10 +84,11 @@ public class VarInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitVarInsn(opcode, var);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new VarInsnNode(opcode, var);
+ return new VarInsnNode(opcode, var).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/analysis/AnalyzerException.java b/src/asm/scala/tools/asm/tree/analysis/AnalyzerException.java
index 5e3f51f21a..52b2a11d6f 100644
--- a/src/asm/scala/tools/asm/tree/analysis/AnalyzerException.java
+++ b/src/asm/scala/tools/asm/tree/analysis/AnalyzerException.java
@@ -37,6 +37,7 @@ import scala.tools.asm.tree.AbstractInsnNode;
* @author Bing Ran
* @author Eric Bruneton
*/
+@SuppressWarnings("serial")
public class AnalyzerException extends Exception {
public final AbstractInsnNode node;
diff --git a/src/asm/scala/tools/asm/tree/analysis/BasicInterpreter.java b/src/asm/scala/tools/asm/tree/analysis/BasicInterpreter.java
index 8d6653c1c5..7d0b7b0694 100644
--- a/src/asm/scala/tools/asm/tree/analysis/BasicInterpreter.java
+++ b/src/asm/scala/tools/asm/tree/analysis/BasicInterpreter.java
@@ -53,7 +53,7 @@ public class BasicInterpreter extends Interpreter<BasicValue> implements
Opcodes {
public BasicInterpreter() {
- super(ASM4);
+ super(ASM5);
}
protected BasicInterpreter(final int api) {
diff --git a/src/asm/scala/tools/asm/tree/analysis/BasicVerifier.java b/src/asm/scala/tools/asm/tree/analysis/BasicVerifier.java
index 71666edb74..b852f20acf 100644
--- a/src/asm/scala/tools/asm/tree/analysis/BasicVerifier.java
+++ b/src/asm/scala/tools/asm/tree/analysis/BasicVerifier.java
@@ -47,7 +47,7 @@ import scala.tools.asm.tree.MethodInsnNode;
public class BasicVerifier extends BasicInterpreter {
public BasicVerifier() {
- super(ASM4);
+ super(ASM5);
}
protected BasicVerifier(final int api) {
diff --git a/src/asm/scala/tools/asm/tree/analysis/Frame.java b/src/asm/scala/tools/asm/tree/analysis/Frame.java
index 0d92edc4d6..44a07ee27c 100644
--- a/src/asm/scala/tools/asm/tree/analysis/Frame.java
+++ b/src/asm/scala/tools/asm/tree/analysis/Frame.java
@@ -134,6 +134,15 @@ public class Frame<V extends Value> {
}
/**
+ * Returns the maximum stack size of this frame.
+ *
+ * @return the maximum stack size of this frame.
+ */
+ public int getMaxStackSize() {
+ return values.length - locals;
+ }
+
+ /**
* Returns the value of the given local variable.
*
* @param i
diff --git a/src/asm/scala/tools/asm/tree/analysis/SimpleVerifier.java b/src/asm/scala/tools/asm/tree/analysis/SimpleVerifier.java
index eaecd057ea..a345981f36 100644
--- a/src/asm/scala/tools/asm/tree/analysis/SimpleVerifier.java
+++ b/src/asm/scala/tools/asm/tree/analysis/SimpleVerifier.java
@@ -107,7 +107,7 @@ public class SimpleVerifier extends BasicVerifier {
public SimpleVerifier(final Type currentClass,
final Type currentSuperClass,
final List<Type> currentClassInterfaces, final boolean isInterface) {
- this(ASM4, currentClass, currentSuperClass, currentClassInterfaces,
+ this(ASM5, currentClass, currentSuperClass, currentClassInterfaces,
isInterface);
}
diff --git a/src/asm/scala/tools/asm/tree/analysis/SourceInterpreter.java b/src/asm/scala/tools/asm/tree/analysis/SourceInterpreter.java
index a68086c073..7d739d3df9 100644
--- a/src/asm/scala/tools/asm/tree/analysis/SourceInterpreter.java
+++ b/src/asm/scala/tools/asm/tree/analysis/SourceInterpreter.java
@@ -50,7 +50,7 @@ public class SourceInterpreter extends Interpreter<SourceValue> implements
Opcodes {
public SourceInterpreter() {
- super(ASM4);
+ super(ASM5);
}
protected SourceInterpreter(final int api) {
diff --git a/src/asm/scala/tools/asm/util/ASMifier.java b/src/asm/scala/tools/asm/util/ASMifier.java
index 7e6b223853..521e07541b 100644
--- a/src/asm/scala/tools/asm/util/ASMifier.java
+++ b/src/asm/scala/tools/asm/util/ASMifier.java
@@ -40,6 +40,7 @@ import scala.tools.asm.Handle;
import scala.tools.asm.Label;
import scala.tools.asm.Opcodes;
import scala.tools.asm.Type;
+import scala.tools.asm.TypePath;
/**
* A {@link Printer} that prints the ASM code to generate the classes if visits.
@@ -83,9 +84,15 @@ public class ASMifier extends Printer {
* Constructs a new {@link ASMifier}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #ASMifier(int, String, int)} version.
+ *
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public ASMifier() {
- this(Opcodes.ASM4, "cw", 0);
+ this(Opcodes.ASM5, "cw", 0);
+ if (getClass() != ASMifier.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -93,7 +100,7 @@ public class ASMifier extends Printer {
*
* @param api
* the ASM API version implemented by this class. Must be one of
- * {@link Opcodes#ASM4}.
+ * {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param name
* the name of the visitor variable in the produced code.
* @param id
@@ -170,7 +177,6 @@ public class ASMifier extends Printer {
}
text.add("import java.util.*;\n");
text.add("import scala.tools.asm.*;\n");
- text.add("import scala.tools.asm.attrs.*;\n");
text.add("public class " + simpleName + "Dump implements Opcodes {\n\n");
text.add("public static byte[] dump () throws Exception {\n\n");
text.add("ClassWriter cw = new ClassWriter(0);\n");
@@ -261,6 +267,12 @@ public class ASMifier extends Printer {
}
@Override
+ public ASMifier visitClassTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ return visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+
+ @Override
public void visitClassAttribute(final Attribute attr) {
visitAttribute(attr);
}
@@ -423,6 +435,12 @@ public class ASMifier extends Printer {
}
@Override
+ public ASMifier visitFieldTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ return visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+
+ @Override
public void visitFieldAttribute(final Attribute attr) {
visitAttribute(attr);
}
@@ -439,6 +457,16 @@ public class ASMifier extends Printer {
// ------------------------------------------------------------------------
@Override
+ public void visitParameter(String parameterName, int access) {
+ buf.setLength(0);
+ buf.append(name).append(".visitParameter(");
+ appendString(buf, parameterName);
+ buf.append(", ");
+ appendAccess(access);
+ text.add(buf.append(");\n").toString());
+ }
+
+ @Override
public ASMifier visitAnnotationDefault() {
buf.setLength(0);
buf.append("{\n").append("av0 = ").append(name)
@@ -457,6 +485,12 @@ public class ASMifier extends Printer {
}
@Override
+ public ASMifier visitMethodTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ return visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+
+ @Override
public ASMifier visitParameterAnnotation(final int parameter,
final String desc, final boolean visible) {
buf.setLength(0);
@@ -582,9 +616,30 @@ public class ASMifier extends Printer {
text.add(buf.toString());
}
+ @Deprecated
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) {
+ if (api >= Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc);
+ return;
+ }
+ doVisitMethodInsn(opcode, owner, name, desc,
+ opcode == Opcodes.INVOKEINTERFACE);
+ }
+
+ @Override
+ public void visitMethodInsn(final int opcode, final String owner,
+ final String name, final String desc, final boolean itf) {
+ if (api < Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc, itf);
+ return;
+ }
+ doVisitMethodInsn(opcode, owner, name, desc, itf);
+ }
+
+ private void doVisitMethodInsn(final int opcode, final String owner,
+ final String name, final String desc, final boolean itf) {
buf.setLength(0);
buf.append(this.name).append(".visitMethodInsn(")
.append(OPCODES[opcode]).append(", ");
@@ -593,6 +648,8 @@ public class ASMifier extends Printer {
appendConstant(name);
buf.append(", ");
appendConstant(desc);
+ buf.append(", ");
+ buf.append(itf ? "true" : "false");
buf.append(");\n");
text.add(buf.toString());
}
@@ -711,6 +768,13 @@ public class ASMifier extends Printer {
}
@Override
+ public ASMifier visitInsnAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ return visitTypeAnnotation("visitInsnAnnotation", typeRef, typePath,
+ desc, visible);
+ }
+
+ @Override
public void visitTryCatchBlock(final Label start, final Label end,
final Label handler, final String type) {
buf.setLength(0);
@@ -730,6 +794,13 @@ public class ASMifier extends Printer {
}
@Override
+ public ASMifier visitTryCatchAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ return visitTypeAnnotation("visitTryCatchAnnotation", typeRef,
+ typePath, desc, visible);
+ }
+
+ @Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
final int index) {
@@ -749,6 +820,39 @@ public class ASMifier extends Printer {
}
@Override
+ public Printer visitLocalVariableAnnotation(int typeRef, TypePath typePath,
+ Label[] start, Label[] end, int[] index, String desc,
+ boolean visible) {
+ buf.setLength(0);
+ buf.append("{\n").append("av0 = ").append(name)
+ .append(".visitLocalVariableAnnotation(");
+ buf.append(typeRef);
+ buf.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
+ buf.append("new Label[] {");
+ for (int i = 0; i < start.length; ++i) {
+ buf.append(i == 0 ? " " : ", ");
+ appendLabel(start[i]);
+ }
+ buf.append(" }, new Label[] {");
+ for (int i = 0; i < end.length; ++i) {
+ buf.append(i == 0 ? " " : ", ");
+ appendLabel(end[i]);
+ }
+ buf.append(" }, new int[] {");
+ for (int i = 0; i < index.length; ++i) {
+ buf.append(i == 0 ? " " : ", ").append(index[i]);
+ }
+ buf.append(" }, ");
+ appendConstant(desc);
+ buf.append(", ").append(visible).append(");\n");
+ text.add(buf.toString());
+ ASMifier a = createASMifier("av", 0);
+ text.add(a.getText());
+ text.add("}\n");
+ return a;
+ }
+
+ @Override
public void visitLineNumber(final int line, final Label start) {
buf.setLength(0);
buf.append(name).append(".visitLineNumber(").append(line).append(", ");
@@ -789,6 +893,28 @@ public class ASMifier extends Printer {
return a;
}
+ public ASMifier visitTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ return visitTypeAnnotation("visitTypeAnnotation", typeRef, typePath,
+ desc, visible);
+ }
+
+ public ASMifier visitTypeAnnotation(final String method, final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ buf.setLength(0);
+ buf.append("{\n").append("av0 = ").append(name).append(".")
+ .append(method).append("(");
+ buf.append(typeRef);
+ buf.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
+ appendConstant(desc);
+ buf.append(", ").append(visible).append(");\n");
+ text.add(buf.toString());
+ ASMifier a = createASMifier("av", 0);
+ text.add(a.getText());
+ text.add("}\n");
+ return a;
+ }
+
public void visitAttribute(final Attribute attr) {
buf.setLength(0);
buf.append("// ATTRIBUTE ").append(attr.type).append('\n');
@@ -809,7 +935,7 @@ public class ASMifier extends Printer {
// ------------------------------------------------------------------------
protected ASMifier createASMifier(final String name, final int id) {
- return new ASMifier(Opcodes.ASM4, name, id);
+ return new ASMifier(Opcodes.ASM5, name, id);
}
/**
@@ -950,6 +1076,13 @@ public class ASMifier extends Printer {
buf.append("ACC_DEPRECATED");
first = false;
}
+ if ((access & Opcodes.ACC_MANDATED) != 0) {
+ if (!first) {
+ buf.append(" + ");
+ }
+ buf.append("ACC_MANDATED");
+ first = false;
+ }
if (first) {
buf.append('0');
}
diff --git a/src/asm/scala/tools/asm/util/CheckAnnotationAdapter.java b/src/asm/scala/tools/asm/util/CheckAnnotationAdapter.java
index f00a8f04a2..70441d1df4 100644
--- a/src/asm/scala/tools/asm/util/CheckAnnotationAdapter.java
+++ b/src/asm/scala/tools/asm/util/CheckAnnotationAdapter.java
@@ -49,7 +49,7 @@ public class CheckAnnotationAdapter extends AnnotationVisitor {
}
CheckAnnotationAdapter(final AnnotationVisitor av, final boolean named) {
- super(Opcodes.ASM4, av);
+ super(Opcodes.ASM5, av);
this.named = named;
}
@@ -70,7 +70,7 @@ public class CheckAnnotationAdapter extends AnnotationVisitor {
}
if (value instanceof Type) {
int sort = ((Type) value).getSort();
- if (sort != Type.OBJECT && sort != Type.ARRAY) {
+ if (sort == Type.METHOD) {
throw new IllegalArgumentException("Invalid annotation value");
}
}
diff --git a/src/asm/scala/tools/asm/util/CheckClassAdapter.java b/src/asm/scala/tools/asm/util/CheckClassAdapter.java
index 0bfa143a95..9909208cc4 100644
--- a/src/asm/scala/tools/asm/util/CheckClassAdapter.java
+++ b/src/asm/scala/tools/asm/util/CheckClassAdapter.java
@@ -46,6 +46,8 @@ import scala.tools.asm.Label;
import scala.tools.asm.MethodVisitor;
import scala.tools.asm.Opcodes;
import scala.tools.asm.Type;
+import scala.tools.asm.TypePath;
+import scala.tools.asm.TypeReference;
import scala.tools.asm.tree.ClassNode;
import scala.tools.asm.tree.MethodNode;
import scala.tools.asm.tree.analysis.Analyzer;
@@ -91,9 +93,9 @@ import scala.tools.asm.tree.analysis.SimpleVerifier;
* insnNumber locals : stack):
*
* <pre>
- * scala.tools.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found .
- * at scala.tools.asm.tree.analysis.Analyzer.analyze(Analyzer.java:289)
- * at scala.tools.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:135)
+ * org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found .
+ * at org.objectweb.asm.tree.analysis.Analyzer.analyze(Analyzer.java:289)
+ * at org.objectweb.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:135)
* ...
* remove()V
* 00000 LinkedBlockingQueue$Itr . . . . . . . . :
@@ -106,7 +108,7 @@ import scala.tools.asm.tree.analysis.SimpleVerifier;
* 00071 LinkedBlockingQueue$Itr <b>.</b> I . . . . . . :
* ILOAD 1
* 00072 <b>?</b>
- * INVOKESPECIAL java/lang/Integer.<init> (I)V
+ * INVOKESPECIAL java/lang/Integer.&lt;init&gt; (I)V
* ...
* </pre>
*
@@ -215,7 +217,7 @@ public class CheckClassAdapter extends ClassVisitor {
List<Type> interfaces = new ArrayList<Type>();
for (Iterator<String> i = cn.interfaces.iterator(); i.hasNext();) {
- interfaces.add(Type.getObjectType(i.next().toString()));
+ interfaces.add(Type.getObjectType(i.next()));
}
for (int i = 0; i < methods.size(); ++i) {
@@ -328,9 +330,14 @@ public class CheckClassAdapter extends ClassVisitor {
* <tt>false</tt> to not perform any data flow check (see
* {@link CheckMethodAdapter}). This option requires valid
* maxLocals and maxStack values.
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) {
- this(Opcodes.ASM4, cv, checkDataFlow);
+ this(Opcodes.ASM5, cv, checkDataFlow);
+ if (getClass() != CheckClassAdapter.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -338,7 +345,7 @@ public class CheckClassAdapter extends ClassVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param cv
* the class visitor to which this adapter must delegate calls.
* @param checkDataFlow
@@ -440,7 +447,15 @@ public class CheckClassAdapter extends ClassVisitor {
CheckMethodAdapter.checkInternalName(outerName, "outer class name");
}
if (innerName != null) {
- CheckMethodAdapter.checkIdentifier(innerName, "inner class name");
+ int start = 0;
+ while (start < innerName.length()
+ && Character.isDigit(innerName.charAt(start))) {
+ start++;
+ }
+ if (start == 0 || start < innerName.length()) {
+ CheckMethodAdapter.checkIdentifier(innerName, start, -1,
+ "inner class name");
+ }
}
checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
+ Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
@@ -517,6 +532,23 @@ public class CheckClassAdapter extends ClassVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ checkState();
+ int sort = typeRef >>> 24;
+ if (sort != TypeReference.CLASS_TYPE_PARAMETER
+ && sort != TypeReference.CLASS_TYPE_PARAMETER_BOUND
+ && sort != TypeReference.CLASS_EXTENDS) {
+ throw new IllegalArgumentException("Invalid type reference sort 0x"
+ + Integer.toHexString(sort));
+ }
+ checkTypeRefAndPath(typeRef, typePath);
+ CheckMethodAdapter.checkDesc(desc, false);
+ return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef,
+ typePath, desc, visible));
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
checkState();
if (attr == null) {
@@ -661,6 +693,77 @@ public class CheckClassAdapter extends ClassVisitor {
}
/**
+ * Checks the reference to a type in a type annotation.
+ *
+ * @param typeRef
+ * a reference to an annotated type.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ */
+ static void checkTypeRefAndPath(int typeRef, TypePath typePath) {
+ int mask = 0;
+ switch (typeRef >>> 24) {
+ case TypeReference.CLASS_TYPE_PARAMETER:
+ case TypeReference.METHOD_TYPE_PARAMETER:
+ case TypeReference.METHOD_FORMAL_PARAMETER:
+ mask = 0xFFFF0000;
+ break;
+ case TypeReference.FIELD:
+ case TypeReference.METHOD_RETURN:
+ case TypeReference.METHOD_RECEIVER:
+ case TypeReference.LOCAL_VARIABLE:
+ case TypeReference.RESOURCE_VARIABLE:
+ case TypeReference.INSTANCEOF:
+ case TypeReference.NEW:
+ case TypeReference.CONSTRUCTOR_REFERENCE:
+ case TypeReference.METHOD_REFERENCE:
+ mask = 0xFF000000;
+ break;
+ case TypeReference.CLASS_EXTENDS:
+ case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
+ case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
+ case TypeReference.THROWS:
+ case TypeReference.EXCEPTION_PARAMETER:
+ mask = 0xFFFFFF00;
+ break;
+ case TypeReference.CAST:
+ case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+ case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
+ case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
+ case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
+ mask = 0xFF0000FF;
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid type reference sort 0x"
+ + Integer.toHexString(typeRef >>> 24));
+ }
+ if ((typeRef & ~mask) != 0) {
+ throw new IllegalArgumentException("Invalid type reference 0x"
+ + Integer.toHexString(typeRef));
+ }
+ if (typePath != null) {
+ for (int i = 0; i < typePath.getLength(); ++i) {
+ int step = typePath.getStep(i);
+ if (step != TypePath.ARRAY_ELEMENT
+ && step != TypePath.INNER_TYPE
+ && step != TypePath.TYPE_ARGUMENT
+ && step != TypePath.WILDCARD_BOUND) {
+ throw new IllegalArgumentException(
+ "Invalid type path step " + i + " in " + typePath);
+ }
+ if (step != TypePath.TYPE_ARGUMENT
+ && typePath.getStepArgument(i) != 0) {
+ throw new IllegalArgumentException(
+ "Invalid type path step argument for step " + i
+ + " in " + typePath);
+ }
+ }
+ }
+ }
+
+ /**
* Checks the formal type parameters of a class or method signature.
*
* @param signature
diff --git a/src/asm/scala/tools/asm/util/CheckFieldAdapter.java b/src/asm/scala/tools/asm/util/CheckFieldAdapter.java
index 4657605936..e682df47af 100644
--- a/src/asm/scala/tools/asm/util/CheckFieldAdapter.java
+++ b/src/asm/scala/tools/asm/util/CheckFieldAdapter.java
@@ -33,6 +33,8 @@ import scala.tools.asm.AnnotationVisitor;
import scala.tools.asm.Attribute;
import scala.tools.asm.FieldVisitor;
import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
+import scala.tools.asm.TypeReference;
/**
* A {@link FieldVisitor} that checks that its methods are properly used.
@@ -48,9 +50,14 @@ public class CheckFieldAdapter extends FieldVisitor {
*
* @param fv
* the field visitor to which this adapter must delegate calls.
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public CheckFieldAdapter(final FieldVisitor fv) {
- this(Opcodes.ASM4, fv);
+ this(Opcodes.ASM5, fv);
+ if (getClass() != CheckFieldAdapter.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -58,7 +65,7 @@ public class CheckFieldAdapter extends FieldVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param fv
* the field visitor to which this adapter must delegate calls.
*/
@@ -75,6 +82,21 @@ public class CheckFieldAdapter extends FieldVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ checkEnd();
+ int sort = typeRef >>> 24;
+ if (sort != TypeReference.FIELD) {
+ throw new IllegalArgumentException("Invalid type reference sort 0x"
+ + Integer.toHexString(sort));
+ }
+ CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
+ CheckMethodAdapter.checkDesc(desc, false);
+ return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef,
+ typePath, desc, visible));
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
checkEnd();
if (attr == null) {
diff --git a/src/asm/scala/tools/asm/util/CheckMethodAdapter.java b/src/asm/scala/tools/asm/util/CheckMethodAdapter.java
index 9da01c9d6e..131dfa5e5b 100644
--- a/src/asm/scala/tools/asm/util/CheckMethodAdapter.java
+++ b/src/asm/scala/tools/asm/util/CheckMethodAdapter.java
@@ -46,6 +46,8 @@ import scala.tools.asm.Label;
import scala.tools.asm.MethodVisitor;
import scala.tools.asm.Opcodes;
import scala.tools.asm.Type;
+import scala.tools.asm.TypePath;
+import scala.tools.asm.TypeReference;
import scala.tools.asm.tree.MethodNode;
import scala.tools.asm.tree.analysis.Analyzer;
import scala.tools.asm.tree.analysis.BasicValue;
@@ -390,10 +392,15 @@ public class CheckMethodAdapter extends MethodVisitor {
* the method visitor to which this adapter must delegate calls.
* @param labels
* a map of already visited labels (in other methods).
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public CheckMethodAdapter(final MethodVisitor mv,
final Map<Label, Integer> labels) {
- this(Opcodes.ASM4, mv, labels);
+ this(Opcodes.ASM5, mv, labels);
+ if (getClass() != CheckMethodAdapter.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -434,7 +441,7 @@ public class CheckMethodAdapter extends MethodVisitor {
public CheckMethodAdapter(final int access, final String name,
final String desc, final MethodVisitor cmv,
final Map<Label, Integer> labels) {
- this(new MethodNode(access, name, desc, null, null) {
+ this(new MethodNode(Opcodes.ASM5, access, name, desc, null, null) {
@Override
public void visitEnd() {
Analyzer<BasicValue> a = new Analyzer<BasicValue>(
@@ -462,6 +469,16 @@ public class CheckMethodAdapter extends MethodVisitor {
}
@Override
+ public void visitParameter(String name, int access) {
+ if (name != null) {
+ checkUnqualifiedName(version, name, "name");
+ }
+ CheckClassAdapter.checkAccess(access, Opcodes.ACC_FINAL
+ + Opcodes.ACC_MANDATED + Opcodes.ACC_SYNTHETIC);
+ super.visitParameter(name, access);
+ }
+
+ @Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
checkEndMethod();
@@ -470,6 +487,26 @@ public class CheckMethodAdapter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ checkEndMethod();
+ int sort = typeRef >>> 24;
+ if (sort != TypeReference.METHOD_TYPE_PARAMETER
+ && sort != TypeReference.METHOD_TYPE_PARAMETER_BOUND
+ && sort != TypeReference.METHOD_RETURN
+ && sort != TypeReference.METHOD_RECEIVER
+ && sort != TypeReference.METHOD_FORMAL_PARAMETER
+ && sort != TypeReference.THROWS) {
+ throw new IllegalArgumentException("Invalid type reference sort 0x"
+ + Integer.toHexString(sort));
+ }
+ CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
+ CheckMethodAdapter.checkDesc(desc, false);
+ return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef,
+ typePath, desc, visible));
+ }
+
+ @Override
public AnnotationVisitor visitAnnotationDefault() {
checkEndMethod();
return new CheckAnnotationAdapter(super.visitAnnotationDefault(), false);
@@ -647,9 +684,30 @@ public class CheckMethodAdapter extends MethodVisitor {
++insnCount;
}
+ @Deprecated
@Override
- public void visitMethodInsn(final int opcode, final String owner,
- final String name, final String desc) {
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc) {
+ if (api >= Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc);
+ return;
+ }
+ doVisitMethodInsn(opcode, owner, name, desc,
+ opcode == Opcodes.INVOKEINTERFACE);
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc, boolean itf) {
+ if (api < Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc, itf);
+ return;
+ }
+ doVisitMethodInsn(opcode, owner, name, desc, itf);
+ }
+
+ private void doVisitMethodInsn(int opcode, final String owner,
+ final String name, final String desc, final boolean itf) {
checkStartCode();
checkEndCode();
checkOpcode(opcode, 5);
@@ -658,7 +716,21 @@ public class CheckMethodAdapter extends MethodVisitor {
}
checkInternalName(owner, "owner");
checkMethodDesc(desc);
- super.visitMethodInsn(opcode, owner, name, desc);
+ if (opcode == Opcodes.INVOKEVIRTUAL && itf) {
+ throw new IllegalArgumentException(
+ "INVOKEVIRTUAL can't be used with interfaces");
+ }
+ if (opcode == Opcodes.INVOKEINTERFACE && !itf) {
+ throw new IllegalArgumentException(
+ "INVOKEINTERFACE can't be used with classes");
+ }
+ // Calling super.visitMethodInsn requires to call the correct version
+ // depending on this.api (otherwise infinite loops can occur). To
+ // simplify and to make it easier to automatically remove the backward
+ // compatibility code, we inline the code of the overridden method here.
+ if (mv != null) {
+ mv.visitMethodInsn(opcode, owner, name, desc, itf);
+ }
++insnCount;
}
@@ -797,6 +869,29 @@ public class CheckMethodAdapter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitInsnAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ checkStartCode();
+ checkEndCode();
+ int sort = typeRef >>> 24;
+ if (sort != TypeReference.INSTANCEOF && sort != TypeReference.NEW
+ && sort != TypeReference.CONSTRUCTOR_REFERENCE
+ && sort != TypeReference.METHOD_REFERENCE
+ && sort != TypeReference.CAST
+ && sort != TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ && sort != TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT
+ && sort != TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ && sort != TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT) {
+ throw new IllegalArgumentException("Invalid type reference sort 0x"
+ + Integer.toHexString(sort));
+ }
+ CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
+ CheckMethodAdapter.checkDesc(desc, false);
+ return new CheckAnnotationAdapter(super.visitInsnAnnotation(typeRef,
+ typePath, desc, visible));
+ }
+
+ @Override
public void visitTryCatchBlock(final Label start, final Label end,
final Label handler, final String type) {
checkStartCode();
@@ -821,6 +916,22 @@ public class CheckMethodAdapter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTryCatchAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ checkStartCode();
+ checkEndCode();
+ int sort = typeRef >>> 24;
+ if (sort != TypeReference.EXCEPTION_PARAMETER) {
+ throw new IllegalArgumentException("Invalid type reference sort 0x"
+ + Integer.toHexString(sort));
+ }
+ CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
+ CheckMethodAdapter.checkDesc(desc, false);
+ return new CheckAnnotationAdapter(super.visitTryCatchAnnotation(
+ typeRef, typePath, desc, visible));
+ }
+
+ @Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
final int index) {
@@ -841,6 +952,40 @@ public class CheckMethodAdapter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
+ TypePath typePath, Label[] start, Label[] end, int[] index,
+ String desc, boolean visible) {
+ checkStartCode();
+ checkEndCode();
+ int sort = typeRef >>> 24;
+ if (sort != TypeReference.LOCAL_VARIABLE
+ && sort != TypeReference.RESOURCE_VARIABLE) {
+ throw new IllegalArgumentException("Invalid type reference sort 0x"
+ + Integer.toHexString(sort));
+ }
+ CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
+ checkDesc(desc, false);
+ if (start == null || end == null || index == null
+ || end.length != start.length || index.length != start.length) {
+ throw new IllegalArgumentException(
+ "Invalid start, end and index arrays (must be non null and of identical length");
+ }
+ for (int i = 0; i < start.length; ++i) {
+ checkLabel(start[i], true, "start label");
+ checkLabel(end[i], true, "end label");
+ checkUnsignedShort(index[i], "Invalid variable index");
+ int s = labels.get(start[i]).intValue();
+ int e = labels.get(end[i]).intValue();
+ if (e < s) {
+ throw new IllegalArgumentException(
+ "Invalid start and end labels (end must be greater than start)");
+ }
+ }
+ return super.visitLocalVariableAnnotation(typeRef, typePath, start,
+ end, index, desc, visible);
+ }
+
+ @Override
public void visitLineNumber(final int line, final Label start) {
checkStartCode();
checkEndCode();
@@ -1202,7 +1347,7 @@ public class CheckMethodAdapter extends MethodVisitor {
checkIdentifier(name, begin, slash, null);
begin = slash + 1;
} while (slash != max);
- } catch (IllegalArgumentException _) {
+ } catch (IllegalArgumentException unused) {
throw new IllegalArgumentException(
"Invalid "
+ msg
@@ -1280,7 +1425,7 @@ public class CheckMethodAdapter extends MethodVisitor {
}
try {
checkInternalName(desc, start + 1, index, null);
- } catch (IllegalArgumentException _) {
+ } catch (IllegalArgumentException unused) {
throw new IllegalArgumentException("Invalid descriptor: "
+ desc);
}
diff --git a/src/asm/scala/tools/asm/util/CheckSignatureAdapter.java b/src/asm/scala/tools/asm/util/CheckSignatureAdapter.java
index e69302b8a6..54c9033c90 100644
--- a/src/asm/scala/tools/asm/util/CheckSignatureAdapter.java
+++ b/src/asm/scala/tools/asm/util/CheckSignatureAdapter.java
@@ -113,7 +113,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
* <tt>null</tt>.
*/
public CheckSignatureAdapter(final int type, final SignatureVisitor sv) {
- this(Opcodes.ASM4, type, sv);
+ this(Opcodes.ASM5, type, sv);
}
/**
@@ -121,7 +121,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param type
* the type of signature to be checked. See
* {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and
diff --git a/src/asm/scala/tools/asm/util/Printer.java b/src/asm/scala/tools/asm/util/Printer.java
index 86e0f9e122..4135672c6b 100644
--- a/src/asm/scala/tools/asm/util/Printer.java
+++ b/src/asm/scala/tools/asm/util/Printer.java
@@ -37,6 +37,7 @@ import scala.tools.asm.Attribute;
import scala.tools.asm.Handle;
import scala.tools.asm.Label;
import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
/**
* An abstract converter from visit events to text.
@@ -116,7 +117,7 @@ public abstract class Printer {
/**
* The ASM API version implemented by this class. The value of this field
- * must be one of {@link Opcodes#ASM4}.
+ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
protected final int api;
@@ -175,6 +176,15 @@ public abstract class Printer {
final boolean visible);
/**
+ * Class type annotation. See
+ * {@link scala.tools.asm.ClassVisitor#visitTypeAnnotation}.
+ */
+ public Printer visitClassTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
* Class attribute. See
* {@link scala.tools.asm.ClassVisitor#visitAttribute}.
*/
@@ -249,6 +259,15 @@ public abstract class Printer {
final boolean visible);
/**
+ * Field type annotation. See
+ * {@link scala.tools.asm.FieldVisitor#visitTypeAnnotation}.
+ */
+ public Printer visitFieldTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
* Field attribute. See
* {@link scala.tools.asm.FieldVisitor#visitAttribute}.
*/
@@ -264,6 +283,14 @@ public abstract class Printer {
// ------------------------------------------------------------------------
/**
+ * Method parameter. See
+ * {@link scala.tools.asm.MethodVisitor#visitParameter(String, int)}.
+ */
+ public void visitParameter(String name, int access) {
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
* Method default annotation. See
* {@link scala.tools.asm.MethodVisitor#visitAnnotationDefault}.
*/
@@ -277,6 +304,15 @@ public abstract class Printer {
final boolean visible);
/**
+ * Method type annotation. See
+ * {@link scala.tools.asm.MethodVisitor#visitTypeAnnotation}.
+ */
+ public Printer visitMethodTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
* Method parameter annotation. See
* {@link scala.tools.asm.MethodVisitor#visitParameterAnnotation}.
*/
@@ -336,8 +372,33 @@ public abstract class Printer {
* Method instruction. See
* {@link scala.tools.asm.MethodVisitor#visitMethodInsn}.
*/
- public abstract void visitMethodInsn(final int opcode, final String owner,
- final String name, final String desc);
+ @Deprecated
+ public void visitMethodInsn(final int opcode, final String owner,
+ final String name, final String desc) {
+ if (api >= Opcodes.ASM5) {
+ boolean itf = opcode == Opcodes.INVOKEINTERFACE;
+ visitMethodInsn(opcode, owner, name, desc, itf);
+ return;
+ }
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
+ * Method instruction. See
+ * {@link scala.tools.asm.MethodVisitor#visitMethodInsn}.
+ */
+ public void visitMethodInsn(final int opcode, final String owner,
+ final String name, final String desc, final boolean itf) {
+ if (api < Opcodes.ASM5) {
+ if (itf != (opcode == Opcodes.INVOKEINTERFACE)) {
+ throw new IllegalArgumentException(
+ "INVOKESPECIAL/STATIC on interfaces require ASM 5");
+ }
+ visitMethodInsn(opcode, owner, name, desc);
+ return;
+ }
+ throw new RuntimeException("Must be overriden");
+ }
/**
* Method instruction. See
@@ -391,6 +452,15 @@ public abstract class Printer {
final int dims);
/**
+ * Instruction type annotation. See
+ * {@link scala.tools.asm.MethodVisitor#visitInsnAnnotation}.
+ */
+ public Printer visitInsnAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
* Method exception handler. See
* {@link scala.tools.asm.MethodVisitor#visitTryCatchBlock}.
*/
@@ -398,6 +468,15 @@ public abstract class Printer {
final Label handler, final String type);
/**
+ * Try catch block type annotation. See
+ * {@link scala.tools.asm.MethodVisitor#visitTryCatchAnnotation}.
+ */
+ public Printer visitTryCatchAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
* Method debug info. See
* {@link scala.tools.asm.MethodVisitor#visitLocalVariable}.
*/
@@ -406,6 +485,16 @@ public abstract class Printer {
final Label end, final int index);
/**
+ * Local variable type annotation. See
+ * {@link scala.tools.asm.MethodVisitor#visitTryCatchAnnotation}.
+ */
+ public Printer visitLocalVariableAnnotation(final int typeRef,
+ final TypePath typePath, final Label[] start, final Label[] end,
+ final int[] index, final String desc, final boolean visible) {
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
* Method debug info. See
* {@link scala.tools.asm.MethodVisitor#visitLineNumber}.
*/
diff --git a/src/asm/scala/tools/asm/util/Textifier.java b/src/asm/scala/tools/asm/util/Textifier.java
index a5c4f6779e..373e46f5ed 100644
--- a/src/asm/scala/tools/asm/util/Textifier.java
+++ b/src/asm/scala/tools/asm/util/Textifier.java
@@ -40,6 +40,8 @@ import scala.tools.asm.Handle;
import scala.tools.asm.Label;
import scala.tools.asm.Opcodes;
import scala.tools.asm.Type;
+import scala.tools.asm.TypePath;
+import scala.tools.asm.TypeReference;
import scala.tools.asm.signature.SignatureReader;
/**
@@ -135,15 +137,26 @@ public class Textifier extends Printer {
*/
protected Map<Label, String> labelNames;
+ /**
+ * Class access flags
+ */
+ private int access;
+
private int valueNumber = 0;
/**
* Constructs a new {@link Textifier}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the {@link #Textifier(int)}
* version.
+ *
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public Textifier() {
- this(Opcodes.ASM4);
+ this(Opcodes.ASM5);
+ if (getClass() != Textifier.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -151,7 +164,7 @@ public class Textifier extends Printer {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
protected Textifier(final int api) {
super(api);
@@ -208,6 +221,7 @@ public class Textifier extends Printer {
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
final String[] interfaces) {
+ this.access = access;
int major = version & 0xFFFF;
int minor = version >>> 16;
buf.setLength(0);
@@ -294,6 +308,13 @@ public class Textifier extends Printer {
}
@Override
+ public Printer visitClassTypeAnnotation(int typeRef, TypePath typePath,
+ String desc, boolean visible) {
+ text.add("\n");
+ return visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+
+ @Override
public void visitClassAttribute(final Attribute attr) {
text.add("\n");
visitAttribute(attr);
@@ -393,7 +414,7 @@ public class Textifier extends Printer {
}
buf.append(tab);
- appendAccess(access);
+ appendAccess(access & ~Opcodes.ACC_VOLATILE);
if ((access & Opcodes.ACC_NATIVE) != 0) {
buf.append("native ");
}
@@ -403,6 +424,11 @@ public class Textifier extends Printer {
if ((access & Opcodes.ACC_BRIDGE) != 0) {
buf.append("bridge ");
}
+ if ((this.access & Opcodes.ACC_INTERFACE) != 0
+ && (access & Opcodes.ACC_ABSTRACT) == 0
+ && (access & Opcodes.ACC_STATIC) == 0) {
+ buf.append("default ");
+ }
buf.append(name);
appendDescriptor(METHOD_DESCRIPTOR, desc);
@@ -617,6 +643,12 @@ public class Textifier extends Printer {
}
@Override
+ public Printer visitFieldTypeAnnotation(int typeRef, TypePath typePath,
+ String desc, boolean visible) {
+ return visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+
+ @Override
public void visitFieldAttribute(final Attribute attr) {
visitAttribute(attr);
}
@@ -630,6 +662,16 @@ public class Textifier extends Printer {
// ------------------------------------------------------------------------
@Override
+ public void visitParameter(final String name, final int access) {
+ buf.setLength(0);
+ buf.append(tab2).append("// parameter ");
+ appendAccess(access);
+ buf.append(' ').append((name == null) ? "<no name>" : name)
+ .append('\n');
+ text.add(buf.toString());
+ }
+
+ @Override
public Textifier visitAnnotationDefault() {
text.add(tab2 + "default=");
Textifier t = createTextifier();
@@ -645,6 +687,12 @@ public class Textifier extends Printer {
}
@Override
+ public Printer visitMethodTypeAnnotation(int typeRef, TypePath typePath,
+ String desc, boolean visible) {
+ return visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+
+ @Override
public Textifier visitParameterAnnotation(final int parameter,
final String desc, final boolean visible) {
buf.setLength(0);
@@ -761,9 +809,30 @@ public class Textifier extends Printer {
text.add(buf.toString());
}
+ @Deprecated
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) {
+ if (api >= Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc);
+ return;
+ }
+ doVisitMethodInsn(opcode, owner, name, desc,
+ opcode == Opcodes.INVOKEINTERFACE);
+ }
+
+ @Override
+ public void visitMethodInsn(final int opcode, final String owner,
+ final String name, final String desc, final boolean itf) {
+ if (api < Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc, itf);
+ return;
+ }
+ doVisitMethodInsn(opcode, owner, name, desc, itf);
+ }
+
+ private void doVisitMethodInsn(final int opcode, final String owner,
+ final String name, final String desc, final boolean itf) {
buf.setLength(0);
buf.append(tab2).append(OPCODES[opcode]).append(' ');
appendDescriptor(INTERNAL_NAME, owner);
@@ -781,26 +850,35 @@ public class Textifier extends Printer {
buf.append(name);
appendDescriptor(METHOD_DESCRIPTOR, desc);
buf.append(" [");
+ buf.append('\n');
+ buf.append(tab3);
appendHandle(bsm);
+ buf.append('\n');
buf.append(tab3).append("// arguments:");
if (bsmArgs.length == 0) {
buf.append(" none");
} else {
- buf.append('\n').append(tab3);
+ buf.append('\n');
for (int i = 0; i < bsmArgs.length; i++) {
+ buf.append(tab3);
Object cst = bsmArgs[i];
if (cst instanceof String) {
Printer.appendString(buf, (String) cst);
} else if (cst instanceof Type) {
- buf.append(((Type) cst).getDescriptor()).append(".class");
+ Type type = (Type) cst;
+ if(type.getSort() == Type.METHOD){
+ appendDescriptor(METHOD_DESCRIPTOR, type.getDescriptor());
+ } else {
+ buf.append(type.getDescriptor()).append(".class");
+ }
} else if (cst instanceof Handle) {
appendHandle((Handle) cst);
} else {
buf.append(cst);
}
- buf.append(", ");
+ buf.append(", \n");
}
- buf.setLength(buf.length() - 2);
+ buf.setLength(buf.length() - 3);
}
buf.append('\n');
buf.append(tab2).append("]\n");
@@ -890,6 +968,12 @@ public class Textifier extends Printer {
}
@Override
+ public Printer visitInsnAnnotation(int typeRef, TypePath typePath,
+ String desc, boolean visible) {
+ return visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+
+ @Override
public void visitTryCatchBlock(final Label start, final Label end,
final Label handler, final String type) {
buf.setLength(0);
@@ -906,6 +990,25 @@ public class Textifier extends Printer {
}
@Override
+ public Printer visitTryCatchAnnotation(int typeRef, TypePath typePath,
+ String desc, boolean visible) {
+ buf.setLength(0);
+ buf.append(tab2).append("TRYCATCHBLOCK @");
+ appendDescriptor(FIELD_DESCRIPTOR, desc);
+ buf.append('(');
+ text.add(buf.toString());
+ Textifier t = createTextifier();
+ text.add(t.getText());
+ buf.setLength(0);
+ buf.append(") : ");
+ appendTypeReference(typeRef);
+ buf.append(", ").append(typePath);
+ buf.append(visible ? "\n" : " // invisible\n");
+ text.add(buf.toString());
+ return t;
+ }
+
+ @Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
final int index) {
@@ -932,6 +1035,33 @@ public class Textifier extends Printer {
}
@Override
+ public Printer visitLocalVariableAnnotation(int typeRef, TypePath typePath,
+ Label[] start, Label[] end, int[] index, String desc,
+ boolean visible) {
+ buf.setLength(0);
+ buf.append(tab2).append("LOCALVARIABLE @");
+ appendDescriptor(FIELD_DESCRIPTOR, desc);
+ buf.append('(');
+ text.add(buf.toString());
+ Textifier t = createTextifier();
+ text.add(t.getText());
+ buf.setLength(0);
+ buf.append(") : ");
+ appendTypeReference(typeRef);
+ buf.append(", ").append(typePath);
+ for (int i = 0; i < start.length; ++i) {
+ buf.append(" [ ");
+ appendLabel(start[i]);
+ buf.append(" - ");
+ appendLabel(end[i]);
+ buf.append(" - ").append(index[i]).append(" ]");
+ }
+ buf.append(visible ? "\n" : " // invisible\n");
+ text.add(buf.toString());
+ return t;
+ }
+
+ @Override
public void visitLineNumber(final int line, final Label start) {
buf.setLength(0);
buf.append(tab2).append("LINENUMBER ").append(line).append(' ');
@@ -981,6 +1111,39 @@ public class Textifier extends Printer {
}
/**
+ * Prints a disassembled view of the given type annotation.
+ *
+ * @param typeRef
+ * a reference to the annotated type. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values.
+ */
+ public Textifier visitTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ buf.setLength(0);
+ buf.append(tab).append('@');
+ appendDescriptor(FIELD_DESCRIPTOR, desc);
+ buf.append('(');
+ text.add(buf.toString());
+ Textifier t = createTextifier();
+ text.add(t.getText());
+ buf.setLength(0);
+ buf.append(") : ");
+ appendTypeReference(typeRef);
+ buf.append(", ").append(typePath);
+ buf.append(visible ? "\n" : " // invisible\n");
+ text.add(buf.toString());
+ return t;
+ }
+
+ /**
* Prints a disassembled view of the given attribute.
*
* @param attr
@@ -1061,10 +1224,10 @@ public class Textifier extends Printer {
* a handle, non null.
*/
protected void appendHandle(final Handle h) {
- buf.append('\n').append(tab3);
int tag = h.getTag();
buf.append("// handle kind 0x").append(Integer.toHexString(tag))
.append(" : ");
+ boolean isMethodHandle = false;
switch (tag) {
case Opcodes.H_GETFIELD:
buf.append("GETFIELD");
@@ -1080,18 +1243,23 @@ public class Textifier extends Printer {
break;
case Opcodes.H_INVOKEINTERFACE:
buf.append("INVOKEINTERFACE");
+ isMethodHandle = true;
break;
case Opcodes.H_INVOKESPECIAL:
buf.append("INVOKESPECIAL");
+ isMethodHandle = true;
break;
case Opcodes.H_INVOKESTATIC:
buf.append("INVOKESTATIC");
+ isMethodHandle = true;
break;
case Opcodes.H_INVOKEVIRTUAL:
buf.append("INVOKEVIRTUAL");
+ isMethodHandle = true;
break;
case Opcodes.H_NEWINVOKESPECIAL:
buf.append("NEWINVOKESPECIAL");
+ isMethodHandle = true;
break;
}
buf.append('\n');
@@ -1099,9 +1267,13 @@ public class Textifier extends Printer {
appendDescriptor(INTERNAL_NAME, h.getOwner());
buf.append('.');
buf.append(h.getName());
- buf.append('(');
+ if(!isMethodHandle){
+ buf.append('(');
+ }
appendDescriptor(HANDLE_DESCRIPTOR, h.getDesc());
- buf.append(')').append('\n');
+ if(!isMethodHandle){
+ buf.append(')');
+ }
}
/**
@@ -1145,6 +1317,9 @@ public class Textifier extends Printer {
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
buf.append("synthetic ");
}
+ if ((access & Opcodes.ACC_MANDATED) != 0) {
+ buf.append("mandated ");
+ }
if ((access & Opcodes.ACC_ENUM) != 0) {
buf.append("enum ");
}
@@ -1156,6 +1331,90 @@ public class Textifier extends Printer {
}
}
+ private void appendTypeReference(final int typeRef) {
+ TypeReference ref = new TypeReference(typeRef);
+ switch (ref.getSort()) {
+ case TypeReference.CLASS_TYPE_PARAMETER:
+ buf.append("CLASS_TYPE_PARAMETER ").append(
+ ref.getTypeParameterIndex());
+ break;
+ case TypeReference.METHOD_TYPE_PARAMETER:
+ buf.append("METHOD_TYPE_PARAMETER ").append(
+ ref.getTypeParameterIndex());
+ break;
+ case TypeReference.CLASS_EXTENDS:
+ buf.append("CLASS_EXTENDS ").append(ref.getSuperTypeIndex());
+ break;
+ case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
+ buf.append("CLASS_TYPE_PARAMETER_BOUND ")
+ .append(ref.getTypeParameterIndex()).append(", ")
+ .append(ref.getTypeParameterBoundIndex());
+ break;
+ case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
+ buf.append("METHOD_TYPE_PARAMETER_BOUND ")
+ .append(ref.getTypeParameterIndex()).append(", ")
+ .append(ref.getTypeParameterBoundIndex());
+ break;
+ case TypeReference.FIELD:
+ buf.append("FIELD");
+ break;
+ case TypeReference.METHOD_RETURN:
+ buf.append("METHOD_RETURN");
+ break;
+ case TypeReference.METHOD_RECEIVER:
+ buf.append("METHOD_RECEIVER");
+ break;
+ case TypeReference.METHOD_FORMAL_PARAMETER:
+ buf.append("METHOD_FORMAL_PARAMETER ").append(
+ ref.getFormalParameterIndex());
+ break;
+ case TypeReference.THROWS:
+ buf.append("THROWS ").append(ref.getExceptionIndex());
+ break;
+ case TypeReference.LOCAL_VARIABLE:
+ buf.append("LOCAL_VARIABLE");
+ break;
+ case TypeReference.RESOURCE_VARIABLE:
+ buf.append("RESOURCE_VARIABLE");
+ break;
+ case TypeReference.EXCEPTION_PARAMETER:
+ buf.append("EXCEPTION_PARAMETER ").append(
+ ref.getTryCatchBlockIndex());
+ break;
+ case TypeReference.INSTANCEOF:
+ buf.append("INSTANCEOF");
+ break;
+ case TypeReference.NEW:
+ buf.append("NEW");
+ break;
+ case TypeReference.CONSTRUCTOR_REFERENCE:
+ buf.append("CONSTRUCTOR_REFERENCE");
+ break;
+ case TypeReference.METHOD_REFERENCE:
+ buf.append("METHOD_REFERENCE");
+ break;
+ case TypeReference.CAST:
+ buf.append("CAST ").append(ref.getTypeArgumentIndex());
+ break;
+ case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+ buf.append("CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT ").append(
+ ref.getTypeArgumentIndex());
+ break;
+ case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
+ buf.append("METHOD_INVOCATION_TYPE_ARGUMENT ").append(
+ ref.getTypeArgumentIndex());
+ break;
+ case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
+ buf.append("CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT ").append(
+ ref.getTypeArgumentIndex());
+ break;
+ case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
+ buf.append("METHOD_REFERENCE_TYPE_ARGUMENT ").append(
+ ref.getTypeArgumentIndex());
+ break;
+ }
+ }
+
private void appendFrameTypes(final int n, final Object[] o) {
for (int i = 0; i < n; ++i) {
if (i > 0) {
diff --git a/src/asm/scala/tools/asm/util/TraceAnnotationVisitor.java b/src/asm/scala/tools/asm/util/TraceAnnotationVisitor.java
index 33e7cf0b26..7a9dbfef06 100644
--- a/src/asm/scala/tools/asm/util/TraceAnnotationVisitor.java
+++ b/src/asm/scala/tools/asm/util/TraceAnnotationVisitor.java
@@ -47,7 +47,7 @@ public final class TraceAnnotationVisitor extends AnnotationVisitor {
}
public TraceAnnotationVisitor(final AnnotationVisitor av, final Printer p) {
- super(Opcodes.ASM4, av);
+ super(Opcodes.ASM5, av);
this.p = p;
}
diff --git a/src/asm/scala/tools/asm/util/TraceClassVisitor.java b/src/asm/scala/tools/asm/util/TraceClassVisitor.java
index ff7a017482..842d286672 100644
--- a/src/asm/scala/tools/asm/util/TraceClassVisitor.java
+++ b/src/asm/scala/tools/asm/util/TraceClassVisitor.java
@@ -37,6 +37,7 @@ import scala.tools.asm.ClassVisitor;
import scala.tools.asm.FieldVisitor;
import scala.tools.asm.MethodVisitor;
import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
/**
* A {@link ClassVisitor} that prints the classes it visits with a
@@ -130,7 +131,7 @@ public final class TraceClassVisitor extends ClassVisitor {
*/
public TraceClassVisitor(final ClassVisitor cv, final Printer p,
final PrintWriter pw) {
- super(Opcodes.ASM4, cv);
+ super(Opcodes.ASM5, cv);
this.pw = pw;
this.p = p;
}
@@ -166,6 +167,16 @@ public final class TraceClassVisitor extends ClassVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ Printer p = this.p.visitClassTypeAnnotation(typeRef, typePath, desc,
+ visible);
+ AnnotationVisitor av = cv == null ? null : cv.visitTypeAnnotation(
+ typeRef, typePath, desc, visible);
+ return new TraceAnnotationVisitor(av, p);
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
p.visitClassAttribute(attr);
super.visitAttribute(attr);
diff --git a/src/asm/scala/tools/asm/util/TraceFieldVisitor.java b/src/asm/scala/tools/asm/util/TraceFieldVisitor.java
index 9547a70008..1d0743a424 100644
--- a/src/asm/scala/tools/asm/util/TraceFieldVisitor.java
+++ b/src/asm/scala/tools/asm/util/TraceFieldVisitor.java
@@ -33,6 +33,7 @@ import scala.tools.asm.AnnotationVisitor;
import scala.tools.asm.Attribute;
import scala.tools.asm.FieldVisitor;
import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
/**
* A {@link FieldVisitor} that prints the fields it visits with a
@@ -49,7 +50,7 @@ public final class TraceFieldVisitor extends FieldVisitor {
}
public TraceFieldVisitor(final FieldVisitor fv, final Printer p) {
- super(Opcodes.ASM4, fv);
+ super(Opcodes.ASM5, fv);
this.p = p;
}
@@ -63,6 +64,16 @@ public final class TraceFieldVisitor extends FieldVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ Printer p = this.p.visitFieldTypeAnnotation(typeRef, typePath, desc,
+ visible);
+ AnnotationVisitor av = fv == null ? null : fv.visitTypeAnnotation(
+ typeRef, typePath, desc, visible);
+ return new TraceAnnotationVisitor(av, p);
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
p.visitFieldAttribute(attr);
super.visitAttribute(attr);
diff --git a/src/asm/scala/tools/asm/util/TraceMethodVisitor.java b/src/asm/scala/tools/asm/util/TraceMethodVisitor.java
index 9034567c8f..db5f051003 100644
--- a/src/asm/scala/tools/asm/util/TraceMethodVisitor.java
+++ b/src/asm/scala/tools/asm/util/TraceMethodVisitor.java
@@ -35,6 +35,7 @@ import scala.tools.asm.Handle;
import scala.tools.asm.Label;
import scala.tools.asm.MethodVisitor;
import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
/**
* A {@link MethodVisitor} that prints the methods it visits with a
@@ -51,11 +52,17 @@ public final class TraceMethodVisitor extends MethodVisitor {
}
public TraceMethodVisitor(final MethodVisitor mv, final Printer p) {
- super(Opcodes.ASM4, mv);
+ super(Opcodes.ASM5, mv);
this.p = p;
}
@Override
+ public void visitParameter(String name, int access) {
+ p.visitParameter(name, access);
+ super.visitParameter(name, access);
+ }
+
+ @Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
Printer p = this.p.visitMethodAnnotation(desc, visible);
@@ -65,6 +72,16 @@ public final class TraceMethodVisitor extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ Printer p = this.p.visitMethodTypeAnnotation(typeRef, typePath, desc,
+ visible);
+ AnnotationVisitor av = mv == null ? null : mv.visitTypeAnnotation(
+ typeRef, typePath, desc, visible);
+ return new TraceAnnotationVisitor(av, p);
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
p.visitMethodAttribute(attr);
super.visitAttribute(attr);
@@ -130,11 +147,31 @@ public final class TraceMethodVisitor extends MethodVisitor {
super.visitFieldInsn(opcode, owner, name, desc);
}
+ @Deprecated
@Override
- public void visitMethodInsn(final int opcode, final String owner,
- final String name, final String desc) {
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc) {
+ if (api >= Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc);
+ return;
+ }
p.visitMethodInsn(opcode, owner, name, desc);
- super.visitMethodInsn(opcode, owner, name, desc);
+ if (mv != null) {
+ mv.visitMethodInsn(opcode, owner, name, desc);
+ }
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc, boolean itf) {
+ if (api < Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc, itf);
+ return;
+ }
+ p.visitMethodInsn(opcode, owner, name, desc, itf);
+ if (mv != null) {
+ mv.visitMethodInsn(opcode, owner, name, desc, itf);
+ }
}
@Override
@@ -189,6 +226,16 @@ public final class TraceMethodVisitor extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitInsnAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ Printer p = this.p
+ .visitInsnAnnotation(typeRef, typePath, desc, visible);
+ AnnotationVisitor av = mv == null ? null : mv.visitInsnAnnotation(
+ typeRef, typePath, desc, visible);
+ return new TraceAnnotationVisitor(av, p);
+ }
+
+ @Override
public void visitTryCatchBlock(final Label start, final Label end,
final Label handler, final String type) {
p.visitTryCatchBlock(start, end, handler, type);
@@ -196,6 +243,16 @@ public final class TraceMethodVisitor extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ Printer p = this.p.visitTryCatchAnnotation(typeRef, typePath, desc,
+ visible);
+ AnnotationVisitor av = mv == null ? null : mv.visitTryCatchAnnotation(
+ typeRef, typePath, desc, visible);
+ return new TraceAnnotationVisitor(av, p);
+ }
+
+ @Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
final int index) {
@@ -204,6 +261,18 @@ public final class TraceMethodVisitor extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
+ TypePath typePath, Label[] start, Label[] end, int[] index,
+ String desc, boolean visible) {
+ Printer p = this.p.visitLocalVariableAnnotation(typeRef, typePath,
+ start, end, index, desc, visible);
+ AnnotationVisitor av = mv == null ? null : mv
+ .visitLocalVariableAnnotation(typeRef, typePath, start, end,
+ index, desc, visible);
+ return new TraceAnnotationVisitor(av, p);
+ }
+
+ @Override
public void visitLineNumber(final int line, final Label start) {
p.visitLineNumber(line, start);
super.visitLineNumber(line, start);
diff --git a/src/asm/scala/tools/asm/util/TraceSignatureVisitor.java b/src/asm/scala/tools/asm/util/TraceSignatureVisitor.java
index 1e23c7ef1a..f99ec2b0c2 100644
--- a/src/asm/scala/tools/asm/util/TraceSignatureVisitor.java
+++ b/src/asm/scala/tools/asm/util/TraceSignatureVisitor.java
@@ -75,13 +75,13 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
private String separator = "";
public TraceSignatureVisitor(final int access) {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
this.declaration = new StringBuffer();
}
private TraceSignatureVisitor(final StringBuffer buf) {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
this.declaration = buf;
}
diff --git a/src/build/bnd/scala-actors.bnd b/src/build/bnd/scala-actors.bnd
index 8d0555777f..69885fc2bf 100644
--- a/src/build/bnd/scala-actors.bnd
+++ b/src/build/bnd/scala-actors.bnd
@@ -3,3 +3,5 @@ Bundle-SymbolicName: org.scala-lang.scala-actors
ver: @VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
+Import-Package: scala.*;version="${range;[==,=+);${ver}}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-compiler-doc.bnd b/src/build/bnd/scala-compiler-doc.bnd
index 4910e5fcb0..9d6d0304d1 100644
--- a/src/build/bnd/scala-compiler-doc.bnd
+++ b/src/build/bnd/scala-compiler-doc.bnd
@@ -3,4 +3,5 @@ Bundle-SymbolicName: org.scala-lang.modules.scala-compiler-doc_@SCALA_BINARY_VER
ver: @SCALA_COMPILER_DOC_VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
-Import-Package: *
+Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-compiler-interactive.bnd b/src/build/bnd/scala-compiler-interactive.bnd
index 34d2f2956d..07e3de35b0 100644
--- a/src/build/bnd/scala-compiler-interactive.bnd
+++ b/src/build/bnd/scala-compiler-interactive.bnd
@@ -3,4 +3,5 @@ Bundle-SymbolicName: org.scala-lang.modules.scala-compiler-interactive_@SCALA_BI
ver: @SCALA_COMPILER_INTERACTIVE_VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
-Import-Package: *
+Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-compiler.bnd b/src/build/bnd/scala-compiler.bnd
index dc30513db4..2bd24d780d 100644
--- a/src/build/bnd/scala-compiler.bnd
+++ b/src/build/bnd/scala-compiler.bnd
@@ -5,4 +5,8 @@ Bundle-Version: ${ver}
Export-Package: *;version=${ver}
Import-Package: jline.*;resolution:=optional, \
org.apache.tools.ant.*;resolution:=optional, \
+ scala.util.parsing.*;version="${range;[====,====];@PARSER_COMBINATORS_VERSION@}";resolution:=optional, \
+ scala.xml.*;version="${range;[====,====];@XML_VERSION@}";resolution:=optional, \
+ scala.*;version="${range;[==,=+);${ver}}", \
*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-continuations-library.bnd b/src/build/bnd/scala-continuations-library.bnd
index bb505b60a9..b36718cc5b 100644
--- a/src/build/bnd/scala-continuations-library.bnd
+++ b/src/build/bnd/scala-continuations-library.bnd
@@ -1,5 +1,7 @@
Bundle-Name: Scala Delimited Continuations Library
Bundle-SymbolicName: org.scala-lang.plugins.scala-continuations-library
-ver: @VERSION@
+ver: @CONTINUATIONS_LIBRARY_VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
+Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-continuations-plugin.bnd b/src/build/bnd/scala-continuations-plugin.bnd
index cd66614a22..2f2464b452 100644
--- a/src/build/bnd/scala-continuations-plugin.bnd
+++ b/src/build/bnd/scala-continuations-plugin.bnd
@@ -1,5 +1,7 @@
Bundle-Name: Scala Delimited Continuations Compiler Plugin
Bundle-SymbolicName: org.scala-lang.plugins.scala-continuations-plugin
-ver: @VERSION@
+ver: @CONTINUATIONS_PLUGIN_VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
+Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-library.bnd b/src/build/bnd/scala-library.bnd
index 03aff45672..7eb4fa4b2a 100644
--- a/src/build/bnd/scala-library.bnd
+++ b/src/build/bnd/scala-library.bnd
@@ -4,3 +4,4 @@ ver: @VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
Import-Package: sun.misc;resolution:=optional, *
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-parser-combinators.bnd b/src/build/bnd/scala-parser-combinators.bnd
index 6ffc3b2760..ef8646cbd0 100644
--- a/src/build/bnd/scala-parser-combinators.bnd
+++ b/src/build/bnd/scala-parser-combinators.bnd
@@ -1,5 +1,7 @@
Bundle-Name: Scala Parser Combinators Library
Bundle-SymbolicName: org.scala-lang.modules.scala-parser-combinators
-ver: @VERSION@
+ver: @PARSER_COMBINATORS_VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
+Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-reflect.bnd b/src/build/bnd/scala-reflect.bnd
index 6cda346d3a..e4bc54e52e 100644
--- a/src/build/bnd/scala-reflect.bnd
+++ b/src/build/bnd/scala-reflect.bnd
@@ -3,4 +3,7 @@ Bundle-SymbolicName: org.scala-lang.scala-reflect
ver: @VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
-Import-Package: scala.tools.nsc;resolution:=optional, *
+Import-Package: scala.*;version="${range;[==,=+);${ver}}", \
+ scala.tools.nsc;resolution:=optional;version="${range;[==,=+);${ver}}", \
+ *
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/bnd/scala-swing.bnd b/src/build/bnd/scala-swing.bnd
index 7cccb1343b..f8b50baa91 100644
--- a/src/build/bnd/scala-swing.bnd
+++ b/src/build/bnd/scala-swing.bnd
@@ -1,5 +1,7 @@
Bundle-Name: Scala Swing
Bundle-SymbolicName: org.scala-lang.modules.scala-swing
-ver: @VERSION@
+ver: @SCALA_SWING_VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
+Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6,JavaSE-1.7
diff --git a/src/build/bnd/scala-xml.bnd b/src/build/bnd/scala-xml.bnd
index 5d64c05e65..01bf0144eb 100644
--- a/src/build/bnd/scala-xml.bnd
+++ b/src/build/bnd/scala-xml.bnd
@@ -1,5 +1,7 @@
Bundle-Name: Scala XML Library
Bundle-SymbolicName: org.scala-lang.modules.scala-xml
-ver: @VERSION@
+ver: @XML_VERSION@
Bundle-Version: ${ver}
Export-Package: *;version=${ver}
+Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7
diff --git a/src/build/maven/scala-dist-pom.xml b/src/build/maven/scala-dist-pom.xml
index 22a24dea21..9477e14285 100644
--- a/src/build/maven/scala-dist-pom.xml
+++ b/src/build/maven/scala-dist-pom.xml
@@ -40,6 +40,11 @@
<version>@VERSION@</version>
</dependency>
<dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scalap</artifactId>
+ <version>@VERSION@</version>
+ </dependency>
+ <dependency>
<groupId>org.scala-lang.plugins</groupId>
<!-- plugins are fully cross-versioned. But, we don't publish with 2.11.0-SNAPSHOT, instead use full version of the last non-snapshot version -->
<artifactId>scala-continuations-plugin_@SCALA_FULL_VERSION@</artifactId>
diff --git a/src/compiler/scala/reflect/macros/contexts/Parsers.scala b/src/compiler/scala/reflect/macros/contexts/Parsers.scala
index 88cfea8157..f4584f3627 100644
--- a/src/compiler/scala/reflect/macros/contexts/Parsers.scala
+++ b/src/compiler/scala/reflect/macros/contexts/Parsers.scala
@@ -9,12 +9,15 @@ trait Parsers {
def parse(code: String) = {
val sreporter = new StoreReporter()
- val unit = new CompilationUnit(newSourceFile(code, "<macro>")) { override def reporter = sreporter }
- val parser = newUnitParser(unit)
- val tree = gen.mkTreeOrBlock(parser.parseStatsOrPackages())
- sreporter.infos.foreach {
- case sreporter.Info(pos, msg, sreporter.ERROR) => throw ParseException(pos, msg)
- }
- tree
+ val oldReporter = global.reporter
+ try {
+ global.reporter = sreporter
+ val parser = newUnitParser(new CompilationUnit(newSourceFile(code, "<macro>")))
+ val tree = gen.mkTreeOrBlock(parser.parseStatsOrPackages())
+ sreporter.infos.foreach {
+ case sreporter.Info(pos, msg, sreporter.ERROR) => throw ParseException(pos, msg)
+ }
+ tree
+ } finally global.reporter = oldReporter
}
} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala
index c2caed70a0..f23bca77cd 100644
--- a/src/compiler/scala/tools/nsc/CompilationUnits.scala
+++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala
@@ -123,31 +123,23 @@ trait CompilationUnits { global: Global =>
*/
val icode: LinkedHashSet[icodes.IClass] = new LinkedHashSet
- def reporter = global.reporter
+ @deprecated("Call global.reporter.echo directly instead.", "2.11.2")
+ final def echo(pos: Position, msg: String): Unit = reporter.echo(pos, msg)
+ @deprecated("Call global.reporter.error (or typer.context.error) directly instead.", "2.11.2")
+ final def error(pos: Position, msg: String): Unit = reporter.error(pos, msg)
+ @deprecated("Call global.reporter.warning (or typer.context.warning) directly instead.", "2.11.2")
+ final def warning(pos: Position, msg: String): Unit = reporter.warning(pos, msg)
+
+ @deprecated("Call global.currentRun.reporting.deprecationWarning directly instead.", "2.11.2")
+ final def deprecationWarning(pos: Position, msg: String): Unit = currentRun.reporting.deprecationWarning(pos, msg)
+ @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)
- def echo(pos: Position, msg: String) =
- reporter.echo(pos, msg)
-
- def error(pos: Position, msg: String) =
- reporter.error(pos, msg)
-
- def warning(pos: Position, msg: String) =
- reporter.warning(pos, msg)
-
- def deprecationWarning(pos: Position, msg: String) =
- currentRun.deprecationWarnings0.warn(pos, msg)
-
- def uncheckedWarning(pos: Position, msg: String) =
- currentRun.uncheckedWarnings0.warn(pos, msg)
-
- def inlinerWarning(pos: Position, msg: String) =
- currentRun.inlinerWarnings.warn(pos, msg)
-
- def incompleteInputError(pos: Position, msg:String) =
- reporter.incompleteInputError(pos, msg)
-
- def comment(pos: Position, msg: String) =
- reporter.comment(pos, msg)
/** 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 6f068e179c..1f3a4237eb 100644
--- a/src/compiler/scala/tools/nsc/CompileServer.scala
+++ b/src/compiler/scala/tools/nsc/CompileServer.scala
@@ -7,7 +7,7 @@ package scala.tools.nsc
import java.io.PrintStream
import scala.tools.nsc.reporters.{Reporter, ConsoleReporter}
-import scala.reflect.internal.util.FakePos //Position
+import scala.reflect.internal.util.{FakePos, Position}
import scala.tools.util.SocketServer
import settings.FscSettings
@@ -37,7 +37,7 @@ class StandardCompileServer extends SocketServer {
/** Create a new compiler instance */
def newGlobal(settings: Settings, reporter: Reporter) =
new Global(settings, reporter) {
- override def inform(msg: String) = out.println(msg)
+ override def inform(pos: Position, msg: String) = out.println(msg)
}
override def timeout() {
diff --git a/src/compiler/scala/tools/nsc/CompilerCommand.scala b/src/compiler/scala/tools/nsc/CompilerCommand.scala
index bab0768ca9..a1d0d52dcf 100644
--- a/src/compiler/scala/tools/nsc/CompilerCommand.scala
+++ b/src/compiler/scala/tools/nsc/CompilerCommand.scala
@@ -20,9 +20,12 @@ class CompilerCommand(arguments: List[String], val settings: Settings) {
def ok = processArgumentsResult._1
def files = processArgumentsResult._2
- /** The name of the command */
+ /** The name of the command. */
def cmdName = "scalac"
+ /** A descriptive alias for version and help messages. */
+ def cmdDesc = "compiler"
+
private def explainAdvanced = "\n" + """
|-- Notes on option parsing --
|Boolean settings are always false unless set.
@@ -85,7 +88,11 @@ class CompilerCommand(arguments: List[String], val settings: Settings) {
def getInfoMessage(global: Global): String = {
import settings._
- if (help) usageMsg + global.pluginOptionsHelp
+ import Properties.{ versionString, copyrightString } //versionFor
+ def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ if (version) versionFor(cmdDesc)
+ else if (help) usageMsg + global.pluginOptionsHelp
else if (Xhelp) xusageMsg
else if (Yhelp) yusageMsg
else if (showPlugins) global.pluginDescriptions
diff --git a/src/compiler/scala/tools/nsc/Driver.scala b/src/compiler/scala/tools/nsc/Driver.scala
index 3ac27a42e8..6befa76b3f 100644
--- a/src/compiler/scala/tools/nsc/Driver.scala
+++ b/src/compiler/scala/tools/nsc/Driver.scala
@@ -2,26 +2,24 @@ package scala
package tools.nsc
import scala.tools.nsc.reporters.ConsoleReporter
-import Properties.{ versionString, copyrightString, residentPromptString }
+import Properties.{ versionMsg, residentPromptString }
import scala.reflect.internal.util.FakePos
abstract class Driver {
val prompt = residentPromptString
- val versionMsg = "Scala compiler " +
- versionString + " -- " +
- copyrightString
-
var reporter: ConsoleReporter = _
protected var command: CompilerCommand = _
protected var settings: Settings = _
- protected def scalacError(msg: String) {
+ protected def scalacError(msg: String): Unit = {
reporter.error(FakePos("scalac"), msg + "\n scalac -help gives more information")
}
- protected def processSettingsHook(): Boolean = true
+ protected def processSettingsHook(): Boolean = {
+ if (settings.version) { reporter echo versionMsg ; false } else true
+ }
protected def newCompiler(): Global
@@ -37,14 +35,12 @@ abstract class Driver {
}
def process(args: Array[String]) {
- val ss = new Settings(scalacError)
- reporter = new ConsoleReporter(ss)
+ val ss = new Settings(scalacError)
+ reporter = new ConsoleReporter(ss)
command = new CompilerCommand(args.toList, ss)
settings = command.settings
- if (settings.version) {
- reporter.echo(versionMsg)
- } else if (processSettingsHook()) {
+ if (processSettingsHook()) {
val compiler = newCompiler()
try {
if (reporter.hasErrors)
@@ -68,5 +64,4 @@ abstract class Driver {
process(args)
sys.exit(if (reporter.hasErrors) 1 else 0)
}
-
}
diff --git a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala
index e710222285..dbdeec809f 100644
--- a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala
+++ b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala
@@ -19,9 +19,10 @@ extends CompilerCommand(args, settings) {
def this(args: List[String]) =
this(args, str => Console.println("Error: " + str))
- /** name of the associated compiler command */
override def cmdName = "scala"
- def compCmdName = "scalac"
+ override def cmdDesc = "code runner"
+
+ def compCmdName = "scalac" // super.cmdName
// change CompilerCommand behavior
override def shouldProcessArguments: Boolean = false
@@ -50,17 +51,16 @@ extends CompilerCommand(args, settings) {
case Nil => AsRepl
case hd :: _ => waysToRun find (_.name == settings.howtorun.value) getOrElse guessHowToRun(hd)
}
- private def interpolate(s: String) = s.trim.replaceAll("@cmd@", cmdName).replaceAll("@compileCmd@", compCmdName) + "\n"
-
- def shortUsageMsg = interpolate("""
-Usage: @cmd@ <options> [<script|class|object|jar> <arguments>]
- or @cmd@ -help
-All options to @compileCmd@ (see @compileCmd@ -help) are also allowed.
-""")
+ def shortUsageMsg =
+s"""|Usage: $cmdName <options> [<script|class|object|jar> <arguments>]
+ | or $cmdName -help
+ |
+ |All options to $compCmdName (see $compCmdName -help) are also allowed.
+""".stripMargin
- override def usageMsg = shortUsageMsg + interpolate("""
-The first given argument other than options to @cmd@ designates
+ override def usageMsg = f"""$shortUsageMsg
+The first given argument other than options to $cmdName designates
what to run. Runnable targets are:
- a file containing scala source
@@ -68,7 +68,7 @@ what to run. Runnable targets are:
- a runnable jar file with a valid Main-Class attribute
- or if no argument is given, the repl (interactive shell) is started
-Options to @cmd@ which reach the java runtime:
+Options to $cmdName which reach the java runtime:
-Dname=prop passed directly to java to set system properties
-J<arg> -J is stripped and <arg> passed to java as-is
@@ -86,8 +86,7 @@ A file argument will be run as a scala script unless it contains only
self-contained compilation units (classes and objects) and exactly one
runnable main method. In that case the file will be compiled and the
main method invoked. This provides a bridge between scripts and standard
-scala source.
- """) + "\n"
+scala source.%n"""
}
object GenericRunnerCommand {
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 35eab94333..572e579aca 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -44,7 +44,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
with Trees
with Printers
with DocComments
- with Positions { self =>
+ with Positions
+ with Reporting { self =>
// the mirror --------------------------------------------------
@@ -227,20 +228,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
*/
def registerTopLevelSym(sym: Symbol) {}
-// ------------------ Reporting -------------------------------------
-
- // not deprecated yet, but a method called "error" imported into
- // nearly every trait really must go. For now using globalError.
- def error(msg: String) = globalError(msg)
-
- override def inform(msg: String) = inform(NoPosition, msg)
- override def globalError(msg: String) = globalError(NoPosition, msg)
- override def warning(msg: String) = warning(NoPosition, msg)
- override def deprecationWarning(pos: Position, msg: String) = currentUnit.deprecationWarning(pos, msg)
-
- def globalError(pos: Position, msg: String) = reporter.error(pos, msg)
- def warning(pos: Position, msg: String) = if (settings.fatalWarnings) globalError(pos, msg) else reporter.warning(pos, msg)
- def inform(pos: Position, msg: String) = reporter.echo(pos, msg)
+// ------------------ Debugging -------------------------------------
// Getting in front of Predef's asserts to supplement with more info.
// This has the happy side effect of masking the one argument forms
@@ -263,12 +251,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
require(requirement, "")
}
- // Needs to call error to make sure the compile fails.
- override def abort(msg: String): Nothing = {
- error(msg)
- super.abort(msg)
- }
-
@inline final def ifDebug(body: => Unit) {
if (settings.debug)
body
@@ -291,8 +273,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
log(s"!!!$pos_s $msg") // such warnings always at least logged
}
- def informComplete(msg: String): Unit = reporter.withoutTruncating(inform(msg))
-
def logError(msg: String, t: Throwable): Unit = ()
override def shouldLogAtThisPhase = settings.log.isSetByUser && (
@@ -351,9 +331,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
}
if (settings.verbose || settings.Ylogcp) {
- // Uses the "do not truncate" inform
- informComplete("[search path for source files: " + classPath.sourcepaths.mkString(",") + "]")
- informComplete("[search path for class files: " + classPath.asClasspathString + "]")
+ reporter.echo(
+ s"[search path for source files: ${classPath.sourcepaths.mkString(",")}]\n"+
+ s"[search path for class files: ${classPath.asClasspathString}")
}
// The current division between scala.reflect.* and scala.tools.nsc.* is pretty
@@ -1112,45 +1092,41 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
/** Don't want to introduce new errors trying to report errors,
* so swallow exceptions.
*/
- override def supplementErrorMessage(errorMessage: String): String = {
- if (currentRun.supplementedError) errorMessage
- else try {
- currentRun.supplementedError = true
- val tree = analyzer.lastTreeToTyper
- val sym = tree.symbol
- val tpe = tree.tpe
- val site = lastSeenContext.enclClassOrMethod.owner
- val pos_s = if (tree.pos.isDefined) s"line ${tree.pos.line} of ${tree.pos.source.file}" else "<unknown>"
- val context_s = try {
- // Taking 3 before, 3 after the fingered line.
- val start = 0 max (tree.pos.line - 3)
- val xs = scala.reflect.io.File(tree.pos.source.file.file).lines drop start take 7
- val strs = xs.zipWithIndex map { case (line, idx) => f"${start + idx}%6d $line" }
- strs.mkString("== Source file context for tree position ==\n\n", "\n", "")
- }
- catch { case t: Exception => devWarning("" + t) ; "<Cannot read source file>" }
-
- val info1 = formatExplain(
- "while compiling" -> currentSource.path,
- "during phase" -> ( if (globalPhase eq phase) phase else "globalPhase=%s, enteringPhase=%s".format(globalPhase, phase) ),
- "library version" -> scala.util.Properties.versionString,
- "compiler version" -> Properties.versionString,
- "reconstructed args" -> settings.recreateArgs.mkString(" ")
- )
- val info2 = formatExplain(
- "last tree to typer" -> tree.summaryString,
- "tree position" -> pos_s,
- "tree tpe" -> tpe,
- "symbol" -> Option(sym).fold("null")(_.debugLocationString),
- "symbol definition" -> Option(sym).fold("null")(s => s.defString + s" (a ${s.shortSymbolClass})"),
- "symbol package" -> sym.enclosingPackage.fullName,
- "symbol owners" -> ownerChainString(sym),
- "call site" -> (site.fullLocationString + " in " + site.enclosingPackage)
- )
- ("\n " + errorMessage + "\n" + info1) :: info2 :: context_s :: Nil mkString "\n\n"
+ override def supplementTyperState(errorMessage: String): String = try {
+ val tree = analyzer.lastTreeToTyper
+ val sym = tree.symbol
+ val tpe = tree.tpe
+ val site = lastSeenContext.enclClassOrMethod.owner
+ val pos_s = if (tree.pos.isDefined) s"line ${tree.pos.line} of ${tree.pos.source.file}" else "<unknown>"
+ val context_s = try {
+ // Taking 3 before, 3 after the fingered line.
+ val start = 0 max (tree.pos.line - 3)
+ val xs = scala.reflect.io.File(tree.pos.source.file.file).lines drop start take 7
+ val strs = xs.zipWithIndex map { case (line, idx) => f"${start + idx}%6d $line" }
+ strs.mkString("== Source file context for tree position ==\n\n", "\n", "")
}
- catch { case _: Exception | _: TypeError => errorMessage }
- }
+ catch { case t: Exception => devWarning("" + t) ; "<Cannot read source file>" }
+
+ val info1 = formatExplain(
+ "while compiling" -> currentSource.path,
+ "during phase" -> ( if (globalPhase eq phase) phase else "globalPhase=%s, enteringPhase=%s".format(globalPhase, phase) ),
+ "library version" -> scala.util.Properties.versionString,
+ "compiler version" -> Properties.versionString,
+ "reconstructed args" -> settings.recreateArgs.mkString(" ")
+ )
+ val info2 = formatExplain(
+ "last tree to typer" -> tree.summaryString,
+ "tree position" -> pos_s,
+ "tree tpe" -> tpe,
+ "symbol" -> Option(sym).fold("null")(_.debugLocationString),
+ "symbol definition" -> Option(sym).fold("null")(s => s.defString + s" (a ${s.shortSymbolClass})"),
+ "symbol package" -> sym.enclosingPackage.fullName,
+ "symbol owners" -> ownerChainString(sym),
+ "call site" -> (site.fullLocationString + " in " + site.enclosingPackage)
+ )
+ ("\n " + errorMessage + "\n" + info1) :: info2 :: context_s :: Nil mkString "\n\n"
+ } catch { case _: Exception | _: TypeError => errorMessage }
+
/** The id of the currently active run
*/
@@ -1162,17 +1138,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
inform("[running phase " + ph.name + " on " + currentRun.size + " compilation units]")
}
- /** Collects for certain classes of warnings during this run. */
- class ConditionalWarning(what: String, option: Settings#BooleanSetting) {
- val warnings = mutable.LinkedHashMap[Position, String]()
- def warn(pos: Position, msg: String) =
- if (option) reporter.warning(pos, msg)
- else if (!(warnings contains pos)) warnings += ((pos, msg))
- def summarize() =
- if (warnings.nonEmpty && (option.isDefault || settings.fatalWarnings))
- warning("there were %d %s warning(s); re-run with %s for details".format(warnings.size, what, option.name))
- }
-
def newSourceFile(code: String, filename: String = "<console>") =
new BatchSourceFile(filename, code)
@@ -1190,7 +1155,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 {
+ class Run extends RunContextApi with RunReporting {
/** 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.
@@ -1199,24 +1164,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
/** The currently compiled unit; set from GlobalPhase */
var currentUnit: CompilationUnit = NoCompilationUnit
- // This change broke sbt; I gave it the thrilling name of uncheckedWarnings0 so
- // as to recover uncheckedWarnings for its ever-fragile compiler interface.
- val deprecationWarnings0 = new ConditionalWarning("deprecation", settings.deprecation)
- val uncheckedWarnings0 = new ConditionalWarning("unchecked", settings.unchecked)
- val featureWarnings = new ConditionalWarning("feature", settings.feature)
- val inlinerWarnings = new ConditionalWarning("inliner", settings.YinlinerWarnings)
- val allConditionalWarnings = List(deprecationWarnings0, uncheckedWarnings0, featureWarnings, inlinerWarnings)
-
- def uncheckedWarnings: List[(Position, String)] = uncheckedWarnings0.warnings.toList // used in sbt
- def deprecationWarnings: List[(Position, String)] = deprecationWarnings0.warnings.toList // used in sbt
-
- var reportedFeature = Set[Symbol]()
-
- /** Has any macro expansion used a fallback during this run? */
- var seenMacroExpansionsFallingBack = false
-
- /** Have we already supplemented the error message of a compiler crash? */
- private[nsc] final var supplementedError = false
+ // used in sbt
+ def uncheckedWarnings: List[(Position, String)] = reporting.uncheckedWarnings
+ // used in sbt
+ def deprecationWarnings: List[(Position, String)] = reporting.deprecationWarnings
private class SyncedCompilationBuffer { self =>
private val underlying = new mutable.ArrayBuffer[CompilationUnit]
@@ -1414,6 +1365,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
refreshProgress()
}
+ // for sbt
def cancel() { reporter.cancelled = true }
private def currentProgress = (phasec * size) + unitc
@@ -1479,10 +1431,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
private def checkDeprecatedSettings(unit: CompilationUnit) {
// issue warnings for any usage of deprecated settings
settings.userSetSettings filter (_.isDeprecated) foreach { s =>
- unit.deprecationWarning(NoPosition, s.name + " is deprecated: " + s.deprecationMessage.get)
+ currentRun.reporting.deprecationWarning(NoPosition, s.name + " is deprecated: " + s.deprecationMessage.get)
}
if (settings.target.value.contains("jvm-1.5"))
- unit.deprecationWarning(NoPosition, settings.target.name + ":" + settings.target.value + " is deprecated: use target for Java 1.6 or above.")
+ currentRun.reporting.deprecationWarning(NoPosition, settings.target.name + ":" + settings.target.value + " is deprecated: use target for Java 1.6 or above.")
}
/* An iterator returning all the units being compiled in this run */
@@ -1563,26 +1515,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
}
}
- def reportCompileErrors() {
- if (!reporter.hasErrors && reporter.hasWarnings && settings.fatalWarnings)
- globalError("No warnings can be incurred under -Xfatal-warnings.")
-
- if (reporter.hasErrors) {
- for ((sym, file) <- symSource.iterator) {
- sym.reset(new loaders.SourcefileLoader(file))
- if (sym.isTerm)
- sym.moduleClass reset loaders.moduleClassLoader
- }
- }
- else {
- allConditionalWarnings foreach (_.summarize())
-
- if (seenMacroExpansionsFallingBack)
- warning("some macros could not be expanded and code fell back to overridden methods;"+
- "\nrecompiling with generated classfiles on the classpath might help.")
- // todo: migrationWarnings
- }
- }
/** Caching member symbols that are def-s in Defintions because they might change from Run to Run. */
val runDefinitions: definitions.RunDefinitions = new definitions.RunDefinitions
@@ -1595,7 +1527,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
def checkDeprecations() = {
checkDeprecatedSettings(newCompilationUnit(""))
- reportCompileErrors()
+ reporting.summarizeErrors()
}
val units = sources map scripted map (new CompilationUnit(_))
@@ -1619,7 +1551,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
checkDeprecatedSettings(unitbuf.head)
globalPhase = fromPhase
- while (globalPhase.hasNext && !reporter.hasErrors) {
+ while (globalPhase.hasNext && !reporter.hasErrors) {
val startTime = currentTime
phase = globalPhase
globalPhase.run()
@@ -1665,6 +1597,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
advancePhase()
}
+ reporting.summarizeErrors()
+
if (traceSymbolActivity)
units map (_.body) foreach (traceSymbols recordSymbolsInTree _)
@@ -1672,8 +1606,15 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
if (settings.Yshow.isDefault)
showMembers()
- reportCompileErrors()
+ if (reporter.hasErrors) {
+ for ((sym, file) <- symSource.iterator) {
+ sym.reset(new loaders.SourcefileLoader(file))
+ if (sym.isTerm)
+ sym.moduleClass reset loaders.moduleClassLoader
+ }
+ }
symSource.keys foreach (x => resetPackageClass(x.owner))
+
informTime("total", startTime)
// Clear any sets or maps created via perRunCaches.
diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala
new file mode 100644
index 0000000000..0263586418
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/Reporting.scala
@@ -0,0 +1,123 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2014 LAMP/EPFL, Typesafe Inc.
+ * @author Adriaan Moors
+ */
+
+package scala
+package tools
+package nsc
+
+import reporters.{ Reporter, ConsoleReporter }
+import scala.collection.{ mutable, immutable }
+import scala.reflect.internal.util.StringOps.countElementsAsString
+
+/** Provides delegates to the reporter doing the actual work.
+ * PerRunReporting implements per-Run stateful info tracking and reporting
+ *
+ * TODO: make reporting configurable
+ */
+trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions with CompilationUnits with scala.reflect.internal.Symbols =>
+ def settings: Settings
+
+ // not deprecated yet, but a method called "error" imported into
+ // nearly every trait really must go. For now using globalError.
+ def error(msg: String) = globalError(msg)
+
+ // a new instance of this class is created for every Run (access the current instance via `currentRun.reporting`)
+ protected def PerRunReporting = new PerRunReporting
+ class PerRunReporting extends PerRunReportingBase {
+ /** Collects for certain classes of warnings during this run. */
+ private class ConditionalWarning(what: String, option: Settings#BooleanSetting) {
+ val warnings = mutable.LinkedHashMap[Position, String]()
+ def warn(pos: Position, msg: String) =
+ if (option) reporter.warning(pos, msg)
+ else if (!(warnings contains pos)) warnings += ((pos, msg))
+ def summarize() =
+ if (warnings.nonEmpty && (option.isDefault || settings.fatalWarnings)) {
+ val numWarnings = warnings.size
+ val warningVerb = if (numWarnings == 1) "was" else "were"
+ val warningCount = countElementsAsString(numWarnings, s"$what warning")
+
+ reporter.warning(NoPosition, s"there $warningVerb $warningCount; re-run with ${option.name} for details")
+ }
+ }
+
+ // This change broke sbt; I gave it the thrilling name of uncheckedWarnings0 so
+ // as to recover uncheckedWarnings for its ever-fragile compiler interface.
+ private val _deprecationWarnings = new ConditionalWarning("deprecation", settings.deprecation)
+ private val _uncheckedWarnings = new ConditionalWarning("unchecked", settings.unchecked)
+ private val _featureWarnings = new ConditionalWarning("feature", settings.feature)
+ private val _inlinerWarnings = new ConditionalWarning("inliner", settings.YinlinerWarnings)
+ private val _allConditionalWarnings = List(_deprecationWarnings, _uncheckedWarnings, _featureWarnings, _inlinerWarnings)
+
+ // TODO: remove in favor of the overload that takes a Symbol, give that argument a default (NoSymbol)
+ def deprecationWarning(pos: Position, msg: String): Unit = _deprecationWarnings.warn(pos, msg)
+ def uncheckedWarning(pos: Position, msg: String): Unit = _uncheckedWarnings.warn(pos, msg)
+ def featureWarning(pos: Position, msg: String): Unit = _featureWarnings.warn(pos, msg)
+ def inlinerWarning(pos: Position, msg: String): Unit = _inlinerWarnings.warn(pos, msg)
+
+ def deprecationWarnings = _deprecationWarnings.warnings.toList
+ def uncheckedWarnings = _uncheckedWarnings.warnings.toList
+ def featureWarnings = _featureWarnings.warnings.toList
+ def inlinerWarnings = _inlinerWarnings.warnings.toList
+
+ def allConditionalWarnings = _allConditionalWarnings flatMap (_.warnings)
+
+ // behold! the symbol that caused the deprecation warning (may not be deprecated itself)
+ def deprecationWarning(pos: Position, sym: Symbol, msg: String): Unit = _deprecationWarnings.warn(pos, msg)
+ def deprecationWarning(pos: Position, sym: Symbol): Unit = {
+ val suffix = sym.deprecationMessage match { case Some(msg) => ": "+ msg case _ => "" }
+ deprecationWarning(pos, sym, s"$sym${sym.locationString} is deprecated$suffix")
+ }
+
+ private[this] var reportedFeature = Set[Symbol]()
+ def featureWarning(pos: Position, featureName: String, featureDesc: String, featureTrait: Symbol, construct: => String = "", required: Boolean): Unit = {
+ val req = if (required) "needs to" else "should"
+ val fqname = "scala.language." + featureName
+ val explain = (
+ if (reportedFeature contains featureTrait) "" else
+ s"""|
+ |This can be achieved by adding the import clause 'import $fqname'
+ |or by setting the compiler option -language:$featureName.
+ |See the Scala docs for value $fqname for a discussion
+ |why the feature $req be explicitly enabled.""".stripMargin
+ )
+ reportedFeature += featureTrait
+
+ val msg = s"$featureDesc $req be enabled\nby making the implicit value $fqname visible.$explain" replace ("#", construct)
+ if (required) reporter.error(pos, msg)
+ else featureWarning(pos, msg)
+ }
+
+ /** Has any macro expansion used a fallback during this run? */
+ var seenMacroExpansionsFallingBack = false
+
+ def summarizeErrors(): Unit = if (!reporter.hasErrors) {
+ _allConditionalWarnings foreach (_.summarize())
+
+ if (seenMacroExpansionsFallingBack)
+ reporter.warning(NoPosition, "some macros could not be expanded and code fell back to overridden methods;"+
+ "\nrecompiling with generated classfiles on the classpath might help.")
+
+ // todo: migrationWarnings
+
+ 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 ffc45b21ea..883fd31dbc 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -205,11 +205,11 @@ self =>
override def newScanner() = new UnitScanner(unit, patches)
override def warning(offset: Offset, msg: String) {
- unit.warning(o2p(offset), msg)
+ reporter.warning(o2p(offset), msg)
}
override def deprecationWarning(offset: Offset, msg: String) {
- unit.deprecationWarning(o2p(offset), msg)
+ currentRun.reporting.deprecationWarning(o2p(offset), msg)
}
private var smartParsing = false
@@ -224,17 +224,17 @@ self =>
val syntaxErrors = new ListBuffer[(Int, String)]
def showSyntaxErrors() =
for ((offset, msg) <- syntaxErrors)
- unit.error(o2p(offset), msg)
+ reporter.error(o2p(offset), msg)
override def syntaxError(offset: Offset, msg: String) {
if (smartParsing) syntaxErrors += ((offset, msg))
- else unit.error(o2p(offset), msg)
+ else reporter.error(o2p(offset), msg)
}
override def incompleteInputError(msg: String) {
val offset = source.content.length - 1
if (smartParsing) syntaxErrors += ((offset, msg))
- else unit.incompleteInputError(o2p(offset), msg)
+ else currentRun.reporting.incompleteInputError(o2p(offset), msg)
}
/** parse unit. If there are inbalanced braces,
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index e8d46704c3..572497ac90 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -1259,9 +1259,9 @@ trait Scanners extends ScannersCommon {
class UnitScanner(val unit: CompilationUnit, patches: List[BracePatch]) extends SourceFileScanner(unit.source) {
def this(unit: CompilationUnit) = this(unit, List())
- override def deprecationWarning(off: Offset, msg: String) = unit.deprecationWarning(unit.position(off), msg)
- override def error (off: Offset, msg: String) = unit.error(unit.position(off), msg)
- override def incompleteInputError(off: Offset, msg: String) = unit.incompleteInputError(unit.position(off), msg)
+ 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)
private var bracePatches: List[BracePatch] = patches
diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala
index 3a695c6f59..64b762696e 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 (global.reporter.incompleteHandled) newUnitParser(unit).parse()
+ else if (currentRun.reporting.incompleteHandled) newUnitParser(unit).parse()
else newUnitParser(unit).smartParse()
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 0da66d43f7..d9f56b47fa 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -680,7 +680,7 @@ abstract class GenICode extends SubComponent {
val dims = arr.dimensions
var elemKind = arr.elementKind
if (args.length > dims)
- unit.error(tree.pos, "too many arguments for array constructor: found " + args.length +
+ reporter.error(tree.pos, "too many arguments for array constructor: found " + args.length +
" but array has only " + dims + " dimension(s)")
if (args.length != dims)
for (i <- args.length until dims) elemKind = ARRAY(elemKind)
@@ -1424,11 +1424,18 @@ abstract class GenICode extends SubComponent {
def genZandOrZor(and: Boolean): Boolean = {
val ctxInterm = ctx.newBlock()
- val branchesReachable = if (and) genCond(lhs, ctx, ctxInterm, elseCtx)
+ val lhsBranchesReachable = if (and) genCond(lhs, ctx, ctxInterm, elseCtx)
else genCond(lhs, ctx, thenCtx, ctxInterm)
- ctxInterm.bb killUnless branchesReachable
+ // If lhs is known to throw, we can kill the just created ctxInterm.
+ ctxInterm.bb killUnless lhsBranchesReachable
- genCond(rhs, ctxInterm, thenCtx, elseCtx)
+ val rhsBranchesReachable = genCond(rhs, ctxInterm, thenCtx, elseCtx)
+
+ // Reachable means "it does not always throw", i.e. "it might not throw".
+ // In an expression (a && b) or (a || b), the b branch might not be evaluated.
+ // Such an expression is therefore known to throw only if both expressions throw. Or,
+ // successors are reachable if either of the two is reachable (SI-8625).
+ lhsBranchesReachable || rhsBranchesReachable
}
def genRefEq(isEq: Boolean) = {
val f = genEqEqPrimitive(lhs, rhs, ctx) _
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
index 856f85d9e3..2af2037fec 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
@@ -8,6 +8,7 @@ package scala.tools.nsc.backend.jvm
import scala.tools.asm.tree.{ClassNode, MethodNode}
import java.io.PrintWriter
import scala.tools.asm.util.{TraceClassVisitor, TraceMethodVisitor, Textifier}
+import scala.tools.asm.ClassReader
object AsmUtils {
@@ -50,4 +51,11 @@ object AsmUtils {
w.flush()
}
+ def traceClass(bytes: Array[Byte]): Unit = traceClass(readClass(bytes))
+
+ def readClass(bytes: Array[Byte]): ClassNode = {
+ val node = new ClassNode()
+ new ClassReader(bytes).accept(node, 0)
+ node
+ }
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
index 3d1b646069..4583462b71 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
@@ -24,6 +24,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
import global._
import definitions._
import bCodeICodeCommon._
+ import bTypes._
/*
* Functionality to build the body of ASM MethodNode, except for `synchronized` and `try` expressions.
@@ -46,16 +47,16 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
def emit(opc: Int) { mnode.visitInsn(opc) }
def emitZeroOf(tk: BType) {
- (tk.sort: @switch) match {
- case asm.Type.BOOLEAN => bc.boolconst(false)
- case asm.Type.BYTE |
- asm.Type.SHORT |
- asm.Type.CHAR |
- asm.Type.INT => bc.iconst(0)
- case asm.Type.LONG => bc.lconst(0)
- case asm.Type.FLOAT => bc.fconst(0)
- case asm.Type.DOUBLE => bc.dconst(0)
- case asm.Type.VOID => ()
+ tk match {
+ case BOOL => bc.boolconst(false)
+ case BYTE |
+ SHORT |
+ CHAR |
+ INT => bc.iconst(0)
+ case LONG => bc.lconst(0)
+ case FLOAT => bc.fconst(0)
+ case DOUBLE => bc.dconst(0)
+ case UNIT => ()
case _ => emit(asm.Opcodes.ACONST_NULL)
}
}
@@ -166,7 +167,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
// load argument on stack
assert(args.length == 1, s"Too many arguments for array get operation: $tree");
genLoad(args.head, INT)
- generatedType = k.getComponentType
+ generatedType = k.asArrayBType.componentType
bc.aload(elementType)
}
else if (scalaPrimitives.isArraySet(code)) {
@@ -320,7 +321,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
generatedType =
if (tree.symbol == ArrayClass) ObjectReference
- else brefType(thisName) // inner class (if any) for claszSymbol already tracked.
+ else ClassBType(thisName) // inner class (if any) for claszSymbol already tracked.
}
case Select(Ident(nme.EMPTY_PACKAGE_NAME), module) =>
@@ -418,7 +419,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
if (hostClass == null) internalName(field.owner)
else internalName(hostClass)
val fieldJName = field.javaSimpleName.toString
- val fieldDescr = symInfoTK(field).getDescriptor
+ val fieldDescr = symInfoTK(field).descriptor
val isStatic = field.isStaticMember
val opc =
if (isLoad) { if (isStatic) asm.Opcodes.GETSTATIC else asm.Opcodes.GETFIELD }
@@ -459,7 +460,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case ClazzTag =>
val toPush: BType = {
val kind = toTypeKind(const.typeValue)
- if (kind.isValueType) classLiteral(kind)
+ if (kind.isPrimitive) classLiteral(kind)
else kind
}
mnode.visitLdcInsn(toPush.toASMType)
@@ -468,7 +469,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val sym = const.symbolValue
val ownerName = internalName(sym.owner)
val fieldName = sym.javaSimpleName.toString
- val fieldDesc = toTypeKind(sym.tpe.underlying).getDescriptor
+ val fieldDesc = toTypeKind(sym.tpe.underlying).descriptor
mnode.visitFieldInsn(
asm.Opcodes.GETSTATIC,
ownerName,
@@ -503,7 +504,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case nextCleanup :: rest =>
if (saveReturnValue) {
if (insideCleanupBlock) {
- cunit.warning(r.pos, "Return statement found in finally-clause, discarding its return-value in favor of that of a more deeply nested return.")
+ reporter.warning(r.pos, "Return statement found in finally-clause, discarding its return-value in favor of that of a more deeply nested return.")
bc drop returnType
} else {
// regarding return value, the protocol is: in place of a `return-stmt`, a sequence of `adapt, store, jump` are inserted.
@@ -540,26 +541,28 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
def genTypeApply(): BType = {
genLoadQualifier(fun)
- if (l.isValueType && r.isValueType)
+ // TODO @lry make pattern match
+ if (l.isPrimitive && r.isPrimitive)
genConversion(l, r, cast)
- else if (l.isValueType) {
+ else if (l.isPrimitive) {
bc drop l
if (cast) {
- mnode.visitTypeInsn(asm.Opcodes.NEW, classCastExceptionReference.getInternalName)
+ mnode.visitTypeInsn(asm.Opcodes.NEW, classCastExceptionReference.internalName)
bc dup ObjectReference
emit(asm.Opcodes.ATHROW)
} else {
bc boolconst false
}
}
- else if (r.isValueType && cast) {
+ else if (r.isPrimitive && cast) {
abort(s"Erasure should have added an unboxing operation to prevent this cast. Tree: $app")
}
- else if (r.isValueType) {
+ else if (r.isPrimitive) {
bc isInstance classLiteral(r)
}
else {
- genCast(r, cast)
+ assert(r.isRef, r) // ensure that it's not a method
+ genCast(r.asRefBType, cast)
}
if (cast) r else BOOL
@@ -579,7 +582,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
genLoadArguments(args, paramTKs(app))
genCallMethod(fun.symbol, invokeStyle, pos = app.pos)
- generatedType = asmMethodType(fun.symbol).getReturnType
+ generatedType = asmMethodType(fun.symbol).returnType
// 'new' constructor call: Note: since constructors are
// thought to return an instance of what they construct,
@@ -590,34 +593,34 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
assert(ctor.isClassConstructor, s"'new' call to non-constructor: ${ctor.name}")
generatedType = tpeTK(tpt)
- assert(generatedType.isRefOrArrayType, s"Non reference type cannot be instantiated: $generatedType")
+ assert(generatedType.isRef, s"Non reference type cannot be instantiated: $generatedType")
generatedType match {
- case arr if generatedType.isArray =>
+ case arr @ ArrayBType(componentType) =>
genLoadArguments(args, paramTKs(app))
- val dims = arr.getDimensions
- var elemKind = arr.getElementType
+ val dims = arr.dimension
+ var elemKind = arr.elementType
val argsSize = args.length
if (argsSize > dims) {
- cunit.error(app.pos, s"too many arguments for array constructor: found ${args.length} but array has only $dims dimension(s)")
+ reporter.error(app.pos, s"too many arguments for array constructor: found ${args.length} but array has only $dims dimension(s)")
}
if (argsSize < dims) {
/* In one step:
* elemKind = new BType(BType.ARRAY, arr.off + argsSize, arr.len - argsSize)
* however the above does not enter a TypeName for each nested arrays in chrs.
*/
- for (i <- args.length until dims) elemKind = arrayOf(elemKind)
+ for (i <- args.length until dims) elemKind = ArrayBType(elemKind)
}
(argsSize : @switch) match {
case 1 => bc newarray elemKind
case _ =>
- val descr = ('[' * argsSize) + elemKind.getDescriptor // denotes the same as: arrayN(elemKind, argsSize).getDescriptor
+ val descr = ('[' * argsSize) + elemKind.descriptor // denotes the same as: arrayN(elemKind, argsSize).descriptor
mnode.visitMultiANewArrayInsn(descr, argsSize)
}
- case rt if generatedType.hasObjectSort =>
+ case rt: ClassBType =>
assert(exemplar(ctor.owner).c == rt, s"Symbol ${ctor.owner.fullName} is different from $rt")
- mnode.visitTypeInsn(asm.Opcodes.NEW, rt.getInternalName)
+ mnode.visitTypeInsn(asm.Opcodes.NEW, rt.internalName)
bc dup generatedType
genLoadArguments(args, paramTKs(app))
genCallMethod(ctor, icodes.opcodes.Static(onInstance = true))
@@ -630,7 +633,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val nativeKind = tpeTK(expr)
genLoad(expr, nativeKind)
val MethodNameAndType(mname, mdesc) = asmBoxTo(nativeKind)
- bc.invokestatic(BoxesRunTime.getInternalName, mname, mdesc)
+ bc.invokestatic(BoxesRunTime.internalName, mname, mdesc)
generatedType = boxResultType(fun.symbol) // was toTypeKind(fun.symbol.tpe.resultType)
case Apply(fun @ _, List(expr)) if currentRun.runDefinitions.isUnbox(fun.symbol) =>
@@ -638,7 +641,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val boxType = unboxResultType(fun.symbol) // was toTypeKind(fun.symbol.owner.linkedClassOfClass.tpe)
generatedType = boxType
val MethodNameAndType(mname, mdesc) = asmUnboxTo(boxType)
- bc.invokestatic(BoxesRunTime.getInternalName, mname, mdesc)
+ bc.invokestatic(BoxesRunTime.internalName, mname, mdesc)
case app @ Apply(fun, args) =>
val sym = fun.symbol
@@ -683,7 +686,12 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case _ =>
}
if ((targetTypeKind != null) && (sym == definitions.Array_clone) && invokeStyle.isDynamic) {
- val target: String = targetTypeKind.getInternalName
+ // An invokevirtual points to a CONSTANT_Methodref_info which in turn points to a
+ // CONSTANT_Class_info of the receiver type.
+ // The JVMS is not explicit about this, but that receiver type may be an array type
+ // descriptor (instead of a class internal name):
+ // invokevirtual #2; //Method "[I".clone:()Ljava/lang/Object
+ val target: String = targetTypeKind.asRefBType.classOrArrayType
bc.invokevirtual(target, "clone", "()Ljava/lang/Object;")
}
else {
@@ -694,7 +702,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
genNormalMethodCall()
- generatedType = asmMethodType(sym).getReturnType
+ generatedType = asmMethodType(sym).returnType
}
}
@@ -706,7 +714,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val ArrayValue(tpt @ TypeTree(), elems) = av
val elmKind = tpeTK(tpt)
- val generatedType = arrayOf(elmKind)
+ val generatedType = ArrayBType(elmKind)
lineNumber(av)
bc iconst elems.length
@@ -876,12 +884,12 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
if (claszSymbol == module.moduleClass && jMethodName != "readResolve" && !inStaticMethod) {
mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
} else {
- val mbt = symInfoTK(module)
+ val mbt = symInfoTK(module).asClassBType
mnode.visitFieldInsn(
asm.Opcodes.GETSTATIC,
- mbt.getInternalName /* + "$" */ ,
+ mbt.internalName /* + "$" */ ,
strMODULE_INSTANCE_FIELD,
- mbt.getDescriptor // for nostalgics: toTypeKind(module.tpe).getDescriptor
+ mbt.descriptor // for nostalgics: toTypeKind(module.tpe).descriptor
)
}
}
@@ -894,7 +902,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
}
}
- def genCast(to: BType, cast: Boolean) {
+ def genCast(to: RefBType, cast: Boolean) {
if (cast) { bc checkCast to }
else { bc isInstance to }
}
@@ -959,10 +967,10 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
)
val receiver = if (useMethodOwner) methodOwner else hostSymbol
val bmOwner = asmClassType(receiver)
- val jowner = bmOwner.getInternalName
+ val jowner = bmOwner.internalName
val jname = method.javaSimpleName.toString
val bmType = asmMethodType(method)
- val mdescr = bmType.getDescriptor
+ val mdescr = bmType.descriptor
def initModule() {
// we initialize the MODULE$ field immediately after the super ctor
@@ -1025,7 +1033,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
private def genCJUMP(success: asm.Label, failure: asm.Label, op: TestOp, tk: BType) {
if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
bc.emitIF_ICMP(op, success)
- } else if (tk.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_)
+ } else if (tk.isRef) { // REFERENCE(_) | ARRAY(_)
bc.emitIF_ACMP(op, success)
} else {
(tk: @unchecked) match {
@@ -1046,7 +1054,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
private def genCZJUMP(success: asm.Label, failure: asm.Label, op: TestOp, tk: BType) {
if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
bc.emitIF(op, success)
- } else if (tk.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_)
+ } else if (tk.isRef) { // REFERENCE(_) | ARRAY(_)
// @unchecked because references aren't compared with GT, GE, LT, LE.
(op : @unchecked) match {
case icodes.EQ => bc emitIFNULL success
@@ -1131,7 +1139,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case ZOR => genZandOrZor(and = false)
case code =>
// TODO !!!!!!!!!! isReferenceType, in the sense of TypeKind? (ie non-array, non-boxed, non-nothing, may be null)
- if (scalaPrimitives.isUniversalEqualityOp(code) && tpeTK(lhs).hasObjectSort) {
+ if (scalaPrimitives.isUniversalEqualityOp(code) && tpeTK(lhs).isClass) {
// `lhs` has reference type
if (code == EQ) genEqEqPrimitive(lhs, rhs, success, failure)
else genEqEqPrimitive(lhs, rhs, failure, success)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala
deleted file mode 100644
index aa7e73a36b..0000000000
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala
+++ /dev/null
@@ -1,718 +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.annotation.switch
-import scala.collection.{ immutable, mutable }
-
-/*
- * Immutable representations of bytecode-level types.
- *
- * @author Miguel Garcia, http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded
- * @version 1.0
- *
- */
-abstract class BCodeGlue extends SubComponent {
-
- import global._
-
- protected val bCodeICodeCommon: BCodeICodeCommon[global.type] = new BCodeICodeCommon(global)
-
- object BType {
-
- import global.chrs
-
- // ------------- sorts -------------
-
- val VOID : Int = 0
- val BOOLEAN: Int = 1
- val CHAR : Int = 2
- val BYTE : Int = 3
- val SHORT : Int = 4
- val INT : Int = 5
- val FLOAT : Int = 6
- val LONG : Int = 7
- val DOUBLE : Int = 8
- val ARRAY : Int = 9
- val OBJECT : Int = 10
- val METHOD : Int = 11
-
- // ------------- primitive types -------------
-
- val VOID_TYPE = new BType(VOID, ('V' << 24) | (5 << 16) | (0 << 8) | 0, 1)
- val BOOLEAN_TYPE = new BType(BOOLEAN, ('Z' << 24) | (0 << 16) | (5 << 8) | 1, 1)
- val CHAR_TYPE = new BType(CHAR, ('C' << 24) | (0 << 16) | (6 << 8) | 1, 1)
- val BYTE_TYPE = new BType(BYTE, ('B' << 24) | (0 << 16) | (5 << 8) | 1, 1)
- val SHORT_TYPE = new BType(SHORT, ('S' << 24) | (0 << 16) | (7 << 8) | 1, 1)
- val INT_TYPE = new BType(INT, ('I' << 24) | (0 << 16) | (0 << 8) | 1, 1)
- val FLOAT_TYPE = new BType(FLOAT, ('F' << 24) | (2 << 16) | (2 << 8) | 1, 1)
- val LONG_TYPE = new BType(LONG, ('J' << 24) | (1 << 16) | (1 << 8) | 2, 1)
- val DOUBLE_TYPE = new BType(DOUBLE, ('D' << 24) | (3 << 16) | (3 << 8) | 2, 1)
-
- /*
- * Returns the Java type corresponding to the given type descriptor.
- *
- * @param off the offset of this descriptor in the chrs buffer.
- * @return the Java type corresponding to the given type descriptor.
- *
- * can-multi-thread
- */
- def getType(off: Int): BType = {
- var len = 0
- chrs(off) match {
- case 'V' => VOID_TYPE
- case 'Z' => BOOLEAN_TYPE
- case 'C' => CHAR_TYPE
- case 'B' => BYTE_TYPE
- case 'S' => SHORT_TYPE
- case 'I' => INT_TYPE
- case 'F' => FLOAT_TYPE
- case 'J' => LONG_TYPE
- case 'D' => DOUBLE_TYPE
- case '[' =>
- len = 1
- while (chrs(off + len) == '[') {
- len += 1
- }
- if (chrs(off + len) == 'L') {
- len += 1
- while (chrs(off + len) != ';') {
- len += 1
- }
- }
- new BType(ARRAY, off, len + 1)
- case 'L' =>
- len = 1
- while (chrs(off + len) != ';') {
- len += 1
- }
- new BType(OBJECT, off + 1, len - 1)
- // case '(':
- case _ =>
- assert(chrs(off) == '(')
- var resPos = off + 1
- while (chrs(resPos) != ')') { resPos += 1 }
- val resType = getType(resPos + 1)
- val len = resPos - off + 1 + resType.len;
- new BType(
- METHOD,
- off,
- if (resType.hasObjectSort) {
- len + 2 // "+ 2" accounts for the "L ... ;" in a descriptor for a non-array reference.
- } else {
- len
- }
- )
- }
- }
-
- /* Params denote an internal name.
- * can-multi-thread
- */
- def getObjectType(index: Int, length: Int): BType = {
- val sort = if (chrs(index) == '[') ARRAY else OBJECT;
- new BType(sort, index, length)
- }
-
- /*
- * @param methodDescriptor a method descriptor.
- *
- * must-single-thread
- */
- def getMethodType(methodDescriptor: String): BType = {
- val n = global.newTypeName(methodDescriptor)
- new BType(BType.METHOD, n.start, n.length) // TODO assert isValidMethodDescriptor
- }
-
- /*
- * Returns the Java method type corresponding to the given argument and return types.
- *
- * @param returnType the return type of the method.
- * @param argumentTypes the argument types of the method.
- * @return the Java type corresponding to the given argument and return types.
- *
- * must-single-thread
- */
- def getMethodType(returnType: BType, argumentTypes: Array[BType]): BType = {
- val n = global.newTypeName(getMethodDescriptor(returnType, argumentTypes))
- new BType(BType.METHOD, n.start, n.length)
- }
-
- /*
- * Returns the Java types corresponding to the argument types of method descriptor whose first argument starts at idx0.
- *
- * @param idx0 index into chrs of the first argument.
- * @return the Java types corresponding to the argument types of the given method descriptor.
- *
- * can-multi-thread
- */
- private def getArgumentTypes(idx0: Int): Array[BType] = {
- assert(chrs(idx0 - 1) == '(', "doesn't look like a method descriptor.")
- val args = new Array[BType](getArgumentCount(idx0))
- var off = idx0
- var size = 0
- while (chrs(off) != ')') {
- args(size) = getType(off)
- off += args(size).len
- if (args(size).sort == OBJECT) { off += 2 }
- // debug: assert("LVZBSCIJFD[)".contains(chrs(off)))
- size += 1
- }
- // debug: var check = 0; while (check < args.length) { assert(args(check) != null); check += 1 }
- args
- }
-
- /*
- * Returns the number of argument types of this method type, whose first argument starts at idx0.
- *
- * @param idx0 index into chrs of the first argument.
- * @return the number of argument types of this method type.
- *
- * can-multi-thread
- */
- private def getArgumentCount(idx0: Int): Int = {
- assert(chrs(idx0 - 1) == '(', "doesn't look like a method descriptor.")
- var off = idx0
- var size = 0
- var keepGoing = true
- while (keepGoing) {
- val car = chrs(off)
- off += 1
- if (car == ')') {
- keepGoing = false
- } else if (car == 'L') {
- while (chrs(off) != ';') { off += 1 }
- off += 1
- size += 1
- } else if (car != '[') {
- size += 1
- }
- }
-
- size
- }
-
- /*
- * Returns the Java type corresponding to the return type of the given
- * method descriptor.
- *
- * @param methodDescriptor a method descriptor.
- * @return the Java type corresponding to the return type of the given method descriptor.
- *
- * must-single-thread
- */
- def getReturnType(methodDescriptor: String): BType = {
- val n = global.newTypeName(methodDescriptor)
- val delta = n.pos(')') // `delta` is relative to the Name's zero-based start position, not a valid index into chrs.
- assert(delta < n.length, s"not a valid method descriptor: $methodDescriptor")
- getType(n.start + delta + 1)
- }
-
- /*
- * Returns the descriptor corresponding to the given argument and return types.
- * Note: no BType is created here for the resulting method descriptor,
- * if that's desired the invoker is responsible for that.
- *
- * @param returnType the return type of the method.
- * @param argumentTypes the argument types of the method.
- * @return the descriptor corresponding to the given argument and return types.
- *
- * can-multi-thread
- */
- def getMethodDescriptor(
- returnType: BType,
- argumentTypes: Array[BType]): String =
- {
- val buf = new StringBuffer()
- buf.append('(')
- var i = 0
- while (i < argumentTypes.length) {
- argumentTypes(i).getDescriptor(buf)
- i += 1
- }
- buf.append(')')
- returnType.getDescriptor(buf)
- buf.toString()
- }
-
- } // end of object BType
-
- /*
- * Based on ASM's Type class. Namer's chrs is used in this class for the same purposes as the `buf` char array in asm.Type.
- *
- * All methods of this classs can-multi-thread
- */
- final class BType(val sort: Int, val off: Int, val len: Int) {
-
- import global.chrs
-
- /*
- * can-multi-thread
- */
- def toASMType: scala.tools.asm.Type = {
- import scala.tools.asm
- // using `asm.Type.SHORT` instead of `BType.SHORT` because otherwise "warning: could not emit switch for @switch annotated match"
- (sort: @switch) match {
- case asm.Type.VOID => asm.Type.VOID_TYPE
- case asm.Type.BOOLEAN => asm.Type.BOOLEAN_TYPE
- case asm.Type.CHAR => asm.Type.CHAR_TYPE
- case asm.Type.BYTE => asm.Type.BYTE_TYPE
- case asm.Type.SHORT => asm.Type.SHORT_TYPE
- case asm.Type.INT => asm.Type.INT_TYPE
- case asm.Type.FLOAT => asm.Type.FLOAT_TYPE
- case asm.Type.LONG => asm.Type.LONG_TYPE
- case asm.Type.DOUBLE => asm.Type.DOUBLE_TYPE
- case asm.Type.ARRAY |
- asm.Type.OBJECT => asm.Type.getObjectType(getInternalName)
- case asm.Type.METHOD => asm.Type.getMethodType(getDescriptor)
- }
- }
-
- /*
- * Unlike for ICode's REFERENCE, isBoxedType(t) implies isReferenceType(t)
- * Also, `isReferenceType(RT_NOTHING) == true` , similarly for RT_NULL.
- * Use isNullType() , isNothingType() to detect Nothing and Null.
- *
- * can-multi-thread
- */
- def hasObjectSort = (sort == BType.OBJECT)
-
- /*
- * Returns the number of dimensions of this array type. This method should
- * only be used for an array type.
- *
- * @return the number of dimensions of this array type.
- *
- * can-multi-thread
- */
- def getDimensions: Int = {
- var i = 1
- while (chrs(off + i) == '[') {
- i += 1
- }
- i
- }
-
- /*
- * Returns the (ultimate) element type of this array type.
- * This method should only be used for an array type.
- *
- * @return Returns the type of the elements of this array type.
- *
- * can-multi-thread
- */
- def getElementType: BType = {
- assert(isArray, s"Asked for the element type of a non-array type: $this")
- BType.getType(off + getDimensions)
- }
-
- /*
- * Returns the internal name of the class corresponding to this object or
- * array type. The internal name of a class is its fully qualified name (as
- * returned by Class.getName(), where '.' are replaced by '/'. This method
- * should only be used for an object or array type.
- *
- * @return the internal name of the class corresponding to this object type.
- *
- * can-multi-thread
- */
- def getInternalName: String = {
- new String(chrs, off, len)
- }
-
- /*
- * @return the suffix of the internal name until the last '/' (if '/' present), internal name otherwise.
- *
- * can-multi-thread
- */
- def getSimpleName: String = {
- assert(hasObjectSort, s"not of object sort: $toString")
- val iname = getInternalName
- val idx = iname.lastIndexOf('/')
- if (idx == -1) iname
- else iname.substring(idx + 1)
- }
-
- /*
- * Returns the argument types of methods of this type.
- * This method should only be used for method types.
- *
- * @return the argument types of methods of this type.
- *
- * can-multi-thread
- */
- def getArgumentTypes: Array[BType] = {
- BType.getArgumentTypes(off + 1)
- }
-
- /*
- * Returns the return type of methods of this type.
- * This method should only be used for method types.
- *
- * @return the return type of methods of this type.
- *
- * can-multi-thread
- */
- def getReturnType: BType = {
- assert(chrs(off) == '(', s"doesn't look like a method descriptor: $toString")
- var resPos = off + 1
- while (chrs(resPos) != ')') { resPos += 1 }
- BType.getType(resPos + 1)
- }
-
- // ------------------------------------------------------------------------
- // Inspector methods
- // ------------------------------------------------------------------------
-
- def isPrimitiveOrVoid = (sort < BType.ARRAY) // can-multi-thread
- def isValueType = (sort < BType.ARRAY) // can-multi-thread
- def isArray = (sort == BType.ARRAY) // can-multi-thread
- def isUnitType = (sort == BType.VOID) // can-multi-thread
-
- def isRefOrArrayType = { hasObjectSort || isArray } // can-multi-thread
- def isNonUnitValueType = { isValueType && !isUnitType } // can-multi-thread
-
- def isNonSpecial = { !isValueType && !isArray && !isPhantomType } // can-multi-thread
- def isNothingType = { (this == RT_NOTHING) || (this == CT_NOTHING) } // can-multi-thread
- def isNullType = { (this == RT_NULL) || (this == CT_NULL) } // can-multi-thread
- def isPhantomType = { isNothingType || isNullType } // can-multi-thread
-
- /*
- * can-multi-thread
- */
- 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
- }
- }
-
- /* On the JVM,
- * BOOL, BYTE, CHAR, SHORT, and INT
- * are like Ints for the purpose of lub calculation.
- *
- * can-multi-thread
- */
- def isIntSizedType = {
- (sort : @switch) match {
- case BType.BOOLEAN | BType.CHAR |
- BType.BYTE | BType.SHORT | BType.INT
- => true
- case _
- => false
- }
- }
-
- /* On the JVM, similar to isIntSizedType except that BOOL isn't integral while LONG is.
- *
- * can-multi-thread
- */
- def isIntegralType = {
- (sort : @switch) match {
- case BType.CHAR |
- BType.BYTE | BType.SHORT | BType.INT |
- BType.LONG
- => true
- case _
- => false
- }
- }
-
- /* On the JVM, FLOAT and DOUBLE.
- *
- * can-multi-thread
- */
- def isRealType = { (sort == BType.FLOAT ) || (sort == BType.DOUBLE) }
-
- def isNumericType = (isIntegralType || isRealType) // can-multi-thread
-
- /* Is this type a category 2 type in JVM terms? (ie, is it LONG or DOUBLE?)
- *
- * can-multi-thread
- */
- def isWideType = (getSize == 2)
-
- /*
- * Element vs. Component type of an array:
- * Quoting from the JVMS, Sec. 2.4 "Reference Types and Values"
- *
- * An array type consists of a component type with a single dimension (whose
- * length is not given by the type). The component type of an array type may itself be
- * an array type. If, starting from any array type, one considers its component type,
- * and then (if that is also an array type) the component type of that type, and so on,
- * eventually one must reach a component type that is not an array type; this is called
- * the element type of the array type. The element type of an array type is necessarily
- * either a primitive type, or a class type, or an interface type.
- *
- */
-
- /* The type of items this array holds.
- *
- * can-multi-thread
- */
- def getComponentType: BType = {
- assert(isArray, s"Asked for the component type of a non-array type: $this")
- BType.getType(off + 1)
- }
-
- // ------------------------------------------------------------------------
- // Conversion to type descriptors
- // ------------------------------------------------------------------------
-
- /*
- * @return the descriptor corresponding to this Java type.
- *
- * can-multi-thread
- */
- def getDescriptor: String = {
- val buf = new StringBuffer()
- getDescriptor(buf)
- buf.toString()
- }
-
- /*
- * Appends the descriptor corresponding to this Java type to the given string buffer.
- *
- * @param buf the string buffer to which the descriptor must be appended.
- *
- * can-multi-thread
- */
- private def getDescriptor(buf: StringBuffer) {
- if (isPrimitiveOrVoid) {
- // descriptor is in byte 3 of 'off' for primitive types (buf == null)
- buf.append(((off & 0xFF000000) >>> 24).asInstanceOf[Char])
- } else if (sort == BType.OBJECT) {
- buf.append('L')
- buf.append(chrs, off, len)
- buf.append(';')
- } else { // sort == ARRAY || sort == METHOD
- buf.append(chrs, off, len)
- }
- }
-
- // ------------------------------------------------------------------------
- // Corresponding size and opcodes
- // ------------------------------------------------------------------------
-
- /*
- * Returns the size of values of this type.
- * This method must not be used for method types.
- *
- * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
- * <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
- *
- * can-multi-thread
- */
- def getSize: Int = {
- // the size is in byte 0 of 'off' for primitive types (buf == null)
- if (isPrimitiveOrVoid) (off & 0xFF) else 1
- }
-
- /*
- * Returns a JVM instruction opcode adapted to this Java type. This method
- * must not be used for method types.
- *
- * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD,
- * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL,
- * ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
- * @return an opcode that is similar to the given opcode, but adapted to
- * this Java type. For example, if this type is <tt>float</tt> and
- * <tt>opcode</tt> is IRETURN, this method returns FRETURN.
- *
- * can-multi-thread
- */
- def getOpcode(opcode: Int): Int = {
- import scala.tools.asm.Opcodes
- if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
- // the offset for IALOAD or IASTORE is in byte 1 of 'off' for
- // primitive types (buf == null)
- opcode + (if (isPrimitiveOrVoid) (off & 0xFF00) >> 8 else 4)
- } else {
- // the offset for other instructions is in byte 2 of 'off' for
- // primitive types (buf == null)
- opcode + (if (isPrimitiveOrVoid) (off & 0xFF0000) >> 16 else 4)
- }
- }
-
- // ------------------------------------------------------------------------
- // Equals, hashCode and toString
- // ------------------------------------------------------------------------
-
- /*
- * Tests if the given object is equal to this type.
- *
- * @param o the object to be compared to this type.
- * @return <tt>true</tt> if the given object is equal to this type.
- *
- * can-multi-thread
- */
- override def equals(o: Any): Boolean = {
- if (!(o.isInstanceOf[BType])) {
- return false
- }
- val t = o.asInstanceOf[BType]
- if (this eq t) {
- return true
- }
- if (sort != t.sort) {
- return false
- }
- if (sort >= BType.ARRAY) {
- if (len != t.len) {
- return false
- }
- // sort checked already
- if (off == t.off) {
- return true
- }
- var i = 0
- while (i < len) {
- if (chrs(off + i) != chrs(t.off + i)) {
- return false
- }
- i += 1
- }
- // If we reach here, we could update the largest of (this.off, t.off) to match the other, so as to simplify future == comparisons.
- // But that would require a var rather than val.
- }
- true
- }
-
- /*
- * @return a hash code value for this type.
- *
- * can-multi-thread
- */
- override def hashCode(): Int = {
- var hc = 13 * sort;
- if (sort >= BType.ARRAY) {
- var i = off
- val end = i + len
- while (i < end) {
- hc = 17 * (hc + chrs(i))
- i += 1
- }
- }
- hc
- }
-
- /*
- * @return the descriptor of this type.
- *
- * can-multi-thread
- */
- override def toString: String = { getDescriptor }
-
- }
-
- /*
- * Creates a TypeName and the BType token for it.
- * This method does not add to `innerClassBufferASM`, use `internalName()` or `asmType()` or `toTypeKind()` for that.
- *
- * must-single-thread
- */
- def brefType(iname: String): BType = { brefType(newTypeName(iname.toCharArray(), 0, iname.length())) }
-
- /*
- * Creates a BType token for the TypeName received as argument.
- * This method does not add to `innerClassBufferASM`, use `internalName()` or `asmType()` or `toTypeKind()` for that.
- *
- * can-multi-thread
- */
- def brefType(iname: TypeName): BType = { BType.getObjectType(iname.start, iname.length) }
-
- // due to keyboard economy only
- val UNIT = BType.VOID_TYPE
- val BOOL = BType.BOOLEAN_TYPE
- val CHAR = BType.CHAR_TYPE
- val BYTE = BType.BYTE_TYPE
- val SHORT = BType.SHORT_TYPE
- val INT = BType.INT_TYPE
- val LONG = BType.LONG_TYPE
- val FLOAT = BType.FLOAT_TYPE
- val DOUBLE = BType.DOUBLE_TYPE
-
- val BOXED_UNIT = brefType("java/lang/Void")
- val BOXED_BOOLEAN = brefType("java/lang/Boolean")
- val BOXED_BYTE = brefType("java/lang/Byte")
- val BOXED_SHORT = brefType("java/lang/Short")
- val BOXED_CHAR = brefType("java/lang/Character")
- val BOXED_INT = brefType("java/lang/Integer")
- val BOXED_LONG = brefType("java/lang/Long")
- val BOXED_FLOAT = brefType("java/lang/Float")
- val BOXED_DOUBLE = brefType("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.
- */
- val RT_NOTHING = brefType("scala/runtime/Nothing$")
- val RT_NULL = brefType("scala/runtime/Null$")
- val CT_NOTHING = brefType("scala/Nothing") // TODO needed?
- val CT_NULL = brefType("scala/Null") // TODO needed?
-
- val srBooleanRef = brefType("scala/runtime/BooleanRef")
- val srByteRef = brefType("scala/runtime/ByteRef")
- val srCharRef = brefType("scala/runtime/CharRef")
- val srIntRef = brefType("scala/runtime/IntRef")
- val srLongRef = brefType("scala/runtime/LongRef")
- val srFloatRef = brefType("scala/runtime/FloatRef")
- val srDoubleRef = brefType("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()
- */
- val classLiteral = immutable.Map[BType, BType](
- 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(mname: String, mdesc: String)
-
- val asmBoxTo: 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;" )
- )
- }
-
- val asmUnboxTo: 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")
- )
- }
-}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
index 1ede914288..31a392ed55 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
@@ -20,8 +20,8 @@ import scala.tools.nsc.io.AbstractFile
*
*/
abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
-
import global._
+ import bTypes._
/*
* must-single-thread
@@ -38,7 +38,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
outputDirectory(csym)
} catch {
case ex: Throwable =>
- cunit.error(cunit.body.pos, s"Couldn't create file for class $cName\n${ex.getMessage}")
+ reporter.error(cunit.body.pos, s"Couldn't create file for class $cName\n${ex.getMessage}")
null
}
}
@@ -56,7 +56,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
/*
* can-multi-thread
*/
- def firstCommonSuffix(as: List[Tracked], bs: List[Tracked]): BType = {
+ def firstCommonSuffix(as: List[Tracked], bs: List[Tracked]): ClassBType = {
var chainA = as
var chainB = bs
var fcs: Tracked = null
@@ -77,17 +77,18 @@ 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()`
+ /**
+ * 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
+ * can-multi-thread
*/
override def getCommonSuperClass(inameA: String, inameB: String): String = {
- val a = brefType(lookupTypeName(inameA.toCharArray))
- val b = brefType(lookupTypeName(inameB.toCharArray))
+ val a = ClassBType(lookupTypeName(inameA.toCharArray))
+ val b = ClassBType(lookupTypeName(inameB.toCharArray))
val lca = jvmWiseLUB(a, b)
- val lcaName = lca.getInternalName // don't call javaName because that side-effects innerClassBuffer.
+ 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.
@@ -95,16 +96,17 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
}
- /*
- * 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
+ /**
+ * 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
+ * can-multi-thread
*/
- def jvmWiseLUB(a: BType, b: BType): BType = {
+ 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")
@@ -139,7 +141,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
*/
def apply(sym: Symbol, csymCompUnit: CompilationUnit): Boolean = {
def fail(msg: String, pos: Position = sym.pos) = {
- csymCompUnit.warning(sym.pos,
+ reporter.warning(sym.pos,
sym.name +
s" has a main method with parameter type Array[String], but ${sym.fullName('.')} will not be a runnable program.\n Reason: $msg"
// TODO: make this next claim true, if possible
@@ -401,14 +403,14 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
*
* must-single-thread
*/
- final def internalName(sym: Symbol): String = { asmClassType(sym).getInternalName }
+ final def internalName(sym: Symbol): String = asmClassType(sym).internalName
/*
* Tracks (if needed) the inner class given by `sym`.
*
* must-single-thread
*/
- final def asmClassType(sym: Symbol): BType = {
+ final def asmClassType(sym: Symbol): ClassBType = {
assert(
hasInternalName(sym),
{
@@ -514,17 +516,18 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
case _: ConstantType => toTypeKind(t.underlying)
case TypeRef(_, sym, args) =>
- if (sym == ArrayClass) arrayOf(toTypeKind(args.head))
+ 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 reduceLeft jvmWiseLUB
+ 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)
@@ -538,12 +541,12 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
/*
* must-single-thread
*/
- def asmMethodType(msym: Symbol): BType = {
+ def asmMethodType(msym: Symbol): MethodBType = {
assert(msym.isMethod, s"not a method-symbol: $msym")
val resT: BType =
- if (msym.isClassConstructor || msym.isConstructor) BType.VOID_TYPE
- else toTypeKind(msym.tpe.resultType);
- BType.getMethodType( resT, mkArray(msym.tpe.paramTypes map toTypeKind) )
+ if (msym.isClassConstructor || msym.isConstructor) UNIT
+ else toTypeKind(msym.tpe.resultType)
+ MethodBType(msym.tpe.paramTypes map toTypeKind, resT)
}
/*
@@ -577,14 +580,14 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
*
* must-single-thread
*/
- final def descriptor(t: Type): String = { toTypeKind(t).getDescriptor }
+ final def descriptor(t: Type): String = { toTypeKind(t).descriptor }
/*
* Tracks (if needed) the inner class given by `sym`.
*
* must-single-thread
*/
- final def descriptor(sym: Symbol): String = { asmClassType(sym).getDescriptor }
+ final def descriptor(sym: Symbol): String = { asmClassType(sym).descriptor }
} // end of trait BCInnerClassGen
@@ -800,7 +803,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
val thrownExceptions: List[String] = getExceptions(throws)
val jReturnType = toTypeKind(methodInfo.resultType)
- val mdesc = BType.getMethodType(jReturnType, mkArray(paramJavaTypes)).getDescriptor
+ val mdesc = MethodBType(paramJavaTypes, jReturnType).descriptor
val mirrorMethodName = m.javaSimpleName.toString
val mirrorMethod: asm.MethodVisitor = jclass.visitMethod(
flags,
@@ -819,13 +822,13 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
var index = 0
for(jparamType <- paramJavaTypes) {
- mirrorMethod.visitVarInsn(jparamType.getOpcode(asm.Opcodes.ILOAD), index)
- assert(jparamType.sort != BType.METHOD, jparamType)
- index += jparamType.getSize
+ mirrorMethod.visitVarInsn(jparamType.typedOpcode(asm.Opcodes.ILOAD), index)
+ assert(!jparamType.isInstanceOf[MethodBType], jparamType)
+ index += jparamType.size
}
- mirrorMethod.visitMethodInsn(asm.Opcodes.INVOKEVIRTUAL, moduleName, mirrorMethodName, asmMethodType(m).getDescriptor)
- mirrorMethod.visitInsn(jReturnType.getOpcode(asm.Opcodes.IRETURN))
+ mirrorMethod.visitMethodInsn(asm.Opcodes.INVOKEVIRTUAL, moduleName, mirrorMethodName, asmMethodType(m).descriptor, false)
+ mirrorMethod.visitInsn(jReturnType.typedOpcode(asm.Opcodes.IRETURN))
mirrorMethod.visitMaxs(0, 0) // just to follow protocol, dummy arguments
mirrorMethod.visitEnd()
@@ -993,7 +996,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
flags,
mirrorName,
null /* no java-generic-signature */,
- JAVA_LANG_OBJECT.getInternalName,
+ JAVA_LANG_OBJECT.internalName,
EMPTY_STRING_ARRAY
)
@@ -1085,12 +1088,11 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
EMPTY_STRING_ARRAY // no throwable exceptions
)
- val stringArrayJType: BType = arrayOf(JAVA_LANG_STRING)
- val conJType: BType =
- BType.getMethodType(
- BType.VOID_TYPE,
- Array(exemplar(definitions.ClassClass).c, stringArrayJType, stringArrayJType)
- )
+ val stringArrayJType: BType = ArrayBType(JAVA_LANG_STRING)
+ val conJType: BType = MethodBType(
+ exemplar(definitions.ClassClass).c :: stringArrayJType :: stringArrayJType :: Nil,
+ UNIT
+ )
def push(lst: List[String]) {
var fi = 0
@@ -1099,7 +1101,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.getOpcode(asm.Opcodes.IASTORE))
+ constructor.visitInsn(JAVA_LANG_STRING.typedOpcode(asm.Opcodes.IASTORE))
fi += 1
}
}
@@ -1112,17 +1114,17 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
// push the string array of field information
constructor.visitLdcInsn(new java.lang.Integer(fieldList.length))
- constructor.visitTypeInsn(asm.Opcodes.ANEWARRAY, JAVA_LANG_STRING.getInternalName)
+ constructor.visitTypeInsn(asm.Opcodes.ANEWARRAY, JAVA_LANG_STRING.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.getInternalName)
+ constructor.visitTypeInsn(asm.Opcodes.ANEWARRAY, JAVA_LANG_STRING.internalName)
push(methodList)
// invoke the superclass constructor, which will do the
// necessary java reflection and create Method objects.
- constructor.visitMethodInsn(asm.Opcodes.INVOKESPECIAL, "scala/beans/ScalaBeanInfo", INSTANCE_CONSTRUCTOR_NAME, conJType.getDescriptor)
+ constructor.visitMethodInsn(asm.Opcodes.INVOKESPECIAL, "scala/beans/ScalaBeanInfo", INSTANCE_CONSTRUCTOR_NAME, conJType.descriptor, false)
constructor.visitInsn(asm.Opcodes.RETURN)
constructor.visitMaxs(0, 0) // just to follow protocol, dummy arguments
@@ -1161,7 +1163,7 @@ 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 tdesc_creator = androidCreatorType.getDescriptor
+ val tdesc_creator = androidCreatorType.descriptor
cnode.visitField(
PublicStaticFinal,
@@ -1182,12 +1184,13 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
)
// INVOKEVIRTUAL `moduleName`.CREATOR() : android.os.Parcelable$Creator;
- val bt = BType.getMethodType(androidCreatorType, Array.empty[BType])
+ val bt = MethodBType(Nil, androidCreatorType)
clinit.visitMethodInsn(
asm.Opcodes.INVOKEVIRTUAL,
moduleName,
"CREATOR",
- bt.getDescriptor
+ bt.descriptor,
+ false
)
// PUTSTATIC `thisName`.CREATOR;
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
index c3492b79a9..9b7c975960 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
@@ -9,8 +9,7 @@ package backend.jvm
import scala.tools.asm
import scala.annotation.switch
-import scala.collection.{ immutable, mutable }
-import collection.convert.Wrappers.JListWrapper
+import scala.collection.mutable
/*
* A high-level facade to the ASM API for bytecode generation.
@@ -19,9 +18,17 @@ import collection.convert.Wrappers.JListWrapper
* @version 1.0
*
*/
-abstract class BCodeIdiomatic extends BCodeGlue {
+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)
+ }
import global._
+ import bTypes._
val classfileVersion: Int = settings.target.value match {
case "jvm-1.5" => asm.Opcodes.V1_5
@@ -44,12 +51,12 @@ abstract class BCodeIdiomatic extends BCodeGlue {
val CLASS_CONSTRUCTOR_NAME = "<clinit>"
val INSTANCE_CONSTRUCTOR_NAME = "<init>"
- val ObjectReference = brefType("java/lang/Object")
+ val ObjectReference = ClassBType("java/lang/Object")
val AnyRefReference = ObjectReference
- val objArrayReference = arrayOf(ObjectReference)
+ val objArrayReference = ArrayBType(ObjectReference)
val JAVA_LANG_OBJECT = ObjectReference
- val JAVA_LANG_STRING = brefType("java/lang/String")
+ val JAVA_LANG_STRING = ClassBType("java/lang/String")
var StringBuilderReference: BType = null
@@ -108,17 +115,6 @@ abstract class BCodeIdiomatic extends BCodeGlue {
a
}
- /*
- * The type of 1-dimensional arrays of `elem` type.
- * The invoker is responsible for tracking (if needed) the inner class given by the elem BType.
- *
- * must-single-thread
- */
- final def arrayOf(elem: BType): BType = {
- assert(!(elem.isUnitType), s"The element type of an array can't be: $elem")
- brefType("[" + elem.getDescriptor)
- }
-
/* Just a namespace for utilities that encapsulate MethodVisitor idioms.
* In the ASM world, org.objectweb.asm.commons.InstructionAdapter plays a similar role,
* but the methods here allow choosing when to transition from ICode to ASM types
@@ -242,12 +238,12 @@ abstract class BCodeIdiomatic extends BCodeGlue {
final def genStringConcat(el: BType) {
val jtype =
- if (el.isArray || el.hasObjectSort) JAVA_LANG_OBJECT
- else el;
+ if (el.isArray || el.isClass) JAVA_LANG_OBJECT
+ else el
- val bt = BType.getMethodType(StringBuilderReference, Array(jtype))
+ val bt = MethodBType(List(jtype), StringBuilderReference)
- invokevirtual(StringBuilderClassName, "append", bt.getDescriptor)
+ invokevirtual(StringBuilderClassName, "append", bt.descriptor)
}
/*
@@ -268,7 +264,7 @@ abstract class BCodeIdiomatic extends BCodeGlue {
final def emitT2T(from: BType, to: BType) {
assert(
- from.isNonUnitValueType && to.isNonUnitValueType,
+ from.isNonVoidPrimitiveType && to.isNonVoidPrimitiveType,
s"Cannot emit primitive conversion from $from to $to"
)
@@ -290,37 +286,37 @@ abstract class BCodeIdiomatic extends BCodeGlue {
assert(from != BOOL && to != BOOL, s"inconvertible types : $from -> $to")
// We're done with BOOL already
- (from.sort: @switch) match {
+ from match {
// using `asm.Type.SHORT` instead of `BType.SHORT` because otherwise "warning: could not emit switch for @switch annotated match"
- case asm.Type.BYTE => pickOne(JCodeMethodN.fromByteT2T)
- case asm.Type.SHORT => pickOne(JCodeMethodN.fromShortT2T)
- case asm.Type.CHAR => pickOne(JCodeMethodN.fromCharT2T)
- case asm.Type.INT => pickOne(JCodeMethodN.fromIntT2T)
+ case BYTE => pickOne(JCodeMethodN.fromByteT2T)
+ case SHORT => pickOne(JCodeMethodN.fromShortT2T)
+ case CHAR => pickOne(JCodeMethodN.fromCharT2T)
+ case INT => pickOne(JCodeMethodN.fromIntT2T)
- case asm.Type.FLOAT =>
+ case FLOAT =>
import asm.Opcodes.{ F2L, F2D, F2I }
- (to.sort: @switch) match {
- case asm.Type.LONG => emit(F2L)
- case asm.Type.DOUBLE => emit(F2D)
- case _ => emit(F2I); emitT2T(INT, to)
+ to match {
+ case LONG => emit(F2L)
+ case DOUBLE => emit(F2D)
+ case _ => emit(F2I); emitT2T(INT, to)
}
- case asm.Type.LONG =>
+ case LONG =>
import asm.Opcodes.{ L2F, L2D, L2I }
- (to.sort: @switch) match {
- case asm.Type.FLOAT => emit(L2F)
- case asm.Type.DOUBLE => emit(L2D)
- case _ => emit(L2I); emitT2T(INT, to)
+ to match {
+ case FLOAT => emit(L2F)
+ case DOUBLE => emit(L2D)
+ case _ => emit(L2I); emitT2T(INT, to)
}
- case asm.Type.DOUBLE =>
+ case DOUBLE =>
import asm.Opcodes.{ D2L, D2F, D2I }
- (to.sort: @switch) match {
- case asm.Type.FLOAT => emit(D2F)
- case asm.Type.LONG => emit(D2L)
- case _ => emit(D2I); emitT2T(INT, to)
+ to match {
+ case FLOAT => emit(D2F)
+ case LONG => emit(D2L)
+ case _ => emit(D2I); emitT2T(INT, to)
}
}
} // end of emitT2T()
@@ -372,24 +368,26 @@ abstract class BCodeIdiomatic extends BCodeGlue {
// can-multi-thread
final def newarray(elem: BType) {
- if (elem.isRefOrArrayType || elem.isPhantomType ) {
- /* phantom type at play in `Array(null)`, SI-1513. On the other hand, Array(()) has element type `scala.runtime.BoxedUnit` which hasObjectSort. */
- jmethod.visitTypeInsn(Opcodes.ANEWARRAY, elem.getInternalName)
- } else {
- val rand = {
- // using `asm.Type.SHORT` instead of `BType.SHORT` because otherwise "warning: could not emit switch for @switch annotated match"
- (elem.sort: @switch) match {
- case asm.Type.BOOLEAN => Opcodes.T_BOOLEAN
- case asm.Type.BYTE => Opcodes.T_BYTE
- case asm.Type.SHORT => Opcodes.T_SHORT
- case asm.Type.CHAR => Opcodes.T_CHAR
- case asm.Type.INT => Opcodes.T_INT
- case asm.Type.LONG => Opcodes.T_LONG
- case asm.Type.FLOAT => Opcodes.T_FLOAT
- case asm.Type.DOUBLE => Opcodes.T_DOUBLE
+ elem match {
+ case c: RefBType =>
+ /* phantom type at play in `Array(null)`, SI-1513. On the other hand, Array(()) has element type `scala.runtime.BoxedUnit` which isObject. */
+ jmethod.visitTypeInsn(Opcodes.ANEWARRAY, c.classOrArrayType)
+ case _ =>
+ assert(elem.isNonVoidPrimitiveType)
+ val rand = {
+ // using `asm.Type.SHORT` instead of `BType.SHORT` because otherwise "warning: could not emit switch for @switch annotated match"
+ elem match {
+ case BOOL => Opcodes.T_BOOLEAN
+ case BYTE => Opcodes.T_BYTE
+ case SHORT => Opcodes.T_SHORT
+ case CHAR => Opcodes.T_CHAR
+ case INT => Opcodes.T_INT
+ case LONG => Opcodes.T_LONG
+ case FLOAT => Opcodes.T_FLOAT
+ case DOUBLE => Opcodes.T_DOUBLE
+ }
}
- }
- jmethod.visitIntInsn(Opcodes.NEWARRAY, rand)
+ jmethod.visitIntInsn(Opcodes.NEWARRAY, rand)
}
}
@@ -409,19 +407,19 @@ abstract class BCodeIdiomatic extends BCodeGlue {
// can-multi-thread
final def invokespecial(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false)
}
// can-multi-thread
final def invokestatic(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false)
}
// can-multi-thread
final def invokeinterface(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc, true)
}
// can-multi-thread
final def invokevirtual(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false)
}
// can-multi-thread
@@ -529,7 +527,7 @@ abstract class BCodeIdiomatic extends BCodeGlue {
// can-multi-thread
final def emitVarInsn(opc: Int, idx: Int, tk: BType) {
assert((opc == Opcodes.ILOAD) || (opc == Opcodes.ISTORE), opc)
- jmethod.visitVarInsn(tk.getOpcode(opc), idx)
+ jmethod.visitVarInsn(tk.typedOpcode(opc), idx)
}
// ---------------- array load and store ----------------
@@ -538,7 +536,7 @@ abstract class BCodeIdiomatic extends BCodeGlue {
final def emitTypeBased(opcs: Array[Int], tk: BType) {
assert(tk != UNIT, tk)
val opc = {
- if (tk.isRefOrArrayType) { opcs(0) }
+ if (tk.isRef) { opcs(0) }
else if (tk.isIntSizedType) {
(tk: @unchecked) match {
case BOOL | BYTE => opcs(1)
@@ -563,11 +561,11 @@ abstract class BCodeIdiomatic extends BCodeGlue {
final def emitPrimitive(opcs: Array[Int], tk: BType) {
val opc = {
// using `asm.Type.SHORT` instead of `BType.SHORT` because otherwise "warning: could not emit switch for @switch annotated match"
- (tk.sort: @switch) match {
- case asm.Type.LONG => opcs(1)
- case asm.Type.FLOAT => opcs(2)
- case asm.Type.DOUBLE => opcs(3)
- case _ => opcs(0)
+ tk match {
+ case LONG => opcs(1)
+ case FLOAT => opcs(2)
+ case DOUBLE => opcs(3)
+ case _ => opcs(0)
}
}
emit(opc)
@@ -582,15 +580,14 @@ abstract class BCodeIdiomatic extends BCodeGlue {
// ---------------- type checks and casts ----------------
// can-multi-thread
- final def isInstance(tk: BType) {
- jmethod.visitTypeInsn(Opcodes.INSTANCEOF, tk.getInternalName)
+ final def isInstance(tk: RefBType): Unit = {
+ jmethod.visitTypeInsn(Opcodes.INSTANCEOF, tk.classOrArrayType)
}
// can-multi-thread
- final def checkCast(tk: BType) {
- assert(tk.isRefOrArrayType, s"checkcast on primitive type: $tk")
+ final def checkCast(tk: RefBType): Unit = {
// TODO ICode also requires: but that's too much, right? assert(!isBoxedType(tk), "checkcast on boxed type: " + tk)
- jmethod.visitTypeInsn(Opcodes.CHECKCAST, tk.getInternalName)
+ jmethod.visitTypeInsn(Opcodes.CHECKCAST, tk.classOrArrayType)
}
} // end of class JCodeMethodN
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
index ee9be5b11c..8845ffa0cd 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
@@ -25,6 +25,7 @@ import java.io.PrintWriter
*/
abstract class BCodeSkelBuilder extends BCodeHelpers {
import global._
+ import bTypes._
/*
* There's a dedicated PlainClassBuilder for each CompilationUnit,
@@ -133,7 +134,7 @@ 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.getInternalName else internalName(ps.head.typeSymbol);
+ 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)
@@ -142,7 +143,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val ifaceTr = arrIfacesTr(i)
val bt = ifaceTr.c
if (ifaceTr.isInnerClass) { innerClassBufferASM += bt }
- arrIfaces(i) = bt.getInternalName
+ arrIfaces(i) = bt.internalName
i += 1
}
arrIfaces
@@ -166,7 +167,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val enclM = getEnclosingMethodAttribute(claszSymbol)
if (enclM != null) {
val EnclMethodEntry(className, methodName, methodType) = enclM
- cnode.visitOuterClass(className, methodName, methodType.getDescriptor)
+ cnode.visitOuterClass(className, methodName, methodType.descriptor)
}
val ssa = getAnnotPickle(thisName, claszSymbol)
@@ -234,7 +235,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
if (isCZStaticModule) {
clinit.visitTypeInsn(asm.Opcodes.NEW, thisName)
clinit.visitMethodInsn(asm.Opcodes.INVOKESPECIAL,
- thisName, INSTANCE_CONSTRUCTOR_NAME, "()V")
+ thisName, INSTANCE_CONSTRUCTOR_NAME, "()V", false)
}
if (isCZParcelable) { legacyAddCreatorCode(clinit, cnode, thisName) }
clinit.visitInsn(asm.Opcodes.RETURN)
@@ -261,7 +262,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val jfield = new asm.tree.FieldNode(
flags,
f.javaSimpleName.toString,
- symInfoTK(f).getDescriptor,
+ symInfoTK(f).descriptor,
javagensig,
null // no initial value
)
@@ -397,8 +398,8 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
assert(nxtIdx != -1, "not a valid start index")
val loc = Local(tk, sym.javaSimpleName.toString, nxtIdx, sym.isSynthetic)
slots += (sym -> loc)
- assert(tk.getSize > 0, "makeLocal called for a symbol whose type is Unit.")
- nxtIdx += tk.getSize
+ assert(tk.size > 0, "makeLocal called for a symbol whose type is Unit.")
+ nxtIdx += tk.size
loc
}
@@ -531,7 +532,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
if (isMethSymStaticCtor) CLASS_CONSTRUCTOR_NAME
else jMethodName
- val mdesc = asmMethodType(methSymbol).getDescriptor
+ val mdesc = asmMethodType(methSymbol).descriptor
mnode = cnode.visitMethod(
flags,
bytecodeName,
@@ -555,7 +556,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
methSymbol = dd.symbol
jMethodName = methSymbol.javaSimpleName.toString
- returnType = asmMethodType(dd.symbol).getReturnType
+ returnType = asmMethodType(dd.symbol).returnType
isMethSymStaticCtor = methSymbol.isStaticConstructor
resetMethodBookkeeping(dd)
@@ -569,7 +570,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
if (params.size > MaximumJvmParameters) {
// SI-7324
- cunit.error(methSymbol.pos, s"Platform restriction: a parameter list's length cannot exceed $MaximumJvmParameters.")
+ reporter.error(methSymbol.pos, s"Platform restriction: a parameter list's length cannot exceed $MaximumJvmParameters.")
return
}
@@ -685,8 +686,8 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val callee = methSymbol.enclClass.primaryConstructor
val jname = callee.javaSimpleName.toString
val jowner = internalName(callee.owner)
- val jtype = asmMethodType(callee).getDescriptor
- insnModB = new asm.tree.MethodInsnNode(asm.Opcodes.INVOKESPECIAL, jowner, jname, jtype)
+ val jtype = asmMethodType(callee).descriptor
+ insnModB = new asm.tree.MethodInsnNode(asm.Opcodes.INVOKESPECIAL, jowner, jname, jtype, false)
}
var insnParcA: asm.tree.AbstractInsnNode = null
@@ -694,7 +695,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).getDescriptor
+ val andrFieldDescr = asmClassType(AndroidCreatorClass).descriptor
cnode.visitField(
asm.Opcodes.ACC_STATIC | asm.Opcodes.ACC_FINAL,
"CREATOR",
@@ -706,8 +707,8 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val callee = definitions.getMember(claszSymbol.companionModule, androidFieldName)
val jowner = internalName(callee.owner)
val jname = callee.javaSimpleName.toString
- val jtype = asmMethodType(callee).getDescriptor
- insnParcA = new asm.tree.MethodInsnNode(asm.Opcodes.INVOKESTATIC, jowner, jname, jtype)
+ val jtype = asmMethodType(callee).descriptor
+ insnParcA = new asm.tree.MethodInsnNode(asm.Opcodes.INVOKESTATIC, jowner, jname, jtype, false)
// PUTSTATIC `thisName`.CREATOR;
insnParcB = new asm.tree.FieldInsnNode(asm.Opcodes.PUTSTATIC, thisName, "CREATOR", andrFieldDescr)
}
@@ -723,7 +724,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
def emitLocalVarScope(sym: Symbol, start: asm.Label, end: asm.Label, force: Boolean = false) {
val Local(tk, name, idx, isSynth) = locals(sym)
if (force || !isSynth) {
- mnode.visitLocalVariable(name, tk.getDescriptor, null, start, end, idx)
+ mnode.visitLocalVariable(name, tk.descriptor, null, start, end, idx)
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala
index 9ddb7a3ce8..c271e7b129 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala
@@ -9,9 +9,7 @@ package tools.nsc
package backend
package jvm
-import scala.collection.{ mutable, immutable }
-import scala.annotation.switch
-
+import scala.collection.immutable
import scala.tools.asm
/*
@@ -22,6 +20,7 @@ import scala.tools.asm
*/
abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
import global._
+ import bTypes._
/*
@@ -184,7 +183,7 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
val caseHandlers: List[EHClause] =
for (CaseDef(pat, _, caseBody) <- catches) yield {
pat match {
- case Typed(Ident(nme.WILDCARD), tpt) => NamelessEH(tpeTK(tpt), caseBody)
+ case Typed(Ident(nme.WILDCARD), tpt) => NamelessEH(tpeTK(tpt).asClassBType, caseBody)
case Ident(nme.WILDCARD) => NamelessEH(ThrowableReference, caseBody)
case Bind(_, _) => BoundEH (pat.symbol, caseBody)
}
@@ -250,7 +249,7 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
// (2.a) emit case clause proper
val startHandler = currProgramPoint()
var endHandler: asm.Label = null
- var excType: BType = null
+ var excType: ClassBType = null
registerCleanup(finCleanup)
ch match {
case NamelessEH(typeToDrop, caseBody) =>
@@ -269,7 +268,7 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
nopIfNeeded(startHandler)
endHandler = currProgramPoint()
emitLocalVarScope(patSymbol, startHandler, endHandler)
- excType = patTK
+ excType = patTK.asClassBType
}
unregisterCleanup(finCleanup)
// (2.b) mark the try-body as protected by this case clause.
@@ -357,10 +356,10 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
}
}
- def protect(start: asm.Label, end: asm.Label, handler: asm.Label, excType: BType) {
+ def protect(start: asm.Label, end: asm.Label, handler: asm.Label, excType: ClassBType) {
val excInternalName: String =
if (excType == null) null
- else excType.getInternalName
+ else excType.internalName
assert(start != end, "protecting a range of zero instructions leads to illegal class format. Solution: add a NOP to that range.")
mnode.visitTryCatchBlock(start, end, handler, excInternalName)
}
@@ -387,7 +386,7 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
def mayCleanStack(tree: Tree): Boolean = tree exists { t => t.isInstanceOf[Try] }
trait EHClause
- case class NamelessEH(typeToDrop: BType, caseBody: Tree) extends EHClause
+ case class NamelessEH(typeToDrop: ClassBType, caseBody: Tree) extends EHClause
case class BoundEH (patSymbol: Symbol, caseBody: Tree) extends EHClause
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala
index 1eca69936a..62dfb4917d 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala
@@ -18,27 +18,25 @@ import scala.collection.{ immutable, mutable }
*
*/
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)
- val srBoxedUnit = brefType("scala/runtime/BoxedUnit")
-
// special names
- var StringReference : BType = null
- var ThrowableReference : BType = null
- var jlCloneableReference : BType = null // java/lang/Cloneable
- var jlNPEReference : BType = null // java/lang/NullPointerException
- var jioSerializableReference : BType = null // java/io/Serializable
- var scalaSerializableReference : BType = null // scala/Serializable
- var classCastExceptionReference : BType = null // java/lang/ClassCastException
+ 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, BType] = null
+ 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
@@ -63,10 +61,10 @@ abstract class BCodeTypes extends BCodeIdiomatic {
val AbstractFunctionReference = new Array[Tracked](definitions.MaxFunctionArity + 1)
val abstractFunctionArityMap = mutable.Map.empty[BType, Int]
- var PartialFunctionReference: BType = null // scala.PartialFunction
- var AbstractPartialFunctionReference: BType = null // scala.runtime.AbstractPartialFunction
+ var PartialFunctionReference: ClassBType = null // scala.PartialFunction
+ var AbstractPartialFunctionReference: ClassBType = null // scala.runtime.AbstractPartialFunction
- var BoxesRunTime: BType = null
+ var BoxesRunTime: ClassBType = null
/*
* must-single-thread
@@ -107,7 +105,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
// 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 = brefType(csym.javaBinaryName.toTypeName)
+ val key = ClassBType(csym.javaBinaryName.toTypeName)
val tr = buildExemplar(key, csym)
symExemplars.put(csym, tr)
exemplars.put(tr.c, tr)
@@ -147,16 +145,6 @@ abstract class BCodeTypes extends BCodeIdiomatic {
scalaSerializableReference = exemplar(SerializableClass).c
classCastExceptionReference = exemplar(ClassCastExceptionClass).c
- /*
- * The bytecode emitter special-cases String concatenation, in that three methods of `JCodeMethodN`
- * ( `genStartConcat()` , `genStringConcat()` , and `genEndConcat()` )
- * don't obtain the method descriptor of the callee via `asmMethodType()` (as normally done)
- * but directly emit callsites on StringBuilder using literal constant for method descriptors.
- * In order to make sure those method descriptors are available as BTypes, they are initialized here.
- */
- BType.getMethodType("()V") // necessary for JCodeMethodN.genStartConcat
- BType.getMethodType("()Ljava/lang/String;") // necessary for JCodeMethodN.genEndConcat
-
PartialFunctionReference = exemplar(PartialFunctionClass).c
for(idx <- 0 to definitions.MaxFunctionArity) {
FunctionReference(idx) = exemplar(FunctionClass(idx))
@@ -165,12 +153,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
AbstractPartialFunctionReference = exemplar(AbstractPartialFunctionClass).c
}
- // later a few analyses (e.g. refreshInnerClasses) will look up BTypes based on descriptors in instructions
- // we make sure those BTypes can be found via lookup as opposed to creating them on the fly.
- BoxesRunTime = brefType("scala/runtime/BoxesRunTime")
- asmBoxTo.values foreach { mnat: MethodNameAndType => BType.getMethodType(mnat.mdesc) }
- asmUnboxTo.values foreach { mnat: MethodNameAndType => BType.getMethodType(mnat.mdesc) }
-
+ BoxesRunTime = ClassBType("scala/runtime/BoxesRunTime")
}
/*
@@ -191,28 +174,41 @@ abstract class BCodeTypes extends BCodeIdiomatic {
// allowing answering `conforms()` without resorting to typer.
// ------------------------------------------------
- val exemplars = new java.util.concurrent.ConcurrentHashMap[BType, Tracked]
- val symExemplars = new java.util.concurrent.ConcurrentHashMap[Symbol, Tracked]
+ /**
+ * TODO @lry should probably be a map form ClassBType to Tracked
+ */
+ val exemplars = new java.util.concurrent.ConcurrentHashMap[BType, Tracked]
- /*
- * Typically, a question about a BType can be answered only by using the BType as lookup key in one or more maps.
- * A `Tracked` object saves time by holding together information required to answer those questions:
+ /**
+ * 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.
*
- * - `sc` denotes the bytecode-level superclass if any, null otherwise
+ * @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.
*
- * - `ifaces` denotes the interfaces explicitly declared.
- * Not included are those transitively supported, but the utility method `allLeafIfaces()` can be used for that.
+ * 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).
*
- * - `innersChain` denotes 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
*
- * All methods of this class can-multi-thread
+ * TODO @lry c: ClassBType. rename to ClassBTypeInfo
*/
- case class Tracked(c: BType, flags: Int, sc: Tracked, ifaces: Array[Tracked], innersChain: Array[InnerClassEntry]) {
+ 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] = {
@@ -223,9 +219,9 @@ abstract class BCodeTypes extends BCodeIdiomatic {
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 == bs.sortBy(_.off))
+ assert(_directMemberClasses.sameElements(bs))
}
- _directMemberClasses = bs.sortBy(_.off)
+ _directMemberClasses = bs
}
/* `isCompilingStdLib` saves the day when compiling:
@@ -247,7 +243,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
def isInnerClass = { innersChain != null }
def isLambda = {
// ie isLCC || isTraditionalClosureClass
- isFinal && (c.getSimpleName.contains(tpnme.ANON_FUN_NAME.toString)) && isFunctionType(c)
+ isFinal && (c.simpleName.contains(tpnme.ANON_FUN_NAME.toString)) && isFunctionType(c)
}
/* can-multi-thread */
@@ -350,8 +346,8 @@ abstract class BCodeTypes extends BCodeIdiomatic {
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}")
+ 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)
}
@@ -380,8 +376,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
if (opt != null) {
return opt
}
-
- val key = brefType(csym.javaBinaryName.toTypeName)
+ 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
@@ -395,12 +390,10 @@ abstract class BCodeTypes extends BCodeIdiomatic {
tr
}
- val EMPTY_TRACKED_ARRAY = Array.empty[Tracked]
-
/*
* must-single-thread
*/
- private def buildExemplar(key: BType, csym: Symbol): Tracked = {
+ private def buildExemplar(key: ClassBType, csym: Symbol): Tracked = {
val sc =
if (csym.isImplClass) definitions.ObjectClass
else csym.superClass
@@ -413,14 +406,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
((sc != NoSymbol) && !sc.isInterface) || isCompilingStdLib,
"superClass out of order"
)
- val ifaces = getSuperInterfaces(csym) map exemplar;
- val ifacesArr =
- if (ifaces.isEmpty) EMPTY_TRACKED_ARRAY
- else {
- val arr = new Array[Tracked](ifaces.size)
- ifaces.copyToArray(arr)
- arr
- }
+ val ifacesArr = getSuperInterfaces(csym).map(exemplar).toArray
val flags = mkFlags(
javaFlags(csym),
@@ -476,29 +462,30 @@ abstract class BCodeTypes extends BCodeIdiomatic {
if ((b == jlCloneableReference) ||
(b == jioSerializableReference) ||
(b == AnyRefReference)) { true }
- else if (b.isArray) { conforms(a.getComponentType, b.getComponentType) }
+ 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.hasObjectSort)) { false }
+ 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.isValueType) { false }
+ else if (b.isPrimitive) { false }
else { true }
}
else if (a.isNothingType) { // known to be Nothing
true
}
- else if (a.isUnitType) {
- b.isUnitType
+ else if (a == UNIT) {
+ b == UNIT
}
- else if (a.hasObjectSort) { // may be null
+ else if (a.isClass) { // may be null
if (a.isNothingType) { true }
- else if (b.hasObjectSort) { exemplars.get(a).isSubtypeOf(b) }
+ 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 }
}
@@ -506,8 +493,8 @@ abstract class BCodeTypes extends BCodeIdiomatic {
def msg = s"(a: $a, b: $b)"
- assert(a.isNonUnitValueType, s"a isn't a non-Unit value type. $msg")
- assert(b.isValueType, s"b isn't a value type. $msg")
+ 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().
@@ -521,7 +508,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
* can-multi-thread
*/
def maxValueType(a: BType, other: BType): BType = {
- assert(a.isValueType, "maxValueType() is defined only for 1st arg valuetypes (2nd arg doesn't matter).")
+ 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")
@@ -537,30 +524,30 @@ abstract class BCodeTypes extends BCodeIdiomatic {
case BOOL => uncomparable
case BYTE =>
- if (other == CHAR) INT
+ if (other == CHAR) INT
else if (other.isNumericType) other
else uncomparable
case SHORT =>
other match {
- case BYTE => SHORT
- case CHAR => INT
+ case BYTE => SHORT
+ case CHAR => INT
case INT | LONG | FLOAT | DOUBLE => other
- case _ => uncomparable
+ case _ => uncomparable
}
case CHAR =>
other match {
- case BYTE | SHORT => INT
+ case BYTE | SHORT => INT
case INT | LONG | FLOAT | DOUBLE => other
- case _ => uncomparable
+ case _ => uncomparable
}
case INT =>
other match {
case BYTE | SHORT | CHAR => INT
case LONG | FLOAT | DOUBLE => other
- case _ => uncomparable
+ case _ => uncomparable
}
case LONG =>
@@ -569,7 +556,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
else uncomparable
case FLOAT =>
- if (other == DOUBLE) DOUBLE
+ if (other == DOUBLE) DOUBLE
else if (other.isNumericType) FLOAT
else uncomparable
@@ -586,18 +573,18 @@ abstract class BCodeTypes extends BCodeIdiomatic {
* can-multi-thread
*/
final def maxType(a: BType, other: BType): BType = {
- if (a.isValueType) { maxValueType(a, other) }
+ 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.hasObjectSort, s"This is not a valuetype and it's not something else, what is it? $a")
+ 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.isRefOrArrayType) { AnyRefReference }
- else { abort(s"Uncomparable BTypes: $a with $other") }
+ if (other.isRef) { AnyRefReference }
+ else { abort(s"Uncomparable BTypes: $a with $other") }
}
}
@@ -609,7 +596,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
* can-multi-thread
*/
def isPartialFunctionType(t: BType): Boolean = {
- (t.hasObjectSort) && exemplars.get(t).isSubtypeOf(PartialFunctionReference)
+ (t.isClass) && exemplars.get(t).isSubtypeOf(PartialFunctionReference)
}
/*
@@ -618,7 +605,7 @@ abstract class BCodeTypes extends BCodeIdiomatic {
* can-multi-thread
*/
def isFunctionType(t: BType): Boolean = {
- if (!t.hasObjectSort) return false
+ if (!t.isClass) return false
var idx = 0
val et: Tracked = exemplars.get(t)
while (idx <= definitions.MaxFunctionArity) {
@@ -724,14 +711,8 @@ abstract class BCodeTypes extends BCodeIdiomatic {
}
}
- // now that we have all of `ics` , `csym` , and soon the inner-classes-chain, it's too tempting not to cache.
- if (chain.isEmpty) { null }
- else {
- val arr = new Array[InnerClassEntry](chain.size)
- (chain map toInnerClassEntry).copyToArray(arr)
-
- arr
- }
+ if (chain.isEmpty) null
+ else chain.map(toInnerClassEntry).toArray
}
/*
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
new file mode 100644
index 0000000000..5b0fa6f7a8
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
@@ -0,0 +1,417 @@
+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).
+ *
+ * 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).
+ */
+abstract class BTypes[G <: Global](val __global_dont_use: G) {
+ def chrs: Array[Char]
+
+ /**
+ * Interface for names stored in `chrs`
+ */
+ type BTypeName <: __global_dont_use.Name
+
+ /**
+ * Create a new name in `chrs`. Names are assumed to be hash-consed. Equality on BType will use
+ * reference equality to compare the names.
+ */
+ def createNewName(s: String): BTypeName
+
+ /*sealed*/ trait BType { // Not sealed for now due to SI-8546
+ final override def toString: String = this match {
+ case UNIT => "V"
+ case BOOL => "Z"
+ case CHAR => "C"
+ case BYTE => "B"
+ case SHORT => "S"
+ case INT => "I"
+ 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
+ }
+
+ /**
+ * @return The Java descriptor of this type. Examples:
+ * - int: I
+ * - java.lang.String: Ljava/lang/String;
+ * - int[]: [I
+ * - Object m(String s, double d): (Ljava/lang/String;D)Ljava/lang/Object;
+ */
+ final def descriptor = toString
+
+ /**
+ * @return 0 for void, 2 for long and double, 1 otherwise
+ */
+ final def size: Int = this match {
+ case UNIT => 0
+ case LONG | DOUBLE => 2
+ case _ => 1
+ }
+
+ final def isPrimitive: Boolean = this.isInstanceOf[PrimitiveBType]
+ final def isRef: Boolean = this.isInstanceOf[RefBType]
+ final def isArray: Boolean = this.isInstanceOf[ArrayBType]
+ final def isClass: Boolean = this.isInstanceOf[ClassBType]
+ 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 isIntSizedType = this == BOOL || this == CHAR || this == BYTE ||
+ this == SHORT || this == INT
+ final def isIntegralType = this == INT || this == BYTE || this == LONG ||
+ this == CHAR || this == SHORT
+ final def isRealType = this == FLOAT || this == DOUBLE
+ final def isNumericType = isIntegralType || isRealType
+ final def isWideType = size == 2
+
+ /**
+ * See documentation of [[typedOpcode]].
+ * The numbers are taken from asm.Type.VOID_TYPE ff., the values are those shifted by << 8.
+ */
+ private def loadStoreOpcodeOffset: Int = this match {
+ case UNIT | INT => 0
+ case BOOL | BYTE => 5
+ case CHAR => 6
+ case SHORT => 7
+ case FLOAT => 2
+ case LONG => 1
+ case DOUBLE => 3
+ case _ => 4
+ }
+
+ /**
+ * See documentation of [[typedOpcode]].
+ * The numbers are taken from asm.Type.VOID_TYPE ff., the values are those shifted by << 16.
+ */
+ private def typedOpcodeOffset: Int = this match {
+ case UNIT => 5
+ case BOOL | CHAR | BYTE | SHORT | INT => 0
+ case FLOAT => 2
+ case LONG => 1
+ case DOUBLE => 3
+ case _ => 4
+ }
+
+ /**
+ * Some JVM opcodes have typed variants. This method returns the correct opcode according to
+ * the type.
+ *
+ * @param opcode A JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD,
+ * IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR
+ * IXOR and IRETURN.
+ * @return The opcode adapted to this java type. For example, if this type is `float` and
+ * `opcode` is `IRETURN`, this method returns `FRETURN`.
+ */
+ final def typedOpcode(opcode: Int): Int = {
+ if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE)
+ opcode + loadStoreOpcodeOffset
+ else
+ opcode + typedOpcodeOffset
+ }
+
+ /**
+ * The asm.Type corresponding to this BType.
+ *
+ * Note about asm.Type.getObjectType (*): For class types, the method expects the internal
+ * name, i.e. without the surrounding 'L' and ';'. For array types on the other hand, the
+ * method expects a full descriptor, for example "[Ljava/lang/String;".
+ *
+ * See method asm.Type.getType that creates a asm.Type from a type descriptor
+ * - for an OBJECT type, the 'L' and ';' are not part of the range of the created Type
+ * - for an ARRAY type, the full descriptor is part of the range
+ */
+ def toASMType: asm.Type = this match {
+ case UNIT => asm.Type.VOID_TYPE
+ case BOOL => asm.Type.BOOLEAN_TYPE
+ case CHAR => asm.Type.CHAR_TYPE
+ case BYTE => asm.Type.BYTE_TYPE
+ case SHORT => asm.Type.SHORT_TYPE
+ case INT => asm.Type.INT_TYPE
+ 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)
+ }
+
+ def asRefBType : RefBType = this.asInstanceOf[RefBType]
+ def asArrayBType: ArrayBType = this.asInstanceOf[ArrayBType]
+ def asClassBType: ClassBType = this.asInstanceOf[ClassBType]
+ }
+
+ object 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
+ */
+ 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)
+ }
+ }
+ }
+
+ sealed trait PrimitiveBType extends BType
+
+ case object UNIT extends PrimitiveBType
+ case object BOOL extends PrimitiveBType
+ case object CHAR extends PrimitiveBType
+ case object BYTE extends PrimitiveBType
+ case object SHORT extends PrimitiveBType
+ case object INT extends PrimitiveBType
+ case object FLOAT extends PrimitiveBType
+ case object LONG extends PrimitiveBType
+ case object DOUBLE extends PrimitiveBType
+
+ sealed trait RefBType extends BType {
+ /**
+ * The class or array type of this reference type. Used for ANEWARRAY, MULTIANEWARRAY,
+ * INSTANCEOF and CHECKCAST instructions. Also used for emitting invokevirtual calls to
+ * (a: Array[T]).clone() for any T, see genApply.
+ *
+ * In contrast to the descriptor, this string does not contain the surrounding 'L' and ';' for
+ * class types, for example "java/lang/String".
+ * However, for array types, the full descriptor is used, for example "[Ljava/lang/String;".
+ *
+ * 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
+ }
+ }
+
+ /**
+ * Class or Interface type.
+ *
+ * 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.
+ *
+ * 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).
+ */
+ 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)
+
+ /**
+ * Construct a ClassBType for a given java class name.
+ *
+ * @param s A class name of the form "java/lang/String", without the surrounding 'L' and ';'.
+ */
+ def this(s: String) = this({
+ assert(!(s.head == 'L' && s.last == ';'), s"Descriptor instead of internal name: $s")
+ createNewName(s)
+ })
+
+ /**
+ * 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)
+
+ /**
+ * @return The class name without the package prefix
+ */
+ def simpleName: String = internalName.split("/").last
+
+ /**
+ * Custom equals / hashCode are needed because this is not a case class.
+ */
+ override def equals(o: Any): Boolean = (this eq o.asInstanceOf[Object]) || (o match {
+ case ClassBType(`offset`, `length`) => true
+ case _ => false
+ })
+
+ override def hashCode: Int = {
+ import scala.runtime.Statics
+ var acc: Int = -889275714
+ acc = Statics.mix(acc, offset)
+ acc = Statics.mix(acc, length)
+ Statics.finalizeHash(acc, 2)
+ }
+ }
+
+ 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)] =
+ if (c == null) None
+ else Some((c.offset, c.length))
+ }
+
+ case class ArrayBType(componentType: BType) extends RefBType {
+ def dimension: Int = componentType match {
+ case a: ArrayBType => 1 + a.dimension
+ case _ => 1
+ }
+
+ def elementType: BType = componentType match {
+ case a: ArrayBType => a.elementType
+ case t => t
+ }
+ }
+
+ 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))
+ }
+
+ 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.
+ */
+ 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
+ */
+ 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;" )
+ )
+ }
+
+ 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")
+ )
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index b7f9b30e19..b0fb3069c1 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -113,7 +113,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
// Warn when classes will overwrite one another on case-insensitive systems.
for ((_, v1 :: v2 :: _) <- sortedClasses groupBy (_.symbol.javaClassName.toString.toLowerCase)) {
- v1.cunit.warning(v1.symbol.pos,
+ reporter.warning(v1.symbol.pos,
s"Class ${v1.symbol.javaClassName} differs only in case from ${v2.symbol.javaClassName}. " +
"Such classes will overwrite one another on case-insensitive filesystems.")
}
@@ -141,7 +141,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
try emitFor(c)
catch {
case e: FileConflictException =>
- c.cunit.error(c.symbol.pos, s"error writing ${c.symbol}: ${e.getMessage}")
+ reporter.error(c.symbol.pos, s"error writing ${c.symbol}: ${e.getMessage}")
}
sortedClasses = sortedClasses.tail
classes -= c.symbol // GC opportunity
@@ -975,7 +975,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
index += jparamType.getSize()
}
- mirrorMethod.visitMethodInsn(asm.Opcodes.INVOKEVIRTUAL, moduleName, mirrorMethodName, javaType(m).getDescriptor)
+ mirrorMethod.visitMethodInsn(asm.Opcodes.INVOKEVIRTUAL, moduleName, mirrorMethodName, javaType(m).getDescriptor, false)
mirrorMethod.visitInsn(jReturnType.getOpcode(asm.Opcodes.IRETURN))
mirrorMethod.visitMaxs(0, 0) // just to follow protocol, dummy arguments
@@ -1061,7 +1061,8 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
asm.Opcodes.INVOKEVIRTUAL,
moduleName,
androidFieldName.toString,
- asm.Type.getMethodDescriptor(creatorType, Array.empty[asm.Type]: _*)
+ asm.Type.getMethodDescriptor(creatorType, Array.empty[asm.Type]: _*),
+ false
)
// PUTSTATIC `thisName`.CREATOR;
@@ -1362,7 +1363,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
if (m.symbol.isStaticConstructor || definitions.isGetClass(m.symbol)) return
if (m.params.size > MaximumJvmParameters) {
- getCurrentCUnit().error(m.symbol.pos, s"Platform restriction: a parameter list's length cannot exceed $MaximumJvmParameters.")
+ reporter.error(m.symbol.pos, s"Platform restriction: a parameter list's length cannot exceed $MaximumJvmParameters.")
return
}
@@ -1400,7 +1401,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
// TODO param names: (m.params map (p => javaName(p.sym)))
- // typestate: entering mode with valid call sequences:
+ // typestate: entering mode with valid call sequences: (see ASM Guide, 3.2.1)
// [ visitAnnotationDefault ] ( visitAnnotation | visitParameterAnnotation | visitAttribute )*
emitAnnotations(jmethod, others)
@@ -1445,7 +1446,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
val hasStaticBitSet = ((flags & asm.Opcodes.ACC_STATIC) != 0)
genCode(m, emitVars, hasStaticBitSet)
- jmethod.visitMaxs(0, 0) // just to follow protocol, dummy arguments
+ // visitMaxs needs to be called according to the protocol. The arguments will be ignored
+ // since maximums (and stack map frames) are computed. See ASM Guide, Section 3.2.1,
+ // section "ClassWriter options"
+ jmethod.visitMaxs(0, 0)
}
jmethod.visitEnd()
@@ -1521,7 +1525,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
if (isStaticModule(clasz.symbol)) {
clinit.visitTypeInsn(asm.Opcodes.NEW, thisName)
clinit.visitMethodInsn(asm.Opcodes.INVOKESPECIAL,
- thisName, INSTANCE_CONSTRUCTOR_NAME, mdesc_arglessvoid)
+ thisName, INSTANCE_CONSTRUCTOR_NAME, mdesc_arglessvoid, false)
}
if (isParcelableClass) { legacyAddCreatorCode(clinit) }
@@ -1665,16 +1669,16 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
def rem(tk: TypeKind) { emitPrimitive(remOpcodes, tk) }
def invokespecial(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false)
}
def invokestatic(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false)
}
def invokeinterface(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc, true)
}
def invokevirtual(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false)
}
def goTo(label: asm.Label) { jmethod.visitJumpInsn(Opcodes.GOTO, label) }
@@ -2924,7 +2928,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
// invoke the superclass constructor, which will do the
// necessary java reflection and create Method objects.
- constructor.visitMethodInsn(asm.Opcodes.INVOKESPECIAL, "scala/beans/ScalaBeanInfo", INSTANCE_CONSTRUCTOR_NAME, conJType.getDescriptor)
+ constructor.visitMethodInsn(asm.Opcodes.INVOKESPECIAL, "scala/beans/ScalaBeanInfo", INSTANCE_CONSTRUCTOR_NAME, conJType.getDescriptor, false)
constructor.visitInsn(asm.Opcodes.RETURN)
constructor.visitMaxs(0, 0) // just to follow protocol, dummy arguments
@@ -3241,7 +3245,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
}
if(!isValidSignature) {
- unit.warning(sym.pos,
+ reporter.warning(sym.pos,
"""|compiler bug: created invalid generic signature for %s in %s
|signature: %s
|if this is reproducible, please report bug at https://issues.scala-lang.org/
@@ -3254,7 +3258,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
val normalizedTpe = enteringErasure(erasure.prepareSigMap(memberTpe))
val bytecodeTpe = owner.thisType.memberInfo(sym)
if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym)(normalizedTpe) =:= bytecodeTpe)) {
- unit.warning(sym.pos,
+ reporter.warning(sym.pos,
"""|compiler bug: created generic signature for %s in %s that does not conform to its erasure
|signature: %s
|original type: %s
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
index 61cf76f524..a401de05e5 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
@@ -156,7 +156,7 @@ abstract class GenBCode extends BCodeSyncAndTry {
case None =>
caseInsensitively.put(lowercaseJavaClassName, claszSymbol)
case Some(dupClassSym) =>
- item.cunit.warning(
+ reporter.warning(
claszSymbol.pos,
s"Class ${claszSymbol.javaClassName} differs only in case from ${dupClassSym.javaClassName}. " +
"Such classes will overwrite one another on case-insensitive filesystems."
@@ -244,14 +244,9 @@ abstract class GenBCode extends BCodeSyncAndTry {
val beanC = if (bean == null) null else SubItem3(bean.name, getByteArray(bean))
if (AsmUtils.traceSerializedClassEnabled && plain.name.contains(AsmUtils.traceSerializedClassPattern)) {
- def readClass(bytes: Array[Byte]): asm.tree.ClassNode = {
- val node = new asm.tree.ClassNode()
- new asm.ClassReader(bytes).accept(node, 0)
- node
- }
- if (mirrorC != null) AsmUtils.traceClass(readClass(mirrorC.jclassBytes))
- AsmUtils.traceClass(readClass(plainC.jclassBytes))
- if (beanC != null) AsmUtils.traceClass(readClass(beanC.jclassBytes))
+ if (mirrorC != null) AsmUtils.traceClass(mirrorC.jclassBytes)
+ AsmUtils.traceClass(plainC.jclassBytes)
+ if (beanC != null) AsmUtils.traceClass(beanC.jclassBytes)
}
q3 add Item3(arrivalPos, mirrorC, plainC, beanC, outFolder)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala
index 01c4ff5a52..2bcde7f7b9 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala
@@ -27,7 +27,7 @@ trait GenJVMASM {
protected def isJavaEntryPoint(icls: IClass) = {
val sym = icls.symbol
def fail(msg: String, pos: Position = sym.pos) = {
- icls.cunit.warning(sym.pos,
+ reporter.warning(sym.pos,
sym.name + " has a main method with parameter type Array[String], but " + sym.fullName('.') + " will not be a runnable program.\n" +
" Reason: " + msg
// TODO: make this next claim true, if possible
diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
index c49f23852f..a866173a88 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
@@ -56,11 +56,8 @@ abstract class ClosureElimination extends SubComponent {
case (BOX(t1), UNBOX(t2)) if (t1 == t2) =>
Some(Nil)
- case (LOAD_FIELD(sym, isStatic), DROP(_)) if !sym.hasAnnotation(definitions.VolatileAttr) =>
- if (isStatic)
- Some(Nil)
- else
- Some(DROP(REFERENCE(definitions.ObjectClass)) :: Nil)
+ case (LOAD_FIELD(sym, /* isStatic */false), DROP(_)) if !sym.hasAnnotation(definitions.VolatileAttr) && inliner.isClosureClass(sym.owner) =>
+ Some(DROP(REFERENCE(definitions.ObjectClass)) :: Nil)
case _ => None
}
diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
index 90c37ba0b3..4b419b210c 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
@@ -169,9 +169,14 @@ abstract class DeadCodeElimination extends SubComponent {
case RETURN(_) | JUMP(_) | CJUMP(_, _, _, _) | CZJUMP(_, _, _, _) | STORE_FIELD(_, _) |
THROW(_) | LOAD_ARRAY_ITEM(_) | STORE_ARRAY_ITEM(_) | SCOPE_ENTER(_) | SCOPE_EXIT(_) | STORE_THIS(_) |
- LOAD_EXCEPTION(_) | SWITCH(_, _) | MONITOR_ENTER() | MONITOR_EXIT() | CHECK_CAST(_) =>
+ LOAD_EXCEPTION(_) | SWITCH(_, _) | MONITOR_ENTER() | MONITOR_EXIT() | CHECK_CAST(_) | CREATE_ARRAY(_, _) =>
moveToWorkList()
+ case LOAD_FIELD(sym, isStatic) if isStatic || !inliner.isClosureClass(sym.owner) =>
+ // static load may trigger static initization.
+ // non-static load can throw NPE (but we know closure fields can't be accessed via a
+ // null reference.
+ moveToWorkList()
case CALL_METHOD(m1, _) if isSideEffecting(m1) =>
moveToWorkList()
@@ -193,6 +198,8 @@ abstract class DeadCodeElimination extends SubComponent {
moveToWorkListIf(necessary)
case LOAD_MODULE(sym) if isLoadNeeded(sym) =>
moveToWorkList() // SI-4859 Module initialization might side-effect.
+ case CALL_PRIMITIVE(Arithmetic(DIV | REM, INT | LONG) | ArrayLength(_)) =>
+ moveToWorkList() // SI-8601 Might divide by zero
case _ => ()
moveToWorkListIf(cond = false)
}
diff --git a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala
index 235e954f88..425c10d153 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala
@@ -182,7 +182,7 @@ abstract class InlineExceptionHandlers extends SubComponent {
// in other words: what's on the stack MUST conform to what's in the THROW(..)!
if (!canReplaceHandler) {
- currentClass.cunit.warning(NoPosition, "Unable to inline the exception handler inside incorrect" +
+ reporter.warning(NoPosition, "Unable to inline the exception handler inside incorrect" +
" block:\n" + bblock.iterator.mkString("\n") + "\nwith stack: " + typeInfo + " just " +
"before instruction index " + index)
}
@@ -383,7 +383,7 @@ abstract class InlineExceptionHandlers extends SubComponent {
Some((exceptionLocal, copy))
case _ =>
- currentClass.cunit.warning(NoPosition, "Unable to inline the exception handler due to incorrect format:\n" +
+ reporter.warning(NoPosition, "Unable to inline the exception handler due to incorrect format:\n" +
handler.iterator.mkString("\n"))
None
}
diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
index f6de522d09..8df3969c49 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
@@ -195,7 +195,7 @@ abstract class Inliners extends SubComponent {
/** The current iclass */
private var currentIClazz: IClass = _
- private def warn(pos: Position, msg: String) = currentIClazz.cunit.inlinerWarning(pos, msg)
+ private def warn(pos: Position, msg: String) = currentRun.reporting.inlinerWarning(pos, msg)
private def ownedName(sym: Symbol): String = exitingUncurry {
val count = (
diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
index a61ad392ee..37b00aa9a3 100644
--- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
+++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
@@ -26,10 +26,10 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners {
def freshName(prefix: String): Name = freshTermName(prefix)
def freshTermName(prefix: String): TermName = unit.freshTermName(prefix)
def freshTypeName(prefix: String): TypeName = unit.freshTypeName(prefix)
- def deprecationWarning(off: Int, msg: String) = unit.deprecationWarning(off, msg)
+ def deprecationWarning(off: Int, msg: String) = currentRun.reporting.deprecationWarning(off, msg)
implicit def i2p(offset : Int) : Position = Position.offset(unit.source, offset)
- def warning(pos : Int, msg : String) : Unit = unit.warning(pos, msg)
- def syntaxError(pos: Int, msg: String) : Unit = unit.error(pos, msg)
+ def warning(pos : Int, msg : String) : Unit = reporter.warning(pos, msg)
+ def syntaxError(pos: Int, msg: String) : Unit = reporter.error(pos, msg)
}
abstract class JavaParser extends ParserCommon {
diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala
index c5401219dd..bddcf6567c 100644
--- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala
+++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala
@@ -860,9 +860,9 @@ trait JavaScanners extends ast.parser.ScannersCommon {
class JavaUnitScanner(unit: CompilationUnit) extends JavaScanner {
in = new JavaCharArrayReader(unit.source.content, !settings.nouescape.value, syntaxError)
init()
- def error (pos: Int, msg: String) = unit. error(pos, msg)
- def incompleteInputError(pos: Int, msg: String) = unit.incompleteInputError(pos, msg)
- def deprecationWarning(pos: Int, msg: String) = unit.deprecationWarning(pos, msg)
+ def error (pos: Int, msg: String) = reporter.error(pos, msg)
+ def incompleteInputError(pos: Int, msg: String) = currentRun.reporting.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/reporters/AbstractReporter.scala b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala
index 16d432438a..6c592ead0d 100644
--- a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala
@@ -62,12 +62,13 @@ abstract class AbstractReporter extends Reporter {
*/
private def testAndLog(pos: Position, severity: Severity, msg: String): Boolean =
pos != null && pos.isDefined && {
- val fpos = pos.focus
+ val fpos = pos.focus
val suppress = positions(fpos) match {
- case ERROR => true // already error at position
- case highest if highest > severity => true // already message higher than present severity
- case `severity` => messages(fpos) contains msg // already issued this exact message
- case _ => false // good to go
+ case ERROR => true // already error at position
+ case highest
+ if highest.id > severity.id => true // already message higher than present severity
+ case `severity` => messages(fpos) contains msg // already issued this exact message
+ case _ => false // good to go
}
suppress || {
diff --git a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
index 3f210a543c..0b218b711c 100644
--- a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
@@ -12,8 +12,7 @@ import scala.reflect.internal.util._
import StringOps._
/**
- * This class implements a Reporter that displays messages on a text
- * console.
+ * This class implements a Reporter that displays messages on a text console.
*/
class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: PrintWriter) extends AbstractReporter {
def this(settings: Settings) = this(settings, Console.in, new PrintWriter(Console.err, true))
diff --git a/src/compiler/scala/tools/nsc/reporters/Reporter.scala b/src/compiler/scala/tools/nsc/reporters/Reporter.scala
index 68362c066d..5b576a547d 100644
--- a/src/compiler/scala/tools/nsc/reporters/Reporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/Reporter.scala
@@ -8,76 +8,50 @@ package reporters
import scala.reflect.internal.util._
-/**
- * This interface provides methods to issue information, warning and
- * error messages.
+/** Report information, warnings and errors.
+ *
+ * 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.
*/
-abstract class Reporter {
- protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit
-
- object severity extends Enumeration
- class Severity(val id: Int) extends severity.Value {
- var count: Int = 0
- }
- val INFO = new Severity(0) {
- override def toString: String = "INFO"
- }
- val WARNING = new Severity(1) {
- override def toString: String = "WARNING"
- }
- val ERROR = new Severity(2) {
- override def toString: String = "ERROR"
- }
-
- /** Whether very long lines can be truncated. This exists so important
- * debugging information (like printing the classpath) is not rendered
- * invisible due to the max message length.
- */
- private var _truncationOK: Boolean = true
- def truncationOK = _truncationOK
- def withoutTruncating[T](body: => T): T = {
- val saved = _truncationOK
- _truncationOK = false
- try body
- finally _truncationOK = saved
- }
-
- private var incompleteHandler: (Position, String) => Unit = null
- def incompleteHandled = incompleteHandler != null
- def withIncompleteHandler[T](handler: (Position, String) => Unit)(thunk: => T) = {
- val saved = incompleteHandler
- incompleteHandler = handler
- try thunk
- finally incompleteHandler = saved
- }
-
- var cancelled = false
- def hasErrors = ERROR.count > 0 || cancelled
- def hasWarnings = WARNING.count > 0
+abstract class Reporter extends scala.reflect.internal.Reporter {
+ /** Informational messages. If `!force`, they may be suppressed. */
+ final def info(pos: Position, msg: String, force: Boolean): Unit = info0(pos, msg, INFO, force)
/** For sending a message which should not be labeled as a warning/error,
* but also shouldn't require -verbose to be visible.
*/
- def echo(msg: String): Unit = info(NoPosition, msg, force = true)
- def echo(pos: Position, msg: String): Unit = info(pos, msg, force = true)
+ def echo(msg: String): Unit = info(NoPosition, msg, force = true)
- /** Informational messages, suppressed unless -verbose or force=true. */
- def info(pos: Position, msg: String, force: Boolean): Unit = info0(pos, msg, INFO, force)
+ // overridden by sbt, IDE -- should not be in the reporting interface
+ // (IDE receives comments from ScaladocAnalyzer using this hook method)
+ // TODO: IDE should override a hook method in the parser instead
+ def comment(pos: Position, msg: String): Unit = {}
- /** Warnings and errors. */
- def warning(pos: Position, msg: String): Unit = withoutTruncating(info0(pos, msg, WARNING, force = false))
- def error(pos: Position, msg: String): Unit = withoutTruncating(info0(pos, msg, ERROR, force = false))
- def incompleteInputError(pos: Position, msg: String): Unit = {
- if (incompleteHandled) incompleteHandler(pos, msg)
- else error(pos, msg)
- }
+ // used by sbt (via unit.cancel) to cancel a compile (see hasErrors)
+ // TODO: figure out how sbt uses this, come up with a separate interface for controlling the build
+ var cancelled: Boolean = false
- def comment(pos: Position, msg: String) { }
- def flush() { }
- def reset() {
- INFO.count = 0
- ERROR.count = 0
- WARNING.count = 0
- cancelled = false
+ override def hasErrors: Boolean = super.hasErrors || cancelled
+
+ override def reset(): Unit = {
+ super.reset()
+ cancelled = false
}
+
+ // the below is copy/pasted from ReporterImpl for now
+ // partest expects this inner class
+ // TODO: rework partest to use the scala.reflect.internal interface,
+ // remove duplication here, and consolidate reflect.internal.{ReporterImpl & ReporterImpl}
+ class Severity(val id: Int)(name: String) { var count: Int = 0 ; override def toString = name}
+ object INFO extends Severity(0)("INFO")
+ object WARNING extends Severity(1)("WARNING")
+ // reason for copy/paste: this is used by partest (must be a val, not an object)
+ // TODO: use count(ERROR) in scala.tools.partest.nest.DirectCompiler#errorCount, rather than ERROR.count
+ lazy val ERROR = new Severity(2)("ERROR")
+
+ def count(severity: Severity): Int = severity.count
+ def resetCount(severity: Severity): Unit = severity.count = 0
}
diff --git a/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala b/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala
index 04c5bdf824..24a61cb171 100644
--- a/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala
@@ -10,8 +10,7 @@ import scala.collection.mutable
import scala.reflect.internal.util.Position
/**
- * This class implements a Reporter that displays messages on a text
- * console.
+ * This class implements a Reporter that stores its reports in the set `infos`.
*/
class StoreReporter extends Reporter {
case class Info(pos: Position, msg: String, severity: Severity) {
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 20ccc30ff6..d22dcacad6 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -42,7 +42,7 @@ trait ScalaSettings extends AbsScalaSettings
def optimiseSettings = List[BooleanSetting](inline, inlineHandlers, Xcloselim, Xdce, YconstOptimization)
/** If any of these settings is enabled, the compiler should print a message and exit. */
- def infoSettings = List[Setting](help, Xhelp, Yhelp, showPlugins, showPhases, genPhaseGraph)
+ def infoSettings = List[Setting](version, help, Xhelp, Yhelp, showPlugins, showPhases, genPhaseGraph)
/** Is an info setting set? */
def isInfo = infoSettings exists (_.isSetByUser)
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
index 6ca2205881..149b4fe446 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
@@ -780,32 +780,40 @@ abstract class ICodeReader extends ClassfileParser {
bb = otherBlock
// Console.println("\t> entering bb: " + bb)
}
- instr match {
- case LJUMP(target) =>
- otherBlock = blocks(target)
- bb.emitOnly(JUMP(otherBlock))
- case LCJUMP(success, failure, cond, kind) =>
- otherBlock = blocks(success)
- val failBlock = blocks(failure)
- bb.emitOnly(CJUMP(otherBlock, failBlock, cond, kind))
+ if (bb.closed) {
+ // the basic block is closed, i.e. the previous instruction was a jump, return or throw,
+ // but the next instruction is not a jump target. this means that the next instruction is
+ // dead code. we can therefore advance until the next jump target.
+ debuglog(s"ICode reader skipping dead instruction $instr in classfile $instanceCode")
+ } else {
+ instr match {
+ case LJUMP(target) =>
+ otherBlock = blocks(target)
+ bb.emitOnly(JUMP(otherBlock))
+
+ case LCJUMP(success, failure, cond, kind) =>
+ otherBlock = blocks(success)
+ val failBlock = blocks(failure)
+ bb.emitOnly(CJUMP(otherBlock, failBlock, cond, kind))
- case LCZJUMP(success, failure, cond, kind) =>
- otherBlock = blocks(success)
- val failBlock = blocks(failure)
- bb.emitOnly(CZJUMP(otherBlock, failBlock, cond, kind))
+ case LCZJUMP(success, failure, cond, kind) =>
+ otherBlock = blocks(success)
+ val failBlock = blocks(failure)
+ bb.emitOnly(CZJUMP(otherBlock, failBlock, cond, kind))
- case LSWITCH(tags, targets) =>
- bb.emitOnly(SWITCH(tags, targets map blocks))
+ case LSWITCH(tags, targets) =>
+ bb.emitOnly(SWITCH(tags, targets map blocks))
- case RETURN(_) =>
- bb emitOnly instr
+ case RETURN(_) =>
+ bb emitOnly instr
- case THROW(clasz) =>
- bb emitOnly instr
+ case THROW(clasz) =>
+ bb emitOnly instr
- case _ =>
- bb emit instr
+ case _ =>
+ bb emit instr
+ }
}
}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
index 592c5497b5..25e13a1314 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
@@ -69,7 +69,7 @@ abstract class Pickler extends SubComponent {
// OPT: do this only as a recovery after fatal error. Checking in advance was expensive.
if (t.isErroneous) {
if (settings.debug) e.printStackTrace()
- unit.error(t.pos, "erroneous or inaccessible type")
+ reporter.error(t.pos, "erroneous or inaccessible type")
return
}
}
@@ -186,7 +186,16 @@ abstract class Pickler extends SubComponent {
val (locals, globals) = sym.children partition (_.isLocalClass)
val children =
if (locals.isEmpty) globals
- else globals + sym.newClassWithInfo(tpnme.LOCAL_CHILD, List(sym.tpe), EmptyScope, pos = sym.pos)
+ else {
+ // The LOCAL_CHILD was introduced in 12a2b3b to fix Aladdin bug 1055. When a sealed
+ // class/trait has local subclasses, a single <local child> class symbol is added
+ // as pickled child (instead of a reference to the anonymous class; that was done
+ // initially, but seems not to work, as the bug shows).
+ // Adding the LOCAL_CHILD is necessary to retain exhaustivity warnings under separate
+ // compilation. See test neg/aladdin1055.
+ val parents = (if (sym.isTrait) List(definitions.ObjectTpe) else Nil) ::: List(sym.tpe)
+ globals + sym.newClassWithInfo(tpnme.LOCAL_CHILD, parents, EmptyScope, pos = sym.pos)
+ }
putChildren(sym, children.toList sortBy (_.sealedSortName))
}
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index f14fce5de9..1664fe0e0d 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -76,7 +76,7 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL {
val qual0 = ad.qual
val params = ad.args
if (settings.logReflectiveCalls)
- unit.echo(ad.pos, "method invocation uses reflection")
+ reporter.echo(ad.pos, "method invocation uses reflection")
val typedPos = typedWithPos(ad.pos) _
@@ -360,13 +360,13 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL {
assert(params.length == mparams.length, ((params, mparams)))
(mparams, resType)
case tpe @ OverloadedType(pre, alts) =>
- unit.warning(ad.pos, s"Overloaded type reached the backend! This is a bug in scalac.\n Symbol: ${ad.symbol}\n Overloads: $tpe\n Arguments: " + ad.args.map(_.tpe))
+ reporter.warning(ad.pos, s"Overloaded type reached the backend! This is a bug in scalac.\n Symbol: ${ad.symbol}\n Overloads: $tpe\n Arguments: " + ad.args.map(_.tpe))
alts filter (_.paramss.flatten.size == params.length) map (_.tpe) match {
case mt @ MethodType(mparams, resType) :: Nil =>
- unit.warning(NoPosition, "Only one overload has the right arity, proceeding with overload " + mt)
+ reporter.warning(NoPosition, "Only one overload has the right arity, proceeding with overload " + mt)
(mparams, resType)
case _ =>
- unit.error(ad.pos, "Cannot resolve overload.")
+ reporter.error(ad.pos, "Cannot resolve overload.")
(Nil, NoType)
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index 391bce5abb..f471440293 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -54,7 +54,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
def check(tree: Tree) = {
for (t <- tree) t match {
case t: RefTree if uninitializedVals(t.symbol.accessedOrSelf) && t.qualifier.symbol == clazz =>
- unit.warning(t.pos, s"Reference to uninitialized ${t.symbol.accessedOrSelf}")
+ reporter.warning(t.pos, s"Reference to uninitialized ${t.symbol.accessedOrSelf}")
case _ =>
}
}
@@ -685,7 +685,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
// mangling before we introduce more of it.
val conflict = clazz.info.nonPrivateMember(acc.name) filter (s => s.isGetter && !s.isOuterField && s.enclClass.isTrait)
if (conflict ne NoSymbol)
- unit.error(acc.pos, "parameter '%s' requires field but conflicts with %s".format(acc.name, conflict.fullLocationString))
+ reporter.error(acc.pos, "parameter '%s' requires field but conflicts with %s".format(acc.name, conflict.fullLocationString))
copyParam(acc, parameter(acc))
}
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index e036035397..ec4deb6be0 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -488,7 +488,7 @@ abstract class Erasure extends AddInterfaces
|| (checkBridgeOverrides(member, other, bridge) match {
case Nil => true
case es if member.owner.isAnonymousClass => resolveAnonymousBridgeClash(member, bridge); true
- case es => for ((pos, msg) <- es) unit.error(pos, msg); false
+ case es => for ((pos, msg) <- es) reporter.error(pos, msg); false
})
)
@@ -724,7 +724,7 @@ abstract class Erasure extends AddInterfaces
)
val when = if (exitingRefchecks(lowType matches highType)) "" else " after erasure: " + exitingPostErasure(highType)
- unit.error(pos,
+ reporter.error(pos,
s"""|$what:
|${exitingRefchecks(highString)} and
|${exitingRefchecks(lowString)}
@@ -865,7 +865,7 @@ abstract class Erasure extends AddInterfaces
fn match {
case TypeApply(sel @ Select(qual, name), List(targ)) =>
if (qual.tpe != null && isPrimitiveValueClass(qual.tpe.typeSymbol) && targ.tpe != null && targ.tpe <:< AnyRefTpe)
- unit.error(sel.pos, "isInstanceOf cannot test if value types are references.")
+ reporter.error(sel.pos, "isInstanceOf cannot test if value types are references.")
def mkIsInstanceOf(q: () => Tree)(tp: Type): Tree =
Apply(
@@ -952,7 +952,7 @@ abstract class Erasure extends AddInterfaces
case nme.length => nme.array_length
case nme.update => nme.array_update
case nme.clone_ => nme.array_clone
- case _ => unit.error(tree.pos, "Unexpected array member, no translation exists.") ; nme.NO_NAME
+ case _ => reporter.error(tree.pos, "Unexpected array member, no translation exists.") ; nme.NO_NAME
}
gen.mkRuntimeCall(arrayMethodName, qual :: args)
}
@@ -1050,20 +1050,18 @@ abstract class Erasure extends AddInterfaces
}
}
- def isAccessible(sym: Symbol) = localTyper.context.isAccessible(sym, sym.owner.thisType)
- if (!isAccessible(owner) && qual.tpe != null) {
+ def isJvmAccessible(sym: Symbol) = (sym.isClass && !sym.isJavaDefined) || localTyper.context.isAccessible(sym, sym.owner.thisType)
+ if (!isJvmAccessible(owner) && qual.tpe != null) {
qual match {
case Super(_, _) =>
- // Insert a cast here at your peril -- see SI-5162. Bail out if the target method is defined in
- // Java, otherwise, we'd get an IllegalAccessError at runtime. If the target method is defined in
- // Scala, however, we should have access.
- if (owner.isJavaDefined) unit.error(tree.pos, s"Unable to access ${tree.symbol.fullLocationString} with a super reference.")
+ // Insert a cast here at your peril -- see SI-5162.
+ reporter.error(tree.pos, s"Unable to access ${tree.symbol.fullLocationString} with a super reference.")
tree
case _ =>
// Todo: Figure out how qual.tpe could be null in the check above (it does appear in build where SwingWorker.this
// has a null type).
val qualSym = qual.tpe.widen.typeSymbol
- if (isAccessible(qualSym) && !qualSym.isPackageClass && !qualSym.isPackageObjectClass) {
+ if (isJvmAccessible(qualSym) && !qualSym.isPackageClass && !qualSym.isPackageObjectClass) {
// insert cast to prevent illegal access error (see #4283)
// util.trace("insert erasure cast ") (*/
treeCopy.Select(tree, gen.mkAttributedCast(qual, qual.tpe.widen), name) //)
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index 0447e23e9e..c291961447 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -481,7 +481,7 @@ abstract class ExplicitOuter extends InfoTransform
// since we can't fix SI-4440 properly (we must drop the outer accessors of final classes when there's no immediate reference to them in sight)
// at least don't crash... this duplicates maybeOmittable from constructors
(acc.owner.isEffectivelyFinal && !acc.isOverridingSymbol)) {
- unit.uncheckedWarning(tree.pos, "The outer reference in this type test cannot be checked at run time.")
+ currentRun.reporting.uncheckedWarning(tree.pos, "The outer reference in this type test cannot be checked at run time.")
transform(TRUE) // urgh... drop condition if there's no accessor (or if it may disappear after constructors)
} else {
// println("(base, acc)= "+(base, acc))
diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
index 2235a93ca4..228c9da624 100644
--- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
@@ -127,7 +127,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
def checkNonCyclic(pos: Position, seen: Set[Symbol], clazz: Symbol): Unit =
if (seen contains clazz)
- unit.error(pos, "value class may not unbox to itself")
+ reporter.error(pos, "value class may not unbox to itself")
else {
val unboxed = definitions.underlyingOfValueClass(clazz).typeSymbol
if (unboxed.isDerivedValueClass) checkNonCyclic(pos, seen + clazz, unboxed)
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index e38c034f4d..f85d8222f0 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -339,7 +339,7 @@ abstract class LambdaLift extends InfoTransform {
if (clazz.isStaticOwner) clazz.fullLocationString
else s"the unconstructed `this` of ${clazz.fullLocationString}"
val msg = s"Implementation restriction: access of ${sym.fullLocationString} from ${currentClass.fullLocationString}, would require illegal premature access to $what"
- currentUnit.error(curTree.pos, msg)
+ reporter.error(curTree.pos, msg)
}
val qual =
if (clazz == currentClass) gen.mkAttributedThis(clazz)
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 33e8e47c76..7927875583 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -336,7 +336,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
rebindSuper(clazz, mixinMember.alias, mixinClass) match {
case NoSymbol =>
- unit.error(clazz.pos, "Member %s of mixin %s is missing a concrete super implementation.".format(
+ reporter.error(clazz.pos, "Member %s of mixin %s is missing a concrete super implementation.".format(
mixinMember.alias, mixinClass))
case alias1 =>
superAccessor.asInstanceOf[TermSymbol] setAlias alias1
@@ -391,7 +391,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
else {
sourceModule setPos sym.pos
if (sourceModule.flags != MODULE) {
- log("!!! Directly setting sourceModule flags from %s to MODULE".format(sourceModule.flagString))
+ log(s"!!! Directly setting sourceModule flags for $sourceModule from ${sourceModule.flagString} to MODULE")
sourceModule.flags = MODULE
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 02e55241b3..908aa69310 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -538,6 +538,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
bytecodeClazz.info
val sClass = clazz.owner.newClass(clazzName, clazz.pos, (clazz.flags | SPECIALIZED) & ~CASE)
+ sClass.setAnnotations(clazz.annotations) // SI-8574 important that the subclass picks up @SerialVersionUID, @strictfp, etc.
def cloneInSpecializedClass(member: Symbol, flagFn: Long => Long, newName: Name = null) =
member.cloneSymbol(sClass, flagFn(member.flags | SPECIALIZED), newName)
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
index 714f189ead..ef534f70fd 100644
--- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala
+++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
@@ -96,7 +96,7 @@ abstract class TailCalls extends Transform {
val failReason = failReasons(ctx)
val failPos = failPositions(ctx)
- unit.error(failPos, s"could not optimize @tailrec annotated $method: $failReason")
+ reporter.error(failPos, s"could not optimize @tailrec annotated $method: $failReason")
}
/** Has the label been accessed? Then its symbol is in this set. */
@@ -268,14 +268,14 @@ abstract class TailCalls extends Transform {
tree match {
case ValDef(_, _, _, _) =>
if (tree.symbol.isLazy && tree.symbol.hasAnnotation(TailrecClass))
- unit.error(tree.pos, "lazy vals are not tailcall transformed")
+ reporter.error(tree.pos, "lazy vals are not tailcall transformed")
super.transform(tree)
case dd @ DefDef(_, name, _, vparamss0, _, rhs0) if isEligible(dd) =>
val newCtx = new DefDefTailContext(dd)
if (newCtx.isMandatory && !(newCtx containsRecursiveCall rhs0))
- unit.error(tree.pos, "@tailrec annotated method contains no recursive calls")
+ reporter.error(tree.pos, "@tailrec annotated method contains no recursive calls")
debuglog(s"Considering $name for tailcalls, with labels in tailpos: ${newCtx.tailLabels}")
val newRHS = transform(rhs0, newCtx)
@@ -328,11 +328,14 @@ abstract class TailCalls extends Transform {
)
case CaseDef(pat, guard, body) =>
+ // CaseDefs are already translated and guards were moved into the body.
+ // If this was not the case, guards would have to be transformed here as well.
+ assert(guard.isEmpty)
deriveCaseDef(tree)(transform)
case If(cond, thenp, elsep) =>
treeCopy.If(tree,
- cond,
+ noTailTransform(cond),
transform(thenp),
transform(elsep)
)
@@ -363,7 +366,7 @@ abstract class TailCalls extends Transform {
rewriteApply(tapply, fun, targs, vargs)
case Apply(fun, args) if fun.symbol == Boolean_or || fun.symbol == Boolean_and =>
- treeCopy.Apply(tree, fun, transformTrees(args))
+ treeCopy.Apply(tree, noTailTransform(fun), transformTrees(args))
// this is to detect tailcalls in translated matches
// it's a one-argument call to a label that is in a tailposition and that looks like label(x) {x}
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index d77c6b54a9..2209aac00f 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -93,7 +93,7 @@ abstract class UnCurry extends InfoTransform
override def transform(tree: Tree): Tree = (
try postTransform(mainTransform(tree))
catch { case ex: TypeError =>
- unit.error(ex.pos, ex.msg)
+ reporter.error(ex.pos, ex.msg)
debugStack(ex)
EmptyTree
}
@@ -174,7 +174,7 @@ abstract class UnCurry extends InfoTransform
cdef <- catches
if catchesThrowable(cdef) && !isSyntheticCase(cdef)
} {
- unit.warning(body.pos, "catch block may intercept non-local return from " + meth)
+ reporter.warning(body.pos, "catch block may intercept non-local return from " + meth)
}
Block(List(keyDef), tryCatch)
@@ -706,10 +706,10 @@ abstract class UnCurry extends InfoTransform
*/
private def saveRepeatedParams(dd: DefDef): Unit =
if (dd.symbol.isConstructor)
- unit.error(dd.symbol.pos, "A constructor cannot be annotated with a `varargs` annotation.")
+ reporter.error(dd.symbol.pos, "A constructor cannot be annotated with a `varargs` annotation.")
else treeInfo.repeatedParams(dd) match {
case Nil =>
- unit.error(dd.symbol.pos, "A method without repeated parameters cannot be annotated with the `varargs` annotation.")
+ reporter.error(dd.symbol.pos, "A method without repeated parameters cannot be annotated with the `varargs` annotation.")
case reps =>
repeatedParams(dd.symbol) = reps
}
@@ -782,7 +782,7 @@ abstract class UnCurry extends InfoTransform
// check if the method with that name and those arguments already exists in the template
currentClass.info.member(forwsym.name).alternatives.find(s => s != forwsym && s.tpe.matches(forwsym.tpe)) match {
- case Some(s) => unit.error(dd.symbol.pos,
+ case Some(s) => reporter.error(dd.symbol.pos,
"A method with a varargs annotation produces a forwarder method with the same signature "
+ s.tpe + " as an existing method.")
case None =>
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala
index fde0aca584..0899507bab 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala
@@ -505,7 +505,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis {
}
- import global.{ConstantType, Constant, SingletonType, Literal, Ident, singleType}
+ import global.{ConstantType, Constant, EmptyScope, SingletonType, Literal, Ident, refinedType, singleType, TypeBounds, NoSymbol}
import global.definitions._
@@ -538,23 +538,30 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis {
private val trees = mutable.HashSet.empty[Tree]
// hashconsing trees (modulo value-equality)
- private[TreesAndTypesDomain] def uniqueTpForTree(t: Tree): Type =
- // a new type for every unstable symbol -- only stable value are uniqued
- // technically, an unreachable value may change between cases
- // thus, the failure of a case that matches on a mutable value does not exclude the next case succeeding
- // (and thuuuuus, the latter case must be considered reachable)
- if (!t.symbol.isStable) t.tpe.narrow
+ private[TreesAndTypesDomain] def uniqueTpForTree(t: Tree): Type = {
+ def freshExistentialSubtype(tp: Type): Type = {
+ // SI-8611 tp.narrow is tempting, but unsuitable. See `testRefinedTypeSI8611` for an explanation.
+ NoSymbol.freshExistential("").setInfo(TypeBounds.upper(tp)).tpe
+ }
+
+ if (!t.symbol.isStable) {
+ // Create a fresh type for each unstable value, since we can never correlate it to another value.
+ // For example `case X => case X =>` should not complaing about the second case being unreachable,
+ // if X is mutable.
+ freshExistentialSubtype(t.tpe)
+ }
else trees find (a => a.correspondsStructure(t)(sameValue)) match {
case Some(orig) =>
- debug.patmat("unique tp for tree: "+ ((orig, orig.tpe)))
+ debug.patmat("unique tp for tree: " + ((orig, orig.tpe)))
orig.tpe
case _ =>
// duplicate, don't mutate old tree (TODO: use a map tree -> type instead?)
- val treeWithNarrowedType = t.duplicate setType t.tpe.narrow
+ val treeWithNarrowedType = t.duplicate setType freshExistentialSubtype(t.tpe)
debug.patmat("uniqued: "+ ((t, t.tpe, treeWithNarrowedType.tpe)))
trees += treeWithNarrowedType
treeWithNarrowedType.tpe
}
+ }
}
sealed abstract class Const {
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
index 894f959319..6f81cbe152 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
@@ -51,7 +51,7 @@ trait TreeAndTypeAnalysis extends Debugging {
// This is a pretty poor approximation.
def unsoundAssumptionUsed = binder.name != nme.WILDCARD && !(pt <:< pat.tpe)
if (settings.lint && unsoundAssumptionUsed)
- global.currentUnit.warning(pat.pos,
+ 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
|count on it having type $pt, as the pattern is matched using `==` (see SI-1503).""")
@@ -104,11 +104,18 @@ trait TreeAndTypeAnalysis extends Debugging {
// TODO case _ if tp.isTupleType => // recurse into component types
case modSym: ModuleClassSymbol =>
Some(List(tp))
+ case sym: RefinementClassSymbol =>
+ val parentSubtypes: List[Option[List[Type]]] = tp.parents.map(parent => enumerateSubtypes(parent))
+ if (parentSubtypes exists (_.isDefined))
+ // If any of the parents is enumerable, then the refinement type is enumerable.
+ Some(
+ // We must only include subtypes of the parents that conform to `tp`.
+ // See neg/virtpatmat_exhaust_compound.scala for an example.
+ parentSubtypes flatMap (_.getOrElse(Nil)) filter (_ <:< tp)
+ )
+ else None
// make sure it's not a primitive, else (5: Byte) match { case 5 => ... } sees no Byte
- case sym if !sym.isSealed || isPrimitiveValueClass(sym) =>
- debug.patmat("enum unsealed "+ ((tp, sym, sym.isSealed, isPrimitiveValueClass(sym))))
- None
- case sym =>
+ case sym if sym.isSealed =>
val subclasses = debug.patmatResult(s"enum $sym sealed, subclasses")(
// symbols which are both sealed and abstract need not be covered themselves, because
// all of their children must be and they cannot otherwise be created.
@@ -136,6 +143,9 @@ trait TreeAndTypeAnalysis extends Debugging {
else None
}
})
+ case sym =>
+ debug.patmat("enum unsealed "+ ((tp, sym, sym.isSealed, isPrimitiveValueClass(sym))))
+ None
}
// approximate a type to the static type that is fully checkable at run time,
@@ -388,7 +398,7 @@ trait MatchAnalysis extends MatchApproximation {
import global.definitions._
trait MatchAnalyzer extends MatchApproximator {
- def uncheckedWarning(pos: Position, msg: String) = global.currentUnit.uncheckedWarning(pos, msg)
+ def uncheckedWarning(pos: Position, msg: String) = currentRun.reporting.uncheckedWarning(pos, msg)
def warn(pos: Position, ex: AnalysisBudget.Exception, kind: String) = uncheckedWarning(pos, s"Cannot check match for $kind.\n${ex.advice}")
// TODO: model dependencies between variables: if V1 corresponds to (x: List[_]) and V2 is (x.hd), V2 cannot be assigned when V1 = null or V1 = Nil
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
index 8ff7824159..e9c81f4728 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
@@ -442,7 +442,7 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {
val distinctAlts = distinctBy(switchableAlts)(extractConst)
if (distinctAlts.size < switchableAlts.size) {
val duplicated = switchableAlts.groupBy(extractConst).flatMap(_._2.drop(1).take(1)) // report the first duplicated
- global.currentUnit.warning(pos, s"Pattern contains duplicate alternatives: ${duplicated.mkString(", ")}")
+ reporter.warning(pos, s"Pattern contains duplicate alternatives: ${duplicated.mkString(", ")}")
}
CaseDef(Alternative(distinctAlts), guard, body)
}
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala
index 4cf8980689..0eaffe7cee 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala
@@ -154,7 +154,7 @@ trait MatchTranslation {
case SymbolBound(sym, expr) => bindingStep(sym, expr)
case Literal(Constant(_)) | Ident(_) | Select(_, _) | This(_) => equalityTestStep()
case Alternative(alts) => alternativesStep(alts)
- case _ => context.unit.error(pos, unsupportedPatternMsg) ; noStep()
+ case _ => reporter.error(pos, unsupportedPatternMsg) ; noStep()
}
def translate(): List[TreeMaker] = nextStep() merge (_.translate())
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala
index 5d8a9fecef..1974befb45 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala
@@ -558,7 +558,7 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging {
}
emitSwitch(scrut, scrutSym, casesNoSubstOnly, pt, matchFailGenOverride, suppression.exhaustive).getOrElse{
- if (requireSwitch) typer.context.unit.warning(scrut.pos, "could not emit switch for @switch annotated match")
+ if (requireSwitch) reporter.warning(scrut.pos, "could not emit switch for @switch annotated match")
if (casesNoSubstOnly nonEmpty) {
// before optimizing, check casesNoSubstOnly for presence of a default case,
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchWarnings.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchWarnings.scala
index a7d7680db1..9e9372f709 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchWarnings.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchWarnings.scala
@@ -67,7 +67,7 @@ trait MatchWarnings {
val cdef = it.next()
// If a default case has been seen, then every succeeding case is unreachable.
if (vpat != null)
- context.unit./*error*/warning(cdef.body.pos, "unreachable code due to " + vpat + addendum(cdef.pat))
+ reporter.warning(cdef.body.pos, "unreachable code due to " + vpat + addendum(cdef.pat)) // TODO: make configurable whether this is an error
// If this is a default case and more cases follow, warn about this one so
// we have a reason to mention its pattern variable name and any corresponding
// symbol in scope. Errors will follow from the remaining cases, at least
@@ -78,7 +78,7 @@ trait MatchWarnings {
case _ => ""
}
vpat = s"variable pattern$vpatName on line ${cdef.pat.pos.line}"
- context.unit.warning(cdef.pos, s"patterns after a variable pattern cannot match (SLS 8.1.1)" + addendum(cdef.pat))
+ reporter.warning(cdef.pos, s"patterns after a variable pattern cannot match (SLS 8.1.1)" + addendum(cdef.pat))
}
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala b/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala
index f6c960d089..ef50e083a1 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala
@@ -65,7 +65,7 @@ trait PatternMatching extends Transform
} catch {
case x: (Types#TypeError) =>
// TODO: this should never happen; error should've been reported during type checking
- unit.error(tree.pos, "error during expansion of this match (this is a scalac bug).\nThe underlying error was: "+ x.msg)
+ reporter.error(tree.pos, "error during expansion of this match (this is a scalac bug).\nThe underlying error was: "+ x.msg)
translated
}
case Try(block, catches, finalizer) =>
@@ -175,13 +175,13 @@ trait Interface extends ast.TreeDSL {
val matchOwner = typer.context.owner
def pureType(tp: Type): Type = tp
- def reportUnreachable(pos: Position) = typer.context.unit.warning(pos, "unreachable code")
+ def reportUnreachable(pos: Position) = reporter.warning(pos, "unreachable code")
def reportMissingCases(pos: Position, counterExamples: List[String]) = {
val ceString =
if (counterExamples.tail.isEmpty) "input: " + counterExamples.head
else "inputs: " + counterExamples.mkString(", ")
- typer.context.unit.warning(pos, "match may not be exhaustive.\nIt would fail on the following "+ ceString)
+ reporter.warning(pos, "match may not be exhaustive.\nIt would fail on the following "+ ceString)
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala
index d10eff1d8d..8f21f4ecfc 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala
@@ -103,8 +103,8 @@ trait ScalacPatternExpanders {
def offerString = if (extractor.isErroneous) "" else s" offering $offering"
def arityExpected = ( if (extractor.hasSeq) "at least " else "" ) + productArity
- def err(msg: String) = currentUnit.error(tree.pos, msg)
- def warn(msg: String) = currentUnit.warning(tree.pos, msg)
+ def err(msg: String) = reporter.error(tree.pos, msg)
+ def warn(msg: String) = reporter.warning(tree.pos, msg)
def arityError(what: String) = err(s"$what patterns for $owner$offerString: expected $arityExpected, found $totalArity")
if (isStar && !isSeq)
@@ -139,8 +139,10 @@ trait ScalacPatternExpanders {
def acceptMessage = if (extractor.isErroneous) "" else s" to hold ${extractor.offeringString}"
val requiresTupling = isUnapply && patterns.totalArity == 1 && productArity > 1
- if (requiresTupling && effectivePatternArity(args) == 1)
- currentUnit.deprecationWarning(sel.pos, s"${sel.symbol.owner} expects $productArity patterns$acceptMessage but crushing into $productArity-tuple to fit single pattern (SI-6675)")
+ if (requiresTupling && effectivePatternArity(args) == 1) {
+ val sym = sel.symbol.owner
+ currentRun.reporting.deprecationWarning(sel.pos, sym, s"${sym} expects $productArity patterns$acceptMessage but crushing into $productArity-tuple to fit single pattern (SI-6675)")
+ }
val normalizedExtractor = if (requiresTupling) tupleExtractor(extractor) else extractor
validateAligned(fn, Aligned(patterns, normalizedExtractor))
diff --git a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala
index 1e544e54f6..2f4d228347 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala
@@ -77,12 +77,13 @@ trait Adaptations {
val msg = "Adaptation of argument list by inserting () has been deprecated: " + (
if (isLeakyTarget) "leaky (Object-receiving) target makes this especially dangerous."
else "this is unlikely to be what you want.")
- context.unit.deprecationWarning(t.pos, adaptWarningMessage(msg))
+ context.deprecationWarning(t.pos, t.symbol, adaptWarningMessage(msg))
}
} 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/AnalyzerPlugins.scala b/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala
index fa6e5399eb..5a70d4c524 100644
--- a/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala
@@ -190,6 +190,16 @@ trait AnalyzerPlugins { self: Analyzer =>
def pluginsTypedMacroBody(typer: Typer, ddef: DefDef): Option[Tree] = None
/**
+ * Figures out whether the given macro definition is blackbox or whitebox.
+ *
+ * Default implementation provided in `self.standardIsBlackbox` loads the macro impl binding
+ * and fetches boxity from the "isBlackbox" field of the macro signature.
+ *
+ * $nonCumulativeReturnValueDoc.
+ */
+ def pluginsIsBlackbox(macroDef: Symbol): Option[Boolean] = None
+
+ /**
* Expands an application of a def macro (i.e. of a symbol that has the MACRO flag set),
* possibly using the current typer mode and the provided prototype.
*
@@ -375,6 +385,14 @@ trait AnalyzerPlugins { self: Analyzer =>
def custom(plugin: MacroPlugin) = plugin.pluginsTypedMacroBody(typer, ddef)
})
+ /** @see MacroPlugin.pluginsIsBlackbox */
+ def pluginsIsBlackbox(macroDef: Symbol): Boolean = invoke(new NonCumulativeOp[Boolean] {
+ def position = macroDef.pos
+ def description = "compute boxity for this macro definition"
+ def default = standardIsBlackbox(macroDef)
+ def custom(plugin: MacroPlugin) = plugin.pluginsIsBlackbox(macroDef)
+ })
+
/** @see MacroPlugin.pluginsMacroExpand */
def pluginsMacroExpand(typer: Typer, expandee: Tree, mode: Mode, pt: Type): Tree = invoke(new NonCumulativeOp[Tree] {
def position = expandee.pos
diff --git a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala
index 13884404b3..3a77cab919 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala
@@ -275,7 +275,7 @@ trait Checkable {
;
// Matching on types like case _: AnyRef { def bippy: Int } => doesn't work -- yet.
case RefinedType(_, decls) if !decls.isEmpty =>
- getContext.unit.warning(tree.pos, s"a pattern match on a refinement type is unchecked")
+ reporter.warning(tree.pos, s"a pattern match on a refinement type is unchecked")
case RefinedType(parents, _) =>
parents foreach (p => checkCheckable(tree, p, X, inPattern, canRemedy))
case _ =>
@@ -285,14 +285,14 @@ trait Checkable {
if (checker.neverMatches) {
val addendum = if (checker.neverSubClass) "" else " (but still might match its erasure)"
- getContext.unit.warning(tree.pos, s"fruitless type test: a value of type $X cannot also be a $PString$addendum")
+ reporter.warning(tree.pos, s"fruitless type test: a value of type $X cannot also be a $PString$addendum")
}
else if (checker.isUncheckable) {
val msg = (
if (checker.uncheckableType =:= P) s"abstract type $where$PString"
else s"${checker.uncheckableMessage} in type $where$PString"
)
- getContext.unit.warning(tree.pos, s"$msg is unchecked since it is eliminated by erasure")
+ reporter.warning(tree.pos, s"$msg is unchecked since it is eliminated by erasure")
}
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 8e1ceffecd..72ca9b879a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -66,7 +66,7 @@ trait Contexts { self: Analyzer =>
def isMask(s: ImportSelector) = s.name != nme.WILDCARD && s.rename == nme.WILDCARD
imp.tree.selectors filterNot (s => isMask(s) || used(s)) foreach { sel =>
- unit.warning(imp posOf sel, "Unused import")
+ reporter.warning(imp posOf sel, "Unused import")
}
}
allUsedSelectors --= imps
@@ -103,7 +103,7 @@ trait Contexts { self: Analyzer =>
// there must be a scala.xml package when xml literals were parsed in this unit
if (unit.hasXml && ScalaXmlPackage == NoSymbol)
- unit.error(unit.firstXmlPos, "To compile XML syntax, the scala.xml package must be on the classpath.\nPlease see http://docs.scala-lang.org/overviews/core/scala-2.11.html#scala-xml.")
+ reporter.error(unit.firstXmlPos, "To compile XML syntax, the scala.xml package must be on the classpath.\nPlease see http://docs.scala-lang.org/overviews/core/scala-2.11.html#scala-xml.")
// scala-xml needs `scala.xml.TopScope` to be in scope globally as `$scope`
// We detect `scala-xml` by looking for `scala.xml.TopScope` and
@@ -359,7 +359,7 @@ trait Contexts { self: Analyzer =>
/** Issue and clear all warnings from the report buffer */
def flushAndIssueWarnings() {
reportBuffer.warnings foreach {
- case (pos, msg) => unit.warning(pos, msg)
+ case (pos, msg) => reporter.warning(pos, msg)
}
reportBuffer.clearAllWarnings()
}
@@ -541,7 +541,7 @@ trait Contexts { self: Analyzer =>
}
private def unitError(pos: Position, msg: String): Unit =
- if (checking) onTreeCheckerError(pos, msg) else unit.error(pos, msg)
+ 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??
@@ -589,10 +589,20 @@ trait Contexts { self: Analyzer =>
/** 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) unit.warning(pos, msg)
+ if (reportErrors || force) reporter.warning(pos, msg)
else if (bufferErrors) reportBuffer += (pos -> msg)
}
+ def deprecationWarning(pos: Position, sym: Symbol, msg: String): Unit =
+ currentRun.reporting.deprecationWarning(pos, sym, msg)
+ def deprecationWarning(pos: Position, sym: Symbol): Unit =
+ currentRun.reporting.deprecationWarning(pos, sym) // TODO: allow this to escalate to an error, and implicit search will ignore deprecated implicits
+
+ 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
// most cases, it is simply the outer context: if we're owned by
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index d87090fa46..73c3e6f016 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -1306,7 +1306,7 @@ trait Implicits {
}
def wrapResult(tree: Tree): SearchResult =
- if (tree == EmptyTree) SearchFailure else new SearchResult(tree, EmptyTreeTypeSubstituter, Nil)
+ if (tree == EmptyTree) SearchFailure else new SearchResult(atPos(pos.focus)(tree), EmptyTreeTypeSubstituter, Nil)
/** Materializes implicits of predefined types (currently, manifests and tags).
* Will be replaced by implicit macros once we fix them.
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index fc0e2c7c80..a3f1da60ce 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -558,7 +558,7 @@ trait Infer extends Checkable {
foreachWithIndex(targs) ((targ, idx) =>
targ.typeSymbol match {
case sym @ (AnyClass | AnyValClass) =>
- context.unit.warning(argumentPosition(idx), s"a type was inferred to be `${sym.name}`; this may indicate a programming error.")
+ reporter.warning(argumentPosition(idx), s"a type was inferred to be `${sym.name}`; this may indicate a programming error.")
case _ =>
}
)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index f4456998c0..9c22688581 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -263,7 +263,12 @@ trait Macros extends MacroRuntimes with Traces with Helpers {
}
def isBlackbox(expandee: Tree): Boolean = isBlackbox(dissectApplied(expandee).core.symbol)
- def isBlackbox(macroDef: Symbol): Boolean = {
+ def isBlackbox(macroDef: Symbol): Boolean = pluginsIsBlackbox(macroDef)
+
+ /** Default implementation of `isBlackbox`.
+ * Can be overridden by analyzer plugins (see AnalyzerPlugins.pluginsIsBlackbox for more details)
+ */
+ def standardIsBlackbox(macroDef: Symbol): Boolean = {
val fastTrackBoxity = fastTrack.get(macroDef).map(_.isBlackbox)
val bindingBoxity = loadMacroImplBinding(macroDef).map(_.isBlackbox)
fastTrackBoxity orElse bindingBoxity getOrElse false
@@ -417,9 +422,10 @@ trait Macros extends MacroRuntimes with Traces with Helpers {
val wrappedArgs = mapWithIndex(args)((arg, j) => {
val fingerprint = implParams(min(j, implParams.length - 1))
+ val duplicatedArg = duplicateAndKeepPositions(arg)
fingerprint match {
- case LiftedTyped => context.Expr[Nothing](arg.duplicate)(TypeTag.Nothing) // TODO: SI-5752
- case LiftedUntyped => arg.duplicate
+ case LiftedTyped => context.Expr[Nothing](duplicatedArg)(TypeTag.Nothing) // TODO: SI-5752
+ case LiftedUntyped => duplicatedArg
case _ => abort(s"unexpected fingerprint $fingerprint in $binding with paramss being $paramss " +
s"corresponding to arg $arg in $argss")
}
@@ -708,7 +714,7 @@ trait Macros extends MacroRuntimes with Traces with Helpers {
sealed abstract class MacroStatus(val result: Tree)
case class Success(expanded: Tree) extends MacroStatus(expanded)
- case class Fallback(fallback: Tree) extends MacroStatus(fallback) { currentRun.seenMacroExpansionsFallingBack = true }
+ case class Fallback(fallback: Tree) extends MacroStatus(fallback) { currentRun.reporting.seenMacroExpansionsFallingBack = true }
case class Delayed(delayed: Tree) extends MacroStatus(delayed)
case class Skipped(skipped: Tree) extends MacroStatus(skipped)
case class Failure(failure: Tree) extends MacroStatus(failure)
@@ -782,7 +788,7 @@ trait Macros extends MacroRuntimes with Traces with Helpers {
}
} catch {
case ex: Throwable =>
- popMacroContext()
+ if (openMacros.nonEmpty) popMacroContext() // weirdly we started popping on an empty stack when refactoring fatalWarnings logic
val realex = ReflectionUtils.unwrapThrowable(ex)
realex match {
case ex: AbortMacroException => MacroGeneratedAbort(expandee, ex)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 4382a2c6f7..1328119aac 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -443,7 +443,7 @@ trait Namers extends MethodSynthesis {
&& clazz.exists
)
if (fails) {
- context.unit.error(tree.pos, (
+ reporter.error(tree.pos, (
s"Companions '$clazz' and '$module' must be defined in same file:\n"
+ s" Found in ${clazz.sourceFile.canonicalPath} and ${module.sourceFile.canonicalPath}")
)
@@ -718,7 +718,7 @@ trait Namers extends MethodSynthesis {
}
val owner = tree.symbol.owner
if (settings.lint && owner.isPackageObjectClass && !mods.isImplicit) {
- context.unit.warning(tree.pos,
+ 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."
)
@@ -730,7 +730,7 @@ trait Namers extends MethodSynthesis {
log("enter implicit wrapper "+tree+", owner = "+owner)
enterImplicitWrapper(tree)
}
- else context.unit.error(tree.pos, "implicit classes must accept exactly one primary constructor parameter")
+ else reporter.error(tree.pos, "implicit classes must accept exactly one primary constructor parameter")
}
validateCompanionDefs(tree)
}
@@ -1040,10 +1040,10 @@ trait Namers extends MethodSynthesis {
* so the resulting type is a valid external method type, it does not contain (references to) skolems.
*/
def thisMethodType(restpe: Type) = {
- val checkDependencies = new DependentTypeChecker(context)(this)
- checkDependencies check vparamSymss
- // DEPMETTODO: check not needed when they become on by default
- checkDependencies(restpe)
+ if (vparamSymss.lengthCompare(0) > 0) { // OPT fast path for methods of 0-1 parameter lists
+ val checkDependencies = new DependentTypeChecker(context)(this)
+ checkDependencies check vparamSymss
+ }
val makeMethodType = (vparams: List[Symbol], restpe: Type) => {
// TODODEPMET: check that we actually don't need to do anything here
@@ -1177,7 +1177,13 @@ trait Namers extends MethodSynthesis {
}
}
- addDefaultGetters(meth, ddef, vparamss, tparams, overriddenSymbol(methResTp))
+ val overridden = {
+ val isConstr = meth.isConstructor
+ if (isConstr || !methOwner.isClass) NoSymbol else overriddenSymbol(methResTp)
+ }
+ val hasDefaults = mexists(vparamss)(_.symbol.hasDefault) || mexists(overridden.paramss)(_.hasDefault)
+ if (hasDefaults)
+ addDefaultGetters(meth, ddef, vparamss, tparams, overridden)
// fast track macros, i.e. macros defined inside the compiler, are hardcoded
// hence we make use of that and let them have whatever right-hand side they need
@@ -1219,7 +1225,7 @@ trait Namers extends MethodSynthesis {
* typechecked, the corresponding param would not yet have the "defaultparam"
* flag.
*/
- private def addDefaultGetters(meth: Symbol, ddef: DefDef, vparamss: List[List[ValDef]], tparams: List[TypeDef], overriddenSymbol: => Symbol) {
+ private def addDefaultGetters(meth: Symbol, ddef: DefDef, vparamss: List[List[ValDef]], tparams: List[TypeDef], overridden: Symbol) {
val DefDef(_, _, rtparams0, rvparamss0, _, _) = resetAttrs(ddef.duplicate)
// having defs here is important to make sure that there's no sneaky tree sharing
// in methods with multiple default parameters
@@ -1227,7 +1233,6 @@ trait Namers extends MethodSynthesis {
def rvparamss = rvparamss0.map(_.map(_.duplicate))
val methOwner = meth.owner
val isConstr = meth.isConstructor
- val overridden = if (isConstr || !methOwner.isClass) NoSymbol else overriddenSymbol
val overrides = overridden != NoSymbol && !overridden.isOverloaded
// value parameters of the base class (whose defaults might be overridden)
var baseParamss = (vparamss, overridden.tpe.paramss) match {
@@ -1745,7 +1750,6 @@ trait Namers extends MethodSynthesis {
for (p <- vps)
this(p.info)
// can only refer to symbols in earlier parameter sections
- // (if the extension is enabled)
okParams ++= vps
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index dceb0a47d8..b6387fd56b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -174,8 +174,8 @@ trait NamesDefaults { self: Analyzer =>
// assigning the correct method symbol, typedSelect will just assign the type. the reason
// to still call 'typed' is to correctly infer singleton types, SI-5259.
val selectPos =
- if(qual.pos.isRange && baseFun.pos.isRange) qual.pos.union(baseFun.pos).withStart(Math.min(qual.pos.end, baseFun.pos.end))
- else baseFun.pos
+ if(qual.pos.isRange && baseFun1.pos.isRange) qual.pos.union(baseFun1.pos).withStart(Math.min(qual.pos.end, baseFun1.pos.end))
+ else baseFun1.pos
val f = blockTyper.typedOperator(Select(newQual, selected).setSymbol(baseFun1.symbol).setPos(selectPos))
if (funTargs.isEmpty) f
else TypeApply(f, funTargs).setType(baseFun.tpe)
@@ -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)
@@ -536,8 +555,8 @@ trait NamesDefaults { self: Analyzer =>
def matchesName(param: Symbol) = !param.isSynthetic && (
(param.name == name) || (param.deprecatedParamName match {
case Some(`name`) =>
- context0.unit.deprecationWarning(arg.pos,
- "the parameter name "+ name +" has been deprecated. Use "+ param.name +" instead.")
+ context0.deprecationWarning(arg.pos, param,
+ s"the parameter name $name has been deprecated. Use ${param.name} instead.")
true
case _ => false
})
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 4540017b62..1b3da26bf2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -147,7 +147,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
val owners = haveDefaults map (_.owner)
// constructors of different classes are allowed to have defaults
if (haveDefaults.exists(x => !x.isConstructor) || owners.distinct.size < haveDefaults.size) {
- unit.error(clazz.pos,
+ reporter.error(clazz.pos,
"in "+ clazz +
", multiple overloaded alternatives of "+ haveDefaults.head +
" define default arguments" + (
@@ -162,7 +162,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
// Check for doomed attempt to overload applyDynamic
if (clazz isSubClass DynamicClass) {
for ((_, m1 :: m2 :: _) <- (clazz.info member nme.applyDynamic).alternatives groupBy (_.typeParams.length)) {
- unit.error(m1.pos, "implementation restriction: applyDynamic cannot be overloaded except by methods with different numbers of type parameters, e.g. applyDynamic[T1](method: String)(arg: T1) and applyDynamic[T1, T2](method: String)(arg1: T1, arg2: T2)")
+ reporter.error(m1.pos, "implementation restriction: applyDynamic cannot be overloaded except by methods with different numbers of type parameters, e.g. applyDynamic[T1](method: String)(arg: T1) and applyDynamic[T1, T2](method: String)(arg1: T1, arg2: T2)")
}
}
@@ -172,7 +172,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
// implicit classes leave both a module symbol and a method symbol as residue
val alts = clazz.info.decl(sym.name).alternatives filterNot (_.isModule)
if (alts.size > 1)
- alts foreach (x => unit.warning(x.pos, "parameterized overloaded implicit methods are not visible as view bounds"))
+ alts foreach (x => reporter.warning(x.pos, "parameterized overloaded implicit methods are not visible as view bounds"))
}
}
}
@@ -281,10 +281,10 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
mixinOverrideErrors.toList match {
case List() =>
case List(MixinOverrideError(_, msg)) =>
- unit.error(clazz.pos, msg)
+ reporter.error(clazz.pos, msg)
case MixinOverrideError(member, msg) :: others =>
val others1 = others.map(_.member.name.decode).filter(member.name.decode != _).distinct
- unit.error(
+ reporter.error(
clazz.pos,
msg+(if (others1.isEmpty) ""
else ";\n other members with override errors are: "+(others1 mkString ", ")))
@@ -347,7 +347,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
)
}
def emitOverrideError(fullmsg: String) {
- if (member.owner == clazz) unit.error(member.pos, fullmsg)
+ if (member.owner == clazz) reporter.error(member.pos, fullmsg)
else mixinOverrideErrors += new MixinOverrideError(member, fullmsg)
}
@@ -464,7 +464,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
checkOverrideDeprecated()
if (settings.warnNullaryOverride) {
if (other.paramss.isEmpty && !member.paramss.isEmpty) {
- unit.warning(member.pos, "non-nullary method overrides nullary method")
+ reporter.warning(member.pos, "non-nullary method overrides nullary method")
}
}
}
@@ -496,7 +496,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
typer.infer.checkKindBounds(high :: Nil, lowType :: Nil, rootType, low.owner) match { // (1.7.2)
case Nil =>
case kindErrors =>
- unit.error(member.pos,
+ reporter.error(member.pos,
"The kind of "+member.keyString+" "+member.varianceString + member.nameString+
" does not conform to the expected kind of " + other.defString + other.locationString + "." +
kindErrors.toList.mkString("\n", ", ", ""))
@@ -507,7 +507,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
typer.infer.checkKindBounds(low :: Nil, lowType.normalize :: Nil, rootType, low.owner) match {
case Nil =>
case kindErrors =>
- unit.error(member.pos,
+ reporter.error(member.pos,
"The kind of the right-hand side "+lowType.normalize+" of "+low.keyString+" "+
low.varianceString + low.nameString+ " does not conform to its expected kind."+
kindErrors.toList.mkString("\n", ", ", ""))
@@ -546,7 +546,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
if (other.hasDeprecatedOverridingAnnotation) {
val suffix = other.deprecatedOverridingMessage map (": " + _) getOrElse ""
val msg = s"overriding ${other.fullLocationString} is deprecated$suffix"
- unit.deprecationWarning(member.pos, msg)
+ currentRun.reporting.deprecationWarning(member.pos, other, msg)
}
}
}
@@ -754,7 +754,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
checkNoAbstractDecls(clazz)
if (abstractErrors.nonEmpty)
- unit.error(clazz.pos, abstractErrorMessage)
+ reporter.error(clazz.pos, abstractErrorMessage)
}
else if (clazz.isTrait && !(clazz isSubClass AnyValClass)) {
// For non-AnyVal classes, prevent abstract methods in interfaces that override
@@ -765,7 +765,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
// override a concrete method in Object. The jvm, however, does not.
val overridden = decl.matchingSymbol(ObjectClass, ObjectTpe)
if (overridden.isFinal)
- unit.error(decl.pos, "trait cannot redefine final method from class AnyRef")
+ reporter.error(decl.pos, "trait cannot redefine final method from class AnyRef")
}
}
@@ -818,7 +818,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
// for (bc <- clazz.info.baseClasses.tail) Console.println("" + bc + " has " + bc.info.decl(member.name) + ":" + bc.info.decl(member.name).tpe);//DEBUG
val nonMatching: List[Symbol] = clazz.info.member(member.name).alternatives.filterNot(_.owner == clazz).filterNot(_.isFinal)
- def issueError(suffix: String) = unit.error(member.pos, member.toString() + " overrides nothing" + suffix)
+ def issueError(suffix: String) = reporter.error(member.pos, member.toString() + " overrides nothing" + suffix)
nonMatching match {
case Nil =>
issueError("")
@@ -871,7 +871,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
case _ :: Nil =>
;// OK
case tp1 :: tp2 :: _ =>
- unit.error(clazz.pos, "illegal inheritance;\n " + clazz +
+ reporter.error(clazz.pos, "illegal inheritance;\n " + clazz +
" inherits different type instances of " + baseClass +
":\n" + tp1 + " and " + tp2)
explainTypes(tp1, tp2)
@@ -888,7 +888,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
case _ => "type "+tp
}
override def issueVarianceError(base: Symbol, sym: Symbol, required: Variance) {
- currentRun.currentUnit.error(base.pos,
+ reporter.error(base.pos,
s"${sym.variance} $sym occurs in $required position in ${tpString(base.info)} of $base")
}
}
@@ -956,7 +956,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
def checkImplicitViewOptionApply(pos: Position, fn: Tree, args: List[Tree]): Unit = if (settings.lint) (fn, args) match {
case (tap@TypeApply(fun, targs), List(view: ApplyImplicitView)) if fun.symbol == currentRun.runDefinitions.Option_apply =>
- unit.warning(pos, s"Suspicious application of an implicit view (${view.fun}) in the argument to Option.apply.") // SI-6567
+ reporter.warning(pos, s"Suspicious application of an implicit view (${view.fun}) in the argument to Option.apply.") // SI-6567
case _ =>
}
@@ -1031,7 +1031,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
def nonSensibleWarning(what: String, alwaysEqual: Boolean) = {
val msg = alwaysEqual == (name == nme.EQ || name == nme.eq)
- unit.warning(pos, s"comparing $what using `${name.decode}' will always yield $msg")
+ reporter.warning(pos, s"comparing $what using `${name.decode}' will always yield $msg")
isNonSensible = true
}
def nonSensible(pre: String, alwaysEqual: Boolean) =
@@ -1046,7 +1046,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
}
def unrelatedTypes() = if (!isNonSensible) {
val weaselWord = if (isEitherValueClass) "" else " most likely"
- unit.warning(pos, s"$typesString are unrelated: they will$weaselWord $unrelatedMsg")
+ reporter.warning(pos, s"$typesString are unrelated: they will$weaselWord $unrelatedMsg")
}
if (nullCount == 2) // null == null
@@ -1141,7 +1141,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
&& callsSelf
)
if (trivialInifiniteLoop)
- unit.warning(valOrDef.rhs.pos, s"${valOrDef.symbol.fullLocationString} does nothing other than call itself recursively")
+ reporter.warning(valOrDef.rhs.pos, s"${valOrDef.symbol.fullLocationString} does nothing other than call itself recursively")
}
// Transformation ------------------------------------------------------------
@@ -1231,7 +1231,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
finally if (currentLevel.maxindex > 0) {
// An implementation restriction to avoid VerifyErrors and lazyvals mishaps; see SI-4717
debuglog("refsym = " + currentLevel.refsym)
- unit.error(currentLevel.refpos, "forward reference not allowed from self constructor invocation")
+ reporter.error(currentLevel.refpos, "forward reference not allowed from self constructor invocation")
}
case ModuleDef(_, _, _) => eliminateModuleDefs(tree)
case ValDef(_, _, _, _) =>
@@ -1241,7 +1241,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
val lazySym = tree.symbol.lazyAccessorOrSelf
if (lazySym.isLocalToBlock && index <= currentLevel.maxindex) {
debuglog("refsym = " + currentLevel.refsym)
- unit.error(currentLevel.refpos, "forward reference extends over definition of " + lazySym)
+ reporter.error(currentLevel.refpos, "forward reference extends over definition of " + lazySym)
}
tree1 :: Nil
}
@@ -1255,7 +1255,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
try typer.infer.checkBounds(tree0, pre, owner, tparams, argtps, "")
catch {
case ex: TypeError =>
- unit.error(tree0.pos, ex.getMessage())
+ reporter.error(tree0.pos, ex.getMessage())
if (settings.explaintypes) {
val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, argtps).bounds)
(argtps, bounds).zipped map ((targ, bound) => explainTypes(bound.lo, targ))
@@ -1287,11 +1287,9 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
private def checkUndesiredProperties(sym: Symbol, pos: Position) {
// If symbol is deprecated, and the point of reference is not enclosed
// in either a deprecated member or a scala bridge method, issue a warning.
- if (sym.isDeprecated && !currentOwner.ownerChain.exists(x => x.isDeprecated || x.hasBridgeAnnotation)) {
- unit.deprecationWarning(pos, "%s%s is deprecated%s".format(
- sym, sym.locationString, sym.deprecationMessage map (": " + _) getOrElse "")
- )
- }
+ if (sym.isDeprecated && !currentOwner.ownerChain.exists(x => x.isDeprecated || x.hasBridgeAnnotation))
+ currentRun.reporting.deprecationWarning(pos, sym)
+
// Similar to deprecation: check if the symbol is marked with @migration
// indicating it has changed semantics between versions.
if (sym.hasMigrationAnnotation && settings.Xmigration.value != NoScalaVersion) {
@@ -1299,12 +1297,12 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
settings.Xmigration.value < ScalaVersion(sym.migrationVersion.get)
catch {
case e : NumberFormatException =>
- unit.warning(pos, s"${sym.fullLocationString} has an unparsable version number: ${e.getMessage()}")
+ reporter.warning(pos, s"${sym.fullLocationString} has an unparsable version number: ${e.getMessage()}")
// if we can't parse the format on the migration annotation just conservatively assume it changed
true
}
if (changed)
- unit.warning(pos, s"${sym.fullLocationString} has changed semantics in version ${sym.migrationVersion.get}:\n${sym.migrationMessage.get}")
+ reporter.warning(pos, s"${sym.fullLocationString} has changed semantics in version ${sym.migrationVersion.get}:\n${sym.migrationMessage.get}")
}
// See an explanation of compileTimeOnly in its scaladoc at scala.annotation.compileTimeOnly.
if (sym.isCompileTimeOnly) {
@@ -1312,7 +1310,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
sm"""Reference to ${sym.fullLocationString} should not have survived past type checking,
|it should have been processed and eliminated during expansion of an enclosing macro."""
// The getOrElse part should never happen, it's just here as a backstop.
- unit.error(pos, sym.compileTimeOnlyMessage getOrElse defaultMsg)
+ reporter.error(pos, sym.compileTimeOnlyMessage getOrElse defaultMsg)
}
}
@@ -1323,7 +1321,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
&& sym.accessedOrSelf.isVal
)
if (settings.lint.value && isLikelyUninitialized)
- unit.warning(pos, s"Selecting ${sym} from ${sym.owner}, which extends scala.DelayedInit, is likely to yield an uninitialized value")
+ reporter.warning(pos, s"Selecting ${sym} from ${sym.owner}, which extends scala.DelayedInit, is likely to yield an uninitialized value")
}
private def lessAccessible(otherSym: Symbol, memberSym: Symbol): Boolean = (
@@ -1355,7 +1353,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
if (memberSym.isDeferred) "may be unable to provide a concrete implementation of"
else "may be unable to override"
- unit.warning(memberSym.pos,
+ reporter.warning(memberSym.pos,
"%s%s references %s %s.".format(
memberSym.fullLocationString, comparison,
accessFlagsToString(otherSym), otherSym
@@ -1390,7 +1388,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
tree match {
case DefDef(_, name, _, params :: _, _, _) =>
if (settings.lint && !treeInfo.isLeftAssoc(name.decodedName) && params.exists(p => isByName(p.symbol)))
- unit.warning(tree.pos,
+ 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 _ =>
}
@@ -1407,10 +1405,10 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
symbol.allOverriddenSymbols.filter(sym =>
!sym.isDeprecated && !sym.isDeferred)
if(!concrOvers.isEmpty)
- unit.deprecationWarning(
+ currentRun.reporting.deprecationWarning(
tree.pos,
- symbol.toString + " overrides concrete, non-deprecated symbol(s):" +
- concrOvers.map(_.name.decode).mkString(" ", ", ", ""))
+ symbol,
+ s"${symbol.toString} overrides concrete, non-deprecated symbol(s): ${concrOvers.map(_.name.decode).mkString(", ")}")
}
}
private def isRepeatedParamArg(tree: Tree) = currentApplication match {
@@ -1471,7 +1469,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
applyChecks(sym.annotations)
// validate implicitNotFoundMessage
analyzer.ImplicitNotFoundMsg.check(sym) foreach { warn =>
- unit.warning(tree.pos, f"Invalid implicitNotFound message for ${sym}%s${sym.locationString}%s:%n$warn")
+ reporter.warning(tree.pos, f"Invalid implicitNotFound message for ${sym}%s${sym.locationString}%s:%n$warn")
}
case tpt@TypeTree() =>
@@ -1596,7 +1594,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
|| sym.allOverriddenSymbols.exists(over => !(over.tpe.resultType =:= sym.tpe.resultType))
)
if (!isOk)
- unit.warning(sym.pos, s"side-effecting nullary methods are discouraged: suggest defining as `def ${sym.name.decode}()` instead")
+ reporter.warning(sym.pos, s"side-effecting nullary methods are discouraged: suggest defining as `def ${sym.name.decode}()` instead")
case _ => ()
}
@@ -1604,15 +1602,15 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
private def checkAnyValSubclass(clazz: Symbol) = {
if (clazz.isDerivedValueClass) {
if (clazz.isTrait)
- unit.error(clazz.pos, "Only classes (not traits) are allowed to extend AnyVal")
+ reporter.error(clazz.pos, "Only classes (not traits) are allowed to extend AnyVal")
else if (clazz.hasAbstractFlag)
- unit.error(clazz.pos, "`abstract' modifier cannot be used with value classes")
+ reporter.error(clazz.pos, "`abstract' modifier cannot be used with value classes")
}
}
private def checkUnexpandedMacro(t: Tree) =
if (!t.isDef && t.hasSymbolField && t.symbol.isTermMacro)
- unit.error(t.pos, "macro has not been expanded")
+ reporter.error(t.pos, "macro has not been expanded")
override def transform(tree: Tree): Tree = {
val savedLocalTyper = localTyper
@@ -1707,7 +1705,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
tree
case treeInfo.WildcardStarArg(_) if !isRepeatedParamArg(tree) =>
- unit.error(tree.pos, "no `: _*' annotation allowed here\n"+
+ reporter.error(tree.pos, "no `: _*' annotation allowed here\n"+
"(such annotations are only allowed in arguments to *-parameters)")
tree
@@ -1780,7 +1778,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
} catch {
case ex: TypeError =>
if (settings.debug) ex.printStackTrace()
- unit.error(tree.pos, ex.getMessage())
+ reporter.error(tree.pos, ex.getMessage())
tree
} finally {
localTyper = savedLocalTyper
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 9b9e641cad..d3a41b9570 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -12,21 +12,47 @@ import scala.collection.{ mutable, immutable }
import mutable.ListBuffer
import symtab.Flags._
-/** This phase adds super accessors for all super calls that either
+/** This phase performs the following functions, each of which could be split out in a
+ * mini-phase:
+ *
+ * (1) Adds super accessors for all super calls that either
* appear in a trait or have as a target a member of some outer class.
- * It also replaces references to parameter accessors with aliases
- * by super references to these aliases. The phase also checks that
- * symbols accessed from super are not abstract, or are overridden by
- * an abstract override. Finally, the phase also mangles the names
- * of class-members which are private up to an enclosing non-package
- * class, in order to avoid overriding conflicts.
*
- * This phase also sets SPECIALIZED flag on type parameters with
+ * (2) Converts references to parameter fields that have the same name as a corresponding
+ * public parameter field in a superclass to a reference to the superclass
+ * field (corresponding = super class field is initialized with subclass field).
+ * This info is pre-computed by the `alias` field in Typer. `dotc` follows a different
+ * route; it computes everything in SuperAccessors and changes the subclass field
+ * to a forwarder instead of manipulating references. This is more modular.
+ *
+ * (3) Adds protected accessors if the access to the protected member happens
+ * in a class which is not a subclass of the member's owner.
+ *
+ * (4) Mangles the names of class-members which are
+ * private up to an enclosing non-package class, in order to avoid overriding conflicts.
+ * This is a dubious, and it would be better to deprecate class-qualified privates.
+ *
+ * (5) This phase also sets SPECIALIZED flag on type parameters with
* `@specialized` annotation. We put this logic here because the
* flag must be set before pickling.
*
- * @author Martin Odersky
- * @version 1.0
+ * It also checks that:
+ *
+ * (1) Symbols accessed from super are not abstract, or are overridden by
+ * an abstract override.
+ *
+ * (2) If a symbol accessed accessed from super is defined in a real class (not a trait),
+ * there are no abstract members which override this member in Java's rules
+ * (see SI-4989; such an access would lead to illegal bytecode)
+ *
+ * (3) Super calls do not go to some synthetic members of Any (see isDisallowed)
+ *
+ * (4) Super calls do not go to synthetic field accessors
+ *
+ * (5) A class and its companion object do not both define a class or module with the
+ * same name.
+ *
+ * TODO: Rename phase to "Accessors" because it handles more than just super accessors
*/
abstract class SuperAccessors extends transform.Transform with transform.TypingTransformers {
import global._
@@ -98,7 +124,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
if (other == NoSymbol)
other = linked.info.decl(sym.name.toTermName).filter(_.isModule)
if (other != NoSymbol)
- unit.error(sym.pos, "name clash: "+sym.owner+" defines "+sym+
+ reporter.error(sym.pos, "name clash: "+sym.owner+" defines "+sym+
"\nand its companion "+sym.owner.companionModule+" also defines "+
other)
}
@@ -113,14 +139,14 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
val member = sym.overridingSymbol(clazz)
if (mix != tpnme.EMPTY || member == NoSymbol ||
!(member.isAbstractOverride && member.isIncompleteIn(clazz)))
- unit.error(sel.pos, ""+sym.fullLocationString+" is accessed from super. It may not be abstract "+
+ reporter.error(sel.pos, ""+sym.fullLocationString+" is accessed from super. It may not be abstract "+
"unless it is overridden by a member declared `abstract' and `override'")
} else if (mix == tpnme.EMPTY && !sym.owner.isTrait){
// SI-4989 Check if an intermediate class between `clazz` and `sym.owner` redeclares the method as abstract.
val intermediateClasses = clazz.info.baseClasses.tail.takeWhile(_ != sym.owner)
intermediateClasses.map(sym.overridingSymbol).find(s => s.isDeferred && !s.isAbstractOverride && !s.owner.isTrait).foreach {
absSym =>
- unit.error(sel.pos, s"${sym.fullLocationString} cannot be directly accessed from ${clazz} because ${absSym.owner} redeclares it as abstract")
+ reporter.error(sel.pos, s"${sym.fullLocationString} cannot be directly accessed from ${clazz} because ${absSym.owner} redeclares it as abstract")
}
}
@@ -226,7 +252,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
qual.symbol.ancestors foreach { parent =>
parent.info.decls filterNot (x => x.isPrivate || x.isLocalToThis) foreach { m2 =>
if (sym.name == m2.name && m2.isGetter && m2.accessed.isMutable) {
- unit.warning(sel.pos,
+ reporter.warning(sel.pos,
sym.accessString + " " + sym.fullLocationString + " shadows mutable " + m2.name
+ " inherited from " + m2.owner + ". Changes to " + m2.name + " will not be visible within "
+ sym.owner + " - you may want to give them distinct names.")
@@ -284,9 +310,9 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
case Super(_, mix) =>
if (sym.isValue && !sym.isMethod || sym.hasAccessorFlag) {
if (!settings.overrideVars)
- unit.error(tree.pos, "super may be not be used on " + sym.accessedOrSelf)
+ reporter.error(tree.pos, "super may be not be used on " + sym.accessedOrSelf)
} else if (isDisallowed(sym)) {
- unit.error(tree.pos, "super not allowed here: use this." + name.decode + " instead")
+ reporter.error(tree.pos, "super not allowed here: use this." + name.decode + " instead")
}
transformSuperSelect(sel)
diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
index a2f52e1905..399a4ca8d5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
@@ -17,7 +17,7 @@ abstract class TreeCheckers extends Analyzer {
override protected def onTreeCheckerError(pos: Position, msg: String) {
if (settings.fatalWarnings)
- currentUnit.warning(pos, "\n** Error during internal checking:\n" + msg)
+ reporter.warning(pos, "\n** Error during internal checking:\n" + msg)
}
case class DiffResult[T](lost: List[T], gained: List[T]) {
@@ -170,7 +170,7 @@ abstract class TreeCheckers extends Analyzer {
)
- def errorFn(pos: Position, msg: Any): Unit = currentUnit.warning(pos, "[check: %s] %s".format(phase.prev, msg))
+ def errorFn(pos: Position, msg: Any): Unit = reporter.warning(pos, "[check: %s] %s".format(phase.prev, msg))
def errorFn(msg: Any): Unit = errorFn(NoPosition, msg)
def informFn(msg: Any) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index 60346e7be1..7440f69e93 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -41,9 +41,9 @@ trait TypeDiagnostics {
* indicate that the restriction may be lifted in the future.
*/
def restrictionWarning(pos: Position, unit: CompilationUnit, msg: String): Unit =
- unit.warning(pos, "Implementation restriction: " + msg)
+ reporter.warning(pos, "Implementation restriction: " + msg)
def restrictionError(pos: Position, unit: CompilationUnit, msg: String): Unit =
- unit.error(pos, "Implementation restriction: " + msg)
+ reporter.error(pos, "Implementation restriction: " + msg)
/** A map of Positions to addendums - if an error involves a position in
* the map, the addendum should also be printed.
@@ -435,12 +435,8 @@ trait TypeDiagnostics {
trait TyperDiagnostics {
self: Typer =>
- private def contextError(context0: Analyzer#Context, pos: Position, msg: String) = context0.error(pos, msg)
- private def contextError(context0: Analyzer#Context, pos: Position, err: Throwable) = context0.error(pos, err)
- private def contextWarning(pos: Position, msg: String) = context.unit.warning(pos, msg)
-
def permanentlyHiddenWarning(pos: Position, hidden: Name, defn: Symbol) =
- contextWarning(pos, "imported `%s' is permanently hidden by definition of %s".format(hidden, defn.fullLocationString))
+ context.warning(pos, "imported `%s' is permanently hidden by definition of %s".format(hidden, defn.fullLocationString))
object checkUnused {
val ignoreNames = Set[TermName]("readResolve", "readObject", "writeObject", "writeReplace")
@@ -542,15 +538,15 @@ trait TypeDiagnostics {
else if (sym.isModule) "object"
else "term"
)
- unit.warning(pos, s"$why $what in ${sym.owner} is never used")
+ reporter.warning(pos, s"$why $what in ${sym.owner} is never used")
}
p.unsetVars foreach { v =>
- unit.warning(v.pos, s"local var ${v.name} in ${v.owner} is never set - it could be a val")
+ reporter.warning(v.pos, s"local var ${v.name} in ${v.owner} is never set - it could be a val")
}
p.unusedTypes foreach { t =>
val sym = t.symbol
val why = if (sym.isPrivate) "private" else "local"
- unit.warning(t.pos, s"$why ${sym.fullLocationString} is never used")
+ reporter.warning(t.pos, s"$why ${sym.fullLocationString} is never used")
}
}
}
@@ -627,13 +623,13 @@ trait TypeDiagnostics {
case Import(expr, _) => expr.pos
case _ => ex.pos
}
- contextError(context0, pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage())
+ context0.error(pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage())
if (sym == ObjectClass)
throw new FatalError("cannot redefine root "+sym)
}
case _ =>
- contextError(context0, ex.pos, ex)
+ context0.error(ex.pos, ex)
}
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index bf98c0e3dc..65f11a360e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -746,21 +746,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (!OK) {
val Some(AnnotationInfo(_, List(Literal(Constant(featureDesc: String)), Literal(Constant(required: Boolean))), _)) =
featureTrait getAnnotation LanguageFeatureAnnot
- val req = if (required) "needs to" else "should"
- val fqname = "scala.language." + featureName
- val explain = (
- if (currentRun.reportedFeature contains featureTrait) "" else
- s"""|
- |This can be achieved by adding the import clause 'import $fqname'
- |or by setting the compiler option -language:$featureName.
- |See the Scala docs for value $fqname for a discussion
- |why the feature $req be explicitly enabled.""".stripMargin
- )
- currentRun.reportedFeature += featureTrait
-
- val msg = s"$featureDesc $req be enabled\nby making the implicit value $fqname visible.$explain" replace ("#", construct)
- if (required) unit.error(pos, msg)
- else currentRun.featureWarnings.warn(pos, msg)
+ context.featureWarning(pos, featureName, featureDesc, featureTrait, construct, required)
}
OK
}
@@ -955,10 +941,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
def adaptConstant(value: Constant): Tree = {
val sym = tree.symbol
- if (sym != null && sym.isDeprecated) {
- val msg = sym.toString + sym.locationString + " is deprecated: " + sym.deprecationMessage.getOrElse("")
- unit.deprecationWarning(tree.pos, msg)
- }
+ if (sym != null && sym.isDeprecated)
+ context.deprecationWarning(tree.pos, sym)
+
treeCopy.Literal(tree, value)
}
@@ -1066,7 +1051,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case coercion =>
def msg = "inferred view from " + tree.tpe + " to " + pt + " = " + coercion + ":" + coercion.tpe
if (settings.logImplicitConv)
- unit.echo(tree.pos, msg)
+ context.echo(tree.pos, msg)
debuglog(msg)
val silentContext = context.makeImplicit(context.ambiguousErrors)
@@ -1226,7 +1211,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case EmptyTree => qual
case coercion =>
if (settings.logImplicitConv)
- unit.echo(qual.pos,
+ context.echo(qual.pos,
"applied implicit conversion from %s to %s = %s".format(
qual.tpe, searchTemplate, coercion.symbol.defString))
@@ -1291,7 +1276,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
private def validateNoCaseAncestor(clazz: Symbol) = {
if (!phase.erasedTypes) {
for (ancestor <- clazz.ancestors find (_.isCase)) {
- unit.error(clazz.pos, (
+ context.error(clazz.pos, (
"case %s has case ancestor %s, but case-to-case inheritance is prohibited."+
" To overcome this limitation, use extractors to pattern match on non-leaf nodes."
).format(clazz, ancestor.fullName))
@@ -1308,7 +1293,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val isValueClass = !clazz.isTrait
def where = if (isValueClass) "value class" else "universal trait extending from class Any"
def implRestriction(tree: Tree, what: String) =
- unit.error(tree.pos, s"implementation restriction: $what is not allowed in $where" +
+ context.error(tree.pos, s"implementation restriction: $what is not allowed in $where" +
"\nThis restriction is planned to be removed in subsequent releases.")
/**
* Deeply traverses the tree in search of constructs that are not allowed
@@ -1337,7 +1322,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
}
for (stat <- body) {
- def notAllowed(what: String) = unit.error(stat.pos, s"$what is not allowed in $where")
+ def notAllowed(what: String) = context.error(stat.pos, s"$what is not allowed in $where")
stat match {
// see https://issues.scala-lang.org/browse/SI-6444
// see https://issues.scala-lang.org/browse/SI-6463
@@ -1365,9 +1350,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
private def validateDerivedValueClass(clazz: Symbol, body: List[Tree]) = {
if (clazz.isTrait)
- unit.error(clazz.pos, "only classes (not traits) are allowed to extend AnyVal")
+ context.error(clazz.pos, "only classes (not traits) are allowed to extend AnyVal")
if (!clazz.isStatic)
- unit.error(clazz.pos, "value class may not be a "+
+ context.error(clazz.pos, "value class may not be a "+
(if (clazz.owner.isTerm) "local class" else "member of another class"))
if (!clazz.isPrimitiveValueClass) {
clazz.primaryConstructor.paramss match {
@@ -1375,26 +1360,26 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val decls = clazz.info.decls
val paramAccessor = clazz.constrParamAccessors.head
if (paramAccessor.isMutable)
- unit.error(paramAccessor.pos, "value class parameter must not be a var")
+ context.error(paramAccessor.pos, "value class parameter must not be a var")
val accessor = decls.toList.find(x => x.isMethod && x.accessedOrSelf == paramAccessor)
accessor match {
case None =>
- unit.error(paramAccessor.pos, "value class parameter must be a val and not be private[this]")
+ context.error(paramAccessor.pos, "value class parameter must be a val and not be private[this]")
case Some(acc) if acc.isProtectedLocal =>
- unit.error(paramAccessor.pos, "value class parameter must not be protected[this]")
+ context.error(paramAccessor.pos, "value class parameter must not be protected[this]")
case Some(acc) =>
if (acc.tpe.typeSymbol.isDerivedValueClass)
- unit.error(acc.pos, "value class may not wrap another user-defined value class")
+ context.error(acc.pos, "value class may not wrap another user-defined value class")
checkEphemeral(clazz, body filterNot (stat => stat.symbol != null && stat.symbol.accessedOrSelf == paramAccessor))
}
case _ =>
- unit.error(clazz.pos, "value class needs to have exactly one val parameter")
+ context.error(clazz.pos, "value class needs to have exactly one val parameter")
}
}
for (tparam <- clazz.typeParams)
if (tparam hasAnnotation definitions.SpecializedClass)
- unit.error(tparam.pos, "type parameter of value class may not be specialized")
+ context.error(tparam.pos, "type parameter of value class may not be specialized")
}
/** Typechecks a parent type reference.
@@ -1687,10 +1672,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val sameSourceFile = context.unit.source.file == psym.sourceFile
- if (psym.hasDeprecatedInheritanceAnnotation && !sameSourceFile) {
+ if (!isPastTyper && psym.hasDeprecatedInheritanceAnnotation && !sameSourceFile) {
val suffix = psym.deprecatedInheritanceMessage map (": " + _) getOrElse ""
val msg = s"inheritance from ${psym.fullLocationString} is deprecated$suffix"
- unit.deprecationWarning(parent.pos, msg)
+ context.deprecationWarning(parent.pos, psym, msg)
}
if (psym.isSealed && !phase.erasedTypes)
@@ -1757,7 +1742,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if ((clazz isNonBottomSubClass ClassfileAnnotationClass) && (clazz != ClassfileAnnotationClass)) {
if (!clazz.owner.isPackageClass)
- unit.error(clazz.pos, "inner classes cannot be classfile annotations")
+ context.error(clazz.pos, "inner classes cannot be classfile annotations")
else restrictionWarning(cdef.pos, unit,
"""|subclassing Classfile does not
|make your annotation visible at runtime. If that is what
@@ -1812,7 +1797,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
private def ensurePredefParentsAreInSameSourceFile(template: Template) = {
val parentSyms = template.parents map (_.symbol) filterNot (_ == AnyRefClass)
if (parentSyms exists (_.associatedFile != PredefModule.associatedFile))
- unit.error(template.pos, s"All parents of Predef must be defined in ${PredefModule.associatedFile}.")
+ context.error(template.pos, s"All parents of Predef must be defined in ${PredefModule.associatedFile}.")
}
/** In order to override this in the TreeCheckers Typer so synthetics aren't re-added
* all the time, it is exposed here the module/class typing methods go through it.
@@ -1883,7 +1868,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
ConstrArgsInParentOfTraitError(parents1.head, clazz)
if ((clazz isSubClass ClassfileAnnotationClass) && !clazz.isTopLevel)
- unit.error(clazz.pos, "inner classes cannot be classfile annotations")
+ context.error(clazz.pos, "inner classes cannot be classfile annotations")
if (!phase.erasedTypes && !clazz.info.resultType.isError) // @S: prevent crash for duplicated type members
checkFinitary(clazz.info.resultType.asInstanceOf[ClassInfoType])
@@ -1911,7 +1896,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (clazz.isTrait) {
for (decl <- clazz.info.decls if decl.isTerm && decl.isEarlyInitialized) {
- unit.warning(decl.pos, "Implementation restriction: early definitions in traits are not initialized before the super class is initialized.")
+ context.warning(decl.pos, "Implementation restriction: early definitions in traits are not initialized before the super class is initialized.")
}
}
@@ -2099,7 +2084,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case xs => xs.map(_.nameString).mkString(" (of ", " with ", ")")
}
def fail(pos: Position, msg: String): Boolean = {
- unit.error(pos, msg)
+ context.error(pos, msg)
false
}
/* Have to examine all parameters in all lists.
@@ -3022,7 +3007,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
|| (looker.hasAccessorFlag && !accessed.hasAccessorFlag && accessed.isPrivate)
)
- def checkNoDoubleDefs(stats: List[Tree]): Unit = {
+ def checkNoDoubleDefs: Unit = {
val scope = if (inBlock) context.scope else context.owner.info.decls
var e = scope.elems
while ((e ne null) && e.owner == scope) {
@@ -3057,8 +3042,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// the corresponding synthetics to the package class, only to the package object class.
def shouldAdd(sym: Symbol) =
inBlock || !context.isInPackageObject(sym, context.owner)
- for (sym <- scope if shouldAdd(sym))
- for (tree <- context.unit.synthetics get sym) {
+ for (sym <- scope)
+ for (tree <- context.unit.synthetics get sym if shouldAdd(sym)) { // OPT: shouldAdd is usually true. Call it here, rather than in the outer loop
newStats += typedStat(tree) // might add even more synthetics to the scope
context.unit.synthetics -= sym
}
@@ -3104,7 +3089,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val stats1 = stats mapConserve typedStat
if (phase.erasedTypes) stats1
else {
- checkNoDoubleDefs(stats1)
+ // As packages are open, it doesn't make sense to check double definitions here. Furthermore,
+ // it is expensive if the package is large. Instead, such double defininitions are checked in `Namers.enterInScope`
+ if (!context.owner.isPackageClass)
+ checkNoDoubleDefs
addSynthetics(stats1)
}
}
@@ -3260,25 +3248,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
@@ -3677,7 +3665,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
if (annType.typeSymbol == DeprecatedAttr && argss.flatten.size < 2)
- unit.deprecationWarning(ann.pos, "@deprecated now takes two arguments; see the scaladoc.")
+ context.deprecationWarning(ann.pos, DeprecatedAttr, "@deprecated now takes two arguments; see the scaladoc.")
if ((typedAnn.tpe == null) || typedAnn.tpe.isErroneous) ErroneousAnnotation
else annInfo(typedAnn)
@@ -4251,7 +4239,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// it is non-Unit) so we have to retype it. Fortunately it won't come up much
// unless the warning is legitimate.
if (typed(expr).tpe.typeSymbol != UnitClass)
- unit.warning(tree.pos, "enclosing method " + name + " has result type Unit: return value discarded")
+ context.warning(tree.pos, "enclosing method " + name + " has result type Unit: return value discarded")
}
val res = treeCopy.Return(tree, checkDead(expr1)).setSymbol(enclMethod.owner)
val tp = pluginsTypedReturn(NothingTpe, this, res, restpt.tpe)
@@ -4396,7 +4384,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (retry) {
val Select(qual, name) = fun
tryTypedArgs(args, forArgMode(fun, mode)) match {
- case Some(args1) =>
+ case Some(args1) if !args1.exists(arg => arg.exists(_.isErroneous)) =>
val qual1 =
if (!pt.isError) adaptToArguments(qual, name, args1, pt, reportAmbiguous = true, saveErrors = true)
else qual
@@ -4709,10 +4697,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// temporarily use `filter` as an alternative for `withFilter`
def tryWithFilterAndFilter(tree: Select, qual: Tree): Tree = {
- def warn() = unit.deprecationWarning(tree.pos, s"`withFilter' method does not yet exist on ${qual.tpe.widen}, using `filter' method instead")
+ def warn(sym: Symbol) = context.deprecationWarning(tree.pos, sym, s"`withFilter' method does not yet exist on ${qual.tpe.widen}, using `filter' method instead")
silent(_ => typedSelect(tree, qual, nme.withFilter)) orElse { _ =>
silent(_ => typed1(Select(qual, nme.filter) setPos tree.pos, mode, pt)) match {
- case SilentResultValue(res) => warn() ; res
+ case SilentResultValue(res) => warn(res.symbol) ; res
case SilentTypeError(err) => WithFilterError(tree, err)
}
}
@@ -5489,11 +5477,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val commonMessage = "macro defs must have explicitly specified return types"
def reportFailure() = {
ddef.symbol.setFlag(IS_ERROR)
- unit.error(ddef.pos, commonMessage)
+ context.error(ddef.pos, commonMessage)
}
def reportWarning(inferredType: Type) = {
val explanation = s"inference of $inferredType from macro impl's c.Expr[$inferredType] is deprecated and is going to stop working in 2.12"
- unit.deprecationWarning(ddef.pos, s"$commonMessage ($explanation)")
+ context.deprecationWarning(ddef.pos, ddef.symbol, s"$commonMessage ($explanation)")
}
computeMacroDefTypeFromMacroImplRef(ddef, rhs1) match {
case ErrorType => ErrorType
diff --git a/src/compiler/scala/tools/reflect/FormatInterpolator.scala b/src/compiler/scala/tools/reflect/FormatInterpolator.scala
index e0f9bb6044..b445f1e2bb 100644
--- a/src/compiler/scala/tools/reflect/FormatInterpolator.scala
+++ b/src/compiler/scala/tools/reflect/FormatInterpolator.scala
@@ -117,7 +117,7 @@ abstract class FormatInterpolator {
c.error(errPoint, msg("unsupported"))
s0
} else {
- c.enclosingUnit.deprecationWarning(errPoint, msg("deprecated"))
+ currentRun.reporting.deprecationWarning(errPoint, msg("deprecated"))
try StringContext.treatEscapes(s0) catch escapeHatch
}
}
@@ -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 3b12086cc7..923297bafb 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -141,6 +141,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
val run = new Run
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
reporter.reset()
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/interactive/scala/tools/nsc/interactive/Main.scala b/src/interactive/scala/tools/nsc/interactive/Main.scala
index c838606f02..7796c65670 100644
--- a/src/interactive/scala/tools/nsc/interactive/Main.scala
+++ b/src/interactive/scala/tools/nsc/interactive/Main.scala
@@ -12,7 +12,7 @@ package interactive
*/
object Main extends nsc.MainClass {
override def processSettingsHook(): Boolean = {
- if (this.settings.Yidedebug) {
+ def run(): Unit = {
this.settings.Xprintpos.value = true
this.settings.Yrangepos.value = true
val compiler = new interactive.Global(this.settings, this.reporter)
@@ -27,8 +27,9 @@ object Main extends nsc.MainClass {
case None => reporter.reset() // Causes other compiler errors to be ignored
}
askShutdown
- false
}
- else true
+ super.processSettingsHook() && (
+ if (this.settings.Yidedebug) { run() ; false } else true
+ )
}
}
diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala
index cd928a2b61..c0468e8b02 100644
--- a/src/library/scala/StringContext.scala
+++ b/src/library/scala/StringContext.scala
@@ -8,6 +8,9 @@
package scala
+import java.lang.{ StringBuilder => JLSBuilder }
+import scala.annotation.tailrec
+
/** This class provides the basic mechanism to do String Interpolation.
* String Interpolation allows users
* to embed variable references directly in *processed* string literals.
@@ -41,7 +44,7 @@ package scala
* val x: JSONObject = json"{ a: $a }"
* }}}
*
- * Here the `JsonHelper` extenion class implicitly adds the `json` method to
+ * Here the `JsonHelper` extension class implicitly adds the `json` method to
* `StringContext` which can be used for `json` string literals.
*
* @since 2.10.0
@@ -118,7 +121,7 @@ case class StringContext(parts: String*) {
checkLengths(args)
val pi = parts.iterator
val ai = args.iterator
- val bldr = new java.lang.StringBuilder(process(pi.next()))
+ val bldr = new JLSBuilder(process(pi.next()))
while (ai.hasNext) {
bldr append ai.next
bldr append process(pi.next())
@@ -186,60 +189,60 @@ object StringContext {
*/
def treatEscapes(str: String): String = treatEscapes0(str, strict = false)
+ /** Treats escapes, but disallows octal escape sequences. */
def processEscapes(str: String): String = treatEscapes0(str, strict = true)
private def treatEscapes0(str: String, strict: Boolean): String = {
- lazy val bldr = new java.lang.StringBuilder
val len = str.length
- var start = 0
- var cur = 0
- var idx = 0
- def output(ch: Char) = {
- bldr.append(str, start, cur)
- bldr append ch
- start = idx
- }
- while (idx < len) {
- cur = idx
- if (str(idx) == '\\') {
- idx += 1
- if (idx >= len) throw new InvalidEscapeException(str, cur)
- if ('0' <= str(idx) && str(idx) <= '7') {
- if (strict) throw new InvalidEscapeException(str, cur)
- val leadch = str(idx)
- var oct = leadch - '0'
- idx += 1
- if (idx < len && '0' <= str(idx) && str(idx) <= '7') {
- oct = oct * 8 + str(idx) - '0'
- idx += 1
- if (idx < len && leadch <= '3' && '0' <= str(idx) && str(idx) <= '7') {
- oct = oct * 8 + str(idx) - '0'
+ // replace escapes with given first escape
+ def replace(first: Int): String = {
+ val b = new JLSBuilder
+ // append replacement starting at index `i`, with `next` backslash
+ @tailrec def loop(i: Int, next: Int): String = {
+ if (next >= 0) {
+ //require(str(next) == '\\')
+ if (next > i) b.append(str, i, next)
+ var idx = next + 1
+ if (idx >= len) throw new InvalidEscapeException(str, next)
+ val c = str(idx) match {
+ case 'b' => '\b'
+ case 't' => '\t'
+ case 'n' => '\n'
+ case 'f' => '\f'
+ case 'r' => '\r'
+ case '"' => '"'
+ case '\'' => '\''
+ case '\\' => '\\'
+ case o if '0' <= o && o <= '7' =>
+ if (strict) throw new InvalidEscapeException(str, next)
+ val leadch = str(idx)
+ var oct = leadch - '0'
idx += 1
- }
+ if (idx < len && '0' <= str(idx) && str(idx) <= '7') {
+ oct = oct * 8 + str(idx) - '0'
+ idx += 1
+ if (idx < len && leadch <= '3' && '0' <= str(idx) && str(idx) <= '7') {
+ oct = oct * 8 + str(idx) - '0'
+ idx += 1
+ }
+ }
+ idx -= 1 // retreat
+ oct.toChar
+ case _ => throw new InvalidEscapeException(str, next)
}
- output(oct.toChar)
+ idx += 1 // advance
+ b append c
+ loop(idx, str.indexOf('\\', idx))
} else {
- val ch = str(idx)
- idx += 1
- output {
- ch match {
- case 'b' => '\b'
- case 't' => '\t'
- case 'n' => '\n'
- case 'f' => '\f'
- case 'r' => '\r'
- case '\"' => '\"'
- case '\'' => '\''
- case '\\' => '\\'
- case _ => throw new InvalidEscapeException(str, cur)
- }
- }
+ if (i < len) b.append(str, i, len)
+ b.toString
}
- } else {
- idx += 1
}
+ loop(0, first)
+ }
+ str indexOf '\\' match {
+ case -1 => str
+ case i => replace(i)
}
- if (start == 0) str
- else bldr.append(str, start, idx).toString
}
}
diff --git a/src/library/scala/collection/IndexedSeqOptimized.scala b/src/library/scala/collection/IndexedSeqOptimized.scala
index ade04e4de8..42cb37aa24 100755
--- a/src/library/scala/collection/IndexedSeqOptimized.scala
+++ b/src/library/scala/collection/IndexedSeqOptimized.scala
@@ -206,7 +206,7 @@ trait IndexedSeqOptimized[+A, +Repr] extends Any with IndexedSeqLike[A, Repr] {
override /*SeqLike*/
def lastIndexWhere(p: A => Boolean, end: Int): Int = {
- var i = end
+ var i = math.min(end, length - 1)
while (i >= 0 && !p(this(i))) i -= 1
i
}
diff --git a/src/library/scala/collection/Iterable.scala b/src/library/scala/collection/Iterable.scala
index a5ab8efd5c..afbffd36c6 100644
--- a/src/library/scala/collection/Iterable.scala
+++ b/src/library/scala/collection/Iterable.scala
@@ -38,7 +38,7 @@ trait Iterable[+A] extends Traversable[A]
}
/** $factoryInfo
- * The current default implementation of a $Coll is a `Vector`.
+ * The current default implementation of a $Coll is a `List`.
* @define coll iterable collection
* @define Coll `Iterable`
*/
diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala
index 1b496383a3..f6f46e158f 100644
--- a/src/library/scala/collection/Iterator.scala
+++ b/src/library/scala/collection/Iterator.scala
@@ -922,11 +922,16 @@ trait Iterator[+A] extends TraversableOnce[A] {
/** For reasons which remain to be determined, calling
* self.take(n).toSeq cause an infinite loop, so we have
* a slight variation on take for local usage.
+ * NB: self.take.toSeq is slice.toStream, lazily built on self,
+ * so a subsequent self.hasNext would not test self after the
+ * group was consumed.
*/
private def takeDestructively(size: Int): Seq[A] = {
val buf = new ArrayBuffer[A]
var i = 0
- while (self.hasNext && i < size) {
+ // The order of terms in the following condition is important
+ // here as self.hasNext could be blocking
+ while (i < size && self.hasNext) {
buf += self.next
i += 1
}
@@ -943,12 +948,10 @@ trait Iterator[+A] extends TraversableOnce[A] {
// so the rest of the code can be oblivious
val xs: Seq[B] = {
val res = takeDestructively(count)
- // extra checks so we don't calculate length unless there's reason
- if (pad.isDefined && !self.hasNext) {
- val shortBy = count - res.length
- if (shortBy > 0) res ++ padding(shortBy) else res
- }
- else res
+ // was: extra checks so we don't calculate length unless there's reason
+ // but since we took the group eagerly, just use the fast length
+ val shortBy = count - res.length
+ if (shortBy > 0 && pad.isDefined) res ++ padding(shortBy) else res
}
lazy val len = xs.length
lazy val incomplete = len < count
diff --git a/src/library/scala/collection/Searching.scala b/src/library/scala/collection/Searching.scala
index fec4bbf502..b68124b3f8 100644
--- a/src/library/scala/collection/Searching.scala
+++ b/src/library/scala/collection/Searching.scala
@@ -54,7 +54,7 @@ object Searching {
*/
final def search[B >: A](elem: B)(implicit ord: Ordering[B]): SearchResult =
coll match {
- case _: IndexedSeq[A] => binarySearch(elem, -1, coll.length)(ord)
+ case _: IndexedSeq[A] => binarySearch(elem, 0, coll.length)(ord)
case _ => linearSearch(coll.view, elem, 0)(ord)
}
@@ -81,18 +81,18 @@ object Searching {
final def search[B >: A](elem: B, from: Int, to: Int)
(implicit ord: Ordering[B]): SearchResult =
coll match {
- case _: IndexedSeq[A] => binarySearch(elem, from-1, to)(ord)
+ case _: IndexedSeq[A] => binarySearch(elem, from, to)(ord)
case _ => linearSearch(coll.view(from, to), elem, from)(ord)
}
@tailrec
private def binarySearch[B >: A](elem: B, from: Int, to: Int)
(implicit ord: Ordering[B]): SearchResult = {
- if ((to-from) == 1) InsertionPoint(from) else {
- val idx = from+(to-from)/2
+ if (to == from) InsertionPoint(from) else {
+ val idx = from+(to-from-1)/2
math.signum(ord.compare(elem, coll(idx))) match {
case -1 => binarySearch(elem, from, idx)(ord)
- case 1 => binarySearch(elem, idx, to)(ord)
+ case 1 => binarySearch(elem, idx + 1, to)(ord)
case _ => Found(idx)
}
}
@@ -105,7 +105,7 @@ object Searching {
while (it.hasNext) {
val cur = it.next()
if (ord.equiv(elem, cur)) return Found(idx)
- else if (ord.lt(elem, cur)) return InsertionPoint(idx-1)
+ else if (ord.lt(elem, cur)) return InsertionPoint(idx)
idx += 1
}
InsertionPoint(idx)
diff --git a/src/library/scala/collection/SetLike.scala b/src/library/scala/collection/SetLike.scala
index 0c5c7e0b29..3e549f72cd 100644
--- a/src/library/scala/collection/SetLike.scala
+++ b/src/library/scala/collection/SetLike.scala
@@ -17,6 +17,9 @@ import parallel.ParSet
/** A template trait for sets.
*
* $setNote
+ * '''Implementation note:'''
+ * This trait provides most of the operations of a `Set` independently of its representation.
+ * It is typically inherited by concrete implementations of sets.
* $setTags
* @since 2.8
*
@@ -24,10 +27,6 @@ import parallel.ParSet
*
* A set is a collection that contains no duplicate elements.
*
- * '''Implementation note:'''
- * This trait provides most of the operations of a `Set` independently of its representation.
- * It is typically inherited by concrete implementations of sets.
- *
* To implement a concrete set, you need to provide implementations of the
* following methods:
* {{{
diff --git a/src/library/scala/collection/Traversable.scala b/src/library/scala/collection/Traversable.scala
index b53724c568..a35750a35f 100644
--- a/src/library/scala/collection/Traversable.scala
+++ b/src/library/scala/collection/Traversable.scala
@@ -87,7 +87,7 @@ trait Traversable[+A] extends TraversableLike[A, Traversable[A]]
}
/** $factoryInfo
- * The current default implementation of a $Coll is a `Vector`.
+ * The current default implementation of a $Coll is a `List`.
*/
object Traversable extends TraversableFactory[Traversable] { self =>
diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala
index b60ea86ab0..d3a7db6968 100644
--- a/src/library/scala/collection/TraversableLike.scala
+++ b/src/library/scala/collection/TraversableLike.scala
@@ -345,8 +345,8 @@ trait TraversableLike[+A, +Repr] extends Any
* $mayNotTerminateInf
*
* @param p the predicate used to test elements.
- * @return `true` if the given predicate `p` holds for all elements
- * of this $coll, otherwise `false`.
+ * @return `true` if this $coll is empty, otherwise `true` if the given predicate `p`
+ * holds for all elements of this $coll, otherwise `false`.
*/
def forall(p: A => Boolean): Boolean = {
var result = true
@@ -362,8 +362,8 @@ trait TraversableLike[+A, +Repr] extends Any
* $mayNotTerminateInf
*
* @param p the predicate used to test elements.
- * @return `true` if the given predicate `p` holds for some of the
- * elements of this $coll, otherwise `false`.
+ * @return `false` if this $coll is empty, otherwise `true` if the given predicate `p`
+ * holds for some of the elements of this $coll, otherwise `false`
*/
def exists(p: A => Boolean): Boolean = {
var result = false
diff --git a/src/library/scala/collection/TraversableOnce.scala b/src/library/scala/collection/TraversableOnce.scala
index 072fd3da44..a8c4e047ab 100644
--- a/src/library/scala/collection/TraversableOnce.scala
+++ b/src/library/scala/collection/TraversableOnce.scala
@@ -85,10 +85,9 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] {
*/
def seq: TraversableOnce[A]
- /** Presently these are abstract because the Traversable versions use
- * breakable/break, and I wasn't sure enough of how that's supposed to
- * function to consolidate them with the Iterator versions.
- */
+ // Presently these are abstract because the Traversable versions use
+ // breakable/break, and I wasn't sure enough of how that's supposed to
+ // function to consolidate them with the Iterator versions.
def forall(p: A => Boolean): Boolean
def exists(p: A => Boolean): Boolean
def find(p: A => Boolean): Option[A]
diff --git a/src/library/scala/collection/convert/DecorateAsScala.scala b/src/library/scala/collection/convert/DecorateAsScala.scala
index c724831c54..5448f5f91c 100644
--- a/src/library/scala/collection/convert/DecorateAsScala.scala
+++ b/src/library/scala/collection/convert/DecorateAsScala.scala
@@ -135,6 +135,12 @@ trait DecorateAsScala {
* If the Java `Map` was previously obtained from an implicit or explicit
* call of `asMap(scala.collection.mutable.Map)` then the original
* Scala `Map` will be returned.
+ *
+ * If the wrapped map is synchronized (e.g. from `java.util.Collections.synchronizedMap`),
+ * it is your responsibility to wrap all
+ * non-atomic operations with `underlying.synchronized`.
+ * This includes `get`, as `java.util.Map`'s API does not allow for an
+ * atomic `get` when `null` values may be present.
*
* @param m The `Map` to be converted.
* @return An object with an `asScala` method that returns a Scala mutable
diff --git a/src/library/scala/collection/convert/WrapAsScala.scala b/src/library/scala/collection/convert/WrapAsScala.scala
index d4ab451b0d..ab151a6778 100644
--- a/src/library/scala/collection/convert/WrapAsScala.scala
+++ b/src/library/scala/collection/convert/WrapAsScala.scala
@@ -133,7 +133,13 @@ trait WrapAsScala {
* If the Java `Map` was previously obtained from an implicit or
* explicit call of `mapAsScalaMap(scala.collection.mutable.Map)` then
* the original Scala Map will be returned.
- *
+ *
+ * If the wrapped map is synchronized (e.g. from `java.util.Collections.synchronizedMap`),
+ * it is your responsibility to wrap all
+ * non-atomic operations with `underlying.synchronized`.
+ * This includes `get`, as `java.util.Map`'s API does not allow for an
+ * atomic `get` when `null` values may be present.
+ *
* @param m The Map to be converted.
* @return A Scala mutable Map view of the argument.
*/
diff --git a/src/library/scala/collection/convert/Wrappers.scala b/src/library/scala/collection/convert/Wrappers.scala
index 7d1d6b3781..9f9732c62f 100644
--- a/src/library/scala/collection/convert/Wrappers.scala
+++ b/src/library/scala/collection/convert/Wrappers.scala
@@ -288,6 +288,13 @@ private[collection] trait Wrappers {
override def empty: Repr = null.asInstanceOf[Repr]
}
+ /** Wraps a Java map as a Scala one. If the map is to support concurrent access,
+ * use [[JConcurrentMapWrapper]] instead. If the wrapped map is synchronized
+ * (e.g. from `java.util.Collections.synchronizedMap`), it is your responsibility
+ * to wrap all non-atomic operations with `underlying.synchronized`.
+ * This includes `get`, as `java.util.Map`'s API does not allow for an
+ * atomic `get` when `null` values may be present.
+ */
case class JMapWrapper[A, B](underlying : ju.Map[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JMapWrapper[A, B]] {
override def empty = JMapWrapper(new ju.HashMap[A, B])
}
@@ -314,6 +321,10 @@ private[collection] trait Wrappers {
def replace(k: A, oldval: B, newval: B) = underlying.replace(k, oldval, newval)
}
+ /** Wraps a concurrent Java map as a Scala one. Single-element concurrent
+ * access is supported; multi-element operations such as maps and filters
+ * are not guaranteed to be atomic.
+ */
case class JConcurrentMapWrapper[A, B](underlying: juc.ConcurrentMap[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]] with concurrent.Map[A, B] {
override def get(k: A) = {
val v = underlying get k
diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala
index 726937efd9..e4b7371ed4 100644
--- a/src/library/scala/collection/immutable/HashSet.scala
+++ b/src/library/scala/collection/immutable/HashSet.scala
@@ -162,6 +162,13 @@ class HashSet[A] extends AbstractSet[A]
def - (e: A): HashSet[A] =
nullToEmpty(removed0(e, computeHash(e), 0))
+ /** Returns this $coll as an immutable set.
+ *
+ * A new set will not be built; lazy collections will stay lazy.
+ */
+ @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0")
+ override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]]
+
override def filter(p: A => Boolean) = {
val buffer = new Array[HashSet[A]](bufferSize(size))
nullToEmpty(filter0(p, false, 0, buffer, 0))
diff --git a/src/library/scala/collection/immutable/Iterable.scala b/src/library/scala/collection/immutable/Iterable.scala
index 6e4eb1e45f..df322396d0 100644
--- a/src/library/scala/collection/immutable/Iterable.scala
+++ b/src/library/scala/collection/immutable/Iterable.scala
@@ -35,6 +35,7 @@ trait Iterable[+A] extends Traversable[A]
}
/** $factoryInfo
+ * The current default implementation of a $Coll is a `List`.
* @define Coll `immutable.Iterable`
* @define coll immutable iterable collection
*/
diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala
index 930e13a9d3..aa9dec2761 100644
--- a/src/library/scala/collection/immutable/List.scala
+++ b/src/library/scala/collection/immutable/List.scala
@@ -190,11 +190,9 @@ sealed abstract class List[+A] extends AbstractSeq[A]
// Overridden methods from IterableLike and SeqLike or overloaded variants of such methods
- override def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That = {
- val b = bf(this)
- if (b.isInstanceOf[ListBuffer[_]]) (this ::: that.seq.toList).asInstanceOf[That]
+ override def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That =
+ if (bf eq List.ReusableCBF) (this ::: that.seq.toList).asInstanceOf[That]
else super.++(that)
- }
override def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That = bf match {
case _: List.GenericCanBuildFrom[_] => (elem :: this).asInstanceOf[That]
diff --git a/src/library/scala/collection/immutable/ListSet.scala b/src/library/scala/collection/immutable/ListSet.scala
index 1bb07eb02d..89d1a9640e 100644
--- a/src/library/scala/collection/immutable/ListSet.scala
+++ b/src/library/scala/collection/immutable/ListSet.scala
@@ -138,6 +138,13 @@ class ListSet[A] extends AbstractSet[A]
override def stringPrefix = "ListSet"
+ /** Returns this $coll as an immutable set.
+ *
+ * A new set will not be built; lazy collections will stay lazy.
+ */
+ @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0")
+ override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]]
+
/** Represents an entry in the `ListSet`.
*/
protected class Node(override val head: A) extends ListSet[A] with Serializable {
diff --git a/src/library/scala/collection/immutable/Set.scala b/src/library/scala/collection/immutable/Set.scala
index 0fbf7942d4..7725ad9ee3 100644
--- a/src/library/scala/collection/immutable/Set.scala
+++ b/src/library/scala/collection/immutable/Set.scala
@@ -35,12 +35,7 @@ trait Set[A] extends Iterable[A]
override def companion: GenericCompanion[Set] = Set
- /** Returns this $coll as an immutable map.
- *
- * A new map will not be built; lazy collections will stay lazy.
- */
- @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0")
- override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]]
+ override def toSet[B >: A]: Set[B] = to[({type l[a] = immutable.Set[B]})#l] // for bincompat; remove in dev
override def seq: Set[A] = this
protected override def parCombiner = ParSet.newCombiner[A] // if `immutable.SetLike` gets introduced, please move this there!
@@ -62,6 +57,7 @@ object Set extends ImmutableSetFactory[Set] {
def - (elem: Any): Set[Any] = this
def iterator: Iterator[Any] = Iterator.empty
override def foreach[U](f: Any => U): Unit = {}
+ override def toSet[B >: Any]: Set[B] = this.asInstanceOf[Set[B]]
}
private[collection] def emptyInstance: Set[Any] = EmptySet
@@ -92,6 +88,8 @@ object Set extends ImmutableSetFactory[Set] {
if (f(elem1)) Some(elem1)
else None
}
+ @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0")
+ override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]]
}
/** An optimized representation for immutable sets of size 2 */
@@ -123,6 +121,8 @@ object Set extends ImmutableSetFactory[Set] {
else if (f(elem2)) Some(elem2)
else None
}
+ @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0")
+ override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]]
}
/** An optimized representation for immutable sets of size 3 */
@@ -156,6 +156,8 @@ object Set extends ImmutableSetFactory[Set] {
else if (f(elem3)) Some(elem3)
else None
}
+ @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0")
+ override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]]
}
/** An optimized representation for immutable sets of size 4 */
@@ -191,6 +193,8 @@ object Set extends ImmutableSetFactory[Set] {
else if (f(elem4)) Some(elem4)
else None
}
+ @deprecatedOverriding("Immutable sets should do nothing on toSet but return themselves cast as a Set.", "2.11.0")
+ override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]]
}
}
diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala
index 60de147477..d3ff5e8abf 100644
--- a/src/library/scala/collection/immutable/Stream.scala
+++ b/src/library/scala/collection/immutable/Stream.scala
@@ -97,6 +97,14 @@ import scala.language.implicitConversions
* If, on the other hand, there is nothing holding on to the head (e.g. we used
* `def` to define the `Stream`) then once it is no longer being used directly,
* it disappears.
+ *
+ * - Note that some operations, including [[drop]], [[dropWhile]],
+ * [[flatMap]] or [[collect]] may process a large number of intermediate
+ * elements before returning. These necessarily hold onto the head, since
+ * they are methods on `Stream`, and a stream holds its own head. For
+ * computations of this sort where memoization is not desired, use
+ * `Iterator` when possible.
+ *
* {{{
* // For example, let's build the natural numbers and do some silly iteration
* // over them.
diff --git a/src/library/scala/collection/immutable/Traversable.scala b/src/library/scala/collection/immutable/Traversable.scala
index 775d635fae..5fc0607a00 100644
--- a/src/library/scala/collection/immutable/Traversable.scala
+++ b/src/library/scala/collection/immutable/Traversable.scala
@@ -29,7 +29,7 @@ trait Traversable[+A] extends scala.collection.Traversable[A]
}
/** $factoryInfo
- * The current default implementation of a $Coll is a `Vector`.
+ * The current default implementation of a $Coll is a `List`.
* @define coll immutable traversable collection
* @define Coll `immutable.Traversable`
*/
diff --git a/src/library/scala/collection/mutable/AVLTree.scala b/src/library/scala/collection/mutable/AVLTree.scala
index de09bb2040..cc2acb74d4 100644
--- a/src/library/scala/collection/mutable/AVLTree.scala
+++ b/src/library/scala/collection/mutable/AVLTree.scala
@@ -14,8 +14,8 @@ package mutable
* An immutable AVL Tree implementation formerly used by mutable.TreeSet
*
* @author Lucien Pereira
- * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.0")
*/
+@deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.2")
private[mutable] sealed trait AVLTree[+A] extends Serializable {
def balance: Int
diff --git a/src/library/scala/collection/mutable/SetLike.scala b/src/library/scala/collection/mutable/SetLike.scala
index d749167870..a377b03124 100644
--- a/src/library/scala/collection/mutable/SetLike.scala
+++ b/src/library/scala/collection/mutable/SetLike.scala
@@ -16,19 +16,20 @@ import scala.annotation.migration
import parallel.mutable.ParSet
/** A template trait for mutable sets of type `mutable.Set[A]`.
+ *
+ * This trait provides most of the operations of a `mutable.Set` independently of its representation.
+ * It is typically inherited by concrete implementations of sets.
+ *
+ * $setNote
+ *
* @tparam A the type of the elements of the set
* @tparam This the type of the set itself.
*
- * $setnote
- *
* @author Martin Odersky
* @version 2.8
* @since 2.8
*
- * @define setnote
- * @note
- * This trait provides most of the operations of a `mutable.Set` independently of its representation.
- * It is typically inherited by concrete implementations of sets.
+ * @define setNote
*
* To implement a concrete mutable set, you need to provide implementations
* of the following methods:
@@ -36,13 +37,13 @@ import parallel.mutable.ParSet
* def contains(elem: A): Boolean
* def iterator: Iterator[A]
* def += (elem: A): this.type
- * def -= (elem: A): this.type</pre>
+ * def -= (elem: A): this.type
* }}}
* If you wish that methods like `take`,
* `drop`, `filter` return the same kind of set,
* you should also override:
* {{{
- * def empty: This</pre>
+ * def empty: This
* }}}
* It is also good idea to override methods `foreach` and
* `size` for efficiency.
diff --git a/src/library/scala/collection/mutable/UnrolledBuffer.scala b/src/library/scala/collection/mutable/UnrolledBuffer.scala
index 1f89199bdc..693c47d86e 100644
--- a/src/library/scala/collection/mutable/UnrolledBuffer.scala
+++ b/src/library/scala/collection/mutable/UnrolledBuffer.scala
@@ -300,27 +300,33 @@ object UnrolledBuffer extends ClassTagTraversableFactory[UnrolledBuffer] {
if (next eq null) true else false // checks if last node was thrown out
} else false
- @tailrec final def insertAll(idx: Int, t: scala.collection.Traversable[T], buffer: UnrolledBuffer[T]): Unit = if (idx < size) {
- // divide this node at the appropriate position and insert all into head
- // update new next
- val newnextnode = new Unrolled[T](0, new Array(array.length), null, buff)
- Array.copy(array, idx, newnextnode.array, 0, size - idx)
- newnextnode.size = size - idx
- newnextnode.next = next
-
- // update this
- nullout(idx, size)
- size = idx
- next = null
-
- // insert everything from iterable to this
- var curr = this
- for (elem <- t) curr = curr append elem
- curr.next = newnextnode
-
- // try to merge the last node of this with the newnextnode
- if (curr.tryMergeWithNext()) buffer.lastPtr = curr
- } else insertAll(idx - size, t, buffer)
+ @tailrec final def insertAll(idx: Int, t: scala.collection.Traversable[T], buffer: UnrolledBuffer[T]): Unit = {
+ if (idx < size) {
+ // divide this node at the appropriate position and insert all into head
+ // update new next
+ val newnextnode = new Unrolled[T](0, new Array(array.length), null, buff)
+ Array.copy(array, idx, newnextnode.array, 0, size - idx)
+ newnextnode.size = size - idx
+ newnextnode.next = next
+
+ // update this
+ nullout(idx, size)
+ size = idx
+ next = null
+
+ // insert everything from iterable to this
+ var curr = this
+ for (elem <- t) curr = curr append elem
+ curr.next = newnextnode
+
+ // try to merge the last node of this with the newnextnode
+ if (curr.tryMergeWithNext()) buffer.lastPtr = curr
+ }
+ else if (idx == size) {
+ var curr = this
+ for (elem <- t) curr = curr append elem
+ } else insertAll(idx - size, t, buffer)
+ }
private def nullout(from: Int, until: Int) {
var idx = from
while (idx < until) {
diff --git a/src/library/scala/concurrent/Channel.scala b/src/library/scala/concurrent/Channel.scala
index 067244bd1c..89ad7d8c0e 100644
--- a/src/library/scala/concurrent/Channel.scala
+++ b/src/library/scala/concurrent/Channel.scala
@@ -10,8 +10,10 @@
package scala.concurrent
-/** This class ...
+/** This class provides a simple FIFO queue of data objects,
+ * which are read by one or more reader threads.
*
+ * @tparam A type of data exchanged
* @author Martin Odersky
* @version 1.0, 10/03/2003
*/
@@ -20,11 +22,14 @@ class Channel[A] {
var elem: A = _
var next: LinkedList[A] = null
}
- private var written = new LinkedList[A] // FIFO buffer, realized through
+ private var written = new LinkedList[A] // FIFO queue, realized through
private var lastWritten = written // aliasing of a linked list
private var nreaders = 0
- /**
+ /** Append a value to the FIFO queue to be read by `read`.
+ * This operation is nonblocking and can be executed by any thread.
+ *
+ * @param x object to enqueue to this channel
*/
def write(x: A) = synchronized {
lastWritten.elem = x
@@ -33,6 +38,11 @@ class Channel[A] {
if (nreaders > 0) notify()
}
+ /** Retrieve the next waiting object from the FIFO queue,
+ * blocking if necessary until an object is available.
+ *
+ * @return next object dequeued from this channel
+ */
def read: A = synchronized {
while (written.next == null) {
try {
@@ -45,5 +55,4 @@ class Channel[A] {
written = written.next
x
}
-
}
diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala
index a1e94c8876..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
}
/**
- * Union interface since Java does not support union types
+ * 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
/**
- * Union interface since Java does not support union types
+ * 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/concurrent/Lock.scala b/src/library/scala/concurrent/Lock.scala
index 1c00c0e91f..8d18da2d38 100644
--- a/src/library/scala/concurrent/Lock.scala
+++ b/src/library/scala/concurrent/Lock.scala
@@ -14,8 +14,8 @@ package scala.concurrent
*
* @author Martin Odersky
* @version 1.0, 10/03/2003
- * @deprecated("Use java.util.concurrent.locks.Lock", "2.11.0")
*/
+@deprecated("Use java.util.concurrent.locks.Lock", "2.11.2")
class Lock {
var available = true
diff --git a/src/library/scala/concurrent/SyncVar.scala b/src/library/scala/concurrent/SyncVar.scala
index d5dc3d7e3f..494c955833 100644
--- a/src/library/scala/concurrent/SyncVar.scala
+++ b/src/library/scala/concurrent/SyncVar.scala
@@ -13,6 +13,7 @@ import java.util.concurrent.TimeUnit
/** A class to provide safe concurrent access to a mutable cell.
* All methods are synchronized.
*
+ * @tparam A type of the contained value
* @author Martin Odersky
* @version 1.0, 10/03/2003
*/
@@ -20,6 +21,12 @@ class SyncVar[A] {
private var isDefined: Boolean = false
private var value: Option[A] = None
+ /**
+ * Waits for this SyncVar to become defined and returns
+ * the result, without modifying the stored value.
+ *
+ * @return value that is held in this container
+ */
def get: A = synchronized {
while (!isDefined) wait()
value.get
@@ -57,8 +64,12 @@ class SyncVar[A] {
value
}
- /** Waits for this SyncVar to become defined and returns
- * the result */
+ /**
+ * Waits for this SyncVar to become defined and returns
+ * the result, unsetting the stored value before returning.
+ *
+ * @return value that was held in this container
+ */
def take(): A = synchronized {
try get
finally unsetVal()
@@ -129,4 +140,3 @@ class SyncVar[A] {
}
}
-
diff --git a/src/library/scala/concurrent/duration/Duration.scala b/src/library/scala/concurrent/duration/Duration.scala
index 1b50b7fa56..2eded9f060 100644
--- a/src/library/scala/concurrent/duration/Duration.scala
+++ b/src/library/scala/concurrent/duration/Duration.scala
@@ -621,7 +621,7 @@ final class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duratio
}
def -(other: Duration) = other match {
case x: FiniteDuration => add(-x.length, x.unit)
- case _ => other
+ case _ => -other
}
def *(factor: Double) =
diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala
index cc1350f5a9..4d88253de4 100644
--- a/src/library/scala/concurrent/package.scala
+++ b/src/library/scala/concurrent/package.scala
@@ -55,6 +55,11 @@ package object concurrent {
}
package concurrent {
+ /**
+ * This marker trait is used by [[Await]] to ensure that [[Awaitable.ready]] and [[Awaitable.result]]
+ * are not directly called by user code. An implicit instance of this trait is only available when
+ * user code is currently calling the methods on [[Await]].
+ */
@implicitNotFound("Don't call `Awaitable` methods directly, use the `Await` object.")
sealed trait CanAwait
diff --git a/src/library/scala/io/BufferedSource.scala b/src/library/scala/io/BufferedSource.scala
index 1c87a1f421..52fa525b24 100644
--- a/src/library/scala/io/BufferedSource.scala
+++ b/src/library/scala/io/BufferedSource.scala
@@ -93,7 +93,7 @@ class BufferedSource(inputStream: InputStream, bufferSize: Int)(implicit val cod
val buf = new Array[Char](bufferSize)
var n = 0
while (n != -1) {
- n = charReader.read(buf)
+ n = allReader.read(buf)
if (n>0) sb.appendAll(buf, 0, n)
}
sb.result
diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala
index 33c5cee783..bced505273 100644
--- a/src/library/scala/reflect/ClassTag.scala
+++ b/src/library/scala/reflect/ClassTag.scala
@@ -70,26 +70,36 @@ trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serial
* `SomeExtractor(...)` is turned into `ct(SomeExtractor(...))` if `T` in `SomeExtractor.unapply(x: T)`
* is uncheckable, but we have an instance of `ClassTag[T]`.
*/
- def unapply(x: Any): Option[T] = unapply_impl(x)
- def unapply(x: Byte): Option[T] = unapply_impl(x)
- def unapply(x: Short): Option[T] = unapply_impl(x)
- def unapply(x: Char): Option[T] = unapply_impl(x)
- def unapply(x: Int): Option[T] = unapply_impl(x)
- def unapply(x: Long): Option[T] = unapply_impl(x)
- def unapply(x: Float): Option[T] = unapply_impl(x)
- def unapply(x: Double): Option[T] = unapply_impl(x)
- def unapply(x: Boolean): Option[T] = unapply_impl(x)
- def unapply(x: Unit): Option[T] = unapply_impl(x)
+ def unapply(x: Any): Option[T] = x match {
+ case null => None
+ case b: Byte => unapply(b)
+ case s: Short => unapply(s)
+ case c: Char => unapply(c)
+ case i: Int => unapply(i)
+ case l: Long => unapply(l)
+ case f: Float => unapply(f)
+ case d: Double => unapply(d)
+ case b: Boolean => unapply(b)
+ case u: Unit => unapply(u)
+ case a: Any => unapplyImpl(a)
+ }
- private def unapply_impl[U: ClassTag](x: U): Option[T] =
- if (x == null) None
- else {
- val staticClass = classTag[U].runtimeClass
- val dynamicClass = x.getClass
- val effectiveClass = if (staticClass.isPrimitive) staticClass else dynamicClass
- val conforms = runtimeClass.isAssignableFrom(effectiveClass)
- if (conforms) Some(x.asInstanceOf[T]) else None
- }
+ // TODO: Inline the bodies of these into the Any-accepting unapply overload above and delete them.
+ // This cannot be done until at least 2.12.0 for reasons of binary compatibility
+ def unapply(x: Byte) : Option[T] = unapplyImpl(x, classOf[Byte])
+ def unapply(x: Short) : Option[T] = unapplyImpl(x, classOf[Short])
+ def unapply(x: Char) : Option[T] = unapplyImpl(x, classOf[Char])
+ def unapply(x: Int) : Option[T] = unapplyImpl(x, classOf[Int])
+ def unapply(x: Long) : Option[T] = unapplyImpl(x, classOf[Long])
+ def unapply(x: Float) : Option[T] = unapplyImpl(x, classOf[Float])
+ def unapply(x: Double) : Option[T] = unapplyImpl(x, classOf[Double])
+ def unapply(x: Boolean) : Option[T] = unapplyImpl(x, classOf[Boolean])
+ def unapply(x: Unit) : Option[T] = unapplyImpl(x, classOf[Unit])
+
+ private[this] def unapplyImpl(x: Any, alternative: jClass[_] = null): Option[T] = {
+ val conforms = runtimeClass.isAssignableFrom(x.getClass) || (alternative != null && runtimeClass.isAssignableFrom(alternative))
+ if (conforms) Some(x.asInstanceOf[T]) else None
+ }
// case class accessories
override def canEqual(x: Any) = x.isInstanceOf[ClassTag[_]]
diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala
index d597feb898..2daa4de9a6 100644
--- a/src/library/scala/util/Properties.scala
+++ b/src/library/scala/util/Properties.scala
@@ -155,9 +155,12 @@ private[scala] trait PropertiesTrait {
// This is looking for javac, tools.jar, etc.
// Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
// and finally the system property based javaHome.
- def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
- def versionMsg = "Scala %s %s -- %s".format(propCategory, versionString, copyrightString)
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
def scalaCmd = if (isWin) "scala.bat" else "scala"
def scalacCmd = if (isWin) "scalac.bat" else "scalac"
diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala
index 6743b9e42a..f35ea566ba 100644
--- a/src/library/scala/util/matching/Regex.scala
+++ b/src/library/scala/util/matching/Regex.scala
@@ -274,12 +274,18 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
// @see UnanchoredRegex
protected def runMatcher(m: Matcher) = m.matches()
- /** Return all matches of this regexp in given character sequence as a [[scala.util.matching.Regex.MatchIterator]],
+ /** Return all non-overlapping matches of this regexp in 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.
+ *
+ * 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"`.
*
* Attempting to retrieve information about a match before initializing
* the iterator can result in [[java.lang.IllegalStateException]]s. See
@@ -292,7 +298,7 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
def findAllIn(source: CharSequence) = new Regex.MatchIterator(source, this, groupNames)
- /** Return all matches of this regexp in given character sequence as a
+ /** Return all non-overlapping matches of this regexp in given character sequence as a
* [[scala.collection.Iterator]] of [[scala.util.matching.Regex.Match]].
*
* @param source The text to match against.
diff --git a/src/partest-javaagent/scala/tools/partest/javaagent/ProfilerVisitor.java b/src/partest-javaagent/scala/tools/partest/javaagent/ProfilerVisitor.java
index b1b100fbb0..d97756c171 100644
--- a/src/partest-javaagent/scala/tools/partest/javaagent/ProfilerVisitor.java
+++ b/src/partest-javaagent/scala/tools/partest/javaagent/ProfilerVisitor.java
@@ -50,7 +50,7 @@ public class ProfilerVisitor extends ClassVisitor implements Opcodes {
mv.visitLdcInsn(name);
mv.visitLdcInsn(desc);
mv.visitMethodInsn(INVOKESTATIC, profilerClass, "methodCalled",
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+ "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", false);
}
}
return mv;
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/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/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/Names.scala b/src/reflect/scala/reflect/internal/Names.scala
index ae9f2da4e5..b50f324074 100644
--- a/src/reflect/scala/reflect/internal/Names.scala
+++ b/src/reflect/scala/reflect/internal/Names.scala
@@ -40,7 +40,10 @@ trait Names extends api.Names {
/** Hashtable for finding type names quickly. */
private val typeHashtable = new Array[TypeName](HASH_SIZE)
- /** The hashcode of a name. */
+ /**
+ * The hashcode of a name depends on the first, the last and the middle character,
+ * and the length of the name.
+ */
private def hashValue(cs: Array[Char], offset: Int, len: Int): Int =
if (len > 0)
(len * (41 * 41 * 41) +
@@ -104,10 +107,21 @@ trait Names extends api.Names {
// The logic order here is future-proofing against the possibility
// that name.toString will become an eager val, in which case the call
// to enterChars cannot follow the construction of the TermName.
- val ncStart = nc
- enterChars(cs, offset, len)
- if (cachedString ne null) new TermName_S(ncStart, len, h, cachedString)
- else new TermName_R(ncStart, len, h)
+ var startIndex = 0
+ if (cs == chrs) {
+ // Optimize for subName, the new name is already stored in chrs
+ startIndex = offset
+ } else {
+ startIndex = nc
+ enterChars(cs, offset, len)
+ }
+ val next = termHashtable(h)
+ val termName =
+ if (cachedString ne null) new TermName_S(startIndex, len, next, cachedString)
+ else new TermName_R(startIndex, len, next)
+ // Add the new termName to the hashtable only after it's been fully constructed
+ termHashtable(h) = termName
+ termName
}
}
if (synchronizeNames) nameLock.synchronized(body) else body
@@ -145,40 +159,20 @@ trait Names extends api.Names {
newTermName(bs, offset, len).toTypeName
/**
- * Used only by the GenBCode backend, to represent bytecode-level types in a way that makes equals() and hashCode() efficient.
- * For bytecode-level types of OBJECT sort, its internal name (not its descriptor) is stored.
- * For those of ARRAY sort, its descriptor is stored ie has a leading '['
- * For those of METHOD sort, its descriptor is stored ie has a leading '('
+ * Used by the GenBCode backend to lookup type names that are known to already exist. This method
+ * might be invoked in a multi-threaded setting. Invoking newTypeName instead might be unsafe.
*
- * can-multi-thread
- * TODO SI-6240 !!! JZ Really? the constructors TermName and TypeName publish unconstructed `this` references
- * into the hash tables; we could observe them here before the subclass constructor completes.
+ * can-multi-thread: names are added to the hash tables only after they are fully constructed.
*/
- final def lookupTypeName(cs: Array[Char]): TypeName = { lookupTypeNameIfExisting(cs, true) }
-
- final def lookupTypeNameIfExisting(cs: Array[Char], failOnNotFound: Boolean): TypeName = {
-
- val hterm = hashValue(cs, 0, cs.size) & HASH_MASK
- var nterm = termHashtable(hterm)
- while ((nterm ne null) && (nterm.length != cs.size || !equals(nterm.start, cs, 0, cs.size))) {
- nterm = nterm.next
- }
- if (nterm eq null) {
- if (failOnNotFound) { assert(false, "TermName not yet created: " + new String(cs)) }
- return null
- }
+ final def lookupTypeName(cs: Array[Char]): TypeName = {
+ val hash = hashValue(cs, 0, cs.length) & HASH_MASK
+ var typeName = typeHashtable(hash)
- val htype = hashValue(chrs, nterm.start, nterm.length) & HASH_MASK
- var ntype = typeHashtable(htype)
- while ((ntype ne null) && ntype.start != nterm.start) {
- ntype = ntype.next
+ while ((typeName ne null) && (typeName.length != cs.length || !equals(typeName.start, cs, 0, cs.length))) {
+ typeName = typeName.next
}
- if (ntype eq null) {
- if (failOnNotFound) { assert(false, "TypeName not yet created: " + new String(cs)) }
- return null
- }
-
- ntype
+ assert(typeName != null, s"TypeName ${new String(cs)} not yet created.")
+ typeName
}
// Classes ----------------------------------------------------------------------
@@ -515,43 +509,47 @@ trait Names extends api.Names {
/** TermName_S and TypeName_S have fields containing the string version of the name.
* TermName_R and TypeName_R recreate it each time toString is called.
*/
- private final class TermName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TermName(index0, len0, hash) {
- protected def createCompanionName(h: Int): TypeName = new TypeName_S(index, len, h, toString)
+ private final class TermName_S(index0: Int, len0: Int, next0: TermName, override val toString: String) extends TermName(index0, len0, next0) {
+ protected def createCompanionName(next: TypeName): TypeName = new TypeName_S(index, len, next, toString)
override def newName(str: String): TermName = newTermNameCached(str)
}
- private final class TypeName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TypeName(index0, len0, hash) {
- protected def createCompanionName(h: Int): TermName = new TermName_S(index, len, h, toString)
+ private final class TypeName_S(index0: Int, len0: Int, next0: TypeName, override val toString: String) extends TypeName(index0, len0, next0) {
override def newName(str: String): TypeName = newTypeNameCached(str)
}
- private final class TermName_R(index0: Int, len0: Int, hash: Int) extends TermName(index0, len0, hash) {
- protected def createCompanionName(h: Int): TypeName = new TypeName_R(index, len, h)
+ private final class TermName_R(index0: Int, len0: Int, next0: TermName) extends TermName(index0, len0, next0) {
+ protected def createCompanionName(next: TypeName): TypeName = new TypeName_R(index, len, next)
override def toString = new String(chrs, index, len)
}
- private final class TypeName_R(index0: Int, len0: Int, hash: Int) extends TypeName(index0, len0, hash) {
- protected def createCompanionName(h: Int): TermName = new TermName_R(index, len, h)
+ private final class TypeName_R(index0: Int, len0: Int, next0: TypeName) extends TypeName(index0, len0, next0) {
override def toString = new String(chrs, index, len)
}
// SYNCNOTE: caller to constructor must synchronize if `synchronizeNames` is enabled
- sealed abstract class TermName(index0: Int, len0: Int, hash: Int) extends Name(index0, len0) with TermNameApi {
+ sealed abstract class TermName(index0: Int, len0: Int, val next: TermName) extends Name(index0, len0) with TermNameApi {
type ThisNameType = TermName
protected[this] def thisName: TermName = this
- val next: TermName = termHashtable(hash)
- termHashtable(hash) = this
+
def isTermName: Boolean = true
def isTypeName: Boolean = false
def toTermName: TermName = this
def toTypeName: TypeName = {
def body = {
+ // Re-computing the hash saves a field for storing it in the TermName
val h = hashValue(chrs, index, len) & HASH_MASK
var n = typeHashtable(h)
while ((n ne null) && n.start != index)
n = n.next
if (n ne null) n
- else createCompanionName(h)
+ else {
+ val next = typeHashtable(h)
+ val typeName = createCompanionName(next)
+ // Add the new typeName to the hashtable only after it's been fully constructed
+ typeHashtable(h) = typeName
+ typeName
+ }
}
if (synchronizeNames) nameLock.synchronized(body) else body
}
@@ -562,7 +560,7 @@ trait Names extends api.Names {
def nameKind = "term"
/** SYNCNOTE: caller must synchronize if `synchronizeNames` is enabled */
- protected def createCompanionName(h: Int): TypeName
+ protected def createCompanionName(next: TypeName): TypeName
}
implicit val TermNameTag = ClassTag[TermName](classOf[TermName])
@@ -572,24 +570,22 @@ trait Names extends api.Names {
def unapply(name: TermName): Option[String] = Some(name.toString)
}
- sealed abstract class TypeName(index0: Int, len0: Int, hash: Int) extends Name(index0, len0) with TypeNameApi {
+ sealed abstract class TypeName(index0: Int, len0: Int, val next: TypeName) extends Name(index0, len0) with TypeNameApi {
type ThisNameType = TypeName
protected[this] def thisName: TypeName = this
- val next: TypeName = typeHashtable(hash)
- typeHashtable(hash) = this
-
def isTermName: Boolean = false
def isTypeName: Boolean = true
def toTermName: TermName = {
def body = {
+ // Re-computing the hash saves a field for storing it in the TypeName
val h = hashValue(chrs, index, len) & HASH_MASK
var n = termHashtable(h)
while ((n ne null) && n.start != index)
n = n.next
- if (n ne null) n
- else createCompanionName(h)
+ assert (n ne null, s"TypeName $this is missing its correspondent")
+ n
}
if (synchronizeNames) nameLock.synchronized(body) else body
}
@@ -601,8 +597,6 @@ trait Names extends api.Names {
def nameKind = "type"
override def decode = if (nameDebug) super.decode + "!" else super.decode
- /** SYNCNOTE: caller must synchronize if `synchronizeNames` is enabled */
- protected def createCompanionName(h: Int): TermName
}
implicit val TypeNameTag = ClassTag[TypeName](classOf[TypeName])
diff --git a/src/reflect/scala/reflect/internal/Positions.scala b/src/reflect/scala/reflect/internal/Positions.scala
index 01fba1efc1..c16d8778d9 100644
--- a/src/reflect/scala/reflect/internal/Positions.scala
+++ b/src/reflect/scala/reflect/internal/Positions.scala
@@ -23,13 +23,10 @@ import scala.collection.mutable.ListBuffer
* Otherwise, the singleton consisting of the node itself.
*/
trait Positions extends api.Positions { self: SymbolTable =>
-
type Position = scala.reflect.internal.util.Position
val NoPosition = scala.reflect.internal.util.NoPosition
implicit val PositionTag = ClassTag[Position](classOf[Position])
- def inform(msg: String): Unit
-
def useOffsetPositions: Boolean = true
/** A position that wraps a set of trees.
@@ -100,7 +97,7 @@ trait Positions extends api.Positions { self: SymbolTable =>
inform("\nWhile validating #" + tree.id)
inform(treeStatus(tree))
inform("\nChildren:")
- tree.children map (t => " " + treeStatus(t, tree)) foreach inform
+ tree.children foreach (t => inform(" " + treeStatus(t, tree)))
inform("=======")
throw new ValidateException(msg)
}
@@ -109,7 +106,7 @@ trait Positions extends api.Positions { self: SymbolTable =>
if (!tree.isEmpty && tree.canHaveAttrs) {
if (settings.Yposdebug && (settings.verbose || settings.Yrangepos))
- println("[%10s] %s".format("validate", treeStatus(tree, encltree)))
+ inform("[%10s] %s".format("validate", treeStatus(tree, encltree)))
if (!tree.pos.isDefined)
positionError("Unpositioned tree #"+tree.id) {
@@ -176,7 +173,7 @@ trait Positions extends api.Positions { self: SymbolTable =>
case r :: rs1 =>
assert(!t.pos.isTransparent)
if (r.isFree && (r.pos includes t.pos)) {
-// println("subdividing "+r+"/"+t.pos)
+// inform("subdividing "+r+"/"+t.pos)
maybeFree(t.pos.end, r.pos.end) ::: List(Range(t.pos, t)) ::: maybeFree(r.pos.start, t.pos.start) ::: rs1
} else {
if (!r.isFree && (r.pos overlaps t.pos)) conflicting += r.tree
@@ -225,7 +222,7 @@ trait Positions extends api.Positions { self: SymbolTable =>
}
} catch {
case ex: Exception =>
- println("error while set children pos "+pos+" of "+trees)
+ inform("error while set children pos "+pos+" of "+trees)
throw ex
}
diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala
index fcc377ba32..2ce861898f 100644
--- a/src/reflect/scala/reflect/internal/Printers.scala
+++ b/src/reflect/scala/reflect/internal/Printers.scala
@@ -596,18 +596,26 @@ trait Printers extends api.Printers { self: SymbolTable =>
}
}
- protected def emptyTree(tree: Tree) = tree match {
- case EmptyTree | build.SyntacticEmptyTypeTree() => true
- case _ => false
+ object EmptyTypeTree {
+ def unapply(tt: TypeTree): Boolean = tt match {
+ case build.SyntacticEmptyTypeTree() if tt.wasEmpty || tt.isEmpty => true
+ case _ => false
+ }
}
+ protected def isEmptyTree(tree: Tree) =
+ tree match {
+ case EmptyTree | EmptyTypeTree() => true
+ case _ => false
+ }
+
protected def originalTypeTrees(trees: List[Tree]) =
- trees.filter(!emptyTree(_)) map {
- case tt: TypeTree => tt.original
- case tree => tree
+ trees.filter(!isEmptyTree(_)) map {
+ case tt: TypeTree if tt.original != null => tt.original
+ case tree => tree
}
- val defaultClasses = List(tpnme.AnyRef)
+ val defaultClasses = List(tpnme.AnyRef, tpnme.Object)
val defaultTraitsForCase = List(tpnme.Product, tpnme.Serializable)
protected def removeDefaultTypesFromList(trees: List[Tree])(classesToRemove: List[Name] = defaultClasses)(traitsToRemove: List[Name]) = {
def removeDefaultTraitsFromList(trees: List[Tree], traitsToRemove: List[Name]): List[Tree] =
@@ -623,9 +631,10 @@ trait Printers extends api.Printers { self: SymbolTable =>
removeDefaultTraitsFromList(removeDefaultClassesFromList(trees, classesToRemove), traitsToRemove)
}
- protected def removeDefaultClassesFromList(trees: List[Tree], classesToRemove: List[Name] = defaultClasses) =
+ protected def removeDefaultClassesFromList(trees: List[Tree], classesToRemove: List[Name] = defaultClasses) =
originalTypeTrees(trees) filter {
case Select(Ident(sc), name) => !(classesToRemove.contains(name) && sc == nme.scala_)
+ case tt: TypeTree if tt.tpe != null => !(classesToRemove contains(newTypeName(tt.tpe.toString())))
case _ => true
}
@@ -637,7 +646,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
}
override def printOpt(prefix: String, tree: Tree) =
- if (!emptyTree(tree)) super.printOpt(prefix, tree)
+ if (!isEmptyTree(tree)) super.printOpt(prefix, tree)
override def printColumn(ts: List[Tree], start: String, sep: String, end: String) = {
super.printColumn(ts.filter(!syntheticToRemove(_)), start, sep, end)
@@ -952,7 +961,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
def printTp = print("(", tp, ")")
tp match {
- case EmptyTree | build.SyntacticEmptyTypeTree() => printTp
+ case EmptyTree | EmptyTypeTree() => printTp
// case for untypechecked trees
case Annotated(annot, arg) if (expr ne null) && (arg ne null) && expr.equalsStructure(arg) => printTp // remove double arg - 5: 5: @unchecked
case tt: TypeTree if tt.original.isInstanceOf[Annotated] => printTp
@@ -963,7 +972,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
// print only fun when targs are TypeTrees with empty original
case TypeApply(fun, targs) =>
- if (targs.exists(emptyTree(_))) {
+ if (targs.exists(isEmptyTree(_))) {
print(fun)
} else super.printTree(tree)
@@ -984,8 +993,8 @@ trait Printers extends api.Printers { self: SymbolTable =>
case treeInfo.Unapplied(body) =>
body match {
case Select(qual, name) if name == nme.unapply => print(qual)
- case TypeApply(Select(qual, name), args) if name == nme.unapply || name == nme.unapplySeq =>
- print(TypeApply(qual, args))
+ case TypeApply(Select(qual, name), _) if name == nme.unapply || name == nme.unapplySeq =>
+ print(qual)
case _ => print(body)
}
case _ => print(fun)
@@ -1061,7 +1070,11 @@ trait Printers extends api.Printers { self: SymbolTable =>
print("(", qualifier, ")#", blankForOperatorName(selector), printedName(selector))
case tt: TypeTree =>
- if (!emptyTree(tt)) print(tt.original)
+ if (!isEmptyTree(tt)) {
+ val original = tt.original
+ if (original != null) print(original)
+ else super.printTree(tree)
+ }
case AppliedTypeTree(tp, args) =>
// it's possible to have (=> String) => String type but Function1[=> String, String] is not correct
diff --git a/src/reflect/scala/reflect/internal/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala
index ad8a2594dd..2caa30d27e 100644
--- a/src/reflect/scala/reflect/internal/ReificationSupport.scala
+++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala
@@ -97,6 +97,8 @@ trait ReificationSupport { self: SymbolTable =>
def toStats(tree: Tree): List[Tree] = tree match {
case EmptyTree => Nil
case SyntacticBlock(stats) => stats
+ case defn if defn.isDef => defn :: Nil
+ case imp: Import => imp :: Nil
case _ => throw new IllegalArgumentException(s"can't flatten $tree")
}
diff --git a/src/reflect/scala/reflect/internal/Reporting.scala b/src/reflect/scala/reflect/internal/Reporting.scala
new file mode 100644
index 0000000000..423127803e
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Reporting.scala
@@ -0,0 +1,113 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2014 LAMP/EPFL, Typesafe Inc.
+ * @author Adriaan Moors
+ */
+
+package scala
+package reflect
+package internal
+
+/** Provides delegates to the reporter doing the actual work.
+ * All forwarding methods should be marked final,
+ * but some subclasses out of our reach stil override them.
+ *
+ * Eventually, this interface should be reduced to one method: `reporter`,
+ * and clients should indirect themselves (reduce duplication of forwarders).
+ */
+trait Reporting { self : Positions =>
+ def reporter: Reporter
+ def currentRun: RunReporting
+
+ trait RunReporting {
+ val reporting: PerRunReporting = PerRunReporting
+ }
+
+ type PerRunReporting <: PerRunReportingBase
+ protected def PerRunReporting: PerRunReporting
+ abstract class PerRunReportingBase {
+ def deprecationWarning(pos: Position, msg: String): Unit
+
+ /** Have we already supplemented the error message of a compiler crash? */
+ private[this] var supplementedError = false
+ def supplementErrorMessage(errorMessage: String): String =
+ if (supplementedError) errorMessage
+ else {
+ supplementedError = true
+ supplementTyperState(errorMessage)
+ }
+
+ }
+
+ // overridden in Global
+ def supplementTyperState(errorMessage: String): String = errorMessage
+
+ def supplementErrorMessage(errorMessage: String) = currentRun.reporting.supplementErrorMessage(errorMessage)
+
+ @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2")
+ def inform(msg: String): Unit = inform(NoPosition, msg)
+ @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2")
+ def warning(msg: String): Unit = warning(NoPosition, msg)
+ // globalError(msg: String) used to abort -- not sure that was a good idea, so I made it more regular
+ // (couldn't find any uses that relied on old behavior)
+ @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2")
+ def globalError(msg: String): Unit = globalError(NoPosition, msg)
+
+ def abort(msg: String): Nothing = {
+ val augmented = supplementErrorMessage(msg)
+ // Needs to call error to make sure the compile fails.
+ globalError(augmented)
+ throw new FatalError(augmented)
+ }
+
+ @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2")
+ def inform(pos: Position, msg: String) = reporter.echo(pos, msg)
+ @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2")
+ def warning(pos: Position, msg: String) = reporter.warning(pos, msg)
+ @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2")
+ def globalError(pos: Position, msg: String) = reporter.error(pos, msg)
+}
+
+import util.Position
+
+/** Report information, warnings and errors.
+ *
+ * This describes the (future) external interface for issuing information, warnings and errors.
+ * Currently, scala.tools.nsc.Reporter is used by sbt/ide/partest.
+ */
+abstract class Reporter {
+ protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit
+
+ def echo(pos: Position, msg: String): Unit = info0(pos, msg, INFO, force = true)
+ def warning(pos: Position, msg: String): Unit = info0(pos, msg, WARNING, force = false)
+ def error(pos: Position, msg: String): Unit = info0(pos, msg, ERROR, force = false)
+
+ type Severity
+ val INFO: Severity
+ val WARNING: Severity
+ val ERROR: Severity
+
+ def count(severity: Severity): Int
+ def resetCount(severity: Severity): Unit
+
+ def hasErrors: Boolean = count(ERROR) > 0
+ def hasWarnings: Boolean = count(WARNING) > 0
+
+ def reset(): Unit = {
+ resetCount(INFO)
+ resetCount(WARNING)
+ resetCount(ERROR)
+ }
+
+ def flush(): Unit = { }
+}
+
+// TODO: move into superclass once partest cuts tie on Severity
+abstract class ReporterImpl extends Reporter {
+ class Severity(val id: Int)(name: String) { var count: Int = 0 ; override def toString = name}
+ object INFO extends Severity(0)("INFO")
+ object WARNING extends Severity(1)("WARNING")
+ object ERROR extends Severity(2)("ERROR")
+
+ def count(severity: Severity): Int = severity.count
+ def resetCount(severity: Severity): Unit = severity.count = 0
+}
diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala
index cf3f356daa..103f885ad4 100644
--- a/src/reflect/scala/reflect/internal/Scopes.scala
+++ b/src/reflect/scala/reflect/internal/Scopes.scala
@@ -48,22 +48,17 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
* This is necessary because when run from reflection every scope needs to have a
* SynchronizedScope as mixin.
*/
- class Scope protected[Scopes] (initElems: ScopeEntry = null, initFingerPrints: Long = 0L) extends ScopeApi with MemberScopeApi {
+ class Scope protected[Scopes]() extends ScopeApi with MemberScopeApi {
- protected[Scopes] def this(base: Scope) = {
- this(base.elems)
- nestinglevel = base.nestinglevel + 1
- }
-
- private[scala] var elems: ScopeEntry = initElems
+ private[scala] var elems: ScopeEntry = _
/** The number of times this scope is nested in another
*/
- private var nestinglevel = 0
+ private[Scopes] var nestinglevel = 0
/** the hash table
*/
- private var hashtable: Array[ScopeEntry] = null
+ private[Scopes] var hashtable: Array[ScopeEntry] = null
/** a cache for all elements, to be used by symbol iterator.
*/
@@ -84,8 +79,6 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
*/
private val MIN_HASH = 8
- if (size >= MIN_HASH) createHash()
-
/** Returns a new scope with the same content as this one. */
def cloneScope: Scope = newScopeWith(this.toList: _*)
@@ -435,7 +428,14 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
}
/** Create a new scope nested in another one with which it shares its elements */
- def newNestedScope(outer: Scope): Scope = new Scope(outer)
+ final def newNestedScope(outer: Scope): Scope = {
+ val nested = newScope // not `new Scope`, we must allow the runtime reflection universe to mixin SynchronizedScopes!
+ nested.elems = outer.elems
+ nested.nestinglevel = outer.nestinglevel + 1
+ if (outer.hashtable ne null)
+ nested.hashtable = java.util.Arrays.copyOf(outer.hashtable, outer.hashtable.length)
+ nested
+ }
/** Create a new scope with given initial elements */
def newScopeWith(elems: Symbol*): Scope = {
diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala
index c76dedbff4..ed5c68fe82 100644
--- a/src/reflect/scala/reflect/internal/SymbolTable.scala
+++ b/src/reflect/scala/reflect/internal/SymbolTable.scala
@@ -46,16 +46,12 @@ abstract class SymbolTable extends macros.Universe
with pickling.Translations
with FreshNames
with Internals
+ with Reporting
{
val gen = new InternalTreeGen { val global: SymbolTable.this.type = SymbolTable.this }
def log(msg: => AnyRef): Unit
- def deprecationWarning(pos: Position, msg: String): Unit = warning(msg)
- def warning(msg: String): Unit = Console.err.println(msg)
- def inform(msg: String): Unit = Console.err.println(msg)
- def globalError(msg: String): Unit = abort(msg)
- def abort(msg: String): Nothing = throw new FatalError(supplementErrorMessage(msg))
protected def elapsedMessage(msg: String, start: Long) =
msg + " in " + (TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start) + "ms"
@@ -82,9 +78,6 @@ abstract class SymbolTable extends macros.Universe
/** Prints a stack trace if -Ydebug or equivalent was given, otherwise does nothing. */
def debugStack(t: Throwable): Unit = devWarning(throwableAsString(t))
- /** Overridden when we know more about what was happening during a failure. */
- def supplementErrorMessage(msg: String): String = msg
-
private[scala] def printCaller[T](msg: String)(result: T) = {
Console.err.println("%s: %s\nCalled from: %s".format(msg, result,
(new Throwable).getStackTrace.drop(2).take(50).mkString("\n")))
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/Variances.scala b/src/reflect/scala/reflect/internal/Variances.scala
index cfe2ad8b87..12b765b7a6 100644
--- a/src/reflect/scala/reflect/internal/Variances.scala
+++ b/src/reflect/scala/reflect/internal/Variances.scala
@@ -79,7 +79,7 @@ trait Variances {
// Unsound pre-2.11 behavior preserved under -Xsource:2.10
if (settings.isScala211 || sym.isOverridingSymbol) Invariant
else {
- deprecationWarning(sym.pos, s"Construct depends on unsound variance analysis and will not compile in scala 2.11 and beyond")
+ currentRun.reporting.deprecationWarning(sym.pos, s"Construct depends on unsound variance analysis and will not compile in scala 2.11 and beyond")
Bivariant
}
)
diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
index 64a1a44722..b808666360 100644
--- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
@@ -290,6 +290,25 @@ abstract class UnPickler {
def pflags = flags & PickledFlags
def finishSym(sym: Symbol): Symbol = {
+ /**
+ * member symbols (symbols owned by a class) are added to the class's scope, with a number
+ * of exceptions:
+ *
+ * (.) ...
+ * (1) `local child` represents local child classes, see comment in Pickler.putSymbol.
+ * Since it is not a member, it should not be entered in the owner's scope.
+ */
+ def shouldEnterInOwnerScope = {
+ sym.owner.isClass &&
+ sym != classRoot &&
+ sym != moduleRoot &&
+ !sym.isModuleClass &&
+ !sym.isRefinementClass &&
+ !sym.isTypeParameter &&
+ !sym.isExistentiallyBound &&
+ sym.rawname != tpnme.LOCAL_CHILD // (1)
+ }
+
markFlagsCompleted(sym)(mask = AllFlags)
sym.privateWithin = privateWithin
sym.info = (
@@ -302,8 +321,7 @@ abstract class UnPickler {
newLazyTypeRefAndAlias(inforef, readNat())
}
)
- if (sym.owner.isClass && sym != classRoot && sym != moduleRoot &&
- !sym.isModuleClass && !sym.isRefinementClass && !sym.isTypeParameter && !sym.isExistentiallyBound)
+ if (shouldEnterInOwnerScope)
symScope(sym.owner) enter sym
sym
@@ -681,10 +699,24 @@ abstract class UnPickler {
private val p = phase
protected def completeInternal(sym: Symbol) : Unit = try {
val tp = at(i, () => readType(sym.isTerm)) // after NMT_TRANSITION, revert `() => readType(sym.isTerm)` to `readType`
- if (p ne null)
- slowButSafeEnteringPhase(p) (sym setInfo tp)
+
+ // This is a temporary fix allowing to read classes generated by an older, buggy pickler.
+ // See the generation of the LOCAL_CHILD class in Pickler.scala. In an earlier version, the
+ // pickler did not add the ObjectTpe superclass, it used a trait as the first parent. This
+ // tripped an assertion in AddInterfaces which checks that the first parent is not a trait.
+ // This workaround can probably be removed in 2.12, because the 2.12 compiler is supposed
+ // to only read classfiles generated by 2.12.
+ val fixLocalChildTp = if (sym.rawname == tpnme.LOCAL_CHILD) tp match {
+ case ClassInfoType(superClass :: traits, decls, typeSymbol) if superClass.typeSymbol.isTrait =>
+ ClassInfoType(definitions.ObjectTpe :: superClass :: traits, decls, typeSymbol)
+ case _ => tp
+ } else tp
+
+ if (p ne null) {
+ slowButSafeEnteringPhase(p)(sym setInfo fixLocalChildTp)
+ }
if (currentRunId != definedAtRunId)
- sym.setInfo(adaptToNewRunMap(tp))
+ sym.setInfo(adaptToNewRunMap(fixLocalChildTp))
}
catch {
case e: MissingRequirementError => throw toTypeError(e)
diff --git a/src/reflect/scala/reflect/internal/util/SourceFile.scala b/src/reflect/scala/reflect/internal/util/SourceFile.scala
index 4fccad74ac..a2642628a4 100644
--- a/src/reflect/scala/reflect/internal/util/SourceFile.scala
+++ b/src/reflect/scala/reflect/internal/util/SourceFile.scala
@@ -40,7 +40,7 @@ abstract class SourceFile {
def lineToString(index: Int): String = {
val start = lineToOffset(index)
var end = start
- while (!isEndOfLine(end) && end <= length) end += 1
+ while (end < length && !isEndOfLine(end)) end += 1
new String(content, start, end - start)
}
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/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala
index b5446694ed..fe39e1f245 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala
@@ -14,15 +14,27 @@ import scala.reflect.api.{TreeCreator, TypeCreator, Universe}
* @contentDiagram hideNodes "*Api" "*Extractor"
*/
class JavaUniverse extends InternalSymbolTable with JavaUniverseForce with ReflectSetup with RuntimeSymbolTable { self =>
-
- override def inform(msg: String): Unit = log(msg)
def picklerPhase = SomePhase
def erasurePhase = SomePhase
lazy val settings = new Settings
- private val isLogging = sys.props contains "scala.debug.reflect"
+ private val isLogging = sys.props contains "scala.debug.reflect"
def log(msg: => AnyRef): Unit = if (isLogging) Console.err.println("[reflect] " + msg)
+ // TODO: why put output under isLogging? Calls to inform are already conditional on debug/verbose/...
+ import scala.reflect.internal.{Reporter, ReporterImpl}
+ override def reporter: Reporter = new ReporterImpl {
+ protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit = log(msg)
+ }
+
+ // minimal Run to get Reporting wired
+ def currentRun = new RunReporting {}
+ class PerRunReporting extends PerRunReportingBase {
+ def deprecationWarning(pos: Position, msg: String): Unit = reporter.warning(pos, msg)
+ }
+ protected def PerRunReporting = new PerRunReporting
+
+
type TreeCopier = InternalTreeCopierOps
implicit val TreeCopierTag: ClassTag[TreeCopier] = ClassTag[TreeCopier](classOf[TreeCopier])
def newStrictTreeCopier: TreeCopier = new StrictTreeCopier
diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
index c56bc28d90..7ba68b8733 100644
--- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
+++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
@@ -91,7 +91,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
//
// Short of significantly changing SymbolLoaders I see no other way than just
// to slap a global lock on materialization in runtime reflection.
- class PackageScope(pkgClass: Symbol) extends Scope(initFingerPrints = -1L) // disable fingerprinting as we do not know entries beforehand
+ class PackageScope(pkgClass: Symbol) extends Scope
with SynchronizedScope {
assert(pkgClass.isType)
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
index c90901410a..4a8585d616 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
@@ -37,8 +37,7 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable
// Scopes
- override def newScope = new Scope() with SynchronizedScope
- override def newNestedScope(outer: Scope): Scope = new Scope(outer) with SynchronizedScope
+ override def newScope = new Scope with SynchronizedScope
trait SynchronizedScope extends Scope {
// we can keep this lock fine-grained, because methods of Scope don't do anything extraordinary, which makes deadlocks impossible
diff --git a/src/reflect/scala/reflect/runtime/package.scala b/src/reflect/scala/reflect/runtime/package.scala
index 3c9bbccba3..e240bed0a7 100644
--- a/src/reflect/scala/reflect/runtime/package.scala
+++ b/src/reflect/scala/reflect/runtime/package.scala
@@ -30,7 +30,8 @@ package runtime {
import c.universe._
val runtimeClass = c.reifyEnclosingRuntimeClass
if (runtimeClass.isEmpty) c.abort(c.enclosingPosition, "call site does not have an enclosing class")
- val runtimeUniverse = Select(Select(Select(Ident(newTermName("scala")), newTermName("reflect")), newTermName("runtime")), newTermName("universe"))
+ val scalaPackage = Select(Ident(newTermName("_root_")), newTermName("scala"))
+ val runtimeUniverse = Select(Select(Select(scalaPackage, newTermName("reflect")), newTermName("runtime")), newTermName("universe"))
val currentMirror = Apply(Select(runtimeUniverse, newTermName("runtimeMirror")), List(Select(runtimeClass, newTermName("getClassLoader"))))
c.Expr[Nothing](currentMirror)(c.WeakTypeTag.Nothing)
}
diff --git a/src/repl/scala/tools/nsc/MainGenericRunner.scala b/src/repl/scala/tools/nsc/MainGenericRunner.scala
index 43f0ea1256..34057ed341 100644
--- a/src/repl/scala/tools/nsc/MainGenericRunner.scala
+++ b/src/repl/scala/tools/nsc/MainGenericRunner.scala
@@ -8,7 +8,6 @@ package tools.nsc
import io.{ File }
import util.{ ClassPath, ScalaClassLoader }
-import Properties.{ versionString, copyrightString }
import GenericRunnerCommand._
object JarRunner extends CommonRunner {
@@ -28,79 +27,78 @@ object JarRunner extends CommonRunner {
}
/** An object that runs Scala code. It has three possible
- * sources for the code to run: pre-compiled code, a script file,
- * or interactive entry.
- */
+ * sources for the code to run: pre-compiled code, a script file,
+ * or interactive entry.
+ */
class MainGenericRunner {
- def errorFn(ex: Throwable): Boolean = {
- ex.printStackTrace()
- false
- }
- def errorFn(str: String): Boolean = {
- Console.err println str
- false
+ def errorFn(str: String, e: Option[Throwable] = None, isFailure: Boolean = true): Boolean = {
+ if (str.nonEmpty) Console.err println str
+ e foreach (_.printStackTrace())
+ !isFailure
}
def process(args: Array[String]): Boolean = {
val command = new GenericRunnerCommand(args.toList, (x: String) => errorFn(x))
- import command.{ settings, howToRun, thingToRun }
- def sampleCompiler = new Global(settings) // def so its not created unless needed
-
- if (!command.ok) return errorFn("\n" + command.shortUsageMsg)
- else if (settings.version) return errorFn("Scala code runner %s -- %s".format(versionString, copyrightString))
- else if (command.shouldStopWithInfo) return errorFn(command getInfoMessage sampleCompiler)
-
- def isE = !settings.execute.isDefault
- def dashe = settings.execute.value
-
- def isI = !settings.loadfiles.isDefault
- def dashi = settings.loadfiles.value
-
- // Deadlocks on startup under -i unless we disable async.
- if (isI)
- settings.Yreplsync.value = true
-
- def combinedCode = {
- val files = if (isI) dashi map (file => File(file).slurp()) else Nil
- val str = if (isE) List(dashe) else Nil
-
- files ++ str mkString "\n\n"
- }
-
- def runTarget(): Either[Throwable, Boolean] = howToRun match {
- case AsObject =>
- ObjectRunner.runAndCatch(settings.classpathURLs, thingToRun, command.arguments)
- case AsScript =>
- ScriptRunner.runScriptAndCatch(settings, thingToRun, command.arguments)
- case AsJar =>
- JarRunner.runJar(settings, thingToRun, command.arguments)
- case Error =>
- Right(false)
- case _ =>
- // We start the repl when no arguments are given.
- Right(new interpreter.ILoop process settings)
+ import command.{ settings, howToRun, thingToRun, shortUsageMsg, shouldStopWithInfo }
+ def sampleCompiler = new Global(settings) // def so it's not created unless needed
+
+ def run(): Boolean = {
+ def isE = !settings.execute.isDefault
+ def dashe = settings.execute.value
+
+ def isI = !settings.loadfiles.isDefault
+ def dashi = settings.loadfiles.value
+
+ // Deadlocks on startup under -i unless we disable async.
+ if (isI)
+ settings.Yreplsync.value = true
+
+ def combinedCode = {
+ val files = if (isI) dashi map (file => File(file).slurp()) else Nil
+ val str = if (isE) List(dashe) else Nil
+
+ files ++ str mkString "\n\n"
+ }
+
+ def runTarget(): Either[Throwable, Boolean] = howToRun match {
+ case AsObject =>
+ ObjectRunner.runAndCatch(settings.classpathURLs, thingToRun, command.arguments)
+ case AsScript =>
+ ScriptRunner.runScriptAndCatch(settings, thingToRun, command.arguments)
+ case AsJar =>
+ JarRunner.runJar(settings, thingToRun, command.arguments)
+ case Error =>
+ Right(false)
+ case _ =>
+ // We start the repl when no arguments are given.
+ Right(new interpreter.ILoop process settings)
+ }
+
+ /** If -e and -i were both given, we want to execute the -e code after the
+ * -i files have been included, so they are read into strings and prepended to
+ * the code given in -e. The -i option is documented to only make sense
+ * interactively so this is a pretty reasonable assumption.
+ *
+ * This all needs a rewrite though.
+ */
+ if (isE) {
+ ScriptRunner.runCommand(settings, combinedCode, thingToRun +: command.arguments)
+ }
+ else runTarget() match {
+ case Left(ex) => errorFn("", Some(ex)) // there must be a useful message of hope to offer here
+ case Right(b) => b
+ }
}
- /** If -e and -i were both given, we want to execute the -e code after the
- * -i files have been included, so they are read into strings and prepended to
- * the code given in -e. The -i option is documented to only make sense
- * interactively so this is a pretty reasonable assumption.
- *
- * This all needs a rewrite though.
- */
- if (isE) {
- ScriptRunner.runCommand(settings, combinedCode, thingToRun +: command.arguments)
- }
- else runTarget() match {
- case Left(ex) => errorFn(ex)
- case Right(b) => b
- }
+ if (!command.ok)
+ errorFn(f"%n$shortUsageMsg")
+ else if (shouldStopWithInfo)
+ errorFn(command getInfoMessage sampleCompiler, isFailure = false)
+ else
+ run()
}
}
object MainGenericRunner extends MainGenericRunner {
- def main(args: Array[String]) {
- if (!process(args))
- sys.exit(1)
- }
+ def main(args: Array[String]): Unit = if (!process(args)) sys.exit(1)
}
diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala
index 47d97dd4dd..8ea8759ee5 100644
--- a/src/repl/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala
@@ -110,7 +110,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
lazy val reporter: ReplReporter = new ReplReporter(this)
import formatting._
- import reporter.{ printMessage, withoutTruncating }
+ import reporter.{ printMessage, printUntruncatedMessage }
// This exists mostly because using the reporter too early leads to deadlock.
private def echo(msg: String) { Console println msg }
@@ -609,7 +609,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
}
else {
// don't truncate stack traces
- withoutTruncating(printMessage(result))
+ printUntruncatedMessage(result)
IR.Error
}
}
@@ -793,7 +793,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
}
((pos, msg)) :: loop(filtered)
}
- val warnings = loop(run.allConditionalWarnings flatMap (_.warnings))
+ val warnings = loop(run.reporting.allConditionalWarnings)
if (warnings.nonEmpty)
mostRecentWarnings = warnings
}
@@ -1121,7 +1121,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
def apply(line: String): Result = debugging(s"""parse("$line")""") {
var isIncomplete = false
- reporter.withIncompleteHandler((_, _) => isIncomplete = true) {
+ currentRun.reporting.withIncompleteHandler((_, _) => isIncomplete = true) {
reporter.reset()
val trees = newUnitParser(line).parseStats()
if (reporter.hasErrors) Error
diff --git a/src/repl/scala/tools/nsc/interpreter/JavapClass.scala b/src/repl/scala/tools/nsc/interpreter/JavapClass.scala
index 915fd57bf8..3cb6ba11c1 100644
--- a/src/repl/scala/tools/nsc/interpreter/JavapClass.scala
+++ b/src/repl/scala/tools/nsc/interpreter/JavapClass.scala
@@ -41,16 +41,16 @@ class JavapClass(
* Byte data for filename args is retrieved with findBytes.
*/
def apply(args: Seq[String]): List[JpResult] = {
- val (options, claases) = args partition (s => (s startsWith "-") && s.length > 1)
+ val (options, classes) = args partition (s => (s startsWith "-") && s.length > 1)
val (flags, upgraded) = upgrade(options)
import flags.{ app, fun, help, raw }
- val targets = if (fun && !help) FunFinder(loader, intp).funs(claases) else claases
- if (help || claases.isEmpty)
+ val targets = if (fun && !help) FunFinder(loader, intp).funs(classes) else classes
+ if (help || classes.isEmpty)
List(JpResult(JavapTool.helper(printWriter)))
else if (targets.isEmpty)
List(JpResult("No anonfuns found."))
else
- tool(raw, upgraded)(targets map (claas => targeted(claas, app)))
+ tool(raw, upgraded)(targets map (klass => targeted(klass, app)))
}
/** Cull our tool options. */
@@ -67,17 +67,18 @@ class JavapClass(
case f: Failure[_] => (path, Failure(f.exception))
}
- /** Find bytes. Handle "-", "-app", "Foo#bar" (by ignoring member), "#bar" (by taking "bar"). */
+ /** Find bytes. Handle "-", "-app", "Foo#bar" (by ignoring member), "#bar" (by taking "bar").
+ * @return the path to use for filtering, and the byte array
+ */
private def bytesFor(path: String, app: Boolean) = Try {
def last = intp.get.mostRecentVar // fail if no intp
- def req = path match {
- case "-" => last
- case HashSplit(prefix, member) =>
- if (prefix != null) prefix
- else if (member != null) member
- else "#"
+ val req = path match {
+ case "-" => last
+ case HashSplit(prefix, _) if prefix != null => prefix
+ case HashSplit(_, member) if member != null => member
+ case s => s
}
- val targetedBytes = if (app) findAppBody(req) else (req, findBytes(req))
+ val targetedBytes = if (app) findAppBody(req) else (path, findBytes(req))
if (targetedBytes._2.isEmpty) throw new FileNotFoundException(s"Could not find class bytes for '$path'")
targetedBytes
}
@@ -217,27 +218,36 @@ class JavapClass(
// if apply is added here, it's for other than -fun: javap Foo#, perhaps m#?
val filterOn = target.splitHashMember._2 map { s => if (s.isEmpty) "apply" else s }
var filtering = false // true if in region matching filter
- // true to output
- def checkFilter(line: String) = if (filterOn.isEmpty) true else {
+ // turn filtering on/off given the pattern of interest
+ def filterStatus(line: String, pattern: String) = {
// cheap heuristic, todo maybe parse for the java sig.
// method sigs end in paren semi
def isAnyMethod = line.endsWith(");")
def isOurMethod = {
val lparen = line.lastIndexOf('(')
val blank = line.lastIndexOf(' ', lparen)
- (blank >= 0 && line.substring(blank+1, lparen) == filterOn.get)
- }
- filtering = if (filtering) {
- // next blank line terminates section
- // for -public, next line is next method, more or less
- line.trim.nonEmpty && !isAnyMethod
- } else {
- isAnyMethod && isOurMethod
+ if (blank < 0) false
+ else {
+ val method = line.substring(blank+1, lparen)
+ (method == pattern || ((method startsWith pattern+"$") && (method endsWith "$sp")))
+ }
}
+ filtering =
+ if (filtering) {
+ // next blank line terminates section
+ // for -public, next line is next method, more or less
+ line.trim.nonEmpty && !isAnyMethod
+ } else {
+ isAnyMethod && isOurMethod
+ }
filtering
}
- for (line <- Source.fromString(preamble + written).getLines(); if checkFilter(line))
- printWriter write line+lineSeparator
+ // do we output this line?
+ def checkFilter(line: String) = filterOn map (filterStatus(line, _)) getOrElse true
+ for {
+ line <- Source.fromString(preamble + written).getLines()
+ if checkFilter(line)
+ } printWriter write f"$line%n"
printWriter.flush()
}
}
@@ -275,7 +285,7 @@ class JavapClass(
override def apply(raw: Boolean, options: Seq[String])(inputs: Seq[Input]): List[JpResult] =
(inputs map {
- case (claas, Success(ba)) => JpResult(showable(raw, claas, newPrinter(new ByteArrayInputStream(ba), newEnv(options))))
+ case (klass, Success(ba)) => JpResult(showable(raw, klass, newPrinter(new ByteArrayInputStream(ba), newEnv(options))))
case (_, Failure(e)) => JpResult(e.toString)
}).toList orFailed List(noToolError)
}
@@ -290,10 +300,10 @@ class JavapClass(
//object TaskResult extends Enumeration {
// val Ok, Error, CmdErr, SysErr, Abnormal = Value
//}
- val TaskClaas = loader.tryToInitializeClass[Task](JavapTool.Tool).orNull
- override protected def failed = TaskClaas eq null
+ val TaskClass = loader.tryToInitializeClass[Task](JavapTool.Tool).orNull
+ override protected def failed = TaskClass eq null
- val TaskCtor = TaskClaas.getConstructor(
+ val TaskCtor = TaskClass.getConstructor(
classOf[Writer],
classOf[JavaFileManager],
classOf[DiagnosticListener[_]],
@@ -344,8 +354,12 @@ class JavapClass(
import Kind._
import StandardLocation._
import JavaFileManager.Location
- import java.net.URI
- def uri(name: String): URI = new URI(name) // new URI("jfo:" + name)
+ import java.net.{ URI, URISyntaxException }
+
+ // name#fragment is OK, but otherwise fragile
+ def uri(name: String): URI =
+ try new URI(name) // new URI("jfo:" + name)
+ catch { case _: URISyntaxException => new URI("dummy") }
def inputNamed(name: String): Try[ByteAry] = (managed find (_._1 == name)).get._2
def managedFile(name: String, kind: Kind) = kind match {
@@ -379,19 +393,19 @@ class JavapClass(
def showable(raw: Boolean, target: String): Showable = showWithPreamble(raw, target, reporter.reportable(raw))
// eventually, use the tool interface
- def task(options: Seq[String], claases: Seq[String], inputs: Seq[Input]): Task = {
+ def task(options: Seq[String], classes: Seq[String], inputs: Seq[Input]): Task = {
//ServiceLoader.load(classOf[javax.tools.DisassemblerTool]).
- //getTask(writer, fileManager, reporter, options.asJava, claases.asJava)
+ //getTask(writer, fileManager, reporter, options.asJava, classes.asJava)
import JavaConverters.asJavaIterableConverter
- TaskCtor.newInstance(writer, fileManager(inputs), reporter, options.asJava, claases.asJava)
+ TaskCtor.newInstance(writer, fileManager(inputs), reporter, options.asJava, classes.asJava)
.orFailed (throw new IllegalStateException)
}
// a result per input
- private def applyOne(raw: Boolean, options: Seq[String], claas: String, inputs: Seq[Input]): Try[JpResult] =
+ private def applyOne(raw: Boolean, options: Seq[String], klass: String, inputs: Seq[Input]): Try[JpResult] =
Try {
- task(options, Seq(claas), inputs).call()
+ task(options, Seq(klass), inputs).call()
} map {
- case true => JpResult(showable(raw, claas))
+ case true => JpResult(showable(raw, klass))
case _ => JpResult(reporter.reportable(raw))
} recoverWith {
case e: java.lang.reflect.InvocationTargetException => e.getCause match {
@@ -402,7 +416,7 @@ class JavapClass(
reporter.clear()
}
override def apply(raw: Boolean, options: Seq[String])(inputs: Seq[Input]): List[JpResult] = (inputs map {
- case (claas, Success(_)) => applyOne(raw, options, claas, inputs).get
+ case (klass, Success(_)) => applyOne(raw, options, klass, inputs).get
case (_, Failure(e)) => JpResult(e.toString)
}).toList orFailed List(noToolError)
}
@@ -534,6 +548,7 @@ class JavapClass(
private def isTaskable(cl: ScalaClassLoader) = hasClass(cl, Tool)
+ /** Select the tool implementation for this platform. */
def apply() = if (isTaskable(loader)) new JavapTool7 else new JavapTool6
}
}
@@ -545,7 +560,8 @@ object JavapClass {
intp: Option[IMain] = None
) = new JavapClass(loader, printWriter, intp)
- val HashSplit = "(.*?)(?:#([^#]*))?".r
+ val HashSplit = "([^#]+)?(?:#(.+)?)?".r
+
// We enjoy flexibility in specifying either a fully-qualified class name com.acme.Widget
// or a resource path com/acme/Widget.class; but not widget.out
implicit class MaybeClassLike(val s: String) extends AnyVal {
@@ -580,11 +596,11 @@ object JavapClass {
/* only the file location from which the given class is loaded */
def locate(k: String): Option[Path] = {
Try {
- val claas = try cl loadClass k catch {
+ val klass = try cl loadClass k catch {
case _: NoClassDefFoundError => null // let it snow
}
// cf ScalaClassLoader.originOfClass
- claas.getProtectionDomain.getCodeSource.getLocation
+ klass.getProtectionDomain.getCodeSource.getLocation
} match {
case Success(null) => None
case Success(loc) if loc.isFile => Some(Path(new JFile(loc.toURI)))
diff --git a/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala b/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala
index b20166d070..88372334d6 100644
--- a/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala
@@ -9,11 +9,29 @@ package interpreter
import reporters._
import IMain._
+import scala.reflect.internal.util.Position
+
/** Like ReplGlobal, a layer for ensuring extra functionality.
*/
class ReplReporter(intp: IMain) extends ConsoleReporter(intp.settings, Console.in, new ReplStrippingWriter(intp)) {
def printUntruncatedMessage(msg: String) = withoutTruncating(printMessage(msg))
+ /** Whether very long lines can be truncated. This exists so important
+ * debugging information (like printing the classpath) is not rendered
+ * invisible due to the max message length.
+ */
+ private var _truncationOK: Boolean = !intp.settings.verbose
+ def truncationOK = _truncationOK
+ def withoutTruncating[T](body: => T): T = {
+ val saved = _truncationOK
+ _truncationOK = false
+ try body
+ finally _truncationOK = saved
+ }
+
+ override def warning(pos: Position, msg: String): Unit = withoutTruncating(super.warning(pos, msg))
+ override def error(pos: Position, msg: String): Unit = withoutTruncating(super.error(pos, msg))
+
override def printMessage(msg: String) {
// Avoiding deadlock if the compiler starts logging before
// the lazy val is complete.
@@ -31,4 +49,5 @@ class ReplReporter(intp: IMain) extends ConsoleReporter(intp.settings, Console.i
if (intp.totalSilence) ()
else super.displayPrompt()
}
+
}
diff --git a/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala b/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala
index dce52af56a..47ddfb8aa9 100644
--- a/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala
@@ -95,11 +95,11 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor
val documentError: PartialFunction[Throwable, Unit] = {
case NoCompilerRunException =>
reporter.info(null, "No documentation generated with unsuccessful compiler run", force = false)
- case _: ClassNotFoundException =>
- ()
+ case e @ (_:ClassNotFoundException | _:IllegalAccessException | _:InstantiationException | _:SecurityException | _:ClassCastException) =>
+ reporter.error(null, s"Cannot load the doclet class ${settings.docgenerator.value} (specified with ${settings.docgenerator.name}): $e. Leaving the default settings will generate the html version of scaladoc.")
}
- /** Generate document(s) for all `files` containing scaladoc documenataion.
+ /** Generate document(s) for all `files` containing scaladoc documentation.
* @param files The list of paths (relative to the compiler's source path, or absolute) of files to document. */
def document(files: List[String]) {
def generate() = {
diff --git a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala
index e5c64c6f45..10c382e169 100644
--- a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala
@@ -39,12 +39,12 @@ trait ScaladocAnalyzer extends Analyzer {
for (useCase <- comment.useCases) {
typer1.silent(_.asInstanceOf[ScaladocTyper].defineUseCases(useCase)) match {
case SilentTypeError(err) =>
- unit.warning(useCase.pos, err.errMsg)
+ reporter.warning(useCase.pos, err.errMsg)
case _ =>
}
for (useCaseSym <- useCase.defined) {
if (sym.name != useCaseSym.name)
- unit.warning(useCase.pos, "@usecase " + useCaseSym.name.decode + " does not match commented symbol: " + sym.name.decode)
+ reporter.warning(useCase.pos, "@usecase " + useCaseSym.name.decode + " does not match commented symbol: " + sym.name.decode)
}
}
}
@@ -191,7 +191,7 @@ abstract class ScaladocSyntaxAnalyzer[G <: Global](val global: G) extends Syntax
}
def isDirty = unclean(unmooredParser parseComment doc)
if ((doc ne null) && (settings.lint || isDirty))
- unit.warning(doc.pos, "discarding unmoored doc comment")
+ reporter.warning(doc.pos, "discarding unmoored doc comment")
}
override def flushDoc(): DocComment = (try lastDoc finally lastDoc = null)
diff --git a/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala b/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala
index a933c35c99..19cc27b40b 100755
--- a/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala
@@ -666,7 +666,7 @@ trait CommentFactoryBase { this: MemberLookupBase =>
}
def summary(): Inline = {
- val i = inline(check("."))
+ val i = inline(checkSentenceEnded())
Summary(
if (jump("."))
Chain(List(i, Text(".")))
@@ -785,6 +785,16 @@ trait CommentFactoryBase { this: MemberLookupBase =>
})
}
+ def checkSentenceEnded(): Boolean = {
+ (char == '.') && {
+ val poff = offset
+ nextChar() // read '.'
+ val ok = char == endOfText || char == endOfLine || isWhitespace(char)
+ offset = poff
+ ok
+ }
+ }
+
def reportError(pos: Position, message: String) {
reporter.warning(pos, message)
}
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.css b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.css
index 55fb370a41..3e352a95b3 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.css
+++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.css
@@ -310,6 +310,7 @@ h1 {
position: fixed;
margin-left: 300px;
display: block;
+ -webkit-overflow-scrolling: touch;
}
#content > iframe {
diff --git a/test/files/jvm/deprecation.check b/test/files/jvm/deprecation.check
index d116778d3f..d57b6b55a5 100644
--- a/test/files/jvm/deprecation.check
+++ b/test/files/jvm/deprecation.check
@@ -1,3 +1,3 @@
-warning: there were 4 deprecation warning(s); re-run with -deprecation for details
+warning: there were four deprecation warnings; re-run with -deprecation for details
Note: deprecation/Use_2.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
diff --git a/test/files/jvm/duration-tck.scala b/test/files/jvm/duration-tck.scala
index 3bc8a2c100..7db6c49964 100644
--- a/test/files/jvm/duration-tck.scala
+++ b/test/files/jvm/duration-tck.scala
@@ -61,6 +61,11 @@ object Test extends App {
minf - inf mustBe minf
minf + minf mustBe minf
+ for (i <- Seq(zero, one, two, three)) {
+ i - inf mustBe minf
+ i - minf mustBe inf
+ }
+
inf.compareTo(inf) mustBe 0
inf.compareTo(one) mustBe 1
inf.compareTo(minf) mustBe 1
diff --git a/test/files/jvm/future-spec.check b/test/files/jvm/future-spec.check
index 844ca54682..df1629dd7e 100644
--- a/test/files/jvm/future-spec.check
+++ b/test/files/jvm/future-spec.check
@@ -1 +1 @@
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
diff --git a/test/files/jvm/interpreter.check b/test/files/jvm/interpreter.check
index b55ecc10e6..d124794e72 100644
--- a/test/files/jvm/interpreter.check
+++ b/test/files/jvm/interpreter.check
@@ -95,7 +95,7 @@ scala> case class Bar(n: Int)
defined class Bar
scala> implicit def foo2bar(foo: Foo) = Bar(foo.n)
-warning: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
foo2bar: (foo: Foo)Bar
scala> val bar: Bar = Foo(3)
@@ -269,7 +269,7 @@ scala> xs map (x => x)
res6: Array[_] = Array(1, 2)
scala> xs map (x => (x, x))
-warning: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
res7: Array[(_$1, _$1)] forSome { type _$1 } = Array((1,1), (2,2))
scala>
diff --git a/test/files/jvm/serialization-new.check b/test/files/jvm/serialization-new.check
index 47d7bfd920..1555135926 100644
--- a/test/files/jvm/serialization-new.check
+++ b/test/files/jvm/serialization-new.check
@@ -1,4 +1,4 @@
-warning: there were 2 deprecation warning(s); re-run with -deprecation for details
+warning: there were two deprecation warnings; re-run with -deprecation for details
a1 = Array[1,2,3]
_a1 = Array[1,2,3]
arrayEquals(a1, _a1): true
diff --git a/test/files/jvm/serialization.check b/test/files/jvm/serialization.check
index 47d7bfd920..1555135926 100644
--- a/test/files/jvm/serialization.check
+++ b/test/files/jvm/serialization.check
@@ -1,4 +1,4 @@
-warning: there were 2 deprecation warning(s); re-run with -deprecation for details
+warning: there were two deprecation warnings; re-run with -deprecation for details
a1 = Array[1,2,3]
_a1 = Array[1,2,3]
arrayEquals(a1, _a1): true
diff --git a/test/files/neg/aladdin1055.check b/test/files/neg/aladdin1055.check
new file mode 100644
index 0000000000..41782ae987
--- /dev/null
+++ b/test/files/neg/aladdin1055.check
@@ -0,0 +1,7 @@
+Test_1.scala:2: warning: match may not be exhaustive.
+It would fail on the following input: (_ : this.<local child>)
+ def foo(t: A.T) = t match {
+ ^
+error: No warnings can be incurred under -Xfatal-warnings.
+one warning found
+one error found
diff --git a/test/files/neg/aladdin1055.flags b/test/files/neg/aladdin1055.flags
new file mode 100644
index 0000000000..e8fb65d50c
--- /dev/null
+++ b/test/files/neg/aladdin1055.flags
@@ -0,0 +1 @@
+-Xfatal-warnings \ No newline at end of file
diff --git a/test/files/neg/aladdin1055/A.scala b/test/files/neg/aladdin1055/A.scala
new file mode 100644
index 0000000000..862336e30c
--- /dev/null
+++ b/test/files/neg/aladdin1055/A.scala
@@ -0,0 +1,6 @@
+object A {
+ sealed trait T { def f: Int }
+ class TT extends T { def f = 0 }
+
+ def foo = new T { def f = 1 } // local subclass of sealed trait T
+}
diff --git a/test/files/neg/aladdin1055/Test_1.scala b/test/files/neg/aladdin1055/Test_1.scala
new file mode 100644
index 0000000000..39d9b1dc98
--- /dev/null
+++ b/test/files/neg/aladdin1055/Test_1.scala
@@ -0,0 +1,5 @@
+object Test {
+ def foo(t: A.T) = t match {
+ case a: A.TT => 0
+ }
+}
diff --git a/test/files/neg/checksensible.check b/test/files/neg/checksensible.check
index e5f1a38d96..7de22fef54 100644
--- a/test/files/neg/checksensible.check
+++ b/test/files/neg/checksensible.check
@@ -97,6 +97,7 @@ checksensible.scala:84: warning: comparing values of types EqEqRefTest.this.C3 a
checksensible.scala:95: warning: comparing values of types Unit and Int using `!=' will always yield true
while ((c = in.read) != -1)
^
+warning: there were three deprecation warnings; re-run with -deprecation for details
error: No warnings can be incurred under -Xfatal-warnings.
-33 warnings found
+34 warnings found
one error found
diff --git a/test/files/neg/double-def-top-level.check b/test/files/neg/double-def-top-level.check
new file mode 100644
index 0000000000..85b16e81e5
--- /dev/null
+++ b/test/files/neg/double-def-top-level.check
@@ -0,0 +1,7 @@
+D_3.scala:1: error: C is already defined as class C
+class C
+ ^
+D_3.scala:2: error: O is already defined as object O
+object O
+ ^
+two errors found
diff --git a/test/files/neg/double-def-top-level/A_1.scala b/test/files/neg/double-def-top-level/A_1.scala
new file mode 100644
index 0000000000..c3d68d9d05
--- /dev/null
+++ b/test/files/neg/double-def-top-level/A_1.scala
@@ -0,0 +1,4 @@
+package p
+
+class C
+object O
diff --git a/test/files/neg/double-def-top-level/B_2.scala b/test/files/neg/double-def-top-level/B_2.scala
new file mode 100644
index 0000000000..c328e8c964
--- /dev/null
+++ b/test/files/neg/double-def-top-level/B_2.scala
@@ -0,0 +1,2 @@
+class C /* noerror */
+object O /* noerror */ \ No newline at end of file
diff --git a/test/files/neg/double-def-top-level/C_3.scala b/test/files/neg/double-def-top-level/C_3.scala
new file mode 100644
index 0000000000..e1c327c15a
--- /dev/null
+++ b/test/files/neg/double-def-top-level/C_3.scala
@@ -0,0 +1,2 @@
+class C
+object O \ No newline at end of file
diff --git a/test/files/neg/double-def-top-level/D_3.scala b/test/files/neg/double-def-top-level/D_3.scala
new file mode 100644
index 0000000000..518e0d1c54
--- /dev/null
+++ b/test/files/neg/double-def-top-level/D_3.scala
@@ -0,0 +1,2 @@
+class C
+object O
diff --git a/test/files/neg/overloaded-implicit.check b/test/files/neg/overloaded-implicit.check
index ca0870705d..0e6617d904 100644
--- a/test/files/neg/overloaded-implicit.check
+++ b/test/files/neg/overloaded-implicit.check
@@ -4,6 +4,7 @@ overloaded-implicit.scala:2: warning: parameterized overloaded implicit methods
overloaded-implicit.scala:3: warning: parameterized overloaded implicit methods are not visible as view bounds
implicit def imp1[T](x: Set[T]): Map[T, T] = Map()
^
+warning: there were four feature warnings; re-run with -feature for details
error: No warnings can be incurred under -Xfatal-warnings.
-two warnings found
+three warnings found
one error found
diff --git a/test/files/neg/t1909-object.check b/test/files/neg/t1909-object.check
index 401c1f7ebf..7141c84d4b 100644
--- a/test/files/neg/t1909-object.check
+++ b/test/files/neg/t1909-object.check
@@ -1,4 +1,6 @@
-t1909-object.scala:4: error: !!! SI-1909 Unable to STATICally lift object InnerTrouble$1, which is defined in the self- or super-constructor call of class Kaboom. A VerifyError is likely.
+t1909-object.scala:4: warning: !!! SI-1909 Unable to STATICally lift object InnerTrouble$1, which is defined in the self- or super-constructor call of class Kaboom. A VerifyError is likely.
object InnerTrouble
^
+error: No warnings can be incurred under -Xfatal-warnings.
+one warning found
one error found
diff --git a/test/files/neg/t5675.check b/test/files/neg/t5675.check
index da608a2b78..3b3b2fa04c 100644
--- a/test/files/neg/t5675.check
+++ b/test/files/neg/t5675.check
@@ -1,2 +1,4 @@
-error: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
+error: No warnings can be incurred under -Xfatal-warnings.
+one warning found
one error found
diff --git a/test/files/neg/t6162-inheritance.check b/test/files/neg/t6162-inheritance.check
index 13c78030d9..c9f4ddaec1 100644
--- a/test/files/neg/t6162-inheritance.check
+++ b/test/files/neg/t6162-inheritance.check
@@ -7,12 +7,6 @@ object SubT extends T
usage.scala:8: warning: inheritance from trait S in package t6126 is deprecated
new S {
^
-usage.scala:3: warning: inheritance from class Foo in package t6126 is deprecated: `Foo` will be made final in a future version.
-class SubFoo extends Foo
- ^
-usage.scala:5: warning: inheritance from trait T in package t6126 is deprecated
-object SubT extends T
- ^
error: No warnings can be incurred under -Xfatal-warnings.
-5 warnings found
+three warnings found
one error found
diff --git a/test/files/neg/t6289.check b/test/files/neg/t6289.check
index f6f43cabd3..989932750f 100644
--- a/test/files/neg/t6289.check
+++ b/test/files/neg/t6289.check
@@ -3,7 +3,7 @@ t6289/J.java:2: method does not override or implement a method from a supertype
@Override public void foo() { }
^
1 error
-#partest java7
+#partest !java6
t6289/J.java:2: error: method does not override or implement a method from a supertype
@Override public void foo() { }
^
diff --git a/test/files/neg/t6567.check b/test/files/neg/t6567.check
index a733d75354..f42f157371 100644
--- a/test/files/neg/t6567.check
+++ b/test/files/neg/t6567.check
@@ -4,6 +4,7 @@ t6567.scala:8: warning: Suspicious application of an implicit view (Test.this.a2
t6567.scala:10: warning: Suspicious application of an implicit view (Test.this.a2b) in the argument to Option.apply.
val b: Option[B] = Option(a)
^
+warning: there was one feature warning; re-run with -feature for details
error: No warnings can be incurred under -Xfatal-warnings.
-two warnings found
+three warnings found
one error found
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/t8630.check b/test/files/neg/t8630.check
new file mode 100644
index 0000000000..98b084b153
--- /dev/null
+++ b/test/files/neg/t8630.check
@@ -0,0 +1,7 @@
+t8630.scala:1: error: '{' expected but 'abstract' found.
+package bobsdelights abstract class Fruit( val name: String, val color: String ) object Fruits { object Apple extends Fruit("apple", "red") object Orange extends Fruit("orange", "orange") object Pear extends Fruit("pear", "yellowish") val menu = List(Apple, Orange, Pear) }
+ ^
+t8630.scala:1: error: '}' expected but eof found.
+package bobsdelights abstract class Fruit( val name: String, val color: String ) object Fruits { object Apple extends Fruit("apple", "red") object Orange extends Fruit("orange", "orange") object Pear extends Fruit("pear", "yellowish") val menu = List(Apple, Orange, Pear) }
+ ^
+two errors found
diff --git a/test/files/neg/t8630.scala b/test/files/neg/t8630.scala
new file mode 100644
index 0000000000..ea25227452
--- /dev/null
+++ b/test/files/neg/t8630.scala
@@ -0,0 +1 @@
+package bobsdelights abstract class Fruit( val name: String, val color: String ) object Fruits { object Apple extends Fruit("apple", "red") object Orange extends Fruit("orange", "orange") object Pear extends Fruit("pear", "yellowish") val menu = List(Apple, Orange, Pear) } \ No newline at end of file
diff --git a/test/files/neg/t8675.check b/test/files/neg/t8675.check
new file mode 100644
index 0000000000..4e44fba918
--- /dev/null
+++ b/test/files/neg/t8675.check
@@ -0,0 +1,11 @@
+t8675.scala:13: error: type mismatch;
+ found : Boolean(true)
+ required: String
+ a.update(0, x[A]({new isString(true)})) // !!! allowed
+ ^
+t8675.scala:22: error: type mismatch;
+ found : Boolean(true)
+ required: String
+ new X().m(x[A]({new isString(true)})) // !!! allowed
+ ^
+two errors found
diff --git a/test/files/neg/t8675.scala b/test/files/neg/t8675.scala
new file mode 100644
index 0000000000..ca9bb57ffa
--- /dev/null
+++ b/test/files/neg/t8675.scala
@@ -0,0 +1,24 @@
+class A(s: String) {
+ def foo(x: A) = x
+}
+
+class isString(s: String)
+
+class Test {
+
+ def x[A](a: Any): A = ???
+
+ def test {
+ val a = Array[A]()
+ a.update(0, x[A]({new isString(true)})) // !!! allowed
+
+ // boils down to
+ class X {
+ def m(p: Any) {}
+ }
+ implicit class XOps(x: X) {
+ def m(p: Any) {}
+ }
+ new X().m(x[A]({new isString(true)})) // !!! allowed
+ }
+}
diff --git a/test/files/neg/t8675b.check b/test/files/neg/t8675b.check
new file mode 100644
index 0000000000..cb7ac8af59
--- /dev/null
+++ b/test/files/neg/t8675b.check
@@ -0,0 +1,6 @@
+t8675b.scala:19: error: missing parameter type for expanded function
+The argument types of an anonymous function must be fully known. (SLS 8.5)
+Expected type was: List[Test.Reportable1[?,?]] => Boolean
+ for (path: List[Any] <- (null : Engine1).asRequirement.pathsIncludingSelf.toList) {
+ ^
+one error found
diff --git a/test/files/neg/t8675b.scala b/test/files/neg/t8675b.scala
new file mode 100644
index 0000000000..2c5015b1d0
--- /dev/null
+++ b/test/files/neg/t8675b.scala
@@ -0,0 +1,22 @@
+object Test {
+ trait Engine1
+
+ implicit class EngineTools1[Params, R](e: Engine1) {
+ def asRequirement: Requirement1[Params, R] = ???
+ }
+ trait Requirement1[Params, R] {
+ def pathsIncludingSelf: Traversable[List[Reportable1[Params, R]]]
+ }
+ trait Reportable1[Params, R]
+
+ // "missing paramater type" error was swallowed in 2.11.0 leading to a crash
+ // in the backend.
+ //
+ // This error is itself a regression (or at least a change) in 2.11.0-M7,
+ // specifically in SI-7944. The type paramaters to the implicit view
+ // `EngineTools1` are undetermined, and are now treated as type variables
+ // in the expected type of the closure argument to `withFilter`.
+ for (path: List[Any] <- (null : Engine1).asRequirement.pathsIncludingSelf.toList) {
+ ???
+ }
+}
diff --git a/test/files/neg/tailrec-4.check b/test/files/neg/tailrec-4.check
new file mode 100644
index 0000000000..3ec3274478
--- /dev/null
+++ b/test/files/neg/tailrec-4.check
@@ -0,0 +1,16 @@
+tailrec-4.scala:6: error: could not optimize @tailrec annotated method foo: it contains a recursive call not in tail position
+ @tailrec def foo: Int = foo + 1
+ ^
+tailrec-4.scala:11: error: could not optimize @tailrec annotated method foo: it contains a recursive call not in tail position
+ @tailrec def foo: Int = foo + 1
+ ^
+tailrec-4.scala:17: error: could not optimize @tailrec annotated method foo: it contains a recursive call not in tail position
+ @tailrec def foo: Int = foo + 1
+ ^
+tailrec-4.scala:23: error: could not optimize @tailrec annotated method foo: it contains a recursive call not in tail position
+ @tailrec def foo: Int = foo + 1
+ ^
+tailrec-4.scala:31: error: could not optimize @tailrec annotated method foo: it contains a recursive call not in tail position
+ @tailrec def foo: Int = foo + 1
+ ^
+5 errors found
diff --git a/test/files/neg/tailrec-4.scala b/test/files/neg/tailrec-4.scala
new file mode 100644
index 0000000000..4822799dfa
--- /dev/null
+++ b/test/files/neg/tailrec-4.scala
@@ -0,0 +1,35 @@
+import annotation._
+
+object Tail {
+ def tcInFunc: Unit = {
+ () => {
+ @tailrec def foo: Int = foo + 1
+ }
+ }
+ def tcInBooleanExprFirstOp(x: Int, v: Int): Boolean = {
+ {
+ @tailrec def foo: Int = foo + 1
+ foo
+ } == v && true
+ }
+ def tcInBooleanExprSecondOp(x: Int, v: Int): Boolean = {
+ true && {
+ @tailrec def foo: Int = foo + 1
+ foo
+ } == v
+ }
+ def tcInIfCond(x: Int, v: Int): Boolean = {
+ if ({
+ @tailrec def foo: Int = foo + 1
+ foo
+ } == v) true else false
+ }
+ def tcInPatternGuard(x: Int, v: Int): Boolean =
+ v match {
+ case _ if
+ {
+ @tailrec def foo: Int = foo + 1
+ foo == 42
+ } => true
+ }
+}
diff --git a/test/files/neg/unchecked-refinement.check b/test/files/neg/unchecked-refinement.check
index e85a51f44d..0bb944621b 100644
--- a/test/files/neg/unchecked-refinement.check
+++ b/test/files/neg/unchecked-refinement.check
@@ -10,6 +10,7 @@ unchecked-refinement.scala:23: warning: a pattern match on a refinement type is
unchecked-refinement.scala:24: warning: a pattern match on a refinement type is unchecked
/* nowarn - todo */ case x: AnyRef { def size: Int } if b => x.size // this could/should do a static conformance test and not warn
^
+warning: there was one feature warning; re-run with -feature for details
error: No warnings can be incurred under -Xfatal-warnings.
-four warnings found
+5 warnings found
one error found
diff --git a/test/files/neg/virtpatmat_exhaust_compound.check b/test/files/neg/virtpatmat_exhaust_compound.check
new file mode 100644
index 0000000000..72e0340682
--- /dev/null
+++ b/test/files/neg/virtpatmat_exhaust_compound.check
@@ -0,0 +1,15 @@
+virtpatmat_exhaust_compound.scala:14: warning: match may not be exhaustive.
+It would fail on the following inputs: O1, O2, O4
+ a match {
+ ^
+virtpatmat_exhaust_compound.scala:18: warning: match may not be exhaustive.
+It would fail on the following input: O4
+ def t1(a: Product with Base with Base2) = a match {
+ ^
+virtpatmat_exhaust_compound.scala:22: warning: match may not be exhaustive.
+It would fail on the following input: O2
+ def t2(a: Product with Base { def foo: Int }) = a match {
+ ^
+error: No warnings can be incurred under -Xfatal-warnings.
+three warnings found
+one error found
diff --git a/test/files/neg/virtpatmat_exhaust_compound.flags b/test/files/neg/virtpatmat_exhaust_compound.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/neg/virtpatmat_exhaust_compound.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/neg/virtpatmat_exhaust_compound.scala b/test/files/neg/virtpatmat_exhaust_compound.scala
new file mode 100644
index 0000000000..386c7af98d
--- /dev/null
+++ b/test/files/neg/virtpatmat_exhaust_compound.scala
@@ -0,0 +1,29 @@
+sealed trait Base
+case object O1 extends Base
+case object O2 extends Base {
+ def foo: Int = 0
+}
+
+sealed trait Base2
+case object O3 extends Base2
+
+case object O4 extends Base with Base2
+
+object Test {
+ val a /*: Product with Serialiable with Base */ = if (true) O1 else O2
+ a match {
+ case null =>
+ }
+
+ def t1(a: Product with Base with Base2) = a match {
+ case null => // O1..O3 should *not* be possible here
+ }
+
+ def t2(a: Product with Base { def foo: Int }) = a match {
+ case null => // O2 in the domain
+ }
+
+ def t3(a: Product with Base { def bar: Int }) = a match {
+ case null => // nothing in the domain
+ }
+}
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/t8596.flags b/test/files/pos/t8596.flags
new file mode 100644
index 0000000000..281f0a10cd
--- /dev/null
+++ b/test/files/pos/t8596.flags
@@ -0,0 +1 @@
+-Yrangepos
diff --git a/test/files/pos/t8596.scala b/test/files/pos/t8596.scala
new file mode 100644
index 0000000000..bfed58eadf
--- /dev/null
+++ b/test/files/pos/t8596.scala
@@ -0,0 +1,7 @@
+class TypeTreeObjects {
+ class Container {
+ def typeParamAndDefaultArg[C](name: String = ""): String = ""
+ }
+ // crashed under -Yrangepos
+ new Container().typeParamAndDefaultArg[Any]()
+}
diff --git a/test/files/pos/t8617.flags b/test/files/pos/t8617.flags
new file mode 100644
index 0000000000..281f0a10cd
--- /dev/null
+++ b/test/files/pos/t8617.flags
@@ -0,0 +1 @@
+-Yrangepos
diff --git a/test/files/pos/t8617.scala b/test/files/pos/t8617.scala
new file mode 100644
index 0000000000..fc825bbcba
--- /dev/null
+++ b/test/files/pos/t8617.scala
@@ -0,0 +1,10 @@
+object Test {
+ def foo[A] = implicitly[OptManifest[A]] // was "unpositioned tree" under -Yrangepos
+
+ // These did not crash, but testing for good measure.
+ implicitly[OptManifest[String]]
+ implicitly[Manifest[String]]
+
+ implicitly[reflect.ClassTag[String]]
+ implicitly[reflect.runtime.universe.TypeTag[String]]
+}
diff --git a/test/files/pos/t8625.scala b/test/files/pos/t8625.scala
new file mode 100644
index 0000000000..95c4b0dbcd
--- /dev/null
+++ b/test/files/pos/t8625.scala
@@ -0,0 +1,5 @@
+object Test {
+ def f1(a: Boolean, b: Boolean) = (a || ???) && (b || ???)
+ def f2(a: Boolean, b: Boolean) = (a || ???) && b
+ def f3(a: Boolean, b: Boolean) = (a && ???) || b
+}
diff --git a/test/files/pos/t8708/Either_1.scala b/test/files/pos/t8708/Either_1.scala
new file mode 100644
index 0000000000..000ed6e7c2
--- /dev/null
+++ b/test/files/pos/t8708/Either_1.scala
@@ -0,0 +1,6 @@
+sealed trait \/[+A, +B]
+
+sealed trait EitherT[F[+_], +A, +B]
+object EitherT {
+ def apply[F[+_], A, B](a: F[A \/ B]): EitherT[F, A, B] = new EitherT[F, A, B] { val run = a }
+}
diff --git a/test/files/pos/t8708/Test_2.scala b/test/files/pos/t8708/Test_2.scala
new file mode 100644
index 0000000000..d0e56b9a37
--- /dev/null
+++ b/test/files/pos/t8708/Test_2.scala
@@ -0,0 +1,13 @@
+import scala.language.higherKinds
+
+trait ClientTypes[M[+_]] {
+ final type Context[+A] = EitherT[M, String, A]
+ object Context {
+ def apply[A](ca: M[String \/ A]): Context[A] = EitherT[M, String, A](ca)
+ }
+
+ final type StatefulContext[+A] = EitherT[Context, String, A]
+ object StatefulContext {
+ def apply[A](state: Context[String \/ A]): StatefulContext[A] = ???
+ }
+}
diff --git a/test/files/presentation/ide-bug-1000531.check b/test/files/presentation/ide-bug-1000531.check
index d8c7a369f7..12eafcd6de 100644
--- a/test/files/presentation/ide-bug-1000531.check
+++ b/test/files/presentation/ide-bug-1000531.check
@@ -1,111 +1,24 @@
-reload: CrashOnLoad.scala
+reload: CrashOnLoad.scala, TestIterable.java
-askTypeCompletion at CrashOnLoad.scala(6,12)
+askTypeCompletion at CrashOnLoad.scala(6,11)
================================================================================
-[response] askTypeCompletion at (6,12)
-retrieved 117 members
+[response] askTypeCompletion at (6,11)
+retrieved 30 members
[inaccessible] protected[package lang] def clone(): Object
[inaccessible] protected[package lang] def finalize(): Unit
-[inaccessible] protected[this] def reversed: List[B]
-class GroupedIterator[B >: A] extends AbstractIterator[Seq[B]] with Iterator[Seq[B]]
def +(other: String): String
-def ++[B >: B](that: => scala.collection.GenTraversableOnce[B]): Iterator[B]
-def ->[B](y: B): (java.util.Iterator[B], B)
-def /:[B](z: B)(op: (B, B) => B): B
-def :\[B](z: B)(op: (B, B) => B): B
-def addString(b: StringBuilder): StringBuilder
-def addString(b: StringBuilder,sep: String): StringBuilder
-def addString(b: StringBuilder,start: String,sep: String,end: String): StringBuilder
-def aggregate[B](z: => B)(seqop: (B, B) => B,combop: (B, B) => B): B
-def buffered: scala.collection.BufferedIterator[B]
-def collectFirst[B](pf: PartialFunction[B,B]): Option[B]
-def collect[B](pf: PartialFunction[B,B]): Iterator[B]
-def contains(elem: Any): Boolean
-def copyToArray[B >: B](xs: Array[B]): Unit
-def copyToArray[B >: B](xs: Array[B],start: Int): Unit
-def copyToArray[B >: B](xs: Array[B],start: Int,len: Int): Unit
-def copyToBuffer[B >: B](dest: scala.collection.mutable.Buffer[B]): Unit
-def corresponds[B](that: scala.collection.GenTraversableOnce[B])(p: (B, B) => Boolean): Boolean
-def count(p: B => Boolean): Int
-def drop(n: Int): Iterator[B]
-def dropWhile(p: B => Boolean): Iterator[B]
-def duplicate: (Iterator[B], Iterator[B])
-def ensuring(cond: Boolean): java.util.Iterator[B]
-def ensuring(cond: Boolean,msg: => Any): java.util.Iterator[B]
-def ensuring(cond: java.util.Iterator[B] => Boolean): java.util.Iterator[B]
-def ensuring(cond: java.util.Iterator[B] => Boolean,msg: => Any): java.util.Iterator[B]
+def ->[B](y: B): (other.TestIterator[Nothing], B)
+def ensuring(cond: Boolean): other.TestIterator[Nothing]
+def ensuring(cond: Boolean,msg: => Any): other.TestIterator[Nothing]
+def ensuring(cond: other.TestIterator[Nothing] => Boolean): other.TestIterator[Nothing]
+def ensuring(cond: other.TestIterator[Nothing] => Boolean,msg: => Any): other.TestIterator[Nothing]
def equals(x$1: Any): Boolean
-def exists(p: B => Boolean): Boolean
-def filter(p: B => Boolean): Iterator[B]
-def filterNot(p: B => Boolean): Iterator[B]
-def find(p: B => Boolean): Option[B]
-def flatMap[B](f: B => scala.collection.GenTraversableOnce[B]): Iterator[B]
-def foldLeft[B](z: B)(op: (B, B) => B): B
-def foldRight[B](z: B)(op: (B, B) => B): B
-def fold[A1 >: B](z: A1)(op: (A1, A1) => A1): A1
-def forall(p: B => Boolean): Boolean
-def foreach[U](f: B => U): Unit
def formatted(fmtstr: String): String
-def grouped[B >: B](size: Int): Iterator[B]#GroupedIterator[B]
-def hasDefiniteSize: Boolean
-def hasNext(): Boolean
+def hasNext: Boolean
def hashCode(): Int
-def indexOf[B >: B](elem: B): Int
-def indexWhere(p: B => Boolean): Int
-def isEmpty: Boolean
-def isTraversableAgain: Boolean
-def length: Int
-def map[B](f: B => B): Iterator[B]
-def maxBy[B](f: B => B)(implicit cmp: Ordering[B]): B
-def max[B >: B](implicit cmp: Ordering[B]): B
-def minBy[B](f: B => B)(implicit cmp: Ordering[B]): B
-def min[B >: B](implicit cmp: Ordering[B]): B
-def mkString(sep: String): String
-def mkString(start: String,sep: String,end: String): String
-def mkString: String
-def next(): B
-def nonEmpty: Boolean
-def padTo[A1 >: B](len: Int,elem: A1): Iterator[A1]
-def partition(p: B => Boolean): (Iterator[B], Iterator[B])
-def patch[B >: B](from: Int,patchElems: Iterator[B],replaced: Int): Iterator[B]
-def product[B >: B](implicit num: Numeric[B]): B
-def reduceLeftOption[B >: B](op: (B, B) => B): Option[B]
-def reduceLeft[B >: B](op: (B, B) => B): B
-def reduceOption[A1 >: B](op: (A1, A1) => A1): Option[A1]
-def reduceRightOption[B >: B](op: (B, B) => B): Option[B]
-def reduceRight[B >: B](op: (B, B) => B): B
-def reduce[A1 >: B](op: (A1, A1) => A1): A1
-def remove(): Unit
-def sameElements(that: Iterator[_]): Boolean
-def scanLeft[B](z: B)(op: (B, B) => B): Iterator[B]
-def scanRight[B](z: B)(op: (B, B) => B): Iterator[B]
-def seq: Iterator[B]
-def size: Int
-def slice(from: Int,until: Int): Iterator[B]
-def sliding[B >: B](size: Int,step: Int): Iterator[B]#GroupedIterator[B]
-def span(p: B => Boolean): (Iterator[B], Iterator[B])
-def sum[B >: B](implicit num: Numeric[B]): B
-def take(n: Int): Iterator[B]
-def takeWhile(p: B => Boolean): Iterator[B]
-def toArray[B >: B](implicit evidence$1: scala.reflect.ClassTag[B]): Array[B]
-def toBuffer[B >: B]: scala.collection.mutable.Buffer[B]
-def toIndexedSeq: scala.collection.immutable.IndexedSeq[B]
-def toIterable: Iterable[B]
-def toIterator: Iterator[B]
-def toList: List[B]
-def toMap[T, U](implicit ev: <:<[B,(T, U)]): scala.collection.immutable.Map[T,U]
-def toSeq: Seq[B]
-def toSet[B >: B]: scala.collection.immutable.Set[B]
-def toStream: scala.collection.immutable.Stream[B]
+def next: T
def toString(): String
-def toTraversable: Traversable[B]
-def toVector: Vector[B]
-def to[Col[_]](implicit cbf: scala.collection.generic.CanBuildFrom[Nothing,B,Col[B]]): Col[B]
-def withFilter(p: B => Boolean): Iterator[B]
-def zipAll[B, A1 >: B, B1 >: B](that: Iterator[B],thisElem: A1,thatElem: B1): Iterator[(A1, B1)]
-def zipWithIndex: Iterator[(B, Int)]
-def zip[B](that: Iterator[B]): Iterator[(B, B)]
-def →[B](y: B): (java.util.Iterator[B], B)
+def →[B](y: B): (other.TestIterator[Nothing], B)
final def !=(x$1: Any): Boolean
final def ##(): Int
final def ==(x$1: Any): Boolean
diff --git a/test/files/presentation/ide-bug-1000531/src/CrashOnLoad.scala b/test/files/presentation/ide-bug-1000531/src/CrashOnLoad.scala
index 878bbfa19e..3f59282083 100644
--- a/test/files/presentation/ide-bug-1000531/src/CrashOnLoad.scala
+++ b/test/files/presentation/ide-bug-1000531/src/CrashOnLoad.scala
@@ -1,7 +1,14 @@
/** When this files is opened within the IDE, a typing error is reported. */
-class A[B] extends java.lang.Iterable[B] {
+class A[B] extends TestIterable[B] {
import scala.collection.JavaConversions._
- def iterator = Iterator.empty
+ def iterator: other.TestIterator[Nothing] = ???
- iterator. /*!*/
-} \ No newline at end of file
+ iterator./*!*/
+}
+
+object other {
+ trait TestIterator[T] {
+ def hasNext: Boolean
+ def next: T
+ }
+}
diff --git a/test/files/presentation/ide-bug-1000531/src/TestIterable.java b/test/files/presentation/ide-bug-1000531/src/TestIterable.java
new file mode 100644
index 0000000000..84a6fe77f1
--- /dev/null
+++ b/test/files/presentation/ide-bug-1000531/src/TestIterable.java
@@ -0,0 +1,7 @@
+public abstract class TestIterable<T> {
+ public abstract TestIterator<T> iterator();
+ public static abstract class TestIterator<T> {
+ public abstract T next();
+ public abstract boolean hasNext();
+ }
+}
diff --git a/test/files/presentation/t7915.check b/test/files/presentation/t7915.check
index b18b4ddb55..0849aaa82b 100644
--- a/test/files/presentation/t7915.check
+++ b/test/files/presentation/t7915.check
@@ -9,3 +9,23 @@ askHyperlinkPos for `bar` at (7,22) Foo.scala
================================================================================
[response] found askHyperlinkPos for `bar` at (2,7) Foo.scala
================================================================================
+
+askHyperlinkPos for `Bar` at (8,11) Foo.scala
+================================================================================
+[response] found askHyperlinkPos for `Bar` at (1,7) Foo.scala
+================================================================================
+
+askHyperlinkPos for `baz` at (8,22) Foo.scala
+================================================================================
+[response] found askHyperlinkPos for `baz` at (2,31) Foo.scala
+================================================================================
+
+askHyperlinkPos for `Bar` at (9,11) Foo.scala
+================================================================================
+[response] found askHyperlinkPos for `Bar` at (1,7) Foo.scala
+================================================================================
+
+askHyperlinkPos for `baz` at (9,22) Foo.scala
+================================================================================
+[response] found askHyperlinkPos for `baz` at (2,31) Foo.scala
+================================================================================
diff --git a/test/files/presentation/t7915/src/Foo.scala b/test/files/presentation/t7915/src/Foo.scala
index a4166ae5b4..5c9ca36a6e 100644
--- a/test/files/presentation/t7915/src/Foo.scala
+++ b/test/files/presentation/t7915/src/Foo.scala
@@ -1,9 +1,11 @@
class Bar {
- def bar(b: Int = 2) {}
+ def bar(b: Int = 2) {}; def baz[X](b: Int = 2) {}
}
class Foo {
def foo() {
new Bar/*#*/().bar/*#*/()
+ new Bar/*#*/().baz/*#*/[Any]()
+ new Bar/*#*/().baz/*#*/()
}
}
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/analyzerPlugins.check b/test/files/run/analyzerPlugins.check
index e3ab554d4c..9803465ddc 100644
--- a/test/files/run/analyzerPlugins.check
+++ b/test/files/run/analyzerPlugins.check
@@ -19,7 +19,7 @@ canAdaptAnnotations(Trees$Typed, Any) [1]
canAdaptAnnotations(Trees$Typed, Int) [1]
lub(List(Int @testAnn, Int)) [1]
pluginsPt(?, Trees$Annotated) [7]
-pluginsPt(?, Trees$Apply) [9]
+pluginsPt(?, Trees$Apply) [8]
pluginsPt(?, Trees$ApplyImplicitView) [2]
pluginsPt(?, Trees$Assign) [7]
pluginsPt(?, Trees$Block) [4]
@@ -31,13 +31,13 @@ pluginsPt(?, Trees$Literal) [16]
pluginsPt(?, Trees$New) [5]
pluginsPt(?, Trees$PackageDef) [1]
pluginsPt(?, Trees$Return) [1]
-pluginsPt(?, Trees$Select) [48]
+pluginsPt(?, Trees$Select) [47]
pluginsPt(?, Trees$Super) [2]
pluginsPt(?, Trees$This) [20]
-pluginsPt(?, Trees$TypeApply) [4]
+pluginsPt(?, Trees$TypeApply) [3]
pluginsPt(?, Trees$TypeBoundsTree) [2]
pluginsPt(?, Trees$TypeDef) [1]
-pluginsPt(?, Trees$TypeTree) [39]
+pluginsPt(?, Trees$TypeTree) [38]
pluginsPt(?, Trees$Typed) [1]
pluginsPt(?, Trees$ValDef) [21]
pluginsPt(Any, Trees$Literal) [2]
@@ -98,7 +98,6 @@ pluginsTyped(()String, Trees$Ident) [1]
pluginsTyped(()String, Trees$TypeApply) [1]
pluginsTyped(()scala.annotation.Annotation, Trees$Select) [1]
pluginsTyped(()testAnn, Trees$Select) [10]
-pluginsTyped(()type, Trees$TypeApply) [1]
pluginsTyped((str: String)A <and> (param: Double)A, Trees$Select) [1]
pluginsTyped((x$1: Any)Boolean <and> (x: Double)Boolean <and> (x: Float)Boolean <and> (x: Long)Boolean <and> (x: Int)Boolean <and> (x: Char)Boolean <and> (x: Short)Boolean <and> (x: Byte)Boolean, Trees$Select) [1]
pluginsTyped((x$1: Int)Unit, Trees$Select) [1]
@@ -173,7 +172,7 @@ pluginsTyped(Unit, Trees$Literal) [5]
pluginsTyped(Unit, Trees$TypeTree) [1]
pluginsTyped([A](xs: A*)List[A], Trees$Select) [1]
pluginsTyped([T <: Int]=> Int, Trees$Select) [1]
-pluginsTyped([T0]()T0, Trees$Select) [2]
+pluginsTyped([T0]()T0, Trees$Select) [1]
pluginsTyped([T](xs: Array[T])scala.collection.mutable.WrappedArray[T], Trees$Select) [1]
pluginsTyped(annotation.type, Trees$Select) [4]
pluginsTyped(math.type, Trees$Select) [9]
@@ -190,7 +189,5 @@ pluginsTyped(testAnn, Trees$New) [5]
pluginsTyped(testAnn, Trees$This) [1]
pluginsTyped(testAnn, Trees$TypeTree) [2]
pluginsTyped(testAnn.super.type, Trees$Super) [1]
-pluginsTyped(type, Trees$Apply) [1]
pluginsTyped(type, Trees$Select) [1]
-pluginsTyped(type, Trees$TypeTree) [1]
pluginsTypedReturn(return f, String) [1]
diff --git a/test/files/run/classfile-format-51.scala b/test/files/run/classfile-format-51.scala
index f92382d89b..24b1ee8397 100644
--- a/test/files/run/classfile-format-51.scala
+++ b/test/files/run/classfile-format-51.scala
@@ -32,7 +32,7 @@ object Test extends DirectTest {
val constructor = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null)
constructor.visitCode()
constructor.visitVarInsn(ALOAD, 0)
- constructor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V")
+ constructor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)
constructor.visitInsn(RETURN)
constructor.visitMaxs(1, 1)
constructor.visitEnd()
@@ -47,19 +47,19 @@ object Test extends DirectTest {
val bootstrap = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, bootstrapMethodName, bootStrapMethodType, null, null)
bootstrap.visitCode()
// val lookup = MethodHandles.lookup();
- bootstrap.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;")
+ bootstrap.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false)
bootstrap.visitVarInsn(ASTORE, 3) // lookup
// val clazz = lookup.lookupClass();
bootstrap.visitVarInsn(ALOAD, 3) // lookup
- bootstrap.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "lookupClass", "()Ljava/lang/Class;")
+ bootstrap.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "lookupClass", "()Ljava/lang/Class;", false)
bootstrap.visitVarInsn(ASTORE, 4) // clazz
// val methodType = MethodType.fromMethodDescriptorString("()Ljava/lang/String, clazz.getClassLoader()")
bootstrap.visitLdcInsn("()Ljava/lang/String;")
bootstrap.visitVarInsn(ALOAD, 4) // CLAZZ
- bootstrap.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;")
- bootstrap.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "fromMethodDescriptorString", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;")
+ bootstrap.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false)
+ bootstrap.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "fromMethodDescriptorString", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;", false)
bootstrap.visitVarInsn(ASTORE, 5) // methodType
// val methodHandle = lookup.findStatic(thisClass, "target", methodType)
@@ -67,14 +67,14 @@ object Test extends DirectTest {
bootstrap.visitVarInsn(ALOAD, 4) // clazz
bootstrap.visitLdcInsn("target")
bootstrap.visitVarInsn(ALOAD, 5) // methodType
- bootstrap.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStatic", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;")
+ bootstrap.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStatic", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false)
bootstrap.visitVarInsn(ASTORE, 6) // methodHandle
// new ConstantCallSite(methodHandle)
bootstrap.visitTypeInsn(NEW, "java/lang/invoke/ConstantCallSite")
bootstrap.visitInsn(DUP)
bootstrap.visitVarInsn(ALOAD, 6) // methodHandle
- bootstrap.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", "<init>", "(Ljava/lang/invoke/MethodHandle;)V")
+ bootstrap.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", "<init>", "(Ljava/lang/invoke/MethodHandle;)V", false)
bootstrap.visitInsn(ARETURN)
bootstrap.visitMaxs(4,7)
bootstrap.visitEnd()
diff --git a/test/files/run/collection-stacks.check b/test/files/run/collection-stacks.check
index 895bde374d..3a366bfcdf 100644
--- a/test/files/run/collection-stacks.check
+++ b/test/files/run/collection-stacks.check
@@ -1,4 +1,4 @@
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
3-2-1: true
3-2-1: true
apply
diff --git a/test/files/run/colltest.check b/test/files/run/colltest.check
index 1e850bb582..9579d781aa 100644
--- a/test/files/run/colltest.check
+++ b/test/files/run/colltest.check
@@ -1,4 +1,4 @@
-warning: there were 2 deprecation warning(s); re-run with -deprecation for details
+warning: there were two deprecation warnings; re-run with -deprecation for details
true
false
true
diff --git a/test/files/run/colltest1.scala b/test/files/run/colltest1.scala
index 8dce69afc9..e0ec378585 100644
--- a/test/files/run/colltest1.scala
+++ b/test/files/run/colltest1.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warning\(s\); re-run with -Yinline-warnings for details
+ * filter: inliner warnings; re-run with -Yinline-warnings for details
*/
import scala.collection._
import scala.language.postfixOps
diff --git a/test/files/run/compiler-asSeenFrom.scala b/test/files/run/compiler-asSeenFrom.scala
index ea96c6fba7..677dd40ddc 100644
--- a/test/files/run/compiler-asSeenFrom.scala
+++ b/test/files/run/compiler-asSeenFrom.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warning\(s\); re-run with -Yinline-warnings for details
+ * filter: inliner warning; re-run with -Yinline-warnings for details
*/
import scala.tools.nsc._
import scala.tools.partest.DirectTest
diff --git a/test/files/run/constrained-types.check b/test/files/run/constrained-types.check
index 9a106785a1..a3cd59b9fb 100644
--- a/test/files/run/constrained-types.check
+++ b/test/files/run/constrained-types.check
@@ -71,11 +71,11 @@ scala> var four = "four"
four: String = four
scala> val four2 = m(four) // should have an existential bound
-warning: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
four2: String @Annot(x) forSome { val x: String } = four
scala> val four3 = four2 // should have the same type as four2
-warning: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
four3: String @Annot(x) forSome { val x: String } = four
scala> val stuff = m("stuff") // should not crash
@@ -98,7 +98,7 @@ scala> def m = {
val y : String @Annot(x) = x
y
} // x should not escape the local scope with a narrow type
-warning: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
m: String @Annot(x) forSome { val x: String }
scala>
@@ -112,7 +112,7 @@ scala> def n(y: String) = {
}
m("stuff".stripMargin)
} // x should be existentially bound
-warning: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
n: (y: String)String @Annot(x) forSome { val x: String }
scala>
diff --git a/test/files/run/delambdafy_t6028.check b/test/files/run/delambdafy_t6028.check
index 92cfbaefb6..7bd8cd7202 100644
--- a/test/files/run/delambdafy_t6028.check
+++ b/test/files/run/delambdafy_t6028.check
@@ -54,4 +54,4 @@ package <empty> {
}
}
-warning: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
diff --git a/test/files/run/delay-bad.check b/test/files/run/delay-bad.check
index 5d8c5fa1d4..cb6e329f7a 100644
--- a/test/files/run/delay-bad.check
+++ b/test/files/run/delay-bad.check
@@ -4,7 +4,7 @@ delay-bad.scala:53: warning: a pure expression does nothing in statement positio
delay-bad.scala:73: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
f(new { val x = 5 } with E() { 5 })
^
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
// new C { }
diff --git a/test/files/run/eta-expand-star2.check b/test/files/run/eta-expand-star2.check
index cbf4781255..d6929e4969 100644
--- a/test/files/run/eta-expand-star2.check
+++ b/test/files/run/eta-expand-star2.check
@@ -1,2 +1,2 @@
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
hello
diff --git a/test/files/run/existentials-in-compiler.scala b/test/files/run/existentials-in-compiler.scala
index d019d56b42..dfc7048b31 100644
--- a/test/files/run/existentials-in-compiler.scala
+++ b/test/files/run/existentials-in-compiler.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warning\(s\); re-run with -Yinline-warnings for details
+ * filter: inliner warnings; re-run with -Yinline-warnings for details
*/
import scala.tools.nsc._
import scala.tools.partest.CompilerTest
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/icode-reader-dead-code.check b/test/files/run/icode-reader-dead-code.check
new file mode 100644
index 0000000000..d1739fed3b
--- /dev/null
+++ b/test/files/run/icode-reader-dead-code.check
@@ -0,0 +1,19 @@
+Bytecode for method f
+ L0
+ LINENUMBER 4 L0
+ ICONST_1
+ IRETURN
+ L1
+ LOCALVARIABLE this Lp/A; L0 L1 0
+ MAXSTACK = 1
+ MAXLOCALS = 1
+Bytecode for method f
+ L0
+ LINENUMBER 4 L0
+ ICONST_1
+ ATHROW
+ IRETURN
+ L1
+ LOCALVARIABLE this Lp/A; L0 L1 0
+ MAXSTACK = 1
+ MAXLOCALS = 1
diff --git a/test/files/run/icode-reader-dead-code.scala b/test/files/run/icode-reader-dead-code.scala
new file mode 100644
index 0000000000..00ba58829f
--- /dev/null
+++ b/test/files/run/icode-reader-dead-code.scala
@@ -0,0 +1,82 @@
+import java.io.{FileOutputStream, FileInputStream}
+
+import scala.tools.asm.{ClassWriter, Opcodes, ClassReader}
+import scala.tools.asm.tree.{InsnNode, ClassNode}
+import scala.tools.nsc.backend.jvm.AsmUtils
+import scala.tools.partest.DirectTest
+import scala.collection.JavaConverters._
+
+/**
+ * Test that the ICodeReader does not crash if the bytecode of a method has unreachable code.
+ */
+object Test extends DirectTest {
+ def code: String = ???
+
+ def show(): Unit = {
+ // The bytecode of f will be modified using ASM by `addDeadCode`
+ val aCode =
+ """
+ |package p
+ |class A {
+ | @inline final def f = 1
+ |}
+ """.stripMargin
+
+ val bCode =
+ """
+ |package p
+ |class B {
+ | def g = (new A()).f
+ |}
+ """.stripMargin
+
+ compileString(newCompiler("-usejavacp"))(aCode)
+
+ addDeadCode()
+
+ // If inlining fails, the compiler will issue an inliner warning that is not present in the
+ // check file
+ compileString(newCompiler("-usejavacp", "-optimise"))(bCode)
+ }
+
+ def readClass(file: String) = {
+ val cnode = new ClassNode()
+ val is = new FileInputStream(file)
+ val reader = new ClassReader(is)
+ reader.accept(cnode, 0)
+ is.close()
+ cnode
+ }
+
+ def writeClass(file: String, cnode: ClassNode): Unit = {
+ val writer = new ClassWriter(0)
+ cnode.accept(writer)
+
+ val os = new FileOutputStream(file)
+ os.write(writer.toByteArray)
+ os.close()
+ }
+
+ def addDeadCode() {
+ val file = (testOutput / "p" / "A.class").path
+ val cnode = readClass(file)
+ val method = cnode.methods.asScala.find(_.name == "f").head
+
+ AsmUtils.traceMethod(method)
+
+ val insns = method.instructions
+ val it = insns.iterator()
+ while (it.hasNext) {
+ val in = it.next()
+ if (in.getOpcode == Opcodes.IRETURN) {
+ // Insert an ATHROW before the IRETURN. The IRETURN will then be dead code.
+ // The ICodeReader should not crash if there's dead code.
+ insns.insert(in.getPrevious, new InsnNode(Opcodes.ATHROW))
+ }
+ }
+
+ AsmUtils.traceMethod(method)
+
+ writeClass(file, cnode)
+ }
+}
diff --git a/test/files/run/inferred-type-constructors.check b/test/files/run/inferred-type-constructors.check
index 5992ef02ad..4a63853bd9 100644
--- a/test/files/run/inferred-type-constructors.check
+++ b/test/files/run/inferred-type-constructors.check
@@ -1,4 +1,4 @@
-warning: there were 2 feature warning(s); re-run with -feature for details
+warning: there were two feature warnings; re-run with -feature for details
p.Iterable[Int]
p.Set[Int]
p.Seq[Int]
diff --git a/test/files/run/is-valid-num.scala b/test/files/run/is-valid-num.scala
index 65e8ceeca6..4ab2fac8dd 100644
--- a/test/files/run/is-valid-num.scala
+++ b/test/files/run/is-valid-num.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warning\(s\); re-run with -Yinline-warnings for details
+ * filter: inliner warnings; re-run with -Yinline-warnings for details
*/
object Test {
def x = BigInt("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
diff --git a/test/files/run/iterator-from.scala b/test/files/run/iterator-from.scala
index 269e859657..e2ca5864ea 100644
--- a/test/files/run/iterator-from.scala
+++ b/test/files/run/iterator-from.scala
@@ -1,5 +1,5 @@
/* This file tests iteratorFrom, keysIteratorFrom, and valueIteratorFrom on various sorted sets and maps
- * filter: inliner warning\(s\); re-run with -Yinline-warnings for details
+ * filter: inliner warnings; re-run with -Yinline-warnings for details
*/
import scala.util.{Random => R}
diff --git a/test/files/run/large_class.check b/test/files/run/large_class.check
new file mode 100644
index 0000000000..0585c267ac
--- /dev/null
+++ b/test/files/run/large_class.check
@@ -0,0 +1,3 @@
+newSource1.scala:1: error: Could not write class BigEnoughToFail because it exceeds JVM code size limits. Class file too large!
+class BigEnoughToFail {
+ ^
diff --git a/test/files/run/large_class.scala b/test/files/run/large_class.scala
new file mode 100644
index 0000000000..aa486ef8f7
--- /dev/null
+++ b/test/files/run/large_class.scala
@@ -0,0 +1,27 @@
+import scala.tools.partest._
+import java.io.{Console => _, _}
+
+// a cold run of partest takes about 15s for this test on my laptop
+object Test extends DirectTest {
+ override def extraSettings: String = "-usejavacp -d " + testOutput.path
+
+ def s(n: Int) = "\""+n+"\""
+
+ override def code
+ = s"""
+ |class BigEnoughToFail {
+ | def m(a: String, b: String, c: String, d: String, e: String, f: String) = null
+ | ${(1 to 5500) map (n => "def f"+n+" = m("+ s(n+10000)+","+
+ s(n+20000)+","+
+ s(n+30000)+","+
+ s(n+40000)+","+
+ s(n+50000)+","+
+ s(n+60000)+")") mkString ";"}
+ |}""".stripMargin.trim
+
+ override def show(): Unit = {
+ Console.withErr(System.out) {
+ compile()
+ }
+ }
+}
diff --git a/test/files/run/literals.check b/test/files/run/literals.check
index ed7c6ca5b3..62c5fd68ae 100644
--- a/test/files/run/literals.check
+++ b/test/files/run/literals.check
@@ -1,4 +1,4 @@
-warning: there were 5 deprecation warning(s); re-run with -deprecation for details
+warning: there were 5 deprecation warnings; re-run with -deprecation for details
test '\u0024' == '$' was successful
test '\u005f' == '_' was successful
test 65.asInstanceOf[Char] == 'A' was successful
diff --git a/test/files/run/macro-rangepos-args.check b/test/files/run/macro-rangepos-args.check
new file mode 100644
index 0000000000..d779505c66
--- /dev/null
+++ b/test/files/run/macro-rangepos-args.check
@@ -0,0 +1 @@
+Line: 3. Width: 5.
diff --git a/test/files/run/macro-rangepos-args.flags b/test/files/run/macro-rangepos-args.flags
new file mode 100644
index 0000000000..fcf951d907
--- /dev/null
+++ b/test/files/run/macro-rangepos-args.flags
@@ -0,0 +1 @@
+-Yrangepos \ No newline at end of file
diff --git a/test/files/run/macro-rangepos-args/Macros_1.scala b/test/files/run/macro-rangepos-args/Macros_1.scala
new file mode 100644
index 0000000000..97b938613c
--- /dev/null
+++ b/test/files/run/macro-rangepos-args/Macros_1.scala
@@ -0,0 +1,10 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox.Context
+
+object Macros {
+ def impl(c: Context)(x: c.Tree): c.Tree = {
+ import c.universe._
+ Literal(Constant(s"Line: ${x.pos.line}. Width: ${x.pos.end - x.pos.start}."))
+ }
+ def pos(x: Any): String = macro impl
+}
diff --git a/test/files/run/macro-rangepos-args/Test_2.scala b/test/files/run/macro-rangepos-args/Test_2.scala
new file mode 100644
index 0000000000..8c770e9010
--- /dev/null
+++ b/test/files/run/macro-rangepos-args/Test_2.scala
@@ -0,0 +1,4 @@
+object Test extends App {
+ val x = 2
+ println(Macros.pos(x + 2))
+} \ No newline at end of file
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/macroPlugins-isBlackbox/Macros_2.scala b/test/files/run/macroPlugins-isBlackbox/Macros_2.scala
new file mode 100644
index 0000000000..a90dd702df
--- /dev/null
+++ b/test/files/run/macroPlugins-isBlackbox/Macros_2.scala
@@ -0,0 +1,11 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox.Context
+
+object Macros {
+ def impl(c: Context) = {
+ import c.universe._
+ q"42"
+ }
+
+ def foo: Any = macro impl
+} \ No newline at end of file
diff --git a/test/files/run/macroPlugins-isBlackbox/Plugin_1.scala b/test/files/run/macroPlugins-isBlackbox/Plugin_1.scala
new file mode 100644
index 0000000000..b78a18ea6a
--- /dev/null
+++ b/test/files/run/macroPlugins-isBlackbox/Plugin_1.scala
@@ -0,0 +1,21 @@
+package isblackbox
+
+import scala.tools.nsc.Global
+import scala.tools.nsc.plugins.{Plugin => NscPlugin}
+
+class Plugin(val global: Global) extends NscPlugin {
+ import global._
+ import analyzer._
+ import scala.reflect.internal.Mode
+
+ val name = "isBlackbox"
+ val description = "A sample analyzer plugin that overrides isBlackbox."
+ val components = Nil
+ addMacroPlugin(MacroPlugin)
+
+ object MacroPlugin extends MacroPlugin {
+ override def pluginsIsBlackbox(macroDef: Symbol): Option[Boolean] = {
+ Some(false)
+ }
+ }
+} \ No newline at end of file
diff --git a/test/files/run/macroPlugins-isBlackbox/Test_3.flags b/test/files/run/macroPlugins-isBlackbox/Test_3.flags
new file mode 100644
index 0000000000..966df731d0
--- /dev/null
+++ b/test/files/run/macroPlugins-isBlackbox/Test_3.flags
@@ -0,0 +1 @@
+-Xplugin:. \ No newline at end of file
diff --git a/test/files/run/macroPlugins-isBlackbox/Test_3.scala b/test/files/run/macroPlugins-isBlackbox/Test_3.scala
new file mode 100644
index 0000000000..552e888143
--- /dev/null
+++ b/test/files/run/macroPlugins-isBlackbox/Test_3.scala
@@ -0,0 +1,3 @@
+object Test extends App {
+ val x: Int = Macros.foo
+} \ No newline at end of file
diff --git a/test/files/run/macroPlugins-isBlackbox/scalac-plugin.xml b/test/files/run/macroPlugins-isBlackbox/scalac-plugin.xml
new file mode 100644
index 0000000000..09b9c14648
--- /dev/null
+++ b/test/files/run/macroPlugins-isBlackbox/scalac-plugin.xml
@@ -0,0 +1,4 @@
+<plugin>
+ <name>is-blackbox</name>
+ <classname>isblackbox.Plugin</classname>
+</plugin> \ No newline at end of file
diff --git a/test/files/run/mapConserve.scala b/test/files/run/mapConserve.scala
index d1d52f3107..f52af3b9f4 100644
--- a/test/files/run/mapConserve.scala
+++ b/test/files/run/mapConserve.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warning\(s\); re-run with -Yinline-warnings for details
+ * filter: inliner warnings; re-run with -Yinline-warnings for details
*/
import scala.annotation.tailrec
import scala.collection.mutable.ListBuffer
diff --git a/test/files/run/names-defaults.check b/test/files/run/names-defaults.check
index 0037822f3b..c358dc5849 100644
--- a/test/files/run/names-defaults.check
+++ b/test/files/run/names-defaults.check
@@ -1,7 +1,7 @@
names-defaults.scala:269: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
spawn(b = { val ttt = 1; ttt }, a = 0)
^
-warning: there were 4 deprecation warning(s); re-run with -deprecation for details
+warning: there were four deprecation warnings; re-run with -deprecation for details
1: @
get: $
get: 2
@@ -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/pc-conversions.scala b/test/files/run/pc-conversions.scala
index 19fef355c8..5fecac9d94 100644
--- a/test/files/run/pc-conversions.scala
+++ b/test/files/run/pc-conversions.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warning\(s\); re-run with -Yinline-warnings for details
+ * filter: inliner warning; re-run with -Yinline-warnings for details
*/
import collection._
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-java-annotations.check b/test/files/run/reflection-java-annotations.check
index 72d40989fe..842037254e 100644
--- a/test/files/run/reflection-java-annotations.check
+++ b/test/files/run/reflection-java-annotations.check
@@ -1,4 +1,4 @@
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
List(JavaComplexAnnotation_1(v1 = 1, v10 = "hello", v101 = [101, 101], v102 = [102, 102], v103 = ['g', 'g'], v104 = [104, 104], v105 = [105L, 105L], v106 = [106.0, 106.0], v107 = [107.0, 107.0], v108 = [false, true], v11 = classOf[JavaAnnottee_1], v110 = ["hello", "world"], v111 = [classOf[JavaSimpleAnnotation_1], classOf[JavaComplexAnnotation_1]], v112 = [FOO, BAR], v113 = [JavaSimpleAnnotation_1(v1 = 21, v10 = "world2", v11 = classOf[JavaComplexAnnotation_1], v12 = BAR, v2 = 22, v3 = '\027', v4 = 24, v5 = 25L, v6 = 26.0, v7 = 27.0, v8 = false)], v12 = FOO, v13 = JavaSimpleAnnotation_1(v1 = 11, v10 = "world1", v11 = classOf[JavaSimpleAnnotation_1], v12 = FOO, v2 = 12, v3 = '\r', v4 = 14, v5 = 15L, v6 = 16.0, v7 = 17.0, v8 = false), v2 = 2, v3 = '\03', v4 = 4, v5 = 5L, v6 = 6.0, v7 = 7.0, v8 = false))
=======
new JavaComplexAnnotation_1(v1 = 1, v10 = "hello", v101 = Array(101, 101), v102 = Array(102, 102), v103 = Array('g', 'g'), v104 = Array(104, 104), v105 = Array(105L, 105L), v106 = Array(106.0, 106.0), v107 = Array(107.0, 107.0), v108 = Array(false, true), v11 = classOf[JavaAnnottee_1], v110 = Array("hello", "world"), v111 = Array(classOf[JavaSimpleAnnotation_1], classOf[JavaComplexAnnotation_1]), v112 = Array(FOO, BAR), v113 = Array(new JavaSimpleAnnotation_1(v1 = 21, v10 = "world2", v11 = classOf[JavaComplexAnnotation_1], v12 = BAR, v2 = 22, v3 = '\027', v4 = 24, v5 = 25L, v6 = 26.0, v7 = 27.0, v8 = false)), v12 = FOO, v13 = new JavaSimpleAnnotation_1(v1 = 11, v10 = "world1", v11 = classOf[JavaSimpleAnnotation_1], v12 = FOO, v2 = 12, v3 = '\r', v4 = 14, v5 = 15L, v6 = 16.0, v7 = 17.0, v8 = false), v2 = 2, v3 = '\03', v4 = 4, v5 = 5L, v6 = 6.0, v7 = 7.0, v8 = false)
diff --git a/test/files/run/reflection-magicsymbols-repl.check b/test/files/run/reflection-magicsymbols-repl.check
index a1bee76652..72aef1d3be 100644
--- a/test/files/run/reflection-magicsymbols-repl.check
+++ b/test/files/run/reflection-magicsymbols-repl.check
@@ -21,7 +21,7 @@ scala> def test(n: Int): Unit = {
val x = sig.asInstanceOf[MethodType].params.head
println(x.info)
}
-warning: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
test: (n: Int)Unit
scala> for (i <- 1 to 8) test(i)
diff --git a/test/files/run/repl-javap-app.check b/test/files/run/repl-javap-app.check
index 490860585c..1136b415d7 100644
--- a/test/files/run/repl-javap-app.check
+++ b/test/files/run/repl-javap-app.check
@@ -1,4 +1,5 @@
#partest java6
+Welcome to Scala
Type in expressions to have them evaluated.
Type :help for more information.
@@ -6,16 +7,17 @@ scala> :javap -app MyApp$
public final void delayedEndpoint$MyApp$1();
Code:
Stack=2, Locals=1, Args_size=1
- 0: getstatic #61; //Field scala/Console$.MODULE$:Lscala/Console$;
- 3: ldc #63; //String Hello, delayed world.
- 5: invokevirtual #67; //Method scala/Console$.println:(Ljava/lang/Object;)V
+ 0: getstatic #XX; //Field scala/Console$.MODULE$:Lscala/Console$;
+ 3: ldc #XX; //String Hello, delayed world.
+ 5: invokevirtual #XX; //Method scala/Console$.println:(Ljava/lang/Object;)V
8: return
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this LMyApp$;
scala>
-#partest !java6
+#partest java7
+Welcome to Scala
Type in expressions to have them evaluated.
Type :help for more information.
@@ -24,9 +26,9 @@ scala> :javap -app MyApp$
flags: ACC_PUBLIC, ACC_FINAL
Code:
stack=2, locals=1, args_size=1
- 0: getstatic #61 // Field scala/Console$.MODULE$:Lscala/Console$;
- 3: ldc #63 // String Hello, delayed world.
- 5: invokevirtual #67 // Method scala/Console$.println:(Ljava/lang/Object;)V
+ 0: getstatic #XX // Field scala/Console$.MODULE$:Lscala/Console$;
+ 3: ldc #XX // String Hello, delayed world.
+ 5: invokevirtual #XX // Method scala/Console$.println:(Ljava/lang/Object;)V
8: return
LocalVariableTable:
Start Length Slot Name Signature
@@ -36,3 +38,26 @@ scala> :javap -app MyApp$
}
scala>
+#partest java8
+Welcome to Scala
+Type in expressions to have them evaluated.
+Type :help for more information.
+
+scala> :javap -app MyApp$
+ public final void delayedEndpoint$MyApp$1();
+ descriptor: ()V
+ flags: ACC_PUBLIC, ACC_FINAL
+ Code:
+ stack=2, locals=1, args_size=1
+ 0: getstatic #XX // Field scala/Console$.MODULE$:Lscala/Console$;
+ 3: ldc #XX // String Hello, delayed world.
+ 5: invokevirtual #XX // Method scala/Console$.println:(Ljava/lang/Object;)V
+ 8: return
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 9 0 this LMyApp$;
+ LineNumberTable:
+ line 5: 0
+}
+
+scala>
diff --git a/test/files/run/repl-javap-app.scala b/test/files/run/repl-javap-app.scala
index be04920be1..ad6076c2d5 100644
--- a/test/files/run/repl-javap-app.scala
+++ b/test/files/run/repl-javap-app.scala
@@ -7,4 +7,15 @@ object MyApp extends App {
object Test extends ReplTest {
def code = ":javap -app MyApp$"
+
+ override def welcoming = true
+
+ // The constant pool indices are not the same for GenASM / GenBCode, so
+ // replacing the exact numbers by XX.
+ lazy val hasConstantPoolRef = """(.*)(#\d\d)(.*)""".r
+
+ override def normalize(s: String) = s match {
+ case hasConstantPoolRef(start, ref, end) => start + "#XX" + end
+ case _ => super.normalize(s)
+ }
}
diff --git a/test/files/run/repl-power.check b/test/files/run/repl-power.check
index e56901e0f2..8a8ca46012 100644
--- a/test/files/run/repl-power.check
+++ b/test/files/run/repl-power.check
@@ -11,11 +11,11 @@ scala> :power
scala> // guarding against "error: reference to global is ambiguous"
scala> global.emptyValDef // "it is imported twice in the same scope by ..."
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
res0: $r.global.noSelfType.type = private val _ = _
scala> val tp = ArrayClass[scala.util.Random] // magic with tags
-warning: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
tp: $r.global.Type = Array[scala.util.Random]
scala> tp.memberType(Array_apply) // evidence
diff --git a/test/files/run/richs.check b/test/files/run/richs.check
index 02a98b376d..cf265ae007 100644
--- a/test/files/run/richs.check
+++ b/test/files/run/richs.check
@@ -1,4 +1,4 @@
-warning: there were 2 deprecation warning(s); re-run with -deprecation for details
+warning: there were two deprecation warnings; re-run with -deprecation for details
RichCharTest1:
true
diff --git a/test/files/run/search.check b/test/files/run/search.check
index a885696509..e0c55043e3 100644
--- a/test/files/run/search.check
+++ b/test/files/run/search.check
@@ -1,6 +1,6 @@
Found(2)
Found(4)
-InsertionPoint(9)
+InsertionPoint(10)
Found(2)
Found(4)
-InsertionPoint(9)
+InsertionPoint(10)
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 ff779dd1d3..e18375d521 100644
--- a/test/files/run/stringinterpolation_macro-run.scala
+++ b/test/files/run/stringinterpolation_macro-run.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warning\(s\); re-run with -Yinline-warnings for details
+ * filter: inliner warnings; re-run with -Yinline-warnings for details
*/
object Test extends App {
@@ -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/synchronized.check b/test/files/run/synchronized.check
index 6e99739633..eab191b4ed 100644
--- a/test/files/run/synchronized.check
+++ b/test/files/run/synchronized.check
@@ -1,4 +1,4 @@
-warning: there were 14 inliner warning(s); re-run with -Yinline-warnings for details
+warning: there were 14 inliner warnings; re-run with -Yinline-warnings for details
.|. c1.f1: OK
.|. c1.fi: OK
.|... c1.fv: OK
diff --git a/test/files/run/t2212.check b/test/files/run/t2212.check
index 8ab4d60ab3..1465f1341a 100644
--- a/test/files/run/t2212.check
+++ b/test/files/run/t2212.check
@@ -1,4 +1,4 @@
-warning: there were 2 deprecation warning(s); re-run with -deprecation for details
+warning: there were two deprecation warnings; re-run with -deprecation for details
LinkedList(1)
LinkedList(1)
true
diff --git a/test/files/run/t3361.check b/test/files/run/t3361.check
index c18bdc9aff..5e0a763501 100644
--- a/test/files/run/t3361.check
+++ b/test/files/run/t3361.check
@@ -1 +1 @@
-warning: there were 16 deprecation warning(s); re-run with -deprecation for details
+warning: there were 16 deprecation warnings; re-run with -deprecation for details
diff --git a/test/files/run/t3888.check b/test/files/run/t3888.check
index 844ca54682..df1629dd7e 100644
--- a/test/files/run/t3888.check
+++ b/test/files/run/t3888.check
@@ -1 +1 @@
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
diff --git a/test/files/run/t3970.check b/test/files/run/t3970.check
index bd89fff9d9..0683a6c1a6 100644
--- a/test/files/run/t3970.check
+++ b/test/files/run/t3970.check
@@ -1 +1 @@
-warning: there were 5 deprecation warning(s); re-run with -deprecation for details
+warning: there were 5 deprecation warnings; re-run with -deprecation for details
diff --git a/test/files/run/t3996.check b/test/files/run/t3996.check
index a92ddc0e51..a9ecc29fea 100644
--- a/test/files/run/t3996.check
+++ b/test/files/run/t3996.check
@@ -1 +1 @@
-warning: there were 2 deprecation warning(s); re-run with -deprecation for details
+warning: there were two deprecation warnings; re-run with -deprecation for details
diff --git a/test/files/run/t4080.check b/test/files/run/t4080.check
index 1953a68ad3..462e925b76 100644
--- a/test/files/run/t4080.check
+++ b/test/files/run/t4080.check
@@ -1,2 +1,2 @@
-warning: there were 3 deprecation warning(s); re-run with -deprecation for details
+warning: there were three deprecation warnings; re-run with -deprecation for details
LinkedList(1, 0, 2, 3)
diff --git a/test/files/run/t4172.check b/test/files/run/t4172.check
index d94638d27e..a748430e2e 100644
--- a/test/files/run/t4172.check
+++ b/test/files/run/t4172.check
@@ -2,7 +2,7 @@ Type in expressions to have them evaluated.
Type :help for more information.
scala> val c = { class C { override def toString = "C" }; ((new C, new C { def f = 2 })) }
-warning: there were 1 feature warning(s); re-run with -feature for details
+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>
diff --git a/test/files/run/t4396.check b/test/files/run/t4396.check
index a75e1f257f..d38fb7fae7 100644
--- a/test/files/run/t4396.check
+++ b/test/files/run/t4396.check
@@ -1,4 +1,4 @@
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
hallo
constructor
out:22
diff --git a/test/files/run/t4461.check b/test/files/run/t4461.check
index 9488669324..346993af6f 100644
--- a/test/files/run/t4461.check
+++ b/test/files/run/t4461.check
@@ -1,4 +1,4 @@
-warning: there were 4 deprecation warning(s); re-run with -deprecation for details
+warning: there were four deprecation warnings; re-run with -deprecation for details
Include(End,1)
Include(End,2)
Include(End,3)
diff --git a/test/files/run/t4594-repl-settings.scala b/test/files/run/t4594-repl-settings.scala
index d2335460e5..8b8b2e3746 100644
--- a/test/files/run/t4594-repl-settings.scala
+++ b/test/files/run/t4594-repl-settings.scala
@@ -11,7 +11,7 @@ object Test extends SessionTest {
|depp: String
|
|scala> def a = depp
- |warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+ |warning: there was one deprecation warning; re-run with -deprecation for details
|a: String
|
|scala> :settings +deprecation
diff --git a/test/files/run/t4680.check b/test/files/run/t4680.check
index 512bfd4b54..21a1e0cd15 100644
--- a/test/files/run/t4680.check
+++ b/test/files/run/t4680.check
@@ -4,7 +4,7 @@ t4680.scala:51: warning: a pure expression does nothing in statement position; y
t4680.scala:69: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
new { val x = 5 } with E() { 5 }
^
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
// new C { }
diff --git a/test/files/run/t4710.check b/test/files/run/t4710.check
index f2335d1bdd..6ee7198b4b 100644
--- a/test/files/run/t4710.check
+++ b/test/files/run/t4710.check
@@ -2,7 +2,7 @@ Type in expressions to have them evaluated.
Type :help for more information.
scala> def method : String = { implicit def f(s: Symbol) = "" ; 'symbol }
-warning: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
method: String
scala>
diff --git a/test/files/run/t4813.check b/test/files/run/t4813.check
index a92ddc0e51..a9ecc29fea 100644
--- a/test/files/run/t4813.check
+++ b/test/files/run/t4813.check
@@ -1 +1 @@
-warning: there were 2 deprecation warning(s); re-run with -deprecation for details
+warning: there were two deprecation warnings; re-run with -deprecation for details
diff --git a/test/files/run/t5428.check b/test/files/run/t5428.check
index a46514ae7c..52fce09399 100644
--- a/test/files/run/t5428.check
+++ b/test/files/run/t5428.check
@@ -1,2 +1,2 @@
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
Stack(8, 7, 6, 5, 4, 3)
diff --git a/test/files/run/t576.check b/test/files/run/t576.check
index 6458d5d743..22f3843abf 100644
--- a/test/files/run/t576.check
+++ b/test/files/run/t576.check
@@ -1,4 +1,4 @@
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
1
2
3
diff --git a/test/files/run/t5905-features.scala b/test/files/run/t5905-features.scala
index a3848eef2a..b518d61145 100644
--- a/test/files/run/t5905-features.scala
+++ b/test/files/run/t5905-features.scala
@@ -3,13 +3,13 @@ import tools.partest.DirectTest
// verify that all languageFeature names are accepted by -language
object Test extends DirectTest {
- override def code = "class Code { def f = (1 to 10) size }" // exercise a feature
+ override def code = "class Code { def f = (1 to 10) size }" // exercise a feature to sanity-check coverage of -language options
override def extraSettings = s"-usejavacp -d ${testOutput.path}"
override def show() = {
- val global = newCompiler("-language:postfixOps", "-Ystop-after:typer")
- compileString(global)(code)
+ val global = newCompiler("-Ystop-after:typer")
+ compileString(global)("") // warm me up, scotty
import global._
exitingTyper {
//def isFeature(s: Symbol) = s.annotations.exists((a: AnnotationInfo) => a.tpe <:< typeOf[scala.annotation.meta.languageFeature])
@@ -21,6 +21,8 @@ object Test extends DirectTest {
assert(feats.nonEmpty, "Test must find feature flags.")
+ //compile("junk") // tragically, does not fail the test, i.e., arg must not be totally borked
+
//dynamics,postfixOps,reflectiveCalls,implicitConversions,higherKinds,existentials,experimental.macros
compile(s"-language:$all")
}
diff --git a/test/files/run/t6028.check b/test/files/run/t6028.check
index a6c4db8f11..55ff42d8d7 100644
--- a/test/files/run/t6028.check
+++ b/test/files/run/t6028.check
@@ -81,4 +81,4 @@ package <empty> {
}
}
-warning: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
diff --git a/test/files/run/t6111.check b/test/files/run/t6111.check
index 1f23a87f73..5880658001 100644
--- a/test/files/run/t6111.check
+++ b/test/files/run/t6111.check
@@ -1,3 +1,3 @@
-warning: there were 2 deprecation warning(s); re-run with -deprecation for details
+warning: there were two deprecation warnings; re-run with -deprecation for details
(8,8)
(x,x)
diff --git a/test/files/run/t6292.check b/test/files/run/t6292.check
index 6232ba7519..6f7430d5b8 100644
--- a/test/files/run/t6292.check
+++ b/test/files/run/t6292.check
@@ -1 +1 @@
-warning: there were 7 deprecation warning(s); re-run with -deprecation for details
+warning: there were 7 deprecation warnings; re-run with -deprecation for details
diff --git a/test/files/run/t6318_primitives.check b/test/files/run/t6318_primitives.check
index b330f91276..4bc5e598eb 100644
--- a/test/files/run/t6318_primitives.check
+++ b/test/files/run/t6318_primitives.check
@@ -1,36 +1,54 @@
-true
+Checking if byte matches byte
Some(1)
-false
+Checking if byte matches short
None
-true
+Checking if class java.lang.Byte matches byte
Some(1)
-false
+Checking if short matches short
+Some(1)
+Checking if short matches char
None
-true
+Checking if class java.lang.Short matches short
+Some(1)
+Checking if char matches char
Some()
-false
+Checking if char matches int
None
-true
+Checking if class java.lang.Character matches char
+Some()
+Checking if int matches int
Some(1)
-false
+Checking if int matches long
None
-true
+Checking if class java.lang.Integer matches int
Some(1)
-false
+Checking if long matches long
+Some(1)
+Checking if long matches float
None
-true
+Checking if class java.lang.Long matches long
+Some(1)
+Checking if float matches float
Some(1.0)
-false
+Checking if float matches double
None
-true
+Checking if class java.lang.Float matches float
Some(1.0)
-false
+Checking if double matches double
+Some(1.0)
+Checking if double matches boolean
None
-true
+Checking if class java.lang.Double matches double
+Some(1.0)
+Checking if boolean matches boolean
Some(true)
-false
+Checking if boolean matches void
None
-true
+Checking if class java.lang.Boolean matches boolean
+Some(true)
+Checking if void matches void
Some(())
-false
+Checking if void matches byte
None
+Checking if class scala.runtime.BoxedUnit matches void
+Some(())
diff --git a/test/files/run/t6318_primitives.scala b/test/files/run/t6318_primitives.scala
index 30f27120b3..bc8ec88359 100644
--- a/test/files/run/t6318_primitives.scala
+++ b/test/files/run/t6318_primitives.scala
@@ -2,70 +2,88 @@ import scala.reflect.{ClassTag, classTag}
object Test extends App {
def test[T: ClassTag](x: T) {
- println(classTag[T].runtimeClass.isAssignableFrom(x.getClass))
+ println(s"Checking if ${x.getClass} matches ${classTag[T].runtimeClass}")
println(classTag[T].unapply(x))
}
{
val x = 1.toByte
- println(ClassTag.Byte.runtimeClass.isAssignableFrom(x.getClass))
+ println(s"Checking if ${x.getClass} matches ${classTag[Byte].runtimeClass}")
println(ClassTag.Byte.unapply(x))
+ println(s"Checking if ${x.getClass} matches ${classTag[Short].runtimeClass}")
+ println(ClassTag.Short.unapply(x))
test(x)
}
{
val x = 1.toShort
- println(ClassTag.Short.runtimeClass.isAssignableFrom(x.getClass))
+ println(s"Checking if ${x.getClass} matches ${classTag[Short].runtimeClass}")
println(ClassTag.Short.unapply(x))
+ println(s"Checking if ${x.getClass} matches ${classTag[Char].runtimeClass}")
+ println(ClassTag.Char.unapply(x))
test(x)
}
{
val x = 1.toChar
- println(ClassTag.Char.runtimeClass.isAssignableFrom(x.getClass))
+ println(s"Checking if ${x.getClass} matches ${classTag[Char].runtimeClass}")
println(ClassTag.Char.unapply(x))
+ println(s"Checking if ${x.getClass} matches ${classTag[Int].runtimeClass}")
+ println(ClassTag.Int.unapply(x))
test(x)
}
{
val x = 1.toInt
- println(ClassTag.Int.runtimeClass.isAssignableFrom(x.getClass))
+ println(s"Checking if ${x.getClass} matches ${classTag[Int].runtimeClass}")
println(ClassTag.Int.unapply(x))
+ println(s"Checking if ${x.getClass} matches ${classTag[Long].runtimeClass}")
+ println(ClassTag.Long.unapply(x))
test(x)
}
{
val x = 1.toLong
- println(ClassTag.Long.runtimeClass.isAssignableFrom(x.getClass))
+ println(s"Checking if ${x.getClass} matches ${classTag[Long].runtimeClass}")
println(ClassTag.Long.unapply(x))
+ println(s"Checking if ${x.getClass} matches ${classTag[Float].runtimeClass}")
+ println(ClassTag.Float.unapply(x))
test(x)
}
{
val x = 1.toFloat
- println(ClassTag.Float.runtimeClass.isAssignableFrom(x.getClass))
+ println(s"Checking if ${x.getClass} matches ${classTag[Float].runtimeClass}")
println(ClassTag.Float.unapply(x))
+ println(s"Checking if ${x.getClass} matches ${classTag[Double].runtimeClass}")
+ println(ClassTag.Double.unapply(x))
test(x)
}
{
val x = 1.toDouble
- println(ClassTag.Double.runtimeClass.isAssignableFrom(x.getClass))
+ println(s"Checking if ${x.getClass} matches ${classTag[Double].runtimeClass}")
println(ClassTag.Double.unapply(x))
+ println(s"Checking if ${x.getClass} matches ${classTag[Boolean].runtimeClass}")
+ println(ClassTag.Boolean.unapply(x))
test(x)
}
{
val x = true
- println(ClassTag.Boolean.runtimeClass.isAssignableFrom(x.getClass))
+ println(s"Checking if ${x.getClass} matches ${classTag[Boolean].runtimeClass}")
println(ClassTag.Boolean.unapply(x))
+ println(s"Checking if ${x.getClass} matches ${classTag[Unit].runtimeClass}")
+ println(ClassTag.Unit.unapply(x))
test(x)
}
{
val x = ()
- println(ClassTag.Unit.runtimeClass.isAssignableFrom(x.getClass))
+ println(s"Checking if ${x.getClass} matches ${classTag[Unit].runtimeClass}")
println(ClassTag.Unit.unapply(x))
+ println(s"Checking if ${x.getClass} matches ${classTag[Byte].runtimeClass}")
+ println(ClassTag.Byte.unapply(x))
test(x)
}
-} \ No newline at end of file
+}
diff --git a/test/files/run/t6329_repl.check b/test/files/run/t6329_repl.check
index 5049426ab4..ad0bb46e5b 100644
--- a/test/files/run/t6329_repl.check
+++ b/test/files/run/t6329_repl.check
@@ -5,28 +5,28 @@ scala> import scala.reflect.classTag
import scala.reflect.classTag
scala> classManifest[scala.List[_]]
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
res0: scala.reflect.ClassTag[List[_]] = scala.collection.immutable.List[<?>]
scala> classTag[scala.List[_]]
res1: scala.reflect.ClassTag[List[_]] = scala.collection.immutable.List
scala> classManifest[scala.collection.immutable.List[_]]
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
res2: scala.reflect.ClassTag[List[_]] = scala.collection.immutable.List[<?>]
scala> classTag[scala.collection.immutable.List[_]]
res3: scala.reflect.ClassTag[List[_]] = scala.collection.immutable.List
scala> classManifest[Predef.Set[_]]
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
res4: scala.reflect.ClassTag[scala.collection.immutable.Set[_]] = scala.collection.immutable.Set[<?>]
scala> classTag[Predef.Set[_]]
res5: scala.reflect.ClassTag[scala.collection.immutable.Set[_]] = scala.collection.immutable.Set
scala> classManifest[scala.collection.immutable.Set[_]]
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
res6: scala.reflect.ClassTag[scala.collection.immutable.Set[_]] = scala.collection.immutable.Set[<?>]
scala> classTag[scala.collection.immutable.Set[_]]
diff --git a/test/files/run/t6329_repl_bug.check b/test/files/run/t6329_repl_bug.check
index 44c41cfd03..38a8de5606 100644
--- a/test/files/run/t6329_repl_bug.check
+++ b/test/files/run/t6329_repl_bug.check
@@ -8,7 +8,7 @@ scala> import scala.reflect.runtime._
import scala.reflect.runtime._
scala> classManifest[List[_]]
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
res0: scala.reflect.ClassTag[List[_]] = scala.collection.immutable.List[<?>]
scala> scala.reflect.classTag[List[_]]
diff --git a/test/files/run/t6329_vanilla_bug.check b/test/files/run/t6329_vanilla_bug.check
index 640d168a8a..01bf0636ea 100644
--- a/test/files/run/t6329_vanilla_bug.check
+++ b/test/files/run/t6329_vanilla_bug.check
@@ -1,3 +1,3 @@
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
scala.collection.immutable.List[<?>]
scala.collection.immutable.List
diff --git a/test/files/run/t6481.check b/test/files/run/t6481.check
index df40722242..4a3f6f7ee9 100644
--- a/test/files/run/t6481.check
+++ b/test/files/run/t6481.check
@@ -1,4 +1,4 @@
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
delayed init
new foo(1, 2)
delayed init
diff --git a/test/files/run/t6690.check b/test/files/run/t6690.check
index a92ddc0e51..a9ecc29fea 100644
--- a/test/files/run/t6690.check
+++ b/test/files/run/t6690.check
@@ -1 +1 @@
-warning: there were 2 deprecation warning(s); re-run with -deprecation for details
+warning: there were two deprecation warnings; re-run with -deprecation for details
diff --git a/test/files/run/t6863.check b/test/files/run/t6863.check
index fea22b582f..d4df5f7a74 100644
--- a/test/files/run/t6863.check
+++ b/test/files/run/t6863.check
@@ -10,4 +10,4 @@ t6863.scala:46: warning: comparing values of types Unit and Unit using `==' will
t6863.scala:59: warning: comparing values of types Unit and Unit using `==' will always yield true
assert({ () => x }.apply == ())
^
-warning: there were 4 deprecation warning(s); re-run with -deprecation for details
+warning: there were four deprecation warnings; re-run with -deprecation for details
diff --git a/test/files/run/t6935.check b/test/files/run/t6935.check
index 844ca54682..df1629dd7e 100644
--- a/test/files/run/t6935.check
+++ b/test/files/run/t6935.check
@@ -1 +1 @@
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
diff --git a/test/files/run/t7096.scala b/test/files/run/t7096.scala
index e7a894fc23..872562dd4d 100644
--- a/test/files/run/t7096.scala
+++ b/test/files/run/t7096.scala
@@ -1,5 +1,5 @@
/*
- * filter: inliner warning\(s\); re-run with -Yinline-warnings for details
+ * filter: inliner warning; re-run with -Yinline-warnings for details
*/
import scala.tools.partest._
import scala.tools.nsc._
diff --git a/test/files/run/t7319.check b/test/files/run/t7319.check
index b7443aa0c4..2ac4142098 100644
--- a/test/files/run/t7319.check
+++ b/test/files/run/t7319.check
@@ -5,15 +5,15 @@ scala> class M[A]
defined class M
scala> implicit def ma0[A](a: A): M[A] = null
-warning: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
ma0: [A](a: A)M[A]
scala> implicit def ma1[A](a: A): M[A] = null
-warning: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
ma1: [A](a: A)M[A]
scala> def convert[F[X <: F[X]]](builder: F[_ <: F[_]]) = 0
-warning: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
convert: [F[X <: F[X]]](builder: F[_ <: F[_]])Int
scala> convert(Some[Int](0))
diff --git a/test/files/run/t7582.check b/test/files/run/t7582.check
index 225fb1ace8..cd951d8d4f 100644
--- a/test/files/run/t7582.check
+++ b/test/files/run/t7582.check
@@ -1,2 +1,2 @@
-warning: there were 1 inliner warning(s); re-run with -Yinline-warnings for details
+warning: there was one inliner warning; re-run with -Yinline-warnings for details
2
diff --git a/test/files/run/t7582b.check b/test/files/run/t7582b.check
index 225fb1ace8..cd951d8d4f 100644
--- a/test/files/run/t7582b.check
+++ b/test/files/run/t7582b.check
@@ -1,2 +1,2 @@
-warning: there were 1 inliner warning(s); re-run with -Yinline-warnings for details
+warning: there was one inliner warning; re-run with -Yinline-warnings for details
2
diff --git a/test/files/run/t7932.check b/test/files/run/t7932.check
index 13d64f1d3c..3f0a0c4f62 100644
--- a/test/files/run/t7932.check
+++ b/test/files/run/t7932.check
@@ -1,3 +1,3 @@
-warning: there were 1 feature warning(s); re-run with -feature for details
+warning: there was one feature warning; re-run with -feature for details
public Category<?> C.category()
public Category<scala.Tuple2> C.category1()
diff --git a/test/files/run/t7974.check b/test/files/run/t7974.check
index 0be496d8d0..d8152d3286 100644
--- a/test/files/run/t7974.check
+++ b/test/files/run/t7974.check
@@ -1,6 +1,5 @@
public class Symbols {
- // compiled from: Symbols.scala
@@ -18,20 +17,14 @@ public class Symbols {
// access flags 0x9
public static <clinit>()V
- L0
- LINENUMBER 2 L0
GETSTATIC scala/Symbol$.MODULE$ : Lscala/Symbol$;
LDC "Symbolic1"
INVOKEVIRTUAL scala/Symbol$.apply (Ljava/lang/String;)Lscala/Symbol;
PUTSTATIC Symbols.symbol$1 : Lscala/Symbol;
- L1
- LINENUMBER 3 L1
GETSTATIC scala/Symbol$.MODULE$ : Lscala/Symbol$;
LDC "Symbolic2"
INVOKEVIRTUAL scala/Symbol$.apply (Ljava/lang/String;)Lscala/Symbol;
PUTSTATIC Symbols.symbol$2 : Lscala/Symbol;
- L2
- LINENUMBER 5 L2
GETSTATIC scala/Symbol$.MODULE$ : Lscala/Symbol$;
LDC "Symbolic3"
INVOKEVIRTUAL scala/Symbol$.apply (Ljava/lang/String;)Lscala/Symbol;
@@ -42,63 +35,41 @@ public class Symbols {
// access flags 0x1
public someSymbol1()Lscala/Symbol;
- L0
- LINENUMBER 2 L0
GETSTATIC Symbols.symbol$1 : Lscala/Symbol;
ARETURN
- L1
- LOCALVARIABLE this LSymbols; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public someSymbol2()Lscala/Symbol;
- L0
- LINENUMBER 3 L0
GETSTATIC Symbols.symbol$2 : Lscala/Symbol;
ARETURN
- L1
- LOCALVARIABLE this LSymbols; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public sameSymbol1()Lscala/Symbol;
- L0
- LINENUMBER 4 L0
GETSTATIC Symbols.symbol$1 : Lscala/Symbol;
ARETURN
- L1
- LOCALVARIABLE this LSymbols; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public someSymbol3()Lscala/Symbol;
- L0
- LINENUMBER 5 L0
ALOAD 0
GETFIELD Symbols.someSymbol3 : Lscala/Symbol;
ARETURN
- L1
- LOCALVARIABLE this LSymbols; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public <init>()V
- L0
- LINENUMBER 6 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
- L1
- LINENUMBER 5 L1
ALOAD 0
GETSTATIC Symbols.symbol$3 : Lscala/Symbol;
PUTFIELD Symbols.someSymbol3 : Lscala/Symbol;
RETURN
- L2
- LOCALVARIABLE this LSymbols; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
}
diff --git a/test/files/run/t7974/Test.scala b/test/files/run/t7974/Test.scala
index 433d9061a7..29d2b9cb64 100644
--- a/test/files/run/t7974/Test.scala
+++ b/test/files/run/t7974/Test.scala
@@ -6,7 +6,7 @@ import scala.tools.nsc.util.stringFromWriter
object Test extends BytecodeTest {
def show {
- val classNode = loadClassNode("Symbols", skipDebugInfo = false)
+ val classNode = loadClassNode("Symbols", skipDebugInfo = true)
val textifier = new Textifier
classNode.accept(new TraceClassVisitor(null, textifier, null))
diff --git a/test/files/run/t8196.check b/test/files/run/t8196.check
index b32f42cf07..d11dc27e68 100644
--- a/test/files/run/t8196.check
+++ b/test/files/run/t8196.check
@@ -1,7 +1,7 @@
t8196.scala:26: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
form2.g1 // comment this line in order to make the test pass
^
-warning: there were 2 feature warning(s); re-run with -feature for details
+warning: there were two feature warnings; re-run with -feature for details
Scope{
final private val f1: Int
}
diff --git a/test/files/run/t8346.check b/test/files/run/t8346.check
new file mode 100644
index 0000000000..1ba5c31abe
--- /dev/null
+++ b/test/files/run/t8346.check
@@ -0,0 +1,6 @@
+BitSet: List(invariant, invariant, invariant, invariant)
+HashSet: List(covariant (true), covariant (true), covariant (true), covariant (true))
+ListSet: List(covariant (true), covariant (true), covariant (true), covariant (true))
+SortedSet: List(invariant, invariant, invariant, invariant)
+TreeSet: List(invariant, invariant, invariant, invariant)
+ValueSet: invariant
diff --git a/test/files/run/t8346.scala b/test/files/run/t8346.scala
new file mode 100644
index 0000000000..5f3df84174
--- /dev/null
+++ b/test/files/run/t8346.scala
@@ -0,0 +1,34 @@
+object Test extends App {
+ import reflect.ClassTag
+
+ object SomeEnum extends Enumeration {
+ val one, two, three, four = Value
+ }
+
+ def sctor[A <: Set[Int]](f: Int => A)(implicit A: ClassTag[A])
+ : (String, Int => Set[Int]) =
+ (A.runtimeClass.getSimpleName, f)
+
+ val inits: Seq[(String, Int => Set[Int])] = {
+ import collection.immutable.{Seq => _, _}
+ Seq(sctor(BitSet(_)),
+ sctor(HashSet(_)),
+ sctor(ListSet(_)),
+ sctor(SortedSet(_)),
+ sctor(TreeSet(_)))
+ }
+
+ def sVarInfo[A](sa: Set[A]): String = {
+ val saa = sa.toSet[Any]
+ if (sa eq saa) s"""covariant (${(saa + "hi") contains "hi"})"""
+ else "invariant"
+ }
+
+ inits foreach {case (name, singleton) =>
+ print(s"${name}: ")
+ val one = singleton(1)
+ println(Seq(2,3,4).scanLeft(one)(_ + _) map sVarInfo toList)
+ }
+
+ println(s"ValueSet: ${sVarInfo(SomeEnum.values)}")
+}
diff --git a/test/files/run/t8549.check b/test/files/run/t8549.check
index a92ddc0e51..a9ecc29fea 100644
--- a/test/files/run/t8549.check
+++ b/test/files/run/t8549.check
@@ -1 +1 @@
-warning: there were 2 deprecation warning(s); re-run with -deprecation for details
+warning: there were two deprecation warnings; re-run with -deprecation for details
diff --git a/test/files/run/t8574.scala b/test/files/run/t8574.scala
new file mode 100644
index 0000000000..8c23ada482
--- /dev/null
+++ b/test/files/run/t8574.scala
@@ -0,0 +1,27 @@
+import annotation._
+
+@SerialVersionUID(42) @strictfp class Foo[@specialized(Int) T] extends Serializable {
+ def foo(t: T) = t
+}
+
+object Test extends App {
+ def checkUID(cls: Class[_], expected: Long) = {
+ val actual = java.io.ObjectStreamClass.lookup(cls).getSerialVersionUID
+ assert(actual == expected, s"$actual != expected for ${cls}")
+ }
+ def checkStrictFp(cls: Class[_]) = {
+ import java.lang.reflect._
+ for (m <- cls.getDeclaredMethods) {
+ val isStrict = Modifier.isStrict(m.getModifiers)
+ assert(isStrict, cls)
+ }
+ }
+ def check(x: AnyRef) {
+ checkUID(x.getClass, 42)
+ checkStrictFp(x.getClass)
+ }
+
+ check(new Foo[String])
+ check(new Foo[Int])
+}
+
diff --git a/test/files/run/t8601-closure-elim.flags b/test/files/run/t8601-closure-elim.flags
new file mode 100644
index 0000000000..49d036a887
--- /dev/null
+++ b/test/files/run/t8601-closure-elim.flags
@@ -0,0 +1 @@
+-optimize
diff --git a/test/files/run/t8601-closure-elim.scala b/test/files/run/t8601-closure-elim.scala
new file mode 100644
index 0000000000..2c5b03af77
--- /dev/null
+++ b/test/files/run/t8601-closure-elim.scala
@@ -0,0 +1,26 @@
+import scala.tools.partest.BytecodeTest
+import scala.tools.asm
+import scala.tools.asm.util._
+import scala.collection.JavaConverters._
+
+object Test extends BytecodeTest {
+ val nullChecks = Set(asm.Opcodes.NEW)
+
+ def show: Unit = {
+ def test(methodName: String) {
+ val classNode = loadClassNode("Foo")
+ val methodNode = getMethod(classNode, "b")
+ val ops = methodNode.instructions.iterator.asScala.map(_.getOpcode).toList
+ assert(!ops.contains(asm.Opcodes.NEW), ops)// should be allocation free if the closure is eliminiated
+ }
+ test("b")
+ }
+}
+
+class Foo {
+ @inline final def a(x: Int => Int) = x(1)
+ final def b {
+ val delta = 0
+ a(x => delta + 1)
+ }
+}
diff --git a/test/files/run/t8601.flags b/test/files/run/t8601.flags
new file mode 100644
index 0000000000..1182725e86
--- /dev/null
+++ b/test/files/run/t8601.flags
@@ -0,0 +1 @@
+-optimize \ No newline at end of file
diff --git a/test/files/run/t8601.scala b/test/files/run/t8601.scala
new file mode 100644
index 0000000000..e1afc23cc4
--- /dev/null
+++ b/test/files/run/t8601.scala
@@ -0,0 +1,15 @@
+object Test {
+ def idiv(x: Int): Unit = x / 0
+ def ldiv(x: Long): Unit = x / 0
+ def irem(x: Int): Unit = x % 0
+ def lrem(x: Long): Unit = x % 0
+
+ def check(x: => Any) = try { x; sys.error("failed to throw divide by zero!") } catch { case _: ArithmeticException => }
+
+ def main(args: Array[String]) {
+ check(idiv(1))
+ check(ldiv(1L))
+ check(irem(1))
+ check(lrem(1L))
+ }
+}
diff --git a/test/files/run/t8601b.flags b/test/files/run/t8601b.flags
new file mode 100644
index 0000000000..1182725e86
--- /dev/null
+++ b/test/files/run/t8601b.flags
@@ -0,0 +1 @@
+-optimize \ No newline at end of file
diff --git a/test/files/run/t8601b.scala b/test/files/run/t8601b.scala
new file mode 100644
index 0000000000..9c37ce33d6
--- /dev/null
+++ b/test/files/run/t8601b.scala
@@ -0,0 +1,14 @@
+object Test {
+ def len(x: Array[String]): Unit = x.length
+ def load(x: Array[String]): Unit = x(0)
+ def newarray(i: Int): Unit = new Array[Int](i)
+
+ def check(x: => Any) = try { x; sys.error("failed to throw NPE!") } catch { case _: NullPointerException => }
+ def checkNegSize(x: => Any) = try { x; sys.error("failed to throw NegativeArraySizeException!") } catch { case _: NegativeArraySizeException => }
+
+ def main(args: Array[String]) {
+ check(len(null)) // bug: did not NPE
+ check(load(null))
+ checkNegSize(newarray(-1))
+ }
+}
diff --git a/test/files/run/t8601c.flags b/test/files/run/t8601c.flags
new file mode 100644
index 0000000000..1182725e86
--- /dev/null
+++ b/test/files/run/t8601c.flags
@@ -0,0 +1 @@
+-optimize \ No newline at end of file
diff --git a/test/files/run/t8601c.scala b/test/files/run/t8601c.scala
new file mode 100644
index 0000000000..c487d6825e
--- /dev/null
+++ b/test/files/run/t8601c.scala
@@ -0,0 +1,12 @@
+object Test {
+ def loadField(x: scala.runtime.IntRef): Unit = x.elem
+ def storeField(x: scala.runtime.IntRef): Unit = x.elem = 42
+
+ def check(x: => Any) = try { x; sys.error("failed to throw NPE!") } catch { case _: NullPointerException => }
+
+ def main(args: Array[String]) {
+ check(loadField(null)) // bug: did not NPE under -Ydead-code
+ check(storeField(null))
+
+ }
+}
diff --git a/test/files/run/t8601d.flags b/test/files/run/t8601d.flags
new file mode 100644
index 0000000000..1182725e86
--- /dev/null
+++ b/test/files/run/t8601d.flags
@@ -0,0 +1 @@
+-optimize \ No newline at end of file
diff --git a/test/files/run/t8601d.scala b/test/files/run/t8601d.scala
new file mode 100644
index 0000000000..ac89963d67
--- /dev/null
+++ b/test/files/run/t8601d.scala
@@ -0,0 +1,8 @@
+object Test {
+ def monitor(x: AnyRef): Unit = {x.synchronized(()); ()}
+ def check(x: => Any) = try { x; sys.error("failed to throw NPE") } catch { case _: NullPointerException => }
+
+ def main(args: Array[String]) {
+ check(monitor(null))
+ }
+}
diff --git a/test/files/run/t8601e.flags b/test/files/run/t8601e.flags
new file mode 100644
index 0000000000..49d036a887
--- /dev/null
+++ b/test/files/run/t8601e.flags
@@ -0,0 +1 @@
+-optimize
diff --git a/test/files/run/t8601e/StaticInit.class b/test/files/run/t8601e/StaticInit.class
new file mode 100644
index 0000000000..99a0e2a643
--- /dev/null
+++ b/test/files/run/t8601e/StaticInit.class
Binary files differ
diff --git a/test/files/run/t8601e/StaticInit.java b/test/files/run/t8601e/StaticInit.java
new file mode 100644
index 0000000000..7543ed98b8
--- /dev/null
+++ b/test/files/run/t8601e/StaticInit.java
@@ -0,0 +1,8 @@
+public class StaticInit {
+ static {
+ if ("".isEmpty()) {
+ throw new RuntimeException();
+ }
+ }
+ public static int fld = 42;
+}
diff --git a/test/files/run/t8601e/Test.scala b/test/files/run/t8601e/Test.scala
new file mode 100644
index 0000000000..838114f6a7
--- /dev/null
+++ b/test/files/run/t8601e/Test.scala
@@ -0,0 +1,12 @@
+class C {
+ def foo: Unit = {StaticInit.fld}
+}
+
+object Test extends App {
+ try {
+ new C().foo
+ sys.error("StaticInit.<clinit> was not run!")
+ } catch {
+ case t: ExceptionInInitializerError =>
+ }
+}
diff --git a/test/files/run/t8607.scala b/test/files/run/t8607.scala
new file mode 100644
index 0000000000..1b8ef9bbd0
--- /dev/null
+++ b/test/files/run/t8607.scala
@@ -0,0 +1,36 @@
+package p1 {
+ private[p1] trait B extends Any {
+ def a: Any = ""
+ }
+
+ class C(val value: Int) extends AnyVal with B {
+ // def b = ""
+ }
+}
+
+object Test {
+ def main(args: Array[String]) {
+ val c = new p1.C(42)
+ c.a
+ /*
+ new p1.C.<init>(
+ c.$asInstanceOf[scala.this.Int]()
+ ).a();
+
+
+ new p1.C.<init>(
+ new p1.C.<init>(
+ c.$asInstanceOf[scala.this.Int]()
+ ).$asInstanceOf[ErasedValueType(class C, scala.this.Int)]()
+ .$asInstanceOf[scala.this.Int]()
+ ).a();
+
+ new p1.C.<init>(
+ new p1.C.<init>(c)
+ .$asInstanceOf[scala.this.Int]()
+ .$asInstanceOf[scala.this.Int]()
+ ).a();
+
+ */
+ }
+}
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/t8611a.flags b/test/files/run/t8611a.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/run/t8611a.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/run/t8611a.scala b/test/files/run/t8611a.scala
new file mode 100644
index 0000000000..99304df762
--- /dev/null
+++ b/test/files/run/t8611a.scala
@@ -0,0 +1,16 @@
+trait K
+trait L
+
+object O {
+ type LK = K with L
+ val A: LK = new K with L
+ val B: LK = new K with L
+}
+
+object Test extends App {
+ val scrut: O.LK = O.B
+ scrut match {
+ case O.A => ???
+ case O.B => // spurious unreachable
+ }
+}
diff --git a/test/files/run/t8611b.flags b/test/files/run/t8611b.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/run/t8611b.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/run/t8611b.scala b/test/files/run/t8611b.scala
new file mode 100644
index 0000000000..2df17c9ca0
--- /dev/null
+++ b/test/files/run/t8611b.scala
@@ -0,0 +1,54 @@
+sealed trait KrafsDescription
+
+abstract class NotWorkingEnum extends Enumeration {
+
+ type ExtendedValue = Value with KrafsDescription
+
+ def Enum(inDescription: String): ExtendedValue = {
+ new Val(nextId) with KrafsDescription {
+ }
+ }
+}
+
+abstract class WorkingEnum extends Enumeration {
+
+ type ExtendedValue = Value
+
+ def Enum(inDescription: String): ExtendedValue = {
+ new Val(nextId) {
+ }
+ }
+}
+
+object NotWorkingTab extends NotWorkingEnum {
+ val a = Enum("A")
+ val b = Enum("B")
+}
+
+object WorkingTab extends WorkingEnum {
+ val a = Enum("A")
+ val b = Enum("B")
+}
+
+object Test extends App {
+ testGris()
+ testWorking()
+
+ def testGris() {
+ val pipp = NotWorkingTab.b
+ pipp match {
+ case NotWorkingTab.a => ???
+ case NotWorkingTab.b =>
+ case _ => ???
+ }
+ }
+
+ def testWorking() {
+ val stuff = WorkingTab.a
+ stuff match {
+ case WorkingTab.a =>
+ case WorkingTab.b => ???
+ case _ => ???
+ }
+ }
+}
diff --git a/test/files/run/t8611c.flags b/test/files/run/t8611c.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/run/t8611c.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/run/t8611c.scala b/test/files/run/t8611c.scala
new file mode 100644
index 0000000000..2bd17f29a5
--- /dev/null
+++ b/test/files/run/t8611c.scala
@@ -0,0 +1,21 @@
+trait K
+trait L
+
+object O {
+ type LK = K with L
+}
+
+object Test extends App {
+ local
+
+ def local = {
+ val A: O.LK = new K with L
+ val B: O.LK = new K with L
+ val scrut: O.LK = A
+ scrut match {
+ case B if "".isEmpty => ???
+ case A =>
+ case B => ???
+ }
+ }
+}
diff --git a/test/files/run/t8637.check b/test/files/run/t8637.check
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/files/run/t8637.check
diff --git a/test/files/run/t8637.scala b/test/files/run/t8637.scala
new file mode 100644
index 0000000000..99c8d4c413
--- /dev/null
+++ b/test/files/run/t8637.scala
@@ -0,0 +1,9 @@
+import scala.reflect.runtime.universe._
+import scala.reflect.runtime.currentMirror
+import scala.tools.reflect.ToolBox
+
+object Test extends App {
+ val tb = currentMirror.mkToolBox()
+ tb.compile(q"true > true")
+ tb.typecheck(q"true > true")
+} \ No newline at end of file
diff --git a/test/files/run/t8690.check b/test/files/run/t8690.check
new file mode 100644
index 0000000000..72f076c4d8
--- /dev/null
+++ b/test/files/run/t8690.check
@@ -0,0 +1,2 @@
+non-empty iterator
+abcdef
diff --git a/test/files/run/t8690.scala b/test/files/run/t8690.scala
new file mode 100644
index 0000000000..ab8b45b2a7
--- /dev/null
+++ b/test/files/run/t8690.scala
@@ -0,0 +1,12 @@
+import scala.io.Source
+import java.io.ByteArrayInputStream
+
+object Test extends App {
+ val txt = "abcdef"
+
+ val in = new ByteArrayInputStream(txt.getBytes());
+ val source = Source.fromInputStream(in);
+ println(source.toString) // forces the BufferedSource to look at the head of the input
+
+ println(source.mkString) // used to return "bcdef" ...
+}
diff --git a/test/files/run/t8708_b.check b/test/files/run/t8708_b.check
new file mode 100644
index 0000000000..30be62a307
--- /dev/null
+++ b/test/files/run/t8708_b.check
@@ -0,0 +1,8 @@
+Scope{
+ def <init>: <?>;
+ sealed abstract trait T extends ;
+ def foo: <?>
+}
+Scope{
+ def f: <?>
+}
diff --git a/test/files/run/t8708_b/A_1.scala b/test/files/run/t8708_b/A_1.scala
new file mode 100644
index 0000000000..e767420f9e
--- /dev/null
+++ b/test/files/run/t8708_b/A_1.scala
@@ -0,0 +1,8 @@
+package p
+
+class C {
+
+ sealed trait T { def f: Int }
+
+ def foo: T = new T { def f = 1 }
+}
diff --git a/test/files/run/t8708_b/Test_2.scala b/test/files/run/t8708_b/Test_2.scala
new file mode 100644
index 0000000000..c978490609
--- /dev/null
+++ b/test/files/run/t8708_b/Test_2.scala
@@ -0,0 +1,21 @@
+import scala.tools.partest._
+import java.io.{Console => _, _}
+
+object Test extends DirectTest {
+
+ override def extraSettings: String = "-usejavacp -cp " + testOutput.path
+
+ override def code = ""
+
+ override def show(): Unit = {
+ val g = newCompiler()
+ withRun(g)(r => {
+ val c = g.rootMirror.getRequiredClass("p.C")
+ println(c.info.decls)
+ val t = c.info.member(g.newTypeName("T"))
+ // this test ensrues that the <local child> dummy class symbol is not entered in the
+ // scope of trait T during unpickling.
+ println(t.info.decls)
+ })
+ }
+}
diff --git a/test/files/run/tailcalls.check b/test/files/run/tailcalls.check
index 7607921856..92d4f8a3c8 100644
--- a/test/files/run/tailcalls.check
+++ b/test/files/run/tailcalls.check
@@ -50,6 +50,10 @@ test NonTailCall.f2
test TailCall.b1 was successful
test TailCall.b2 was successful
test FancyTailCalls.tcTryLocal was successful
+test FancyTailCalls.tcInBooleanExprFirstOp was successful
+test FancyTailCalls.tcInBooleanExprSecondOp was successful
+test FancyTailCalls.tcInIfCond was successful
+test FancyTailCalls.tcInPatternGuard was successful
test FancyTailCalls.differentInstance was successful
test PolyObject.tramp was successful
#partest avian
@@ -104,5 +108,9 @@ test NonTailCall.f2
test TailCall.b1 was successful
test TailCall.b2 was successful
test FancyTailCalls.tcTryLocal was successful
+test FancyTailCalls.tcInBooleanExprFirstOp was successful
+test FancyTailCalls.tcInBooleanExprSecondOp was successful
+test FancyTailCalls.tcInIfCond was successful
+test FancyTailCalls.tcInPatternGuard was successful
test FancyTailCalls.differentInstance was successful
test PolyObject.tramp was successful
diff --git a/test/files/run/tailcalls.scala b/test/files/run/tailcalls.scala
index 1653b14de9..8df2dcfcb6 100644
--- a/test/files/run/tailcalls.scala
+++ b/test/files/run/tailcalls.scala
@@ -213,6 +213,33 @@ class FancyTailCalls {
} finally {}
}
+ def tcInBooleanExprFirstOp(x: Int, v: Int): Boolean = {
+ {
+ def loop(n: Int): Int = if (n == 0) v else loop(n - 1)
+ loop(x)
+ } == v && true
+ }
+ def tcInBooleanExprSecondOp(x: Int, v: Int): Boolean = {
+ true && {
+ def loop(n: Int): Int = if (n == 0) v else loop(n - 1)
+ loop(x)
+ } == v
+ }
+ def tcInIfCond(x: Int, v: Int): Boolean = {
+ if ({
+ def loop(n: Int): Int = if (n == 0) v else loop(n - 1)
+ loop(x)
+ } == v) true else false
+ }
+ def tcInPatternGuard(x: Int, v: Int): Boolean =
+ v match {
+ case _ if
+ {
+ def loop(n: Int): Int = if (n == 0) v else loop(n - 1)
+ loop(x) == v
+ } => true
+ }
+
import FancyTailCalls._
final def differentInstance(n: Int, v: Int): Int = {
if (n == 0) v
@@ -376,8 +403,12 @@ object Test {
check_success_b("TailCall.b2", TailCall.b2(max), true)
val FancyTailCalls = new FancyTailCalls;
- check_success("FancyTailCalls.tcTryLocal", FancyTailCalls.tcTryLocal(max, max), max)
- check_success("FancyTailCalls.differentInstance", FancyTailCalls.differentInstance(max, 42), 42)
+ check_success("FancyTailCalls.tcTryLocal", FancyTailCalls.tcTryLocal(max, max), max)
+ check_success_b("FancyTailCalls.tcInBooleanExprFirstOp", FancyTailCalls.tcInBooleanExprFirstOp(max, max), true)
+ check_success_b("FancyTailCalls.tcInBooleanExprSecondOp", FancyTailCalls.tcInBooleanExprSecondOp(max, max), true)
+ check_success_b("FancyTailCalls.tcInIfCond", FancyTailCalls.tcInIfCond(max, max), true)
+ check_success_b("FancyTailCalls.tcInPatternGuard", FancyTailCalls.tcInPatternGuard(max, max), true)
+ check_success("FancyTailCalls.differentInstance", FancyTailCalls.differentInstance(max, 42), 42)
check_success("PolyObject.tramp", PolyObject.tramp[Int](max), 0)
}
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/unittest_collection.check b/test/files/run/unittest_collection.check
index 844ca54682..df1629dd7e 100644
--- a/test/files/run/unittest_collection.check
+++ b/test/files/run/unittest_collection.check
@@ -1 +1 @@
-warning: there were 1 deprecation warning(s); re-run with -deprecation for details
+warning: there was one deprecation warning; re-run with -deprecation for details
diff --git a/test/files/run/virtpatmat_typetag.check b/test/files/run/virtpatmat_typetag.check
index cac9d9a4d6..00df8b5e81 100644
--- a/test/files/run/virtpatmat_typetag.check
+++ b/test/files/run/virtpatmat_typetag.check
@@ -1,9 +1,9 @@
-1 is not a Int; it's a class java.lang.Integer
+1 is a Int
1 is a java.lang.Integer
1 is not a java.lang.String; it's a class java.lang.Integer
true is a Any
woele is a java.lang.String
-1 is not a Int; it's a class java.lang.Integer
+1 is a Int
1 is a java.lang.Integer
1 is not a java.lang.String; it's a class java.lang.Integer
true is a Any
diff --git a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala
index 45392de582..409f07037e 100644
--- a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala
@@ -310,4 +310,16 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") {
val cases = List(cq"a => b", cq"c => d")
assertEqAst(q"{ case ..$cases }", "{ case a => b case c => d }")
}
+
+ property("SI-8609 a") = test {
+ val q1 = q"val x = 1"
+ val q2 = q"..$q1; val y = 2"
+ assert(q2 ≈ q"{ val x = 1; val y = 2 }")
+ }
+
+ property("SI-8609 b") = test {
+ val q1 = q"import foo.bar"
+ val q2 = q"..$q1; val y = 2"
+ assert(q2 ≈ q"{ import foo.bar; val y = 2 }")
+ }
}
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
new file mode 100644
index 0000000000..5abfe90cd1
--- /dev/null
+++ b/test/junit/scala/StringContextTest.scala
@@ -0,0 +1,51 @@
+
+package scala
+
+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 StringContextTest {
+
+ import StringContext._
+
+ @Test def noEscape() = {
+ val s = "string"
+ val res = processEscapes(s)
+ assertEquals(s, res)
+ }
+ @Test def tabbed() = {
+ val s = """a\tb"""
+ val res = processEscapes(s)
+ assertEquals("a\tb", res)
+ }
+ @Test def quoted() = {
+ val s = """hello, \"world\""""
+ val res = processEscapes(s)
+ assertEquals("""hello, "world"""", res)
+ }
+ @Test def octal() = {
+ val s = """\123cala"""
+ val res = treatEscapes(s)
+ assertEquals("Scala", res)
+ }
+ @Test def doubled() = {
+ val s = """\123cala\123yntax"""
+ val res = treatEscapes(s)
+ assertEquals("ScalaSyntax", res)
+ }
+ @Test def badly() = assertThrows[InvalidEscapeException] {
+ val s = """Scala\"""
+ val res = treatEscapes(s)
+ assertEquals("Scala", res)
+ }
+ @Test def noOctal() = assertThrows[InvalidEscapeException] {
+ val s = """\123cala"""
+ val res = processEscapes(s)
+ assertEquals("Scala", res)
+ }
+}
diff --git a/test/junit/scala/collection/IndexedSeqOptimizedTest.scala b/test/junit/scala/collection/IndexedSeqOptimizedTest.scala
new file mode 100644
index 0000000000..e5382907af
--- /dev/null
+++ b/test/junit/scala/collection/IndexedSeqOptimizedTest.scala
@@ -0,0 +1,16 @@
+package scala.collection
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Assert._
+import org.junit.Test
+
+@RunWith(classOf[JUnit4])
+class IndexedSeqOptimizedTest {
+
+ @Test
+ def notThrowsAnExceptionInLastIndexOf() {
+ assertEquals(0, (Array(2): collection.mutable.WrappedArray[Int]).lastIndexWhere(_ => true, 1))
+ assertEquals(2, "abc123".lastIndexWhere(_.isLetter, 6))
+ }
+}
diff --git a/test/junit/scala/collection/IteratorTest.scala b/test/junit/scala/collection/IteratorTest.scala
new file mode 100644
index 0000000000..b7a9805c9f
--- /dev/null
+++ b/test/junit/scala/collection/IteratorTest.scala
@@ -0,0 +1,28 @@
+
+package scala.collection
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(classOf[JUnit4])
+class IteratorTest {
+
+ @Test
+ def groupedIteratorShouldNotAskForUnneededElement(): Unit = {
+ var counter = 0
+ val it = new Iterator[Int] { var i = 0 ; def hasNext = { counter = i; true } ; def next = { i += 1; i } }
+ val slidingIt = it sliding 2
+ slidingIt.next
+ assertEquals("Counter should be one, that means we didn't look further than needed", 1, counter)
+ }
+
+ @Test def groupedIteratorIsLazyWhenPadded(): Unit = {
+ var counter = 0
+ def it = new Iterator[Int] { var i = 0 ; def hasNext = { counter = i; true } ; def next = { i += 1; i } }
+ val slidingIt = it sliding 2 withPadding -1
+ slidingIt.next
+ assertEquals("Counter should be one, that means we didn't look further than needed", 1, counter)
+ }
+}
diff --git a/test/junit/scala/reflect/internal/NamesTest.scala b/test/junit/scala/reflect/internal/NamesTest.scala
new file mode 100644
index 0000000000..549c10abed
--- /dev/null
+++ b/test/junit/scala/reflect/internal/NamesTest.scala
@@ -0,0 +1,95 @@
+package scala.reflect.internal
+
+import scala.tools.testing.AssertUtil._
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+import org.junit.Assert._
+import scala.tools.nsc.symtab.SymbolTableForUnitTesting
+
+@RunWith(classOf[JUnit4])
+class NamesTest {
+ object symbolTable extends SymbolTableForUnitTesting
+ import symbolTable._
+
+ val h1 = newTermName("hai")
+ val h2 = newTermName("hai")
+ val f = newTermName("fisch")
+
+ val h1y = h1.toTypeName
+ val h2y = newTypeName("hai")
+ val fy = newTypeName("fisch")
+
+ val uy = newTypeName("uhu")
+ val u = uy.toTermName // calling toTermName after constructing a typeName. This tests the fact
+ // that creating a typeName always also first creates a termName. There is
+ // an assertion for that in toTermName.
+
+ @Test
+ def termNamesAreHashConsed() {
+ assertTrue(h1 eq h2)
+ assertEquals(h1, h2)
+ assertTrue(h1 ne f)
+ assertTrue(h1 != f)
+ }
+
+ @Test
+ def termNamesNotEqualsTypeNames() {
+ assert(h1 ne h1y)
+ assert(h1 != h1y)
+ assert(h2 ne h2y)
+ assert(h2 != h2y)
+ }
+
+ @Test
+ def termNamesTypeNamesSameRange() {
+ assert(h1.start == h1y.start && h1.length == h1y.length)
+ assert(h2.start == h2y.start && h2.length == h2y.length)
+ assert(u.start == uy.start && u.length == uy.length)
+ }
+
+ @Test
+ def testLookupTypeName() {
+ assert(lookupTypeName("hai".toCharArray) eq h1y)
+ assert(lookupTypeName("fisch".toCharArray) eq fy)
+ assert(lookupTypeName("uhu".toCharArray) eq uy)
+
+ assertThrows[AssertionError](lookupTypeName("dog".toCharArray), _ contains "not yet created")
+ val d = newTermName("dog")
+ assertThrows[AssertionError](lookupTypeName("dog".toCharArray), _ contains "not yet created")
+ val dy = d.toTypeName
+ assert(lookupTypeName("dog".toCharArray) eq dy)
+ }
+
+ @Test
+ def emptyName() {
+ val z = newTermName("")
+ val zy = z.toTypeName
+ assertEquals(z.toString, "")
+ assertEquals(zy.toString, "")
+ assert(z eq newTermName(""))
+ assert(zy eq newTypeName(""))
+ }
+
+ @Test
+ def subNameTest() {
+ val i = f.subName(1, f.length)
+ assert(i.start == (f.start + 1) && i.length == (f.length - 1))
+ assert(f.subName(0, f.length) eq f)
+
+ val iy = fy.subName(1, fy.length)
+ assert(iy.start == (fy.start + 1) && iy.length == (fy.length - 1))
+ assert(fy.subName(0, fy.length) eq fy)
+
+ assert(f.subName(1,1) eq newTermName(""))
+ assert(f.subName(1, 0) eq newTermName(""))
+
+ assertThrows[IllegalArgumentException](f.subName(0 - f.start - 1, 1))
+ }
+
+ @Test
+ def stringEqualsTest() {
+ assert(h1 string_== h2)
+ assert(h1 string_== h1y)
+ }
+}
diff --git a/test/junit/scala/reflect/internal/PrintersTest.scala b/test/junit/scala/reflect/internal/PrintersTest.scala
index 4587417a99..1458b942dc 100644
--- a/test/junit/scala/reflect/internal/PrintersTest.scala
+++ b/test/junit/scala/reflect/internal/PrintersTest.scala
@@ -33,10 +33,10 @@ object PrinterHelper {
def wrapCode(source: String) = {
val context = sm"""
|trait PrintersContext {
- | class baz extends scala.annotation.StaticAnnotation;
- | class foo1[A, B] extends scala.annotation.StaticAnnotation;
- | class foo2[A, B](a: scala.Int)(b: scala.Int) extends scala.annotation.StaticAnnotation;
- | class foo3[Af, Bf](a: scala.Int)(b: scala.Float, c: PrintersContext.this.foo1[Af, Bf]) extends scala.annotation.StaticAnnotation;
+ | class baz extends scala.annotation.Annotation with scala.annotation.StaticAnnotation;
+ | class foo1[A, B] extends scala.annotation.Annotation with scala.annotation.StaticAnnotation;
+ | class foo2[A, B](a: scala.Int)(b: scala.Int) extends scala.annotation.Annotation with scala.annotation.StaticAnnotation;
+ | class foo3[Af, Bf](a: scala.Int)(b: scala.Float, c: PrintersContext.this.foo1[Af, Bf]) extends scala.annotation.Annotation with scala.annotation.StaticAnnotation;
| trait A1;
| trait B1;
|${source.trim.lines map {" " + _} mkString s"$LF"}
@@ -54,8 +54,12 @@ object PrinterHelper {
}
}
- def assertTreeCode(tree: Tree)(code: String) = {
- assertEquals("using quasiquote or given tree"+LF, code.trim, normalizeEOL(showCode(tree)))
+ def assertTreeCode(tree: Tree, typecheck: Boolean = false)(code: String) = {
+ if (typecheck) {
+ assertEquals("using quasiquote or given tree (typechecked)"+LF, code.trim, normalizeEOL(showCode(toolbox.typecheck(tree))))
+ } else {
+ assertEquals("using quasiquote or given tree"+LF, code.trim, normalizeEOL(showCode(tree)))
+ }
}
def assertPrintedCode(source: String, checkTypedTree: Boolean = true, wrapCode: Boolean = false) = {
@@ -312,17 +316,17 @@ trait BasePrintTests {
@Test def testFunc1 = assertResultCode(
code = "List(1, 2, 3).map((i: Int) => i - 1)")(
parsedCode = "List(1, 2, 3).map(((i: Int) => i.-(1)))",
- typedCode = sm"scala.collection.immutable.List.apply(1, 2, 3).map(((i: scala.Int) => i.-(1)))(scala.collection.immutable.List.canBuildFrom)")
+ typedCode = sm"scala.collection.immutable.List.apply[Int](1, 2, 3).map[Int, List[Int]](((i: scala.Int) => i.-(1)))(scala.collection.immutable.List.canBuildFrom[Int])")
@Test def testFunc2 = assertResultCode(
code = "val sum: Seq[Int] => Int = _ reduceLeft (_+_)")(
parsedCode = "val sum: _root_.scala.Function1[Seq[Int], Int] = ((x$1) => x$1.reduceLeft(((x$2, x$3) => x$2.+(x$3))))",
- typedCode = "val sum: _root_.scala.Function1[scala.`package`.Seq[scala.Int], scala.Int] = ((x$1) => x$1.reduceLeft(((x$2, x$3) => x$2.+(x$3))))")
+ typedCode = "val sum: _root_.scala.Function1[scala.`package`.Seq[scala.Int], scala.Int] = ((x$1: Seq[Int]) => x$1.reduceLeft[Int](((x$2: Int, x$3: Int) => x$2.+(x$3))))")
@Test def testFunc3 = assertResultCode(
code = "List(1, 2, 3) map (_ - 1)")(
parsedCode = "List(1, 2, 3).map(((x$1) => x$1.-(1))) ",
- typedCode = "scala.collection.immutable.List.apply(1, 2, 3).map(((x$1) => x$1.-(1)))(scala.collection.immutable.List.canBuildFrom)")
+ typedCode = "scala.collection.immutable.List.apply[Int](1, 2, 3).map[Int, List[Int]](((x$1: Int) => x$1.-(1)))(scala.collection.immutable.List.canBuildFrom[Int])")
@Test def testFunc4 = assertResultCode(
code = "val x: String => Int = ((str: String) => 1)")(
@@ -401,7 +405,8 @@ trait ClassPrintTests {
@Test def testClassWithImplicitParams = assertPrintedCode("class X(var i: scala.Int)(implicit val d: scala.Double, var f: scala.Float)")
- @Test def testClassWithEarly = assertPrintedCode(sm"""
+ @Test def testClassWithEarly =
+ assertPrintedCode(sm"""
|class X(var i: scala.Int) extends {
| val a = i;
| type B
@@ -419,15 +424,22 @@ trait ClassPrintTests {
| throw Throw2.this.e
|}""")
- /*
- class Test {
- val (a, b) = (1, 2)
- }
- */
- @Test def testClassWithAssignmentWithTuple1 = assertPrintedCode(sm"""
+ @Test def testClassWithAssignmentWithTuple1 = assertResultCode(sm"""
|class Test {
- | private[this] val x$$1 = (scala.Tuple2.apply(1, 2): @scala.unchecked) match {
- | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2.apply(a, b)
+ | val (a, b) = (1, 2)
+ |}""")(
+ parsedCode = sm"""
+ |class Test {
+ | private[this] val x$$1 = (scala.Tuple2(1, 2): @scala.unchecked) match {
+ | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2(a, b)
+ | };
+ | val a = x$$1._1;
+ | val b = x$$1._2
+ |}""",
+ typedCode = sm"""
+ |class Test {
+ | private[this] val x$$1 = (scala.Tuple2.apply[Int, Int](1, 2): @scala.unchecked) match {
+ | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2.apply[Int, Int](a, b)
| };
| val a = Test.this.x$$1._1;
| val b = Test.this.x$$1._2
@@ -448,8 +460,8 @@ trait ClassPrintTests {
|}""",
typedCode = sm"""
|class Test {
- | private[this] val x$$1 = (scala.Predef.ArrowAssoc(1).->(2): @scala.unchecked) match {
- | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2.apply(a, b)
+ | private[this] val x$$1 = (scala.Predef.ArrowAssoc[Int](1).->[Int](2): @scala.unchecked) match {
+ | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2.apply[Int, Int](a, b)
| };
| val a = Test.this.x$$1._1;
| val b = Test.this.x$$1._2
@@ -462,8 +474,8 @@ trait ClassPrintTests {
*/
@Test def testClassWithPatternMatchInAssignment = assertPrintedCode(sm"""
|class Test {
- | private[this] val x$$1 = (scala.collection.immutable.List.apply(1, 3, 5): @scala.unchecked) match {
- | case scala.collection.immutable.List((one @ _), (three @ _), (five @ _)) => scala.Tuple3.apply(one, three, five)
+ | private[this] val x$$1 = (scala.collection.immutable.List.apply[scala.Int](1, 3, 5): @scala.unchecked) match {
+ | case scala.collection.immutable.List((one @ _), (three @ _), (five @ _)) => scala.Tuple3.apply[scala.Int, scala.Int, scala.Int](one, three, five)
| };
| val one = Test.this.x$$1._1;
| val three = Test.this.x$$1._2;
@@ -626,7 +638,7 @@ trait ClassPrintTests {
@Test def testObjectWithPatternMatch1 = assertPrintedCode(sm"""
|object PM1 {
- | scala.collection.immutable.List.apply(1, 2) match {
+ | scala.collection.immutable.List.apply[scala.Int](1, 2) match {
| case (i @ _) => i
| }
|}""")
@@ -715,7 +727,7 @@ trait ClassPrintTests {
|}""",
typedCode = sm"""
|object PM5 {
- | scala.collection.immutable.List.apply(1, 2) match {
+ | scala.collection.immutable.List.apply[Int](1, 2) match {
| case scala.`package`.::((x @ _), (xs @ _)) => x
| }
|}""")
@@ -756,7 +768,7 @@ trait ClassPrintTests {
@Test def testObjectWithPatternMatch8 = assertPrintedCode(sm"""
|{
| object Extractor {
- | def unapply(i: scala.Int) = scala.Some.apply(i)
+ | def unapply(i: scala.Int) = scala.Some.apply[scala.Int](i)
| };
| object PM9 {
| 42 match {
@@ -991,7 +1003,7 @@ trait ValAndDefPrintTests {
@Test def testDefWithLazyVal2 = assertPrintedCode(sm"""
|def a = {
- | lazy val test = {
+ | lazy val test: Unit = {
| scala.Predef.println();
| scala.Predef.println()
| };
@@ -1161,4 +1173,17 @@ trait QuasiTreesPrintTests {
|case class X(x: Int, s: String) {
| def y = "test"
|}""")
+
+ @Test def testQuasiCaseClassWithTypes1 = assertTreeCode(q"""case class X(x: ${typeOf[Int]}, s: ${typeOf[String]}){ def y = "test" }""")(sm"""
+ |case class X(x: Int, s: String) {
+ | def y = "test"
+ |}""")
+
+ @Test def testQuasiCaseClassWithTypes2 = assertTreeCode(q"""case class X(x: ${typeOf[Int]}, s: ${typeOf[String]}){ def y = "test" }""", typecheck = true)(sm"""
+ |{
+ | case class X(x: Int, s: String) {
+ | def y = "test"
+ | };
+ | ()
+ |}""")
} \ No newline at end of file
diff --git a/test/junit/scala/reflect/internal/ScopeTest.scala b/test/junit/scala/reflect/internal/ScopeTest.scala
new file mode 100644
index 0000000000..5166620189
--- /dev/null
+++ b/test/junit/scala/reflect/internal/ScopeTest.scala
@@ -0,0 +1,54 @@
+package symtab
+
+import scala.tools.nsc.symtab
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.tools.testing.AssertUtil.assertThrows
+import scala.tools.nsc.symtab.SymbolTableForUnitTesting
+
+@RunWith(classOf[JUnit4])
+class ScopeTest {
+ object symbolTable extends SymbolTableForUnitTesting
+
+ import symbolTable._
+
+ @Test
+ def testNestedScopeSmall(): Unit = testNestedScope(0)
+ @Test
+ def testNestedScopeLarge(): Unit = testNestedScope(64) // exceeding MIN_HASH
+
+ private def testNestedScope(initSize: Int) {
+ def sym(termName: String): Symbol = NoSymbol.newValue(TermName(termName))
+ val foo = sym("foo")
+ val bar = sym("bar")
+
+ val outerElems = List.tabulate(initSize)(i => sym(i.toString))
+ val outer = newScopeWith(outerElems ++ List(foo, bar) : _*)
+ assertTrue(outer.containsName(foo.name))
+ assertTrue(outer.containsName(bar.name))
+
+ val baz = sym("baz")
+ val nested = newNestedScope(outer)
+
+ // Entries from the outer scope are entered in the nested.
+ assertTrue(outer.containsName(foo.name))
+ assertTrue(outer.containsName(bar.name))
+
+ // Nested scopes structurally share ScopeEntry-s with the outer.
+ assertSame(outer.lookupEntry(foo.name), nested.lookupEntry(foo.name))
+ nested.enter(baz)
+
+ // Symbols entered in the nested scope aren't visible in the outer.
+ assertTrue(nested.containsName(baz.name))
+ assertTrue(!outer.containsName(baz.name))
+
+ // Unlinking a symbol in the inner scope doesn't modify the outer
+ nested.unlink(bar)
+ assert(!nested.containsName(bar.name))
+ assert(outer.containsName(bar.name))
+ }
+}
diff --git a/test/junit/scala/reflect/internal/TypesTest.scala b/test/junit/scala/reflect/internal/TypesTest.scala
new file mode 100644
index 0000000000..95194ef0a4
--- /dev/null
+++ b/test/junit/scala/reflect/internal/TypesTest.scala
@@ -0,0 +1,35 @@
+package scala.reflect.internal
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import scala.tools.nsc.symtab.SymbolTableForUnitTesting
+
+@RunWith(classOf[JUnit4])
+class TypesTest {
+
+ object symbolTable extends SymbolTableForUnitTesting
+ import symbolTable._, definitions._
+
+ @Test
+ def testRefinedTypeSI8611(): Unit = {
+ def stringNarrowed = StringTpe.narrow
+ assert(stringNarrowed != stringNarrowed)
+ assert(!(stringNarrowed =:= stringNarrowed))
+
+ def boolWithString = refinedType(BooleanTpe :: StringTpe :: Nil, NoSymbol)
+ assert(boolWithString != boolWithString)
+ assert(boolWithString =:= boolWithString)
+
+ val boolWithString1 = boolWithString
+ val boolWithString1narrow1 = boolWithString1.narrow
+ val boolWithString1narrow2 = boolWithString1.narrow
+ // Two narrowings of the same refinement end up =:=. This was the root
+ // cause of SI-8611. See `narrowUniquely` in `Logic` for the workaround.
+ assert(boolWithString1narrow1 =:= boolWithString1narrow2)
+ val uniquelyNarrowed1 = refinedType(boolWithString1narrow1 :: Nil, NoSymbol)
+ val uniquelyNarrowed2 = refinedType(boolWithString1narrow2 :: Nil, NoSymbol)
+ assert(uniquelyNarrowed1 =:= uniquelyNarrowed2)
+ }
+}
diff --git a/test/junit/scala/reflect/internal/util/SourceFileTest.scala b/test/junit/scala/reflect/internal/util/SourceFileTest.scala
index 903e705ba2..cad23eba14 100644
--- a/test/junit/scala/reflect/internal/util/SourceFileTest.scala
+++ b/test/junit/scala/reflect/internal/util/SourceFileTest.scala
@@ -17,6 +17,11 @@ class SourceFileTest {
assertFalse(file.isEndOfLine(Int.MaxValue))
}
+ @Test def si8630_lineToString(): Unit = {
+ val code = "abc "
+ assertEquals(code, new BatchSourceFile("", code).lineToString(0))
+ }
+
@Test
def si8205_lineToString(): Unit = {
assertEquals("", lineContentOf("", 0))
diff --git a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
new file mode 100644
index 0000000000..b592d06501
--- /dev/null
+++ b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
@@ -0,0 +1,104 @@
+package scala.tools.nsc
+package backend.jvm
+
+import scala.tools.testing.AssertUtil._
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+import scala.tools.asm.Opcodes
+import org.junit.Assert._
+
+@RunWith(classOf[JUnit4])
+class BTypesTest {
+ val g: Global = new Global(new Settings())
+
+ val btypes = new BTypes[g.type](g) {
+ def chrs = g.chrs
+ override type BTypeName = g.TypeName
+ override def createNewName(s: String) = g.newTypeName(s)
+ }
+
+ import btypes._
+
+ val jls = "java/lang/String"
+ val jlo = "java/lang/Object"
+
+ val o = ClassBType(jlo)
+ val s = ClassBType(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)
+ assertEquals(s1, s2)
+ assertEquals(s1.hashCode, s2.hashCode)
+ assert(s1 != o)
+ assert(s2 != o)
+ }
+
+ @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)
+ assert(BOOL.typedOpcode(Opcodes.IALOAD) == Opcodes.BALOAD)
+ assert(BYTE.typedOpcode(Opcodes.IALOAD) == Opcodes.BALOAD)
+ assert(CHAR.typedOpcode(Opcodes.IALOAD) == Opcodes.CALOAD)
+ assert(SHORT.typedOpcode(Opcodes.IALOAD) == Opcodes.SALOAD)
+ 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(UNIT.typedOpcode(Opcodes.IRETURN) == Opcodes.RETURN)
+ assert(BOOL.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN)
+ assert(CHAR.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN)
+ assert(BYTE.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN)
+ assert(SHORT.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN)
+ assert(INT.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN)
+ 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)
+ }
+
+ @Test
+ def descriptors() {
+ assert(o.descriptor == "Ljava/lang/Object;")
+ assert(s.descriptor == "Ljava/lang/String;")
+ assert(oArr.descriptor == "[Ljava/lang/Object;")
+ assert(method.descriptor == "([Ljava/lang/Object;IDLjava/lang/String;)V")
+ }
+
+ @Test
+ def toAsmTypeTest() {
+ for (t <- List(o, s, oArr, method, INT, UNIT, DOUBLE)) {
+ assertEquals(o.descriptor, o.toASMType.getDescriptor)
+ }
+ }
+
+ @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)
+ }
+
+ // 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/symtab/SymbolTableForUnitTesting.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
index 25d8c4667f..91868a5683 100644
--- a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
+++ b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
@@ -72,6 +72,18 @@ class SymbolTableForUnitTesting extends SymbolTable {
def picklerPhase: scala.reflect.internal.Phase = SomePhase
def erasurePhase: scala.reflect.internal.Phase = SomePhase
+ // Members declared in scala.reflect.internal.Reporting
+ def reporter = new scala.reflect.internal.ReporterImpl {
+ protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit = println(msg)
+ }
+
+ // minimal Run to get Reporting wired
+ def currentRun = new RunReporting {}
+ class PerRunReporting extends PerRunReportingBase {
+ def deprecationWarning(pos: Position, msg: String): Unit = reporter.warning(pos, msg)
+ }
+ protected def PerRunReporting = new PerRunReporting
+
// Members declared in scala.reflect.internal.SymbolTable
def currentRunId: Int = 1
def log(msg: => AnyRef): Unit = println(msg)
diff --git a/test/junit/scala/tools/testing/AssertUtil.scala b/test/junit/scala/tools/testing/AssertUtil.scala
index 9efac64a97..9a97c5114f 100644
--- a/test/junit/scala/tools/testing/AssertUtil.scala
+++ b/test/junit/scala/tools/testing/AssertUtil.scala
@@ -5,15 +5,20 @@ package testing
* that are ultimately based on junit.Assert primitives.
*/
object AssertUtil {
- /** Check if exception T (or a subclass) was thrown during evaluation of f.
- * If any other exception or throwable is found instead it will be re-thrown.
+ /**
+ * Check if throwable T (or a subclass) was thrown during evaluation of f, and that its message
+ * satisfies the `checkMessage` predicate.
+ * If any other exception will be re-thrown.
*/
- def assertThrows[T <: Exception](f: => Any)(implicit manifest: Manifest[T]): Unit =
+ def assertThrows[T <: Throwable](f: => Any,
+ checkMessage: String => Boolean = s => true)
+ (implicit manifest: Manifest[T]): Unit = {
try f
catch {
- case e: Exception =>
- val clazz = manifest.erasure.asInstanceOf[Class[T]]
+ case e: Throwable if checkMessage(e.getMessage) =>
+ val clazz = manifest.runtimeClass
if (!clazz.isAssignableFrom(e.getClass))
throw e
}
-} \ No newline at end of file
+ }
+}
diff --git a/test/scaladoc/run/t8672.check b/test/scaladoc/run/t8672.check
new file mode 100644
index 0000000000..d7194c73bf
--- /dev/null
+++ b/test/scaladoc/run/t8672.check
@@ -0,0 +1,4 @@
+Some(Chain(List(Text(New in release 1.2.3.4, it works), Text(.))))
+Some(Text(Sentence no period))
+Some(Chain(List(Text(Sentence period at end), Text(.))))
+Done.
diff --git a/test/scaladoc/run/t8672.scala b/test/scaladoc/run/t8672.scala
new file mode 100644
index 0000000000..8a9b5086bd
--- /dev/null
+++ b/test/scaladoc/run/t8672.scala
@@ -0,0 +1,32 @@
+import scala.tools.nsc.doc.model._
+import scala.tools.partest.ScaladocModelTest
+
+object Test extends ScaladocModelTest {
+ override def code = """
+ class C {
+
+ /**
+ * New in release 1.2.3.4, it works. Next sentence.
+ * Next Line.
+ */
+ def method1 = 0
+
+ /** Sentence no period */
+ def method2 = 0
+
+ /** Sentence period at end.*/
+ def method3 = 0
+ }
+ """
+
+ def scaladocSettings = ""
+
+ def testModel(root: Package) = {
+ import access._
+ val ms = List("method1", "method2", "method3")
+ for (m <- ms) {
+ val method = root._class("C")._method(m)
+ println(method.comment.get.body.summary)
+ }
+ }
+}
diff --git a/versions.properties b/versions.properties
index 0e56f731ed..c334629d20 100644
--- a/versions.properties
+++ b/versions.properties
@@ -1,10 +1,10 @@
-#Wed, 16 Apr 2014 11:13:08 +0200
+#Tue, 20 May 2014 10:01:37 +0200
# NOTE: this file determines the content of the scala-distribution
# via scala-dist-pom.xml and scala-library-all-pom.xml
# when adding new properties that influence a release,
# also add them to the update.versions mechanism in build.xml,
# which is used by scala-release-2.11.x in scala/jenkins-scripts
-starr.version=2.11.0
+starr.version=2.11.1
starr.use.released=1
# These are the versions of the modules that go with this release.
@@ -14,16 +14,17 @@ starr.use.released=1
scala.binary.version=2.11
# e.g. 2.11.0-RC1, 2.11.0, 2.11.1-RC1, 2.11.1
# this defines the dependency on scala-continuations-plugin in scala-dist's pom
-scala.full.version=2.11.0
+scala.full.version=2.11.1
# external modules shipped with distribution, as specified by scala-library-all's pom
-scala-xml.version.number=1.0.1
+scala-xml.version.number=1.0.2
scala-parser-combinators.version.number=1.0.1
-scala-continuations-plugin.version.number=1.0.1
-scala-continuations-library.version.number=1.0.1
+scala-continuations-plugin.version.number=1.0.2
+scala-continuations-library.version.number=1.0.2
scala-swing.version.number=1.0.1
-akka-actor.version.number=2.3.2
+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