summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorAntonio Cunei <antonio.cunei@epfl.ch>2009-11-24 17:30:44 +0000
committerAntonio Cunei <antonio.cunei@epfl.ch>2009-11-24 17:30:44 +0000
commit839d0ee5ec9c27e2e5da6bab6f03c8a95e90a109 (patch)
tree613ed692570fb5891f57e76854d9ff4af8ed13d1 /src/compiler
parent5f71b9208404015f425f30a0b4b3f4b3df4ec83f (diff)
downloadscala-839d0ee5ec9c27e2e5da6bab6f03c8a95e90a109.tar.gz
scala-839d0ee5ec9c27e2e5da6bab6f03c8a95e90a109.tar.bz2
scala-839d0ee5ec9c27e2e5da6bab6f03c8a95e90a109.zip
Merged revisions 19624,19629-19630,19645,19651,...
Merged revisions 19624,19629-19630,19645,19651,19655-19660,19666-19668,19670,19673-19679, 19683-19685,19688,19692,19695-19700,19706-19707,19717-19719,19723-19724, 19726,19730,19735-19740,19742-19744,19746-19759,19762-19764,19767-19769, 19773,19776,19781,19787,19789,19792-19793,19798-19800,19803-19804,19806- 19808,19813-19815,19818-19820,19824 via svnmerge from https://lampsvn.epfl.ch/svn-repos/scala/scala/trunk ........ r19624 | moors | 2009-11-13 13:17:50 +0100 (Fri, 13 Nov 2009) | 2 lines fixed #1236 another Symbol::tpe bites the dust (should'be been tpeHK) ........ r19629 | rytz | 2009-11-13 16:53:11 +0100 (Fri, 13 Nov 2009) | 1 line review board scipt ........ r19630 | rytz | 2009-11-13 17:10:35 +0100 (Fri, 13 Nov 2009) | 1 line updates to review script ........ r19645 | odersky | 2009-11-13 18:31:12 +0100 (Fri, 13 Nov 2009) | 1 line Fixes #1477 by requiring that abstract types with non-volatile upper bounds cannot be overridden by volatile types. ........ r19651 | extempore | 2009-11-14 19:02:10 +0100 (Sat, 14 Nov 2009) | 5 lines Fixes and test cases for #2087 and #2400. This required fixing a long-standing bug in fjbg and recompiling fjbg.jar, which had the side effect of revealing that the current fjbg jar had never been recompiled with target 1.5, so now it's smaller and (I imagine) faster. ........ r19655 | odersky | 2009-11-15 12:14:57 +0100 (Sun, 15 Nov 2009) | 2 lines Fixed #2848 and #2630; Improvements in equality speed ........ r19656 | odersky | 2009-11-15 14:56:21 +0100 (Sun, 15 Nov 2009) | 2 lines Fixed #1459 ........ r19657 | odersky | 2009-11-15 15:17:48 +0100 (Sun, 15 Nov 2009) | 2 lines Added benchmarks with results for equality. ........ r19658 | milessabin | 2009-11-15 16:46:52 +0100 (Sun, 15 Nov 2009) | 1 line Fixed #2627. Also ensure that a non-empty dependencies file is created on the first build. ........ r19659 | extempore | 2009-11-15 19:08:45 +0100 (Sun, 15 Nov 2009) | 3 lines Tweaked a test which has been regularly failing due to heap exhaustion, although what it's supposed to be testing is stack utilization. ........ r19660 | milessabin | 2009-11-15 21:57:46 +0100 (Sun, 15 Nov 2009) | 1 line Corrected help syntax for -Ybuilder-debug. ........ r19666 | milessabin | 2009-11-16 11:17:01 +0100 (Mon, 16 Nov 2009) | 1 line Fixed #2627. ........ r19667 | rytz | 2009-11-16 11:45:54 +0100 (Mon, 16 Nov 2009) | 1 line review requests can now be created outside a checkout ........ r19668 | rytz | 2009-11-16 11:55:59 +0100 (Mon, 16 Nov 2009) | 1 line another minor change to teh review script ........ r19670 | odersky | 2009-11-16 13:31:40 +0100 (Mon, 16 Nov 2009) | 2 lines Fixed #2323; made Pickler do the right thing. ........ r19673 | moors | 2009-11-16 18:44:25 +0100 (Mon, 16 Nov 2009) | 1 line test cases in pending ........ r19674 | dragos | 2009-11-16 19:24:40 +0100 (Mon, 16 Nov 2009) | 2 lines Faster optimizer by caching successors/predecessors in basic blocks, and better lub for icode ........ r19675 | extempore | 2009-11-16 22:30:22 +0100 (Mon, 16 Nov 2009) | 1 line Minor pickler organization stemming from optimizer appeasement. ........ r19676 | extempore | 2009-11-16 22:30:36 +0100 (Mon, 16 Nov 2009) | 2 lines Some organization & duplication removal in GenICode stemming from optimizer appeasement. ........ r19677 | extempore | 2009-11-16 22:30:54 +0100 (Mon, 16 Nov 2009) | 2 lines A lot of minor code adjustments to ease the burden on the optimizer, and various cleanups encountered along the way. ........ r19678 | extempore | 2009-11-16 22:31:07 +0100 (Mon, 16 Nov 2009) | 2 lines Some organization & duplication removal in RefChecks stemming from optimizer appeasement. ........ r19679 | extempore | 2009-11-16 22:56:00 +0100 (Mon, 16 Nov 2009) | 1 line Fix for #2647. ........ r19683 | extempore | 2009-11-17 05:51:43 +0100 (Tue, 17 Nov 2009) | 1 line Fix and test case for #2636. ........ r19684 | extempore | 2009-11-17 06:25:48 +0100 (Tue, 17 Nov 2009) | 2 lines Contents of scala.Math moved into scala.math package object, and scala.Math deprecated. Also a couple janitorial cleanups. ........ r19685 | milessabin | 2009-11-17 10:04:00 +0100 (Tue, 17 Nov 2009) | 1 line More String.isEmpty breakage. ........ r19688 | odersky | 2009-11-17 14:12:31 +0100 (Tue, 17 Nov 2009) | 1 line Allow implicit modifier on single-parameter function literals. Fixes and closes #1492. ........ r19692 | extempore | 2009-11-17 21:51:23 +0100 (Tue, 17 Nov 2009) | 1 line Partial fix for #2625. ........ r19695 | extempore | 2009-11-18 01:18:58 +0100 (Wed, 18 Nov 2009) | 11 lines Removing bits from the library which shouldn't make the 2.8 cut. Removed outright: util.Hashable: unused and I have a better plan for this net.Utility: class created to accomodate expansion which never materialized reflect.Invocation: doesn't go far enough, needs love it won't find right now reflect.RichClass: same as Invocation Moved into compiler: util.ScalaClassLoader: too useful to lose, not done enough to ship ........ r19696 | extempore | 2009-11-18 01:36:26 +0100 (Wed, 18 Nov 2009) | 1 line More minor removals and some cleanups of !!!s and XXXs. ........ r19697 | dcaoyuan | 2009-11-18 05:35:07 +0100 (Wed, 18 Nov 2009) | 1 line Fixed #2631 ........ r19698 | dcaoyuan | 2009-11-18 05:36:59 +0100 (Wed, 18 Nov 2009) | 1 line to fix varies conditions of removed source/class files that were previously recorded in .scala_dependencies. ........ r19699 | extempore | 2009-11-18 06:41:16 +0100 (Wed, 18 Nov 2009) | 3 lines More deprecation work. Removes most elements which have been deprecated since 2.7.2 (still except for lower case primitive type aliases) and removes every deprecated method which has never shipped in a release. ........ r19700 | rytz | 2009-11-18 11:19:30 +0100 (Wed, 18 Nov 2009) | 1 line recompiled msil.jar, it refered to scala.Math$ ........ r19706 | extempore | 2009-11-18 15:45:11 +0100 (Wed, 18 Nov 2009) | 3 lines Fixed a bug in Range which was causing take and drop to overflow and return empty if the argument was larger than the actual length of the Range and arg * step > MaxInt. ........ r19707 | dcaoyuan | 2009-11-18 15:46:01 +0100 (Wed, 18 Nov 2009) | 1 line Fixed #2645 ........ r19717 | extempore | 2009-11-18 23:06:03 +0100 (Wed, 18 Nov 2009) | 3 lines Finally completed the incredibly tedious task of removing the lower case primitive aliases from Predef. Had to rebuild msil.jar along the way. ........ r19718 | extempore | 2009-11-18 23:43:54 +0100 (Wed, 18 Nov 2009) | 2 lines New starr based on r19717 since I'm finding the current starr doesn't have TupleN.zipped fully working. ........ r19719 | extempore | 2009-11-19 00:24:23 +0100 (Thu, 19 Nov 2009) | 2 lines More deprecation soothing. Soon we'll be down to a double-digit warning count. ........ r19723 | extempore | 2009-11-19 05:59:46 +0100 (Thu, 19 Nov 2009) | 2 lines Restoring an embarassingly large quantity of deprecated methods whose time had not yet come. ........ r19724 | dcaoyuan | 2009-11-19 09:24:37 +0100 (Thu, 19 Nov 2009) | 1 line Path.parent now returns Path instead of Option[Path], and it prefers relative path. ........ r19726 | rytz | 2009-11-19 14:44:15 +0100 (Thu, 19 Nov 2009) | 1 line closes #2670. the target-annotations can now be placed on annotation classes as well ........ r19730 | extempore | 2009-11-19 21:31:46 +0100 (Thu, 19 Nov 2009) | 2 lines Deprecation patrol exercises the new capabilities in Tuple2.zipped among other exciting no-ops. ........ r19735 | extempore | 2009-11-20 01:49:58 +0100 (Fri, 20 Nov 2009) | 1 line Fix for infinite loop in StringBuilder pointed out by dpp. ........ r19736 | extempore | 2009-11-20 04:50:12 +0100 (Fri, 20 Nov 2009) | 1 line Slightly more fixy fix than the previous fix. ........ r19737 | plocinic | 2009-11-20 10:04:04 +0100 (Fri, 20 Nov 2009) | 1 line closes #1422 ........ r19738 | odersky | 2009-11-20 14:57:22 +0100 (Fri, 20 Nov 2009) | 1 line Simplifiations in collections libraries, enabled by introduction of Self type in TraversableLike. ........ r19739 | odersky | 2009-11-20 14:58:36 +0100 (Fri, 20 Nov 2009) | 1 line new test ........ r19740 | extempore | 2009-11-20 16:16:45 +0100 (Fri, 20 Nov 2009) | 4 lines More world-shaking deprecation work. Using the scala.math package object, updating some @deprecated messages to give realistic alternatives, properly resolving the semantic mismatch between List.-- and diff, its once-recommended but inequivalent alternative. ........ r19742 | prokopec | 2009-11-20 17:11:19 +0100 (Fri, 20 Nov 2009) | 1 line PriorityQueue fixed, should work ok now. ........ r19743 | prokopec | 2009-11-20 17:11:53 +0100 (Fri, 20 Nov 2009) | 1 line Priority queue test. ........ r19744 | prokopec | 2009-11-20 17:12:48 +0100 (Fri, 20 Nov 2009) | 1 line Priority queue test, updated. ........ r19746 | prokopec | 2009-11-20 18:25:08 +0100 (Fri, 20 Nov 2009) | 1 line Changes made in the clean up phase - now the symbols get interned during classload for each symbol literal - references to them reside in static fields. These static fields get initialized in static constructors - the java backend will now identify ctors with static flags and generate a static initializer containing the necessary code. ........ r19747 | prokopec | 2009-11-20 18:29:39 +0100 (Fri, 20 Nov 2009) | 1 line Removed a couple of unneeded comments. ........ r19748 | extempore | 2009-11-20 18:39:49 +0100 (Fri, 20 Nov 2009) | 3 lines Deprecated the Tuple(...) methods in Predef, but at the same time extended the overload out to 22 and moved them into the scala package object. ........ r19749 | odersky | 2009-11-20 19:02:42 +0100 (Fri, 20 Nov 2009) | 1 line Closed #2641 ........ r19750 | prokopec | 2009-11-20 19:06:41 +0100 (Fri, 20 Nov 2009) | 1 line Commented out anonymous function invocation for which Hudson was complaining it couldn't find the classdef. ........ r19751 | extempore | 2009-11-20 19:08:57 +0100 (Fri, 20 Nov 2009) | 2 lines Subtly altered implementation of iterator which does not go into an infinite loop when deprecated "append" is replaced with ++. ........ r19752 | extempore | 2009-11-20 19:09:08 +0100 (Fri, 20 Nov 2009) | 2 lines Tweak to Iterator.++ to keep it from going into an infinite loop on x ++ x. ........ r19753 | prokopec | 2009-11-20 19:17:13 +0100 (Fri, 20 Nov 2009) | 1 line Trying to get the test to pass on the server. ........ r19754 | extempore | 2009-11-20 19:35:52 +0100 (Fri, 20 Nov 2009) | 1 line Eliminated warning about Tuple2 and Tuple3 importing Traversable. ........ r19755 | extempore | 2009-11-20 19:59:30 +0100 (Fri, 20 Nov 2009) | 1 line More deprecation avoidance and some minor smoothings. ........ r19756 | moors | 2009-11-20 20:25:32 +0100 (Fri, 20 Nov 2009) | 3 lines closes #2585: generate more precise Java generic signatures for classes nested in parametric outer classes fix based on review by Martin baseType is your friend ........ r19757 | michelou | 2009-11-20 21:19:41 +0100 (Fri, 20 Nov 2009) | 2 lines updated/extended serialization tests ........ r19758 | extempore | 2009-11-20 21:37:12 +0100 (Fri, 20 Nov 2009) | 1 line Expanding the warning cleansing into -unchecked territory. ........ r19759 | odersky | 2009-11-20 22:02:23 +0100 (Fri, 20 Nov 2009) | 2 lines Closed #2642 ........ r19762 | extempore | 2009-11-21 18:24:29 +0100 (Sat, 21 Nov 2009) | 1 line Applied performance patch and test case from ijuma; closes #2526. ........ r19763 | extempore | 2009-11-21 20:58:05 +0100 (Sat, 21 Nov 2009) | 2 lines Partially addresses #2626 - pattern matcher no longer depends on drop(n) behavior if n < 0. ........ r19764 | extempore | 2009-11-22 00:55:06 +0100 (Sun, 22 Nov 2009) | 2 lines Cleanup of Cleanup. Finally straightening out a bunch of duplicated boxing code in the right location. ........ r19767 | extempore | 2009-11-22 02:26:04 +0100 (Sun, 22 Nov 2009) | 2 lines Fix (I think) for recently introduced MSIL breakage stemming from eliminating deprecation warnings. ........ r19768 | odersky | 2009-11-22 12:32:26 +0100 (Sun, 22 Nov 2009) | 2 lines Made implicit resolution compatible with numeric conformance. ........ r19769 | odersky | 2009-11-22 13:28:57 +0100 (Sun, 22 Nov 2009) | 2 lines Closed #2635 ........ r19773 | extempore | 2009-11-22 17:07:46 +0100 (Sun, 22 Nov 2009) | 1 line Removed all traces of Boxed*Array. New starr. ........ r19776 | odersky | 2009-11-22 19:13:34 +0100 (Sun, 22 Nov 2009) | 2 lines Moved failing test due to fix of #2635 to pending. ........ r19781 | prokopec | 2009-11-22 23:47:08 +0100 (Sun, 22 Nov 2009) | 2 lines Priority queue reverse is undefined - overriden to throw an exception. Reverse iterator seems to have sense - it is overriden and is defined, and some methods in SeqLike are implemented in terms of it. ........ r19787 | extempore | 2009-11-23 13:51:56 +0100 (Mon, 23 Nov 2009) | 1 line A couple more warning fixes I meant to check in with r19758. ........ r19789 | dragos | 2009-11-23 14:58:56 +0100 (Mon, 23 Nov 2009) | 2 lines == for specialized types will not cause boxing anymore ........ r19792 | odersky | 2009-11-23 15:45:44 +0100 (Mon, 23 Nov 2009) | 1 line Closed #1226. Added new test cases. ........ r19793 | malayeri | 2009-11-23 16:16:25 +0100 (Mon, 23 Nov 2009) | 1 line Closed #2552. Changed Iterator.takeWhile and Iterator.filter to avoid recomputing predicate in next and hasNext methods. ........ r19798 | odersky | 2009-11-23 18:50:54 +0100 (Mon, 23 Nov 2009) | 1 line Partial fix for #2683 ........ r19799 | odersky | 2009-11-23 19:12:34 +0100 (Mon, 23 Nov 2009) | 1 line Closed #1545 ........ r19800 | extempore | 2009-11-23 22:03:51 +0100 (Mon, 23 Nov 2009) | 4 lines Partitioned scala.Math and scala.math a little bit. ALL_CAP aliases are deprecated and only in Math. Formerly unavailable members of java.lang.Math which were added in 1.5 are now available in scala.math. ........ r19803 | extempore | 2009-11-24 01:08:32 +0100 (Tue, 24 Nov 2009) | 2 lines Some more XML cleanups. I'm seeing if I can break the compiler dependency on scala.util.automata. ........ r19804 | milessabin | 2009-11-24 02:13:01 +0100 (Tue, 24 Nov 2009) | 1 line Improved completion for locals and import. ........ r19806 | moors | 2009-11-24 10:09:49 +0100 (Tue, 24 Nov 2009) | 5 lines close #2665 and close #2667: use weak conformance in polymorphic case of isApplicable reviewed by: odersky exprTypeArgs now takes a comparison function: isWeaklyCompatible is passed in isApplicable's typesCompatible (to mimic what happens in the monomorphic case) Martin: please review as this is different from my original proposal (that one broke type inference, this one passes all tests and does not slow down quick.comp) ........ r19807 | moors | 2009-11-24 11:15:58 +0100 (Tue, 24 Nov 2009) | 1 line pending test: see #2660, #2691 ........ r19808 | moors | 2009-11-24 11:19:08 +0100 (Tue, 24 Nov 2009) | 1 line close #2626 as specified by Martin ........ r19813 | odersky | 2009-11-24 15:40:04 +0100 (Tue, 24 Nov 2009) | 1 line relaxed rule requiring `override` modifiers so that it's OK if self type contains overridden symbol. ........ r19814 | odersky | 2009-11-24 16:50:06 +0100 (Tue, 24 Nov 2009) | 1 line Closed #2629 #2639 #2669 ........ r19815 | odersky | 2009-11-24 16:57:17 +0100 (Tue, 24 Nov 2009) | 1 line Closed #2696 ........ r19818 | odersky | 2009-11-24 17:07:49 +0100 (Tue, 24 Nov 2009) | 1 line Closed #2698 ........ r19819 | odersky | 2009-11-24 17:12:18 +0100 (Tue, 24 Nov 2009) | 1 line Closed #2664 ........ r19820 | prokopec | 2009-11-24 17:35:09 +0100 (Tue, 24 Nov 2009) | 1 line Added reverse capabilities to PriorityQueue. Seems to work well - tests pass. ........ r19824 | phaller | 2009-11-24 18:11:45 +0100 (Tue, 24 Nov 2009) | 1 line Made mutable.OpenHashMap a MapLike. Closes #2681. ........
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/ant/Scalac.scala70
-rw-r--r--src/compiler/scala/tools/ant/sabbus/Compiler.scala2
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala55
-rw-r--r--src/compiler/scala/tools/nsc/Interpreter.scala10
-rw-r--r--src/compiler/scala/tools/nsc/MainGenericRunner.scala3
-rw-r--r--src/compiler/scala/tools/nsc/ObjectRunner.scala2
-rw-r--r--src/compiler/scala/tools/nsc/PhaseAssembly.scala178
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala6
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeDSL.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeInfo.scala9
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala70
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala14
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala12
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala122
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Checkers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala762
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Members.scala68
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Printers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala36
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala14
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala21
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala26
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala15
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala217
-rw-r--r--src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala35
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala37
-rw-r--r--src/compiler/scala/tools/nsc/dependencies/Changes.scala16
-rw-r--r--src/compiler/scala/tools/nsc/dependencies/Files.scala29
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala46
-rw-r--r--src/compiler/scala/tools/nsc/interactive/RangePositions.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala6
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Completion.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/File.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/Path.scala51
-rw-r--r--src/compiler/scala/tools/nsc/io/PlainFile.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/VirtualFile.scala2
-rw-r--r--src/compiler/scala/tools/nsc/javac/JavaScanners.scala4
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala57
-rw-r--r--src/compiler/scala/tools/nsc/models/Signatures.scala10
-rw-r--r--src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala101
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolWalker.scala43
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala17
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala140
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala40
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala235
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala216
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala36
-rw-r--r--src/compiler/scala/tools/nsc/transform/LazyVals.scala5
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/TailCalls.scala7
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala12
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Duplicators.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala11
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala108
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala31
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala155
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala420
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala207
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala141
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala63
-rw-r--r--src/compiler/scala/tools/nsc/util/ClassPath.scala2
-rw-r--r--src/compiler/scala/tools/nsc/util/HashSet.scala2
-rw-r--r--src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala93
-rw-r--r--src/compiler/scala/tools/nsc/util/TreeSet.scala10
77 files changed, 2267 insertions, 1900 deletions
diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala
index aaa50cdd08..7b28ee9103 100644
--- a/src/compiler/scala/tools/ant/Scalac.scala
+++ b/src/compiler/scala/tools/ant/Scalac.scala
@@ -10,7 +10,7 @@
package scala.tools.ant
-import java.io.{File,PrintWriter,BufferedWriter,FileWriter}
+import java.io.{File,PrintWriter,BufferedWriter,FileWriter, IOException}
import org.apache.tools.ant.{ BuildException, Project, AntClassLoader }
import org.apache.tools.ant.taskdefs.{MatchingTask,Java}
@@ -18,7 +18,7 @@ import org.apache.tools.ant.types.{Path, Reference, FileSet}
import org.apache.tools.ant.util.{FileUtils, GlobPatternMapper,
SourceFileScanner}
-import scala.tools.nsc.{Global, Settings}
+import scala.tools.nsc.{Global, Settings, Properties}
import scala.tools.nsc.reporters.{Reporter, ConsoleReporter}
/** <p>
@@ -105,10 +105,10 @@ class Scalac extends MatchingTask {
/** Defines valid values for the <code>deprecation</code> and
* <code>unchecked</code> properties. */
object Flag extends PermissibleValue {
- val values = List("yes", "no", "on", "off")
+ val values = List("yes", "no", "on", "off", "true", "false")
def toBoolean(flag: String) =
- if (flag == "yes" || flag == "on") Some(true)
- else if (flag == "no" || flag == "off") Some(false)
+ if (flag == "yes" || flag == "on" || flag == "true") Some(true)
+ else if (flag == "no" || flag == "off" || flag == "false") Some(false)
else None
}
@@ -477,6 +477,9 @@ class Scalac extends MatchingTask {
/** Initializes settings and source files */
protected def initialize: (Settings, List[File], Boolean) = {
+ if (scalacDebugging)
+ log("Base directory is `%s`".format(scala.tools.nsc.io.Path("").normalize))
+
// Tests if all mandatory attributes are set and valid.
if (origin.isEmpty) error("Attribute 'srcdir' is not set.")
if (!destination.isEmpty && !destination.get.isDirectory())
@@ -558,11 +561,64 @@ class Scalac extends MatchingTask {
if (!assemrefs.isEmpty) settings.assemrefs.value = assemrefs.get
log("Scalac params = '" + addParams + "'", Project.MSG_DEBUG)
- settings.parseParams(addParams)
+ // todo, process fs from addParams?
+ val fs = processArguments(settings, addParams.trim.split("""\s+""").toList)
+
+ // resolve dependenciesFile path from project's basedir, so <ant antfile ...> call from other project works.
+ // the dependenciesFile may be relative path to basedir or absolute path, in either case, the following code
+ // will return correct answer.
+ settings.dependenciesFile.value match {
+ case "none" =>
+ case x =>
+ val depFilePath = scala.tools.nsc.io.Path(x)
+ settings.dependenciesFile.value = scala.tools.nsc.io.Path(getProject.getBaseDir).normalize resolve depFilePath path
+ }
(settings, sourceFiles, javaOnly)
}
+ /** Process the arguments and update the settings accordingly.
+ * This method is called only once, during initialization.
+ * @return Accumulated files to compile
+ */
+ protected def processArguments(settings: Settings, arguments: List[String]): List[String] = {
+ /** file extensions of files that the compiler can process */
+ lazy val fileEndings = Properties.fileEndings
+
+ // initialization
+ var ok = true
+ var fs: List[String] = Nil
+ var args = arguments
+ def errorAndNotOk(msg: String) = { error(msg) ; ok = false }
+
+ // given a @ argument expands it out
+ def doExpand(x: String) =
+ try { args = scala.tools.nsc.util.ArgumentsExpander.expandArg(x) ::: args.tail }
+ catch { case ex: IOException => errorAndNotOk(ex.getMessage) }
+
+ // true if it's a legit looking source file
+ def isSourceFile(x: String) =
+ (settings.script.value != "") ||
+ (fileEndings exists (x endsWith _))
+
+ // given an option for scalac finds out what it is
+ def doOption(x: String): Unit = {
+ val argsLeft = settings.parseParams(args)
+ if (args != argsLeft) args = argsLeft
+ else errorAndNotOk("bad option: '" + x + "'")
+ }
+
+ // cycle through args until empty or error
+ while (!args.isEmpty && ok) args.head match {
+ case x if x startsWith "@" => doExpand(x)
+ case x if x startsWith "-" => doOption(x)
+ case x if isSourceFile(x) => fs = x :: fs ; args = args.tail
+ case "" => args = args.tail // quick fix [martin: for what?]
+ case x => errorAndNotOk("don't know what to do with " + x)
+ }
+
+ fs
+ }
override def execute() {
val (settings, sourceFiles, javaOnly) = initialize
@@ -586,7 +642,7 @@ class Scalac extends MatchingTask {
if (compilerPath.isDefined) path add compilerPath.get
else getClass.getClassLoader match {
case cl: AntClassLoader => path add new Path(getProject, cl.getClasspath)
- case _ => error("Cannot determine default classpath for sclac, please specify one!")
+ case _ => error("Cannot determine default classpath for scalac, please specify one!")
}
path
}
diff --git a/src/compiler/scala/tools/ant/sabbus/Compiler.scala b/src/compiler/scala/tools/ant/sabbus/Compiler.scala
index 787c6af870..f6372f741a 100644
--- a/src/compiler/scala/tools/ant/sabbus/Compiler.scala
+++ b/src/compiler/scala/tools/ant/sabbus/Compiler.scala
@@ -13,7 +13,7 @@ package scala.tools.ant.sabbus
import java.io.File
import java.net.URL
import java.lang.reflect.InvocationTargetException
-import scala.util.ScalaClassLoader
+import scala.tools.nsc.util.ScalaClassLoader
class Compiler(classpath: Array[URL], val settings: Settings)
{
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index bae0d624c6..a933c13c39 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -10,7 +10,7 @@ import java.io.{File, FileOutputStream, PrintWriter}
import java.io.{IOException, FileNotFoundException}
import java.nio.charset._
import compat.Platform.currentTime
-import scala.tools.nsc.io.{SourceReader, AbstractFile}
+import scala.tools.nsc.io.{SourceReader, AbstractFile, Path}
import scala.tools.nsc.reporters._
import scala.tools.nsc.util.{ClassPath, MsilClassPath, JavaClassPath, SourceFile, BatchSourceFile, OffsetPosition, RangePosition}
@@ -227,28 +227,12 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
settings.dependenciesFile.value match {
case "none" => ()
case x =>
- val jfile = new java.io.File(x)
- if (!jfile.exists) jfile.createNewFile
- else {
- // This logic moved here from scala.tools.nsc.dependencies.File.
- // Note that it will trip an assertion in lookupPathUnchecked
- // if the path being looked at is absolute.
-
- /** The directory where file lookup should start at. */
- val rootDirectory: AbstractFile = {
- AbstractFile.getDirectory(".")
-// val roots = java.io.File.listRoots()
-// assert(roots.length > 0)
-// new PlainFile(roots(0))
- }
-
- def toFile(path: String) = {
- val file = rootDirectory.lookupPathUnchecked(path, false)
- assert(file ne null, path)
- file
- }
-
- dependencyAnalysis.loadFrom(AbstractFile.getFile(jfile), toFile)
+ val depFilePath = Path(x)
+ if (depFilePath.exists) {
+ /** The directory where file lookup should start */
+ val rootPath = depFilePath.parent
+ def toFile(path: String) = AbstractFile.getFile(rootPath resolve Path(path))
+ dependencyAnalysis.loadFrom(AbstractFile.getFile(depFilePath), toFile)
}
}
@@ -391,10 +375,6 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
val runsRightAfter = None
} with TailCalls
- // object checkDefined extends {
- // val global: Global.this.type = Global.this
- // } with CheckDefined
-
// phaseName = "explicitouter"
object explicitOuter extends {
val global: Global.this.type = Global.this
@@ -841,15 +821,20 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
informTime("total", startTime)
if (!dependencyAnalysis.off) {
-
- def fromFile(file: AbstractFile): String = {
- val path = file.path
- if (path.startsWith("./"))
- path.substring(2, path.length)
- else path
+ settings.dependenciesFile.value match {
+ case "none" =>
+ case x =>
+ val depFilePath = Path(x)
+ if (!depFilePath.exists)
+ dependencyAnalysis.dependenciesFile = AbstractFile.getFile(depFilePath.createFile())
+
+ /** The directory where file lookup should start */
+ val rootPath = depFilePath.parent.normalize
+ def fromFile(file: AbstractFile): String =
+ rootPath.relativize(Path(file.file).normalize).path
+
+ dependencyAnalysis.saveDependencies(fromFile)
}
-
- dependencyAnalysis.saveDependencies(fromFile)
}
}
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala
index 489ab1a3e0..77436fe55f 100644
--- a/src/compiler/scala/tools/nsc/Interpreter.scala
+++ b/src/compiler/scala/tools/nsc/Interpreter.scala
@@ -15,7 +15,8 @@ import reflect.InvocationTargetException
import scala.collection.immutable.ListSet
import scala.collection.mutable
import scala.collection.mutable.{ ListBuffer, HashSet, ArrayBuffer }
-import scala.util.{ ScalaClassLoader, URLClassLoader }
+import scala.tools.nsc.util.ScalaClassLoader
+import ScalaClassLoader.URLClassLoader
import scala.util.control.Exception.{ Catcher, catching, ultimately, unwrapping }
import io.{ PlainFile, VirtualDirectory }
@@ -119,11 +120,14 @@ class Interpreter(val settings: Settings, out: PrintWriter)
/** the compiler's classpath, as URL's */
val compilerClasspath: List[URL] = {
- import scala.net.Utility.parseURL
+ def parseURL(s: String): Option[URL] =
+ catching(classOf[MalformedURLException]) opt new URL(s)
+
val classpathPart =
ClassPath.expandPath(compiler.settings.classpath.value).map(s => new File(s).toURL)
+ val codebasePart =
+ (compiler.settings.Xcodebase.value.split(" ")).toList flatMap parseURL
- val codebasePart = (compiler.settings.Xcodebase.value.split(" ")).toList flatMap parseURL
classpathPart ::: codebasePart
}
diff --git a/src/compiler/scala/tools/nsc/MainGenericRunner.scala b/src/compiler/scala/tools/nsc/MainGenericRunner.scala
index 9cd9cdbd43..0365f28dc3 100644
--- a/src/compiler/scala/tools/nsc/MainGenericRunner.scala
+++ b/src/compiler/scala/tools/nsc/MainGenericRunner.scala
@@ -11,9 +11,8 @@ import java.io.{ File, IOException }
import java.lang.{ClassNotFoundException, NoSuchMethodException}
import java.lang.reflect.InvocationTargetException
import java.net.{ URL, MalformedURLException }
-import scala.util.ScalaClassLoader
-import util.ClassPath
+import util.{ ClassPath, ScalaClassLoader }
import File.pathSeparator
import Properties.{ versionString, copyrightString }
diff --git a/src/compiler/scala/tools/nsc/ObjectRunner.scala b/src/compiler/scala/tools/nsc/ObjectRunner.scala
index e4e0826d32..282cff4987 100644
--- a/src/compiler/scala/tools/nsc/ObjectRunner.scala
+++ b/src/compiler/scala/tools/nsc/ObjectRunner.scala
@@ -8,7 +8,7 @@
package scala.tools.nsc
import java.net.URL
-import scala.util.ScalaClassLoader
+import util.ScalaClassLoader
/** An object that runs another object specified by name.
*
diff --git a/src/compiler/scala/tools/nsc/PhaseAssembly.scala b/src/compiler/scala/tools/nsc/PhaseAssembly.scala
index 918b56fcfb..958bef5652 100644
--- a/src/compiler/scala/tools/nsc/PhaseAssembly.scala
+++ b/src/compiler/scala/tools/nsc/PhaseAssembly.scala
@@ -42,8 +42,8 @@ trait PhaseAssembly { self: Global =>
var level = 0
def allPhaseNames(): String = phaseobj match {
- case None => phasename
- case Some(lst) => lst.map(_.phaseName).reduceLeft(_+","+_)
+ case None => phasename
+ case Some(lst) => lst.map(_.phaseName).reduceLeft(_+","+_)
}
}
@@ -56,9 +56,9 @@ trait PhaseAssembly { self: Global =>
def getNodeByPhase(phs: SubComponent): Node = {
var node: Node = getNodeByPhase(phs.phaseName)
node.phaseobj match {
- case None =>
- node.phaseobj = Some(List[SubComponent](phs))
- case _ =>
+ case None =>
+ node.phaseobj = Some(List[SubComponent](phs))
+ case _ =>
}
node
}
@@ -107,12 +107,12 @@ trait PhaseAssembly { self: Global =>
var lvl = 1
var nds = nodes.valuesIterator.filter(_.level == lvl).toList
while(nds.size > 0) {
- nds = nds.sort((n1,n2) => (n1.phasename compareTo n2.phasename) < 0)
- for (n <- nds) {
- chain = chain ::: n.phaseobj.get
- }
- lvl += 1
- nds = nodes.valuesIterator.filter(_.level == lvl).toList
+ nds = nds.sortWith((n1,n2) => (n1.phasename compareTo n2.phasename) < 0)
+ for (n <- nds) {
+ chain = chain ::: n.phaseobj.get
+ }
+ lvl += 1
+ nds = nodes.valuesIterator.filter(_.level == lvl).toList
}
chain
}
@@ -122,7 +122,7 @@ trait PhaseAssembly { self: Global =>
*/
def collapseHardLinksAndLevels(node: Node, lvl: Int) {
if (node.visited) {
- throw new FatalError(
+ throw new FatalError(
"Cycle in compiler phase dependencies detected, phase " +
node.phasename + " reacted twice!")
}
@@ -131,19 +131,19 @@ trait PhaseAssembly { self: Global =>
var hls = Nil ++ node.before.filter(_.hard)
while (hls.size > 0) {
- for (hl <- hls) {
- node.phaseobj = Some(node.phaseobj.get ++ hl.frm.phaseobj.get)
- node.before = hl.frm.before
- nodes -= hl.frm.phasename
- edges -= hl
- for (edge <- node.before) edge.to = node
- }
- hls = Nil ++ node.before.filter(_.hard)
+ for (hl <- hls) {
+ node.phaseobj = Some(node.phaseobj.get ++ hl.frm.phaseobj.get)
+ node.before = hl.frm.before
+ nodes -= hl.frm.phasename
+ edges -= hl
+ for (edge <- node.before) edge.to = node
+ }
+ hls = Nil ++ node.before.filter(_.hard)
}
node.visited = true
for (edge <- node.before) {
- collapseHardLinksAndLevels( edge.frm, lvl + 1)
+ collapseHardLinksAndLevels( edge.frm, lvl + 1)
}
node.visited = false
@@ -156,44 +156,44 @@ trait PhaseAssembly { self: Global =>
def validateAndEnforceHardlinks() {
var hardlinks = edges.filter(_.hard)
for (hl <- hardlinks) {
- if (hl.frm.after.size > 1) {
- throw new FatalError("phase " + hl.frm.phasename + " want to run right after " + hl.to.phasename + ", but some phase has declared to run before " + hl.frm.phasename + ". Re-run with -Xgenerate-phase-graph <filename> to better see the problem.")
- }
+ if (hl.frm.after.size > 1) {
+ throw new FatalError("phase " + hl.frm.phasename + " want to run right after " + hl.to.phasename + ", but some phase has declared to run before " + hl.frm.phasename + ". Re-run with -Xgenerate-phase-graph <filename> to better see the problem.")
+ }
}
var rerun = true
while (rerun) {
- rerun = false
- hardlinks = edges.filter(_.hard)
- for (hl <- hardlinks) {
- var sanity = Nil ++ hl.to.before.filter(_.hard)
- if (sanity.length == 0) {
- throw new FatalError("There is no runs right after dependency, where there should be one! This is not supposed to happen!")
- } else if (sanity.length > 1) {
- var msg = "Multiple phases want to run right after the phase " + sanity.head.to.phasename + "\n"
- msg += "Phases: "
- sanity = sanity.sort((e1,e2) => (e1.frm.phasename compareTo e2.frm.phasename) < 0)
- for (edge <- sanity) {
- msg += edge.frm.phasename + ", "
- }
- msg += "\nRe-run with -Xgenerate-phase-graph <filename> to better see the problem."
- throw new FatalError(msg)
-
- } else {
-
- var promote = hl.to.before.filter(e => (!e.hard))
- hl.to.before.clear
- sanity foreach (edge => hl.to.before += edge)
- for (edge <- promote) {
- rerun = true
- informProgress(
+ rerun = false
+ hardlinks = edges.filter(_.hard)
+ for (hl <- hardlinks) {
+ var sanity = Nil ++ hl.to.before.filter(_.hard)
+ if (sanity.length == 0) {
+ throw new FatalError("There is no runs right after dependency, where there should be one! This is not supposed to happen!")
+ } else if (sanity.length > 1) {
+ var msg = "Multiple phases want to run right after the phase " + sanity.head.to.phasename + "\n"
+ msg += "Phases: "
+ sanity = sanity.sortWith((e1,e2) => (e1.frm.phasename compareTo e2.frm.phasename) < 0)
+ for (edge <- sanity) {
+ msg += edge.frm.phasename + ", "
+ }
+ msg += "\nRe-run with -Xgenerate-phase-graph <filename> to better see the problem."
+ throw new FatalError(msg)
+
+ } else {
+
+ var promote = hl.to.before.filter(e => (!e.hard))
+ hl.to.before.clear
+ sanity foreach (edge => hl.to.before += edge)
+ for (edge <- promote) {
+ rerun = true
+ informProgress(
"promote the dependency of " + edge.frm.phasename +
": " + edge.to.phasename + " => " + hl.frm.phasename)
- edge.to = hl.frm
- hl.frm.before += edge
- }
- }
- }
+ edge.to = hl.frm
+ hl.frm.before += edge
+ }
+ }
+ }
}
}
@@ -205,17 +205,17 @@ trait PhaseAssembly { self: Global =>
def removeDanglingNodes() {
var dnodes = nodes.valuesIterator filter (_.phaseobj.isEmpty)
for (node <- dnodes) {
- val msg = "dropping dependency on node with no phase object: "+node.phasename
+ val msg = "dropping dependency on node with no phase object: "+node.phasename
informProgress(msg)
- nodes -= node.phasename
- for (edge <- node.before) {
- edges -= edge
- edge.frm.after -= edge
- edge.frm.phaseobj match {
- case Some(lsc) => if (! lsc.head.internal) warning(msg)
- case _ =>
- }
- }
+ nodes -= node.phasename
+ for (edge <- node.before) {
+ edges -= edge
+ edge.frm.after -= edge
+ edge.frm.phaseobj match {
+ case Some(lsc) => if (! lsc.head.internal) warning(msg)
+ case _ =>
+ }
+ }
}
}
@@ -268,30 +268,30 @@ trait PhaseAssembly { self: Global =>
var fromnode = graph.getNodeByPhase(phs)
phs.runsRightAfter match {
- case None =>
- for (phsname <- phs.runsAfter) {
- if (phsname != "terminal") {
- val tonode = graph.getNodeByPhase(phsname)
- graph.softConnectNodes(fromnode, tonode)
- } else {
- error("[phase assembly, after dependency on terminal phase not allowed: " + fromnode.phasename + " => "+ phsname + "]")
- }
- }
- for (phsname <- phs.runsBefore) {
- if (phsname != "parser") {
- val tonode = graph.getNodeByPhase(phsname)
- graph.softConnectNodes(tonode, fromnode)
- } else {
- error("[phase assembly, before dependency on parser phase not allowed: " + phsname + " => "+ fromnode.phasename + "]")
- }
- }
- case Some(phsname) =>
- if (phsname != "terminal") {
- val tonode = graph.getNodeByPhase(phsname)
+ case None =>
+ for (phsname <- phs.runsAfter) {
+ if (phsname != "terminal") {
+ val tonode = graph.getNodeByPhase(phsname)
+ graph.softConnectNodes(fromnode, tonode)
+ } else {
+ error("[phase assembly, after dependency on terminal phase not allowed: " + fromnode.phasename + " => "+ phsname + "]")
+ }
+ }
+ for (phsname <- phs.runsBefore) {
+ if (phsname != "parser") {
+ val tonode = graph.getNodeByPhase(phsname)
+ graph.softConnectNodes(tonode, fromnode)
+ } else {
+ error("[phase assembly, before dependency on parser phase not allowed: " + phsname + " => "+ fromnode.phasename + "]")
+ }
+ }
+ case Some(phsname) =>
+ if (phsname != "terminal") {
+ val tonode = graph.getNodeByPhase(phsname)
graph.hardConnectNodes(fromnode, tonode)
- } else {
- error("[phase assembly, right after dependency on terminal phase not allowed: " + fromnode.phasename + " => "+ phsname + "]")
- }
+ } else {
+ error("[phase assembly, right after dependency on terminal phase not allowed: " + fromnode.phasename + " => "+ phsname + "]")
+ }
}
}
graph
@@ -309,14 +309,14 @@ trait PhaseAssembly { self: Global =>
for (edge <- graph.edges) {
sbuf.append("\"" + edge.frm.allPhaseNames + "(" + edge.frm.level + ")" + "\"->\"" + edge.to.allPhaseNames + "(" + edge.to.level + ")" + "\"")
if (! edge.frm.phaseobj.get.head.internal) {
- extnodes += edge.frm
+ extnodes += edge.frm
}
edge.frm.phaseobj match { case None => null case Some(ln) => if(ln.size > 1) fatnodes += edge.frm }
edge.to.phaseobj match { case None => null case Some(ln) => if(ln.size > 1) fatnodes += edge.to }
if (edge.hard) {
- sbuf.append(" [color=\"#0000ff\"]\n")
+ sbuf.append(" [color=\"#0000ff\"]\n")
} else {
- sbuf.append(" [color=\"#000000\"]\n")
+ sbuf.append(" [color=\"#000000\"]\n")
}
}
for (node <- extnodes) {
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index 5db78420ec..50ef58232b 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -426,7 +426,8 @@ object Settings {
// Ordered (so we can use TreeSet)
def compare(that: Setting): Int = name compare that.name
- def compareLists[T <% Ordered[T]](xs: List[T], ys: List[T]): Boolean = xs.sort(_ < _) == ys.sort(_ < _)
+ def compareLists[T <% Ordered[T]](xs: List[T], ys: List[T]): Boolean =
+ xs.sortWith(_ < _) == ys.sortWith(_ < _)
// Equality
def eqValues: List[Any] = List(name, value)
@@ -832,7 +833,8 @@ trait ScalacSettings {
val specialize = BooleanSetting ("-Yspecialize", "Specialize generic code on types.")
val Yrangepos = BooleanSetting ("-Yrangepos", "Use range positions for syntax trees.")
val Yidedebug = BooleanSetting ("-Yide-debug", "Generate, validate and output trees using the interactive compiler.")
- val Ybuilderdebug = ChoiceSetting ("-Ybuilder-debug", "Compile using the specified build manager", List("none", "refined", "simple"), "none")
+ val Ybuilderdebug = ChoiceSetting ("-Ybuilder-debug", "Compile using the specified build manager", List("none", "refined", "simple"), "none") .
+ withHelpSyntax("-Ybuilder-debug:<method>")
val Ytyperdebug = BooleanSetting ("-Ytyper-debug", "Trace all type assignements")
val Ypmatdebug = BooleanSetting ("-Ypmat-debug", "Trace all pattern matcher activity.")
val Ytailrec = BooleanSetting ("-Ytailrecommend", "Alert methods which would be tail-recursive if private or final.")
diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
index 569b0f7b37..5d0b69e0da 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
@@ -199,6 +199,10 @@ trait TreeDSL {
if (guards.isEmpty) EmptyTree
else guards reduceLeft gen.mkAnd
+ def OR(guards: Tree*) =
+ if (guards.isEmpty) EmptyTree
+ else guards reduceLeft gen.mkOr
+
def IF(tree: Tree) = new IfStart(tree, EmptyTree)
def TRY(tree: Tree) = new TryStart(tree, Nil, EmptyTree)
def BLOCK(xs: Tree*) = Block(xs.init.toList, xs.last)
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
index e128b4e12f..be00805732 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
@@ -193,15 +193,6 @@ abstract class TreeInfo {
reserved addEntry nme.false_
reserved addEntry nme.true_
reserved addEntry nme.null_
- reserved addEntry newTypeName("byte")
- reserved addEntry newTypeName("char")
- reserved addEntry newTypeName("short")
- reserved addEntry newTypeName("int")
- reserved addEntry newTypeName("long")
- reserved addEntry newTypeName("float")
- reserved addEntry newTypeName("double")
- reserved addEntry newTypeName("boolean")
- reserved addEntry newTypeName("unit")
/** Is name a variable name? */
def isVariableName(name: Name): Boolean = {
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index bff4bd51c3..dbbb306130 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -131,13 +131,24 @@ trait Trees {
this
}
+ /** Set tpe to give `tp` and return this.
+ */
def setType(tp: Type): this.type = {
/*assert(kindingIrrelevant(tp) || !kindStar || !tp.isHigherKinded,
- tp+" should not be higher-kinded");*/
+ tp+" should not be higher-kinded"); */
tpe = tp
this
}
+ /** Like `setType`, but if this is a previously empty TypeTree
+ * that fact is remembered so that resetType will snap back.
+ */
+ def defineType(tp: Type): this.type = setType(tp)
+
+ /** Reset type to `null`, with special handling of TypeTrees and the EmptyType
+ */
+ def resetType() { tpe = null }
+
def symbol: Symbol = null
def symbol_=(sym: Symbol) {
throw new Error("symbol_= inapplicable for " + this)
@@ -323,6 +334,7 @@ trait Trees {
super.tpe_=(NoType)
override def tpe_=(t: Type) =
if (t != NoType) throw new Error("tpe_=("+t+") inapplicable for <empty>")
+ override def resetType() {}
override def isEmpty = true
}
@@ -618,17 +630,16 @@ trait Trees {
}})
val (edefs, rest) = body span treeInfo.isEarlyDef
val (evdefs, etdefs) = edefs partition treeInfo.isEarlyValDef
- val (lvdefs, gvdefs) = List.unzip {
- evdefs map {
- case vdef @ ValDef(mods, name, tpt, rhs) =>
- val fld = treeCopy.ValDef(
- vdef.duplicate, mods, name,
- atPos(vdef.pos.focus) { TypeTree() setOriginal tpt setPos tpt.pos.focus }, // atPos in case
- EmptyTree)
- val local = treeCopy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs)
- (local, fld)
- }
- }
+ val (lvdefs, gvdefs) = evdefs map {
+ case vdef @ ValDef(mods, name, tpt, rhs) =>
+ val fld = treeCopy.ValDef(
+ vdef.duplicate, mods, name,
+ atPos(vdef.pos.focus) { TypeTree() setOriginal tpt setPos tpt.pos.focus }, // atPos in case
+ EmptyTree)
+ val local = treeCopy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs)
+ (local, fld)
+ } unzip
+
val constrs = {
if (constrMods.isTrait) {
if (body forall treeInfo.isInterfaceMember) List()
@@ -868,12 +879,25 @@ trait Trees {
case class TypeTree() extends TypTree {
override def symbol = if (tpe == null) null else tpe.typeSymbol
- private var orig: Tree = null // should be EmptyTree?
+ private var orig: Tree = null
+ private var wasEmpty: Boolean = false
def original: Tree = orig
def setOriginal(tree: Tree): this.type = { orig = tree; setPos(tree.pos); this }
+ override def defineType(tp: Type): this.type = {
+ wasEmpty = isEmpty
+ setType(tp)
+ }
+
+ /** Reset type to null, unless type original was empty and then
+ * got its type via a defineType
+ */
+ override def resetType() {
+ if (wasEmpty) tpe = null
+ }
+
override def isEmpty = (tpe eq null) || tpe == NoType
}
@@ -1817,18 +1841,16 @@ trait Trees {
protected def isLocal(sym: Symbol): Boolean = true
protected def resetDef(tree: Tree) {
tree.symbol = NoSymbol
- tree.tpe = null
- super.traverse(tree)
}
- override def traverse(tree: Tree): Unit = tree match {
- case EmptyTree | TypeTree() =>
- ;
- case _: DefTree | Function(_, _) | Template(_, _, _) =>
- resetDef(tree)
- case _ =>
- if (tree.hasSymbol && isLocal(tree.symbol)) tree.symbol = NoSymbol
- tree.tpe = null
- super.traverse(tree)
+ override def traverse(tree: Tree): Unit = {
+ tree match {
+ case _: DefTree | Function(_, _) | Template(_, _, _) =>
+ resetDef(tree)
+ case _ =>
+ if (tree.hasSymbol && isLocal(tree.symbol)) tree.symbol = NoSymbol
+ }
+ tree.resetType()
+ super.traverse(tree)
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index a4f228cffb..ccb46c0500 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -957,7 +957,7 @@ self =>
*/
def statement(location: Int): Tree = expr(location) // !!! still needed?
- /** Expr ::= (Bindings | Id | `_') `=>' Expr
+ /** Expr ::= (Bindings | [`implicit'] Id | `_') `=>' Expr
* | Expr1
* ResultExpr ::= (Bindings | Id `:' CompoundType) `=>' Block
* | Expr1
@@ -1057,6 +1057,14 @@ self =>
atPos(in.skipToken()) {
Throw(expr())
}
+ case IMPLICIT =>
+ val start = in.skipToken()
+ val param0 = convertToParam(atPos(in.offset)(Ident(ident())))
+ val param = treeCopy.ValDef(param0, param0.mods | Flags.IMPLICIT, param0.name, param0.tpt, param0.rhs)
+ atPos(start, in.offset) {
+ accept(ARROW)
+ Function(List(param), if (location != InBlock) expr() else block())
+ }
case _ =>
var t = postfixExpr()
if (in.token == EQUALS) {
@@ -1555,9 +1563,9 @@ self =>
*/
private def normalize(mods: Modifiers): Modifiers =
if ((mods hasFlag Flags.PRIVATE) && mods.privateWithin != nme.EMPTY.toTypeName)
- mods &~ Flags.PRIVATE
+ normalize(mods &~ Flags.PRIVATE)
else if ((mods hasFlag Flags.ABSTRACT) && (mods hasFlag Flags.OVERRIDE))
- mods &~ (Flags.ABSTRACT | Flags.OVERRIDE) | Flags.ABSOVERRIDE
+ normalize(mods &~ (Flags.ABSTRACT | Flags.OVERRIDE) | Flags.ABSOVERRIDE)
else
mods
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index 267d5bd17f..9648735a15 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -680,7 +680,7 @@ trait Scanners {
var value: Long = 0
val divider = if (base == 10) 1 else 2
val limit: Long =
- if (token == LONGLIT) Math.MAX_LONG else Math.MAX_INT
+ if (token == LONGLIT) Long.MaxValue else Int.MaxValue
var i = 0
val len = strVal.length
while (i < len) {
@@ -709,7 +709,7 @@ trait Scanners {
*/
def floatVal(negated: Boolean): Double = {
val limit: Double =
- if (token == DOUBLELIT) Math.MAX_DOUBLE else Math.MAX_FLOAT
+ if (token == DOUBLELIT) Double.MaxValue else Float.MaxValue
try {
val value: Double = java.lang.Double.valueOf(strVal).doubleValue()
if (value > limit)
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index 29a9599744..da864ef706 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -378,7 +378,7 @@ abstract class TreeBuilder {
val rhss = valeqs map { case ValEq(_, _, rhs) => rhs }
val defpat1 = makeBind(pat)
val defpats = pats map makeBind
- val pdefs = (List.map2(defpats, rhss)(makePatDef)).flatten
+ val pdefs = (defpats, rhss).zipped flatMap makePatDef
val ids = (defpat1 :: defpats) map makeValue
val rhs1 = makeForYield(
List(ValFrom(pos, defpat1, rhs)),
diff --git a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala
index 290d90b3e9..88e867e487 100644
--- a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala
+++ b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala
@@ -469,6 +469,18 @@ abstract class ScalaPrimitives {
def isCoercion(code: Int): Boolean = (code >= B2B) && (code <= D2D)
+ final val typeOfArrayOp: Map[Int, TypeKind] = Map(
+ (List(ZARRAY_LENGTH, ZARRAY_GET, ZARRAY_SET) map (_ -> BOOL)) ++
+ (List(BARRAY_LENGTH, BARRAY_GET, BARRAY_SET) map (_ -> BYTE)) ++
+ (List(SARRAY_LENGTH, SARRAY_GET, SARRAY_SET) map (_ -> SHORT)) ++
+ (List(CARRAY_LENGTH, CARRAY_GET, CARRAY_SET) map (_ -> CHAR)) ++
+ (List(IARRAY_LENGTH, IARRAY_GET, IARRAY_SET) map (_ -> INT)) ++
+ (List(LARRAY_LENGTH, LARRAY_GET, LARRAY_SET) map (_ -> LONG)) ++
+ (List(FARRAY_LENGTH, FARRAY_GET, FARRAY_SET) map (_ -> FLOAT)) ++
+ (List(DARRAY_LENGTH, DARRAY_GET, DARRAY_SET) map (_ -> DOUBLE)) ++
+ (List(OARRAY_LENGTH, OARRAY_GET, OARRAY_SET) map (_ -> REFERENCE(AnyRefClass))) : _*
+ )
+
/** Check whether the given operation code is an array operation. */
def isArrayOp(code: Int): Boolean =
isArrayNew(code) | isArrayLength(code) | isArrayGet(code) | isArraySet(code)
diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
index a774473167..b708d4df80 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
@@ -40,8 +40,8 @@ trait BasicBlocks {
def hasFlag(flag: Int): Boolean = (flags & flag) != 0
/** Set the given flag. */
- def setFlag(flag: Int): Unit = flags |= flag
- def resetFlag(flag: Int) {
+ private def setFlag(flag: Int): Unit = flags |= flag
+ private def resetFlag(flag: Int) {
flags &= ~flag
}
@@ -63,9 +63,16 @@ trait BasicBlocks {
def exceptionHandlerStart_=(b: Boolean) =
if (b) setFlag(EX_HEADER) else resetFlag(EX_HEADER)
- /** Has this basic block been modified since the last call to 'toList'? */
- private def touched = hasFlag(TOUCHED)
- private def touched_=(b: Boolean) = if (b) setFlag(TOUCHED) else resetFlag(TOUCHED)
+ /** Has this basic block been modified since the last call to 'successors'? */
+ def touched = hasFlag(DIRTYSUCCS)
+ def touched_=(b: Boolean) = if (b) {
+ setFlag(DIRTYSUCCS | DIRTYPREDS)
+ } else {
+ resetFlag(DIRTYSUCCS | DIRTYPREDS)
+ }
+
+ // basic blocks start in a dirty state
+ setFlag(DIRTYSUCCS | DIRTYPREDS)
/** Cached predecessors. */
var preds: List[BasicBlock] = null
@@ -85,9 +92,9 @@ trait BasicBlocks {
private var instrs: Array[Instruction] = _
override def toList: List[Instruction] = {
- if (closed && touched)
- instructionList = instrs.toList
- instructionList
+ if (closed)
+ instrs.toList
+ else instructionList
}
/** Return an iterator over the instructions in this basic block. */
@@ -101,12 +108,11 @@ trait BasicBlocks {
}
def fromList(is: List[Instruction]) {
+ code.touched = true
instrs = toInstructionArray(is)
closed = true
}
- // public:
-
/** Return the index of inst. Uses reference equality.
* Returns -1 if not found.
*/
@@ -166,9 +172,9 @@ trait BasicBlocks {
*/
def replaceInstruction(pos: Int, instr: Instruction): Boolean = {
assert(closed, "Instructions can be replaced only after the basic block is closed")
-
instr.setPos(instrs(pos).pos)
instrs(pos) = instr
+ code.touched = true
true
}
@@ -187,6 +193,7 @@ trait BasicBlocks {
newInstr.setPos(oldInstr.pos)
instrs(i) = newInstr
changed = true
+ code.touched = true
}
i += 1
}
@@ -213,6 +220,8 @@ trait BasicBlocks {
if (i < instrs.length) {
val newInstrs = new Array[Instruction](instrs.length + is.length - 1);
changed = true
+ code.touched = true
+
Array.copy(instrs, 0, newInstrs, 0, i)
var j = i
for (x <- is) {
@@ -244,6 +253,7 @@ trait BasicBlocks {
Array.copy(instrs, i + 1, newInstrs, j, instrs.length - i)
instrs = newInstrs;
}
+ code.touched = true
}
/** Removes instructions found at the given positions.
@@ -264,6 +274,7 @@ trait BasicBlocks {
i += 1
}
instrs = newInstrs
+ code.touched = true
}
/** Remove the last instruction of this basic block. It is
@@ -274,7 +285,7 @@ trait BasicBlocks {
removeInstructionsAt(size)
else {
instructionList = instructionList.tail
- touched = true
+ code.touched = true
}
}
@@ -287,7 +298,9 @@ trait BasicBlocks {
var i = 0
while (i < instrs.length) {
map get instrs(i) match {
- case Some(instr) => touched = replaceInstruction(i, instr)
+ case Some(instr) =>
+ val changed = replaceInstruction(i, instr)
+ code.touched |= changed
case None => ()
}
i += 1
@@ -321,6 +334,10 @@ trait BasicBlocks {
emit(instr, NoPosition)
}
+ /** Emitting does not set touched to true. During code generation this is a hotspot and
+ * setting the flag for each emit is a waste. Caching should happend only after a block
+ * is closed, which sets the DIRTYSUCCS flag.
+ */
def emit(instr: Instruction, pos: Position) {
if (closed) {
print()
@@ -329,7 +346,6 @@ trait BasicBlocks {
assert(!closed || ignore, "BasicBlock closed")
if (!ignore) {
- touched = true
instr.setPos(pos)
instructionList = instr :: instructionList
_lastInstruction = instr
@@ -357,6 +373,7 @@ trait BasicBlocks {
def close {
assert(instructionList.length > 0, "Empty block.")
closed = true
+ setFlag(DIRTYSUCCS)
instructionList = instructionList.reverse
instrs = toInstructionArray(instructionList)
}
@@ -365,6 +382,7 @@ trait BasicBlocks {
assert(closed)
closed = false
ignore = false
+ touched = true
instructionList = instructionList.reverse // prepare for appending to the head
}
@@ -409,25 +427,37 @@ trait BasicBlocks {
array
}
- def successors : List[BasicBlock] = if (isEmpty) Nil else {
- var res = lastInstruction match {
- case JUMP (whereto) => List(whereto)
- case CJUMP(success, failure, _, _) => failure :: success :: Nil
- case CZJUMP(success, failure, _, _) => failure :: success :: Nil
- case SWITCH(_,labels) => labels
- case RETURN(_) => Nil
- case THROW() => Nil
- case _ =>
- if (closed) {
- dump
- global.abort("The last instruction is not a control flow instruction: " + lastInstruction)
+ /** Cached value of successors. Must be recomputed whenver a block in the current method is changed. */
+ private var succs: List[BasicBlock] = Nil
+
+ def successors : List[BasicBlock] = {
+ if (touched) {
+ resetFlag(DIRTYSUCCS)
+ succs = if (isEmpty) Nil else {
+ var res = lastInstruction match {
+ case JUMP(whereto) => List(whereto)
+ case CJUMP(success, failure, _, _) => failure :: success :: Nil
+ case CZJUMP(success, failure, _, _) => failure :: success :: Nil
+ case SWITCH(_, labels) => labels
+ case RETURN(_) => Nil
+ case THROW() => Nil
+ case _ =>
+ if (closed) {
+ dump
+ global.abort("The last instruction is not a control flow instruction: " + lastInstruction)
+ }
+ else Nil
}
- else Nil
- }
- method.exh.foreach { e: ExceptionHandler =>
- if (e.covers(this)) res = e.startBlock :: res
+ method.exh.foreach {
+ e: ExceptionHandler =>
+ if (e.covers(this)) res = e.startBlock :: res
+ }
+ val res1 = res ++ exceptionalSucc(this, res)
+ res1
+ }
}
- res ++ exceptionalSucc(this, res)
+// println("reusing cached successors for " + this + " in method " + method)
+ succs
}
/** Return a list of successors for 'b' that come from exception handlers
@@ -446,12 +476,12 @@ trait BasicBlocks {
succs.flatMap(findSucc).removeDuplicates
}
- /** Returns the precessors of this block, in the current 'code' chunk.
- * This is signifficant only if there are exception handlers, which live
- * in different code 'chunks' than the rest of the method.
- */
+ /** Returns the precessors of this block. */
def predecessors: List[BasicBlock] = {
- preds = code.blocks.iterator.filter (_.successors.contains(this)).toList
+ if (hasFlag(DIRTYPREDS)) {
+ resetFlag(DIRTYPREDS)
+ preds = code.blocks.iterator.filter (_.successors.contains(this)).toList
+ }
preds
}
@@ -467,7 +497,7 @@ trait BasicBlocks {
def print(out: java.io.PrintStream) {
out.println("block #"+label+" :")
- toList.foreach(i => out.println(" " + i))
+ foreach(i => out.println(" " + i))
out.print("Successors: ")
successors.foreach((x: BasicBlock) => out.print(" "+x.label.toString()))
out.println()
@@ -482,6 +512,17 @@ trait BasicBlocks {
}
override def toString(): String = "" + label
+
+ def flagsString: String =
+ ("block " + label + (
+ if (hasFlag(LOOP_HEADER)) " <loopheader> "
+ else if (hasFlag(IGNORING)) " <ignore> "
+ else if (hasFlag(EX_HEADER)) " <exheader> "
+ else if (hasFlag(CLOSED)) " <closed> "
+ else if (hasFlag(DIRTYSUCCS)) " <dirtysuccs> "
+ else if (hasFlag(DIRTYPREDS)) " <dirtypreds> "
+ else ""
+ ))
}
}
@@ -499,6 +540,9 @@ object BBFlags {
/** This block is closed. No new instructions can be added. */
final val CLOSED = 0x00000008
- /** This block has been changed, cached results are recomputed. */
- final val TOUCHED = 0x00000010
+ /** Code has been changed, recompute successors. */
+ final val DIRTYSUCCS = 0x00000010
+
+ /** Code has been changed, recompute predecessors. */
+ final val DIRTYPREDS = 0x00000020
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala b/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala
index ab32e69944..31abf6c18a 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala
@@ -152,7 +152,7 @@ abstract class Checkers {
else {
if (s1.length != s2.length)
throw new CheckerError("Incompatible stacks: " + s1 + " and " + s2 + " in " + method + " at entry to block: " + bl);
- new TypeStack(List.map2(s1.types, s2.types) (lub))
+ new TypeStack((s1.types, s2.types).zipped map lub)
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index f0c44bb227..22934a78a7 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -12,6 +12,7 @@ package icode
import scala.collection.mutable.{Map, HashMap, ListBuffer, Buffer, HashSet}
import scala.tools.nsc.symtab._
import scala.tools.nsc.util.Position
+import scala.annotation.switch
import PartialFunction._
/** This class ...
@@ -27,7 +28,8 @@ abstract class GenICode extends SubComponent {
import icodes.opcodes._
import definitions.{
ArrayClass, ObjectClass, ThrowableClass,
- Object_equals
+ Object_equals, Object_isInstanceOf, Object_asInstanceOf,
+ isMaybeBoxed
}
import scalaPrimitives.{
isArrayOp, isComparisonOp, isLogicalOp,
@@ -38,6 +40,9 @@ abstract class GenICode extends SubComponent {
override def newPhase(prev: Phase) = new ICodePhase(prev)
+ private def debugLog(msg: => String): Unit =
+ if (settings.debug.value) log(msg)
+
class ICodePhase(prev: Phase) extends StdPhase(prev) {
override def description = "Generate ICode from the AST"
@@ -150,14 +155,8 @@ abstract class GenICode extends SubComponent {
abort("Illegal tree in gen: " + tree)
}
- private def genStat(trees: List[Tree], ctx: Context): Context = {
- var currentCtx = ctx
-
- for (t <- trees)
- currentCtx = genStat(t, currentCtx)
-
- currentCtx
- }
+ private def genStat(trees: List[Tree], ctx: Context): Context =
+ trees.foldLeft(ctx)((currentCtx, t) => genStat(t, currentCtx))
/**
* Generate code for the given tree. The trees should contain statements
@@ -169,30 +168,282 @@ abstract class GenICode extends SubComponent {
* @return a new context. This is necessary for control flow instructions
* which may change the current basic block.
*/
- private def genStat(tree: Tree, ctx: Context): Context = {
+ private def genStat(tree: Tree, ctx: Context): Context = tree match {
+ case Assign(lhs @ Select(_, _), rhs) =>
+ val isStatic = lhs.symbol.isStaticMember
+ var ctx1 = if (isStatic) ctx else genLoadQualifier(lhs, ctx)
- tree match {
- case Assign(lhs @ Select(_, _), rhs) =>
- if (lhs.symbol.isStaticMember) {
- val ctx1 = genLoad(rhs, ctx, toTypeKind(lhs.symbol.info))
- ctx1.bb.emit(STORE_FIELD(lhs.symbol, true), tree.pos)
- ctx1
- } else {
- var ctx1 = genLoadQualifier(lhs, ctx)
- ctx1 = genLoad(rhs, ctx1, toTypeKind(lhs.symbol.info))
- ctx1.bb.emit(STORE_FIELD(lhs.symbol, false), tree.pos)
- ctx1
+ ctx1 = genLoad(rhs, ctx1, toTypeKind(lhs.symbol.info))
+ ctx1.bb.emit(STORE_FIELD(lhs.symbol, isStatic), tree.pos)
+ ctx1
+
+ case Assign(lhs, rhs) =>
+ val ctx1 = genLoad(rhs, ctx, toTypeKind(lhs.symbol.info))
+ val Some(l) = ctx.method.lookupLocal(lhs.symbol)
+ ctx1.bb.emit(STORE_LOCAL(l), tree.pos)
+ ctx1
+
+ case _ =>
+ genLoad(tree, ctx, UNIT)
+ }
+ /**
+ * Generate code for primitive arithmetic operations.
+ * Returns (Context, Generated Type)
+ */
+ private def genArithmeticOp(tree: Tree, ctx: Context, code: Int): (Context, TypeKind) = {
+ val Apply(fun @ Select(larg, _), args) = tree
+ var ctx1 = ctx
+ var resKind = toTypeKind(larg.tpe)
+
+ if (settings.debug.value) {
+ assert(args.length <= 1,
+ "Too many arguments for primitive function: " + fun.symbol)
+ assert(resKind.isNumericType | resKind == BOOL,
+ resKind.toString() + " is not a numeric or boolean type " +
+ "[operation: " + fun.symbol + "]")
+ }
+
+ args match {
+ // unary operation
+ case Nil =>
+ ctx1 = genLoad(larg, ctx1, resKind)
+ code match {
+ case scalaPrimitives.POS =>
+ () // nothing
+ case scalaPrimitives.NEG =>
+ ctx1.bb.emit(CALL_PRIMITIVE(Negation(resKind)), larg.pos)
+ case scalaPrimitives.NOT =>
+ ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(NOT, resKind)), larg.pos)
+ case _ =>
+ abort("Unknown unary operation: " + fun.symbol.fullNameString +
+ " code: " + code)
}
- case Assign(lhs, rhs) =>
- val ctx1 = genLoad(rhs, ctx, toTypeKind(lhs.symbol.info))
- val Some(l) = ctx.method.lookupLocal(lhs.symbol)
- ctx1.bb.emit(STORE_LOCAL(l), tree.pos)
- ctx1
+ // binary operation
+ case rarg :: Nil =>
+ resKind = getMaxType(larg.tpe :: rarg.tpe :: Nil);
+ if (scalaPrimitives.isShiftOp(code) || scalaPrimitives.isBitwiseOp(code))
+ assert(resKind.isIntType | resKind == BOOL,
+ resKind.toString() + " incompatible with arithmetic modulo operation: " + ctx1);
+
+ ctx1 = genLoad(larg, ctx1, resKind)
+ ctx1 = genLoad(rarg,
+ ctx1, // check .NET size of shift arguments!
+ if (scalaPrimitives.isShiftOp(code)) INT else resKind)
+
+ val primitiveOp = code match {
+ case scalaPrimitives.ADD => Arithmetic(ADD, resKind)
+ case scalaPrimitives.SUB => Arithmetic(SUB, resKind)
+ case scalaPrimitives.MUL => Arithmetic(MUL, resKind)
+ case scalaPrimitives.DIV => Arithmetic(DIV, resKind)
+ case scalaPrimitives.MOD => Arithmetic(REM, resKind)
+ case scalaPrimitives.OR => Logical(OR, resKind)
+ case scalaPrimitives.XOR => Logical(XOR, resKind)
+ case scalaPrimitives.AND => Logical(AND, resKind)
+ case scalaPrimitives.LSL => Shift(LSL, resKind)
+ case scalaPrimitives.LSR => Shift(LSR, resKind)
+ case scalaPrimitives.ASR => Shift(ASR, resKind)
+ case _ => abort("Unknown primitive: " + fun.symbol + "[" + code + "]")
+ }
+ ctx1.bb.emit(CALL_PRIMITIVE(primitiveOp), tree.pos)
case _ =>
- genLoad(tree, ctx, UNIT)
+ abort("Too many arguments for primitive function: " + tree)
}
+ (ctx1, resKind)
+ }
+
+ /** Generate primitive array operations.
+ *
+ * @param tree ...
+ * @param ctx ...
+ * @param code ...
+ * @return ...
+ */
+ private def genArrayOp(tree: Tree, ctx: Context, code: Int, expectedType: TypeKind): (Context, TypeKind) = {
+ import scalaPrimitives._
+ val Apply(Select(arrayObj, _), args) = tree
+ val k = toTypeKind(arrayObj.tpe)
+ val ARRAY(elem) = k
+ var ctx1 = genLoad(arrayObj, ctx, k)
+ val elementType = (typeOfArrayOp get code) getOrElse abort("Unknown operation on arrays: " + tree + " code: " + code)
+
+ var generatedType = expectedType
+
+ if (scalaPrimitives.isArrayGet(code)) {
+ // load argument on stack
+ if (settings.debug.value)
+ assert(args.length == 1,
+ "Too many arguments for array get operation: " + tree);
+ ctx1 = genLoad(args.head, ctx1, INT)
+ generatedType = elem
+ ctx1.bb.emit(LOAD_ARRAY_ITEM(elementType), tree.pos)
+ }
+ else if (scalaPrimitives.isArraySet(code)) {
+ if (settings.debug.value)
+ assert(args.length == 2,
+ "Too many arguments for array set operation: " + tree);
+ ctx1 = genLoad(args.head, ctx1, INT)
+ ctx1 = genLoad(args.tail.head, ctx1, toTypeKind(args.tail.head.tpe))
+ // the following line should really be here, but because of bugs in erasure
+ // we pretend we generate whatever type is expected from us.
+ //generatedType = UNIT
+
+ ctx1.bb.emit(STORE_ARRAY_ITEM(elementType), tree.pos)
+ }
+ else {
+ generatedType = INT
+ ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(elementType)), tree.pos)
+ }
+
+ (ctx1, generatedType)
+ }
+ private def genSynchronized(tree: Apply, ctx: Context, expectedType: TypeKind): (Context, TypeKind) = {
+ val Apply(fun, args) = tree
+ val monitor = ctx.makeLocal(tree.pos, ObjectClass.tpe, "monitor")
+ var ctx1 = genLoadQualifier(fun, ctx)
+ ctx1.bb.emit(Seq(
+ DUP(ANY_REF_CLASS),
+ STORE_LOCAL(monitor),
+ MONITOR_ENTER() setPos tree.pos
+ ))
+ ctx1.enterSynchronized(monitor)
+ debugLog("synchronized block start")
+
+ ctx1 = ctx1.Try(
+ bodyCtx => {
+ val ctx2 = genLoad(args.head, bodyCtx, expectedType /* toTypeKind(tree.tpe.resultType) */)
+ ctx2.bb.emit(Seq(
+ LOAD_LOCAL(monitor),
+ MONITOR_EXIT() setPos tree.pos
+ ))
+ ctx2
+ }, List(
+ // tree.tpe / fun.tpe is object, which is no longer true after this transformation
+ (NoSymbol, expectedType, exhCtx => {
+ exhCtx.bb.emit(Seq(
+ LOAD_LOCAL(monitor),
+ MONITOR_EXIT() setPos tree.pos,
+ THROW()
+ ))
+ exhCtx.bb.enterIgnoreMode
+ exhCtx
+ })), EmptyTree, tree)
+
+ debugLog("synchronized block end with block %s closed=%s".format(ctx1.bb, ctx1.bb.closed))
+ ctx1.exitSynchronized(monitor)
+
+ (ctx1, expectedType)
+ }
+
+ private def genLoadIf(tree: If, ctx: Context, expectedType: TypeKind): (Context, TypeKind) = {
+ val If(cond, thenp, elsep) = tree
+
+ var thenCtx = ctx.newBlock
+ var elseCtx = ctx.newBlock
+ val contCtx = ctx.newBlock
+
+ genCond(cond, ctx, thenCtx, elseCtx)
+
+ val ifKind = toTypeKind(tree.tpe)
+ val thenKind = toTypeKind(thenp.tpe)
+ val elseKind = if (elsep == EmptyTree) UNIT else toTypeKind(elsep.tpe)
+
+ // we need to drop unneeded results, if one branch gives
+ // unit and the other gives something on the stack, because
+ // the type of 'if' is scala.Any, and its erasure would be Object.
+ // But unboxed units are not Objects...
+ def hasUnitBranch = thenKind == UNIT || elseKind == UNIT
+ val resKind = if (hasUnitBranch) UNIT else ifKind
+
+ if (hasUnitBranch)
+ debugLog("Will drop result from an if branch")
+
+ thenCtx = genLoad(thenp, thenCtx, resKind)
+ elseCtx = genLoad(elsep, elseCtx, resKind)
+
+ assert(!settings.debug.value || expectedType == UNIT,
+ "I produce UNIT in a context where " + expectedType + " is expected!")
+
+ thenCtx.bb.emitOnly(JUMP(contCtx.bb))
+ elseCtx.bb.emitOnly(
+ if (elsep == EmptyTree) JUMP(contCtx.bb)
+ else JUMP(contCtx.bb) setPos tree.pos
+ )
+
+ (contCtx, resKind)
+ }
+ private def genLoadTry(tree: Try, ctx: Context, setGeneratedType: TypeKind => Unit): Context = {
+ val Try(block, catches, finalizer) = tree
+ val kind = toTypeKind(tree.tpe)
+
+ val caseHandlers =
+ for (CaseDef(pat, _, body) <- catches.reverse) yield {
+ def genWildcardHandler(sym: Symbol): (Symbol, TypeKind, Context => Context) =
+ (sym, kind, ctx => {
+ ctx.bb.emit(DROP(REFERENCE(sym)))
+ genLoad(body, ctx, kind)
+ })
+
+ pat match {
+ case Typed(Ident(nme.WILDCARD), tpt) => genWildcardHandler(tpt.tpe.typeSymbol)
+ case Ident(nme.WILDCARD) => genWildcardHandler(ThrowableClass)
+ case Bind(name, _) =>
+ val exception = ctx.method addLocal new Local(pat.symbol, toTypeKind(pat.symbol.tpe), false)
+
+ (pat.symbol.tpe.typeSymbol, kind, {
+ ctx: Context =>
+ ctx.bb.emit(STORE_LOCAL(exception), pat.pos);
+ genLoad(body, ctx, kind);
+ })
+ }
+ }
+
+ ctx.Try(
+ bodyCtx => {
+ setGeneratedType(kind)
+ genLoad(block, bodyCtx, kind)
+ },
+ caseHandlers,
+ finalizer,
+ tree)
+ }
+
+ private def genPrimitiveOp(tree: Apply, ctx: Context, expectedType: TypeKind): (Context, TypeKind) = {
+ val sym = tree.symbol
+ val Apply(fun @ Select(receiver, _), args) = tree
+ val code = scalaPrimitives.getPrimitive(sym, receiver.tpe)
+
+ if (scalaPrimitives.isArithmeticOp(code))
+ genArithmeticOp(tree, ctx, code)
+ else if (code == scalaPrimitives.CONCAT)
+ (genStringConcat(tree, ctx), STRING)
+ else if (isArrayOp(code))
+ genArrayOp(tree, ctx, code, expectedType)
+ else if (isLogicalOp(code) || isComparisonOp(code)) {
+ val trueCtx = ctx.newBlock
+ val falseCtx = ctx.newBlock
+ val afterCtx = ctx.newBlock
+ genCond(tree, ctx, trueCtx, falseCtx)
+ trueCtx.bb.emitOnly(
+ CONSTANT(Constant(true)) setPos tree.pos,
+ JUMP(afterCtx.bb)
+ )
+ falseCtx.bb.emitOnly(
+ CONSTANT(Constant(false)) setPos tree.pos,
+ JUMP(afterCtx.bb)
+ )
+ (afterCtx, BOOL)
+ }
+ else if (code == scalaPrimitives.SYNCHRONIZED)
+ genSynchronized(tree, ctx, expectedType)
+ else if (scalaPrimitives.isCoercion(code)) {
+ val ctx1 = genLoad(receiver, ctx, toTypeKind(receiver.tpe))
+ genCoercion(tree, ctx1, code)
+ (ctx1, scalaPrimitives.generatedKind(code))
+ }
+ else abort("Primitive operation not handled yet: " + sym.fullNameString + "(" +
+ fun.symbol.simpleName + ") " + " at: " + (tree.pos))
}
/**
@@ -210,186 +461,6 @@ abstract class GenICode extends SubComponent {
if (settings.debug.value)
log("at line: " + (if (tree.pos.isDefined) tree.pos.line else tree.pos))
- /**
- * Generate code for primitive arithmetic operations.
- */
- def genArithmeticOp(tree: Tree, ctx: Context, code: Int): Context = {
- val Apply(fun @ Select(larg, _), args) = tree
- var ctx1 = ctx
- var resKind = toTypeKind(larg.tpe)
-
- if (settings.debug.value) {
- assert(args.length <= 1,
- "Too many arguments for primitive function: " + fun.symbol)
- assert(resKind.isNumericType | resKind == BOOL,
- resKind.toString() + " is not a numeric or boolean type " +
- "[operation: " + fun.symbol + "]")
- }
-
- args match {
- // unary operation
- case Nil =>
- ctx1 = genLoad(larg, ctx1, resKind)
- code match {
- case scalaPrimitives.POS =>
- () // nothing
- case scalaPrimitives.NEG =>
- ctx1.bb.emit(CALL_PRIMITIVE(Negation(resKind)), larg.pos)
- case scalaPrimitives.NOT =>
- ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(NOT, resKind)), larg.pos)
- case _ =>
- abort("Unknown unary operation: " + fun.symbol.fullNameString +
- " code: " + code)
- }
- generatedType = resKind
-
- // binary operation
- case rarg :: Nil =>
- resKind = getMaxType(larg.tpe :: rarg.tpe :: Nil);
- if (scalaPrimitives.isShiftOp(code) || scalaPrimitives.isBitwiseOp(code))
- assert(resKind.isIntType | resKind == BOOL,
- resKind.toString() + " incompatible with arithmetic modulo operation: " + ctx1);
-
- ctx1 = genLoad(larg, ctx1, resKind);
- ctx1 = genLoad(rarg,
- ctx1, // check .NET size of shift arguments!
- if (scalaPrimitives.isShiftOp(code)) INT else resKind)
-
- generatedType = resKind
- code match {
- case scalaPrimitives.ADD =>
- ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(ADD, resKind)), tree.pos)
- case scalaPrimitives.SUB =>
- ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(SUB, resKind)), tree.pos)
- case scalaPrimitives.MUL =>
- ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(MUL, resKind)), tree.pos)
- case scalaPrimitives.DIV =>
- ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(DIV, resKind)), tree.pos)
- case scalaPrimitives.MOD =>
- ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(REM, resKind)), tree.pos)
- case scalaPrimitives.OR =>
- ctx1.bb.emit(CALL_PRIMITIVE(Logical(OR, resKind)), tree.pos)
- case scalaPrimitives.XOR =>
- ctx1.bb.emit(CALL_PRIMITIVE(Logical(XOR, resKind)), tree.pos)
- case scalaPrimitives.AND =>
- ctx1.bb.emit(CALL_PRIMITIVE(Logical(AND, resKind)), tree.pos)
- case scalaPrimitives.LSL =>
- ctx1.bb.emit(CALL_PRIMITIVE(Shift(LSL, resKind)), tree.pos)
- generatedType = resKind
- case scalaPrimitives.LSR =>
- ctx1.bb.emit(CALL_PRIMITIVE(Shift(LSR, resKind)), tree.pos)
- generatedType = resKind
- case scalaPrimitives.ASR =>
- ctx1.bb.emit(CALL_PRIMITIVE(Shift(ASR, resKind)), tree.pos)
- generatedType = resKind
- case _ =>
- abort("Unknown primitive: " + fun.symbol + "[" + code + "]")
- }
-
- case _ =>
- abort("Too many arguments for primitive function: " + tree)
- }
- ctx1
- }
-
- /** Generate primitive array operations.
- *
- * @param tree ...
- * @param ctx ...
- * @param code ...
- * @return ...
- */
- def genArrayOp(tree: Tree, ctx: Context, code: Int): Context = {
- import scalaPrimitives._
- val Apply(Select(arrayObj, _), args) = tree
- val k = toTypeKind(arrayObj.tpe)
- val ARRAY(elem) = k
- var ctx1 = genLoad(arrayObj, ctx, k)
-
- if (scalaPrimitives.isArrayGet(code)) {
- // load argument on stack
- if (settings.debug.value)
- assert(args.length == 1,
- "Too many arguments for array get operation: " + tree);
- ctx1 = genLoad(args.head, ctx1, INT)
- generatedType = elem
- } else if (scalaPrimitives.isArraySet(code)) {
- if (settings.debug.value)
- assert(args.length == 2,
- "Too many arguments for array set operation: " + tree);
- ctx1 = genLoad(args.head, ctx1, INT)
- ctx1 = genLoad(args.tail.head, ctx1, toTypeKind(args.tail.head.tpe))
- // the following line should really be here, but because of bugs in erasure
- // we pretend we generate whatever type is expected from us.
- //generatedType = UNIT
- } else
- generatedType = INT
-
- code match {
- case ZARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(BOOL)), tree.pos)
- case BARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(BYTE)), tree.pos)
- case SARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(SHORT)), tree.pos)
- case CARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(CHAR)), tree.pos)
- case IARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(INT)), tree.pos)
- case LARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(LONG)), tree.pos)
- case FARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(FLOAT)), tree.pos)
- case DARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(DOUBLE)), tree.pos)
- case OARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(ANY_REF_CLASS)), tree.pos)
-
- case ZARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(BOOL), tree.pos)
- case BARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(BYTE), tree.pos)
- case SARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(SHORT), tree.pos)
- case CARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(CHAR), tree.pos)
- case IARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(INT), tree.pos)
- case LARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(LONG), tree.pos)
- case FARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(FLOAT), tree.pos)
- case DARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(DOUBLE), tree.pos)
- case OARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(ANY_REF_CLASS), tree.pos)
-
- case ZARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(BOOL), tree.pos)
- case BARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(BYTE), tree.pos)
- case SARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(SHORT), tree.pos)
- case CARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(CHAR), tree.pos)
- case IARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(INT), tree.pos)
- case LARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(LONG), tree.pos)
- case FARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(FLOAT), tree.pos)
- case DARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(DOUBLE), tree.pos)
- case OARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(ANY_REF_CLASS), tree.pos)
-
- case _ =>
- abort("Unknown operation on arrays: " + tree + " code: " + code)
- }
- ctx1
- }
-
- // genLoad
val resCtx: Context = tree match {
case LabelDef(name, params, rhs) =>
val ctx1 = ctx.newBlock
@@ -436,46 +507,10 @@ abstract class GenICode extends SubComponent {
generatedType = UNIT
ctx1
- case If(cond, thenp, elsep) =>
- var thenCtx = ctx.newBlock
- var elseCtx = ctx.newBlock
- val contCtx = ctx.newBlock
- genCond(cond, ctx, thenCtx, elseCtx)
- val ifKind = toTypeKind(tree.tpe)
-
- val thenKind = toTypeKind(thenp.tpe)
- val elseKind = if (elsep == EmptyTree) UNIT else toTypeKind(elsep.tpe)
-
- generatedType = ifKind
-
- // we need to drop unneeded results, if one branch gives
- // unit and the other gives something on the stack, because
- // the type of 'if' is scala.Any, and its erasure would be Object.
- // But unboxed units are not Objects...
- if (thenKind == UNIT || elseKind == UNIT) {
- if (settings.debug.value)
- log("Will drop result from an if branch");
- thenCtx = genLoad(thenp, thenCtx, UNIT)
- elseCtx = genLoad(elsep, elseCtx, UNIT)
- if (settings.debug.value)
- assert(expectedType == UNIT,
- "I produce UNIT in a context where " +
- expectedType + " is expected!")
- generatedType = UNIT
- } else {
- thenCtx = genLoad(thenp, thenCtx, ifKind)
- elseCtx = genLoad(elsep, elseCtx, ifKind)
- }
-
- thenCtx.bb.emit(JUMP(contCtx.bb))
- thenCtx.bb.close
- if (elsep == EmptyTree)
- elseCtx.bb.emit(JUMP(contCtx.bb), tree.pos)
- else
- elseCtx.bb.emit(JUMP(contCtx.bb))
- elseCtx.bb.close
-
- contCtx
+ case t @ If(cond, thenp, elsep) =>
+ val (newCtx, resKind) = genLoadIf(t, ctx, expectedType)
+ generatedType = resKind
+ newCtx
case Return(expr) =>
val returnedKind = toTypeKind(expr.tpe)
@@ -510,41 +545,7 @@ abstract class GenICode extends SubComponent {
generatedType = expectedType
ctx1
- case Try(block, catches, finalizer) =>
- val kind = toTypeKind(tree.tpe)
-
- var handlers = for (CaseDef(pat, _, body) <- catches.reverse)
- yield pat match {
- case Typed(Ident(nme.WILDCARD), tpt) => (tpt.tpe.typeSymbol, kind, {
- ctx: Context =>
- ctx.bb.emit(DROP(REFERENCE(tpt.tpe.typeSymbol)));
- genLoad(body, ctx, kind);
- })
-
- case Ident(nme.WILDCARD) => (ThrowableClass, kind, {
- ctx: Context =>
- ctx.bb.emit(DROP(REFERENCE(ThrowableClass)))
- genLoad(body, ctx, kind)
- })
-
- case Bind(name, _) =>
- val exception = ctx.method.addLocal(new Local(pat.symbol, toTypeKind(pat.symbol.tpe), false))
-
- (pat.symbol.tpe.typeSymbol, kind, {
- ctx: Context =>
- ctx.bb.emit(STORE_LOCAL(exception), pat.pos);
- genLoad(body, ctx, kind);
- })
- }
-
- ctx.Try(
- bodyCtx => {
- generatedType = kind; //toTypeKind(block.tpe);
- genLoad(block, bodyCtx, generatedType);
- },
- handlers,
- finalizer,
- tree)
+ case t @ Try(_, _, _) => genLoadTry(t, ctx, (x: TypeKind) => generatedType = x)
case Throw(expr) =>
val ctx1 = genLoad(expr, ctx, THROWABLE)
@@ -558,30 +559,27 @@ abstract class GenICode extends SubComponent {
case Apply(TypeApply(fun, targs), _) =>
val sym = fun.symbol
- var ctx1 = ctx
- var cast = false
-
- if (sym == definitions.Object_isInstanceOf)
- cast = false
- else if (sym == definitions.Object_asInstanceOf)
- cast = true
- else
- abort("Unexpected type application " + fun + "[sym: " + sym.fullNameString + "]" + " in: " + tree)
+ val cast = sym match {
+ case Object_isInstanceOf => false
+ case Object_asInstanceOf => true
+ case _ => abort("Unexpected type application " + fun + "[sym: " + sym.fullNameString + "]" + " in: " + tree)
+ }
val Select(obj, _) = fun
val l = toTypeKind(obj.tpe)
val r = toTypeKind(targs.head.tpe)
-
- ctx1 = genLoadQualifier(fun, ctx)
+ val ctx1 = genLoadQualifier(fun, ctx)
if (l.isValueType && r.isValueType)
genConversion(l, r, ctx1, cast)
else if (l.isValueType) {
ctx1.bb.emit(DROP(l), fun.pos)
if (cast) {
- ctx1.bb.emit(NEW(REFERENCE(definitions.getClass("ClassCastException"))))
- ctx1.bb.emit(DUP(ANY_REF_CLASS))
- ctx1.bb.emit(THROW())
+ ctx1.bb.emit(Seq(
+ NEW(REFERENCE(definitions.getClass("ClassCastException"))),
+ DUP(ANY_REF_CLASS),
+ THROW()
+ ))
} else
ctx1.bb.emit(CONSTANT(Constant(false)))
}
@@ -632,11 +630,9 @@ abstract class GenICode extends SubComponent {
assert(generatedType.isReferenceType || generatedType.isArrayType,
"Non reference type cannot be instantiated: " + generatedType)
- var ctx1 = ctx
-
generatedType match {
case arr @ ARRAY(elem) =>
- ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
+ val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
val dims = arr.dimensions
var elemKind = arr.elementKind
if (args.length > dims)
@@ -645,24 +641,25 @@ abstract class GenICode extends SubComponent {
if (args.length != dims)
for (i <- args.length until dims) elemKind = ARRAY(elemKind)
ctx1.bb.emit(CREATE_ARRAY(elemKind, args.length), tree.pos)
+ ctx1
case rt @ REFERENCE(cls) =>
if (settings.debug.value)
assert(ctor.owner == cls,
"Symbol " + ctor.owner.fullNameString + " is different than " + tpt)
val nw = NEW(rt)
- ctx1.bb.emit(nw, tree.pos)
- ctx1.bb.emit(DUP(generatedType))
- ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
+ ctx.bb.emit(nw, tree.pos)
+ ctx.bb.emit(DUP(generatedType))
+ val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
val init = CALL_METHOD(ctor, Static(true))
nw.init = init
ctx1.bb.emit(init, tree.pos)
+ ctx1
case _ =>
abort("Cannot instantiate " + tpt + "of kind: " + generatedType)
}
- ctx1
case Apply(fun @ _, List(expr)) if (definitions.isBox(fun.symbol)) =>
if (settings.debug.value)
@@ -690,7 +687,7 @@ abstract class GenICode extends SubComponent {
ctx1.bb.emit(UNBOX(boxType), expr.pos)
ctx1
- case Apply(fun, args) =>
+ case app @ Apply(fun, args) =>
val sym = fun.symbol
if (sym.isLabel) { // jump to a label
@@ -711,78 +708,12 @@ abstract class GenICode extends SubComponent {
}
}
val ctx1 = genLoadLabelArguments(args, label, ctx)
- if (label.anchored)
- ctx1.bb.emit(JUMP(label.block), tree.pos)
- else
- ctx1.bb.emit(PJUMP(label), tree.pos)
-
- ctx1.bb.close
+ ctx1.bb.emitOnly(if (label.anchored) JUMP(label.block) else PJUMP(label))
ctx1.newBlock
} else if (isPrimitive(sym)) { // primitive method call
- val Select(receiver, _) = fun
-
- val code = scalaPrimitives.getPrimitive(sym, receiver.tpe)
- var ctx1 = ctx
-
- if (scalaPrimitives.isArithmeticOp(code)) {
- ctx1 = genArithmeticOp(tree, ctx1, code)
- } else if (code == scalaPrimitives.CONCAT) {
- ctx1 = genStringConcat(tree, ctx1)
- generatedType = STRING
- } else if (isArrayOp(code)) {
- ctx1 = genArrayOp(tree, ctx1, code)
- } else if (isLogicalOp(code) || isComparisonOp(code)) {
-
- val trueCtx = ctx1.newBlock
- val falseCtx = ctx1.newBlock
- val afterCtx = ctx1.newBlock
- genCond(tree, ctx1, trueCtx, falseCtx)
- trueCtx.bb.emit(CONSTANT(Constant(true)), tree.pos)
- trueCtx.bb.emit(JUMP(afterCtx.bb))
- trueCtx.bb.close
- falseCtx.bb.emit(CONSTANT(Constant(false)), tree.pos)
- falseCtx.bb.emit(JUMP(afterCtx.bb))
- falseCtx.bb.close
- generatedType = BOOL
- ctx1 = afterCtx
- } else if (code == scalaPrimitives.SYNCHRONIZED) {
- val monitor = ctx.makeLocal(tree.pos, ObjectClass.tpe, "monitor")
- ctx1 = genLoadQualifier(fun, ctx1)
- ctx1.bb.emit(DUP(ANY_REF_CLASS))
- ctx1.bb.emit(STORE_LOCAL(monitor))
- ctx1.bb.emit(MONITOR_ENTER(), tree.pos)
- ctx1.enterSynchronized(monitor)
-
- if (settings.debug.value)
- log("synchronized block start");
-
- ctx1 = ctx1.Try(
- bodyCtx => {
- val ctx1 = genLoad(args.head, bodyCtx, expectedType /* toTypeKind(tree.tpe.resultType) */)
- ctx1.bb.emit(LOAD_LOCAL(monitor))
- ctx1.bb.emit(MONITOR_EXIT(), tree.pos)
- ctx1
- }, List(
- // tree.tpe / fun.tpe is object, which is no longer true after this transformation
- (NoSymbol, expectedType, exhCtx => {
- exhCtx.bb.emit(LOAD_LOCAL(monitor))
- exhCtx.bb.emit(MONITOR_EXIT(), tree.pos)
- exhCtx.bb.emit(THROW())
- exhCtx.bb.enterIgnoreMode
- exhCtx
- })), EmptyTree, tree);
- if (settings.debug.value)
- log("synchronized block end with block " + ctx1.bb +
- " closed=" + ctx1.bb.closed);
- ctx1.exitSynchronized(monitor)
- } else if (scalaPrimitives.isCoercion(code)) {
- ctx1 = genLoad(receiver, ctx1, toTypeKind(receiver.tpe))
- genCoercion(tree, ctx1, code)
- generatedType = scalaPrimitives.generatedKind(code)
- } else
- abort("Primitive operation not handled yet: " + sym.fullNameString + "(" +
- fun.symbol.simpleName + ") " + " at: " + (tree.pos));
- ctx1
+ val (newCtx, resKind) = genPrimitiveOp(app, ctx, expectedType)
+ generatedType = resKind
+ newCtx
} else { // normal method call
if (settings.debug.value)
log("Gen CALL_METHOD with sym: " + sym + " isStaticSymbol: " + sym.isStaticMember);
@@ -837,10 +768,9 @@ abstract class GenICode extends SubComponent {
generatedType = REFERENCE(tree.symbol)
} else {
ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos)
- if (tree.symbol == ArrayClass)
- generatedType = REFERENCE(ObjectClass)
- else
- generatedType = REFERENCE(ctx.clazz.symbol)
+ generatedType = REFERENCE(
+ if (tree.symbol == ArrayClass) ObjectClass else ctx.clazz.symbol
+ )
}
ctx
@@ -961,31 +891,26 @@ abstract class GenICode extends SubComponent {
var tags: List[Int] = Nil
var default: BasicBlock = afterCtx.bb
- for (caze <- cases) caze match {
- case CaseDef(Literal(value), EmptyTree, body) =>
- tags = value.intValue :: tags
- val tmpCtx = ctx1.newBlock
- targets = tmpCtx.bb :: targets
-
- caseCtx = genLoad(body, tmpCtx , generatedType)
- caseCtx.bb.emit(JUMP(afterCtx.bb), caze.pos)
- caseCtx.bb.close
-
- case CaseDef(Ident(nme.WILDCARD), EmptyTree, body) =>
- val tmpCtx = ctx1.newBlock
- default = tmpCtx.bb
-
- caseCtx = genLoad(body, tmpCtx , generatedType)
- caseCtx.bb.emit(JUMP(afterCtx.bb), caze.pos)
- caseCtx.bb.close
+ for (caze @ CaseDef(pat, guard, body) <- cases) {
+ assert(guard == EmptyTree)
+ val tmpCtx = ctx1.newBlock
+ pat match {
+ case Literal(value) =>
+ tags = value.intValue :: tags
+ targets = tmpCtx.bb :: targets
+ case Ident(nme.WILDCARD) =>
+ default = tmpCtx.bb
+ case _ =>
+ abort("Invalid case statement in switch-like pattern match: " +
+ tree + " at: " + (tree.pos))
+ }
- case _ =>
- abort("Invalid case statement in switch-like pattern match: " +
- tree + " at: " + (tree.pos))
+ caseCtx = genLoad(body, tmpCtx, generatedType)
+ caseCtx.bb.emitOnly(JUMP(afterCtx.bb) setPos caze.pos)
}
- ctx1.bb.emit(SWITCH(tags.reverse map (x => List(x)),
- (default :: targets).reverse), tree.pos)
- ctx1.bb.close
+ ctx1.bb.emitOnly(
+ SWITCH(tags.reverse map (x => List(x)), (default :: targets).reverse) setPos tree.pos
+ )
afterCtx
case EmptyTree =>
@@ -994,13 +919,12 @@ abstract class GenICode extends SubComponent {
ctx
case _ =>
- abort("Unexpected tree in genLoad: " + tree + " at: " +
- (tree.pos))
+ abort("Unexpected tree in genLoad: " + tree + " at: " + tree.pos)
}
// emit conversion
if (generatedType != expectedType)
- adapt(generatedType, expectedType, resCtx, tree.pos);
+ adapt(generatedType, expectedType, resCtx, tree.pos)
resCtx
}
@@ -1143,7 +1067,7 @@ abstract class GenICode extends SubComponent {
*/
def genCoercion(tree: Tree, ctx: Context, code: Int) = {
import scalaPrimitives._
- code match {
+ (code: @switch) match {
case B2B => ()
case B2C => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, CHAR)), tree.pos)
case B2S => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, SHORT)), tree.pos)
@@ -1409,23 +1333,8 @@ abstract class GenICode extends SubComponent {
* comparison might have a run-time type subtype of java.lang.Number or java.lang.Character.
* When it is statically known that both sides are equal and subtypes of Number of Character,
* not using the rich equality is possible (their own equals method will do ok.)*/
- def mustUseAnyComparator: Boolean = {
- import definitions._
-
- /** The various ways a boxed primitive might materialize at runtime. */
- def isJavaBoxed(sym: Symbol) =
- (sym == ObjectClass) ||
- (sym == SerializableClass) ||
- (sym == ComparableClass) ||
- (sym isNonBottomSubClass BoxedNumberClass) ||
- (sym isNonBottomSubClass BoxedCharacterClass)
-
- def isBoxed(sym: Symbol): Boolean =
- if (forMSIL) (sym isNonBottomSubClass BoxedNumberClass)
- else isJavaBoxed(sym)
-
- isBoxed(l.tpe.typeSymbol) && isBoxed(r.tpe.typeSymbol)
- }
+ def mustUseAnyComparator: Boolean =
+ isMaybeBoxed(l.tpe.typeSymbol) && isMaybeBoxed(r.tpe.typeSymbol)
if (mustUseAnyComparator) {
// when -optimise is on we call the @inline-version of equals, found in ScalaRunTime
@@ -1501,9 +1410,8 @@ abstract class GenICode extends SubComponent {
assert(ctx.clazz.symbol eq cls,
"Classes are not the same: " + ctx.clazz.symbol + ", " + cls)
- for (f <- cls.info.decls.iterator)
- if (!f.isMethod && f.isTerm)
- ctx.clazz.addField(new IField(f));
+ for (f <- cls.info.decls ; if !f.isMethod && f.isTerm)
+ ctx.clazz addField new IField(f)
}
/**
@@ -1624,7 +1532,7 @@ abstract class GenICode extends SubComponent {
do {
changed = false
n += 1
- method.code traverse prune0
+ method.code.blocks foreach prune0
} while (changed)
if (settings.debug.value)
@@ -2061,7 +1969,7 @@ abstract class GenICode extends SubComponent {
}
val map = substMap
- code traverse (_.subst(map))
+ code.blocks foreach (_.subst(map))
}
/**
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
index 19f78626e9..993ce62140 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
@@ -36,6 +36,14 @@ trait Members { self: ICodes =>
var producedStack: TypeStack = null
private var currentLabel: Int = 0
+ private var _touched = false
+
+ def touched = _touched
+ def touched_=(b: Boolean): Unit = if (b) {
+ blocks foreach (_.touched = true)
+ _touched = true
+ } else
+ _touched = false
// Constructor code
startBlock = newBlock
@@ -52,52 +60,11 @@ trait Members { self: ICodes =>
if (b == startBlock)
startBlock = b.successors.head;
blocks -= b
- }
-
- /**
- * Apply a function to all basic blocks, for side-effects. It starts at
- * the given startBlock and checks that are no predecessors of the given node.
- * Only blocks that are reachable via a path from startBlock are ever visited.
- */
- def traverseFrom(startBlock: BasicBlock, f: BasicBlock => Unit) = {
- val visited: Set[BasicBlock] = new HashSet();
-
- def traverse0(toVisit: List[BasicBlock]): Unit = toVisit match {
- case Nil => ();
- case b :: bs => if (!visited.contains(b)) {
- f(b);
- visited += b;
- traverse0(bs ::: b.successors);
- } else
- traverse0(bs);
- }
- assert(startBlock.predecessors == Nil,
- "Starting traverse from a block with predecessors: " + this);
- traverse0(startBlock :: Nil)
- }
+ assert(!blocks.contains(b))
+ for (handler <- method.exh if handler.covers(b))
+ handler.covered -= b
- def traverse(f: BasicBlock => Unit) = blocks.toList foreach f;
-
- /* This method applies the given function to each basic block. */
- def traverseFeedBack(f: (BasicBlock, HashMap[BasicBlock, Boolean]) => Unit) = {
- val visited : HashMap[BasicBlock, Boolean] = new HashMap;
- visited ++= blocks.iterator.map(x => (x, false));
-
- var blockToVisit: List[BasicBlock] = List(startBlock)
-
- while (!blockToVisit.isEmpty) {
- blockToVisit match {
- case b::xs =>
- if (!visited(b)) {
- f(b, visited);
- blockToVisit = b.successors ::: xs;
- visited += (b -> true)
- } else
- blockToVisit = xs
- case _ =>
- error("impossible match")
- }
- }
+ touched = true
}
/** This methods returns a string representation of the ICode */
@@ -112,6 +79,7 @@ trait Members { self: ICodes =>
/* Create a new block and append it to the list
*/
def newBlock: BasicBlock = {
+ touched = true
val block = new BasicBlock(nextLabel, method);
blocks += block;
block
@@ -145,6 +113,11 @@ trait Members { self: ICodes =>
def lookupField(s: Symbol) = fields find (_.symbol == s)
def lookupMethod(s: Symbol) = methods find (_.symbol == s)
def lookupMethod(s: Name) = methods find (_.symbol.name == s)
+
+ /* determines whether or not this class contains a static ctor. */
+ def containsStaticCtor: Boolean = methods.exists(_.isStaticCtor)
+ /* returns this methods static ctor if it has one. */
+ def lookupStaticCtor: Option[IMethod] = methods.find(_.isStaticCtor)
}
/** Represent a field in ICode */
@@ -225,12 +198,15 @@ trait Members { self: ICodes =>
def isStatic: Boolean = symbol.isStaticMember
+ /* determines whether or not this method is the class static constructor. */
+ def isStaticCtor: Boolean = isStatic && symbol.rawname == nme.CONSTRUCTOR
+
override def toString() = symbol.fullNameString
import opcodes._
def checkLocals: Unit = if (code ne null) {
Console.println("[checking locals of " + this + "]")
- for (bb <- code.blocks; i <- bb.toList) i match {
+ for (bb <- code.blocks; i <- bb) i match {
case LOAD_LOCAL(l) =>
if (!this.locals.contains(l))
Console.println("Local " + l + " is not declared in " + this)
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala
index f03b84a50e..e50260b651 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala
@@ -119,9 +119,9 @@ trait Printers { self: ICodes =>
print(bb.label)
if (bb.loopHeader) print("[loop header]")
print(": ");
- if (settings.debug.value) print("pred: " + bb.predecessors + " succs: " + bb.successors)
+ if (settings.debug.value) print("pred: " + bb.predecessors + " succs: " + bb.successors + " flags: " + bb.flagsString)
indent; println
- bb.toList foreach printInstruction
+ bb foreach printInstruction
undent; println
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
index 8ed2b04045..81461c1bf7 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
@@ -108,6 +108,8 @@ trait TypeKinds { self: ICodes =>
def dimensions: Int = 0
}
+ var lubs0 = 0
+
/**
* The least upper bound of two typekinds. They have to be either
* REFERENCE or ARRAY kinds.
@@ -116,16 +118,11 @@ trait TypeKinds { self: ICodes =>
*/
def lub(a: TypeKind, b: TypeKind): TypeKind = {
def lub0(t1: Type, t2: Type): Type = {
- val lubTpe = global.lub(t1 :: t2 :: Nil)
- assert(lubTpe.typeSymbol.isClass,
- "Least upper bound of " + t1 + " and " + t2 + " is not a class: " + lubTpe)
- lubTpe
+ //lubs0 += 1
+ global.lub(t1 :: t2 :: Nil)
}
- if ((a.isReferenceType || a.isArrayType) &&
- (b.isReferenceType || b.isArrayType))
- toTypeKind(lub0(a.toType, b.toType))
- else if (a == b) a
+ if (a == b) a
else if (a == REFERENCE(NothingClass)) b
else if (b == REFERENCE(NothingClass)) a
else (a, b) match {
@@ -136,7 +133,12 @@ trait TypeKinds { self: ICodes =>
case (SHORT, INT) | (INT, SHORT) => INT
case (CHAR, INT) | (INT, CHAR) => INT
case (BOOL, INT) | (INT, BOOL) => INT
- case _ => throw new CheckerError("Incompatible types: " + a + " with " + b)
+ case _ =>
+ if ((a.isReferenceType || a.isArrayType) &&
+ (b.isReferenceType || b.isArrayType))
+ toTypeKind(lub0(a.toType, b.toType))
+ else
+ throw new CheckerError("Incompatible types: " + a + " with " + b)
}
}
@@ -162,28 +164,36 @@ trait TypeKinds { self: ICodes =>
case object BYTE extends TypeKind {
override def maxType(other: TypeKind): TypeKind =
other match {
- case BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE => other
+ case CHAR => INT
+ case BYTE | SHORT | INT | LONG | FLOAT | DOUBLE => other
case REFERENCE(NothingClass) => BYTE
case _ => abort("Uncomparable type kinds: BYTE with " + other)
}
}
+ /** Note that the max of Char/Byte and Char/Short is Int, because
+ * neither strictly encloses the other due to unsignedness.
+ * See ticket #2087 for a consequence.
+ */
+
/** A 2-byte signed integer */
case object SHORT extends TypeKind {
override def maxType(other: TypeKind): TypeKind =
other match {
- case BYTE | SHORT | CHAR => SHORT
+ case CHAR => INT
+ case BYTE | SHORT => SHORT
case REFERENCE(NothingClass) => SHORT
case INT | LONG | FLOAT | DOUBLE => other
case _ => abort("Uncomparable type kinds: SHORT with " + other)
}
}
- /** A 2-byte signed integer */
+ /** A 2-byte UNSIGNED integer */
case object CHAR extends TypeKind {
override def maxType(other: TypeKind): TypeKind =
other match {
- case BYTE | SHORT | CHAR => CHAR
+ case CHAR => CHAR
+ case BYTE | SHORT => INT
case REFERENCE(NothingClass) => CHAR
case INT | LONG | FLOAT | DOUBLE => other
case _ => abort("Uncomparable type kinds: CHAR with " + other)
diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala
index 6e7a81ac1e..eef1863374 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala
@@ -18,7 +18,7 @@ trait TypeStacks { self: ICodes =>
import opcodes._
import global.{Symbol, Type, definitions}
- /* This class simulates the type of the opperand
+ /* This class simulates the type of the operand
* stack of the ICode.
*/
type Rep = List[TypeKind]
@@ -71,20 +71,22 @@ trait TypeStacks { self: ICodes =>
def apply(n: Int): TypeKind = types(n)
/**
- * A TypeStack aggress with another one if they have the same
+ * A TypeStack agrees with another one if they have the same
* length and each type kind agrees position-wise. Two
* types agree if one is a subtype of the other.
*/
def agreesWith(other: TypeStack): Boolean =
(types.length == other.types.length) &&
- List.forall2(types, other.types) ((t1, t2) => t1 <:< t2 || t2 <:< t1)
+ ((types, other.types).zipped forall ((t1, t2) => t1 <:< t2 || t2 <:< t1))
/* This method returns a String representation of the stack */
override def toString() = types.mkString("\n", "\n", "\n")
- override def equals(other: Any): Boolean =
- other.isInstanceOf[TypeStack] &&
- List.forall2(other.asInstanceOf[TypeStack].types, types)((a, b) => a == b)
+ override def hashCode() = types.hashCode()
+ override def equals(other: Any): Boolean = other match {
+ case x: TypeStack => x.types sameElements types
+ case _ => false
+ }
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala
index 9ee628ef19..fe114e3faa 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala
@@ -66,8 +66,8 @@ abstract class CopyPropagation {
if ((other eq bottom) || (this eq bottom))
(this eq other)
else {
- this.bindings == other.bindings &&
- List.forall2(this.stack, other.stack) { (a, b) => a == b }
+ (this.bindings == other.bindings) &&
+ ((this.stack, other.stack).zipped forall (_ == _))
}
}
@@ -188,7 +188,7 @@ abstract class CopyPropagation {
else {
// if (a.stack.length != b.stack.length)
// throw new LubError(a, b, "Invalid stacks in states: ");
- List.map2(a.stack, b.stack) { (v1, v2) =>
+ (a.stack, b.stack).zipped map { (v1, v2) =>
if (v1 == v2) v1 else Unknown
}
}
@@ -245,10 +245,15 @@ abstract class CopyPropagation {
}
def blockTransfer(b: BasicBlock, in: lattice.Elem): lattice.Elem =
- b.toList.foldLeft(in)(interpret)
+ b.foldLeft(in)(interpret)
import opcodes._
+ private def retain[A, B](map: Map[A, B])(p: (A, B) => Boolean) = {
+ for ((k, v) <- map ; if !p(k, v)) map -= k
+ map
+ }
+
/** Abstract interpretation for one instruction. */
def interpret(in: copyLattice.Elem, i: Instruction): copyLattice.Elem = {
var out = in.dup
@@ -458,7 +463,7 @@ abstract class CopyPropagation {
*/
final def cleanReferencesTo(s: copyLattice.State, target: Location) {
def cleanRecord(r: Record): Record = {
- r.bindings retain { (loc, value) =>
+ retain(r.bindings) { (loc, value) =>
(value match {
case Deref(loc1) if (loc1 == target) => false
case Boxed(loc1) if (loc1 == target) => false
@@ -478,7 +483,7 @@ abstract class CopyPropagation {
case _ => v
}}
- s.bindings retain { (loc, value) =>
+ retain(s.bindings) { (loc, value) =>
(value match {
case Deref(loc1) if (loc1 == target) => false
case Boxed(loc1) if (loc1 == target) => false
@@ -531,12 +536,12 @@ abstract class CopyPropagation {
}
state.stack = state.stack map { v => v match {
case Record(cls, bindings) =>
- bindings.retain { (sym: Symbol, v: Value) => shouldRetain(sym) }
+ retain(bindings) { (sym, _) => shouldRetain(sym) }
Record(cls, bindings)
case _ => v
}}
- state.bindings retain {(loc, value) =>
+ retain(state.bindings) { (loc, value) =>
value match {
case Deref(Field(rec, sym)) => shouldRetain(sym)
case Boxed(Field(rec, sym)) => shouldRetain(sym)
diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala
index 09a39f4280..8e14159197 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala
@@ -70,6 +70,8 @@ trait DataFlowAnalysis[L <: CompleteLattice] {
succs foreach { p =>
if (!worklist.contains(p))
worklist += p;
+ if (!in.isDefinedAt(p))
+ assert(false, "Invalid successor for: " + point + " successor " + p + " does not exist")
// if (!p.exceptionHandlerHeader) {
// println("lubbing " + p.predecessors + " outs: " + p.predecessors.map(out.apply).mkString("\n", "\n", ""))
in(p) = lattice.lub(/*in(p) :: */(p.predecessors map out.apply), p.exceptionHandlerStart)
diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala
index 46e24c18ec..0d301347b1 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala
@@ -71,7 +71,7 @@ abstract class Liveness {
def genAndKill(b: BasicBlock): (Set[Local], Set[Local]) = {
var genSet = new ListSet[Local]
var killSet = new ListSet[Local]
- for (i <- b.toList) i match {
+ for (i <- b) i match {
case LOAD_LOCAL(local) if (!killSet(local)) => genSet = genSet + local
case STORE_LOCAL(local) if (!genSet(local)) => killSet = killSet + local
case _ => ()
diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala
index 65065fe0d1..1c714cbd5d 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala
@@ -43,19 +43,19 @@ abstract class ReachingDefinitions {
else if (bottom == b) a
else {
val locals = a.vars ++ b.vars
- val stack = if (a.stack == Nil)
- b.stack
- else if (b.stack == Nil) a.stack
- else List.map2(a.stack, b.stack) (_ ++ _)
-
- val res = IState(locals, stack)
-
-// Console.println("\tlub2: " + a + ", " + b)
-// Console.println("\tis: " + res)
-
-// if (res._1 eq bottom._1) (new ListSet[Definition], Nil)
-// else res
- res
+ val stack =
+ if (a.stack == Nil) b.stack
+ else if (b.stack == Nil) a.stack
+ else (a.stack, b.stack).zipped map (_ ++ _)
+
+ IState(locals, stack)
+
+ // val res = IState(locals, stack)
+ // Console.println("\tlub2: " + a + ", " + b)
+ // Console.println("\tis: " + res)
+ // if (res._1 eq bottom._1) (new ListSet[Definition], Nil)
+ // else res
+ // res
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala
index 32a6037d41..eecae5e578 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala
@@ -53,7 +53,7 @@ abstract class TypeFlowAnalysis {
else {
// if (s1.length != s2.length)
// throw new CheckerError("Incompatible stacks: " + s1 + " and " + s2);
- new TypeStack(List.map2(s1.types, s2.types) (icodes.lub))
+ new TypeStack((s1.types, s2.types).zipped map icodes.lub)
}
}
}
@@ -81,10 +81,14 @@ abstract class TypeFlowAnalysis {
override val top = new Elem(new VarBinding, typeStackLattice.top)
override val bottom = new Elem(new VarBinding, typeStackLattice.bottom)
+// var lubs = 0
+
def lub2(exceptional: Boolean)(a: Elem, b: Elem) = {
val IState(env1, s1) = a
val IState(env2, s2) = b
+// lubs += 1
+
val resultingLocals = new VarBinding
for (binding1 <- env1.iterator) {
@@ -118,7 +122,7 @@ abstract class TypeFlowAnalysis {
/** Initialize the in/out maps for the analysis of the given method. */
def init(m: icodes.IMethod) {
this.method = m
-
+ //typeFlowLattice.lubs = 0
init {
worklist += m.code.startBlock
worklist ++= (m.exh map (_.startBlock))
@@ -168,14 +172,17 @@ abstract class TypeFlowAnalysis {
def run = {
timer.start
+// icodes.lubs0 = 0
forwardAnalysis(blockTransfer)
- timer.stop
+ val t = timer.stop
if (settings.debug.value) {
linearizer.linearize(method).foreach(b => if (b != method.code.startBlock)
assert(visited.contains(b),
"Block " + b + " in " + this.method + " has input equal to bottom -- not visited? .." + visited));
}
- //println("iterations: " + iterations + " for " + method.code.blocks.size)
+// log("" + method.symbol.fullNameString + " [" + method.code.blocks.size + " blocks] "
+// + "\n\t" + iterations + " iterations: " + t + " ms."
+// + "\n\tlubs: " + typeFlowLattice.lubs + " out of which " + icodes.lubs0 + " typer lubs")
}
def blockTransfer(b: BasicBlock, in: lattice.Elem): lattice.Elem = {
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 67f3f7f8b2..c4408c661a 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -47,7 +47,8 @@ abstract class GenJVM extends SubComponent {
override def run {
if (settings.debug.value) inform("[running phase " + name + " on icode]")
if (settings.Xdce.value)
- icodes.classes.retain { (sym: Symbol, cls: IClass) => !inliner.isClosureClass(sym) || deadCode.liveClosures(sym) }
+ for ((sym, cls) <- icodes.classes ; if inliner.isClosureClass(sym) && !deadCode.liveClosures(sym))
+ icodes.classes -= sym
classes.valuesIterator foreach apply
}
@@ -202,7 +203,7 @@ abstract class GenJVM extends SubComponent {
if (isStaticModule(c.symbol) || serialVUID != None || clasz.bootstrapClass.isDefined) {
if (isStaticModule(c.symbol))
addModuleInstanceField;
- addStaticInit(jclass)
+ addStaticInit(jclass, c.lookupStaticCtor)
if (isTopLevelModule(c.symbol)) {
if (c.symbol.linkedClassOfModule == NoSymbol)
@@ -213,6 +214,8 @@ abstract class GenJVM extends SubComponent {
}
}
else {
+ if (c.containsStaticCtor) addStaticInit(jclass, c.lookupStaticCtor)
+
// it must be a top level class (name contains no $s)
def isCandidateForForwarders(sym: Symbol): Boolean =
atPhase (currentRun.picklerPhase.next) {
@@ -431,9 +434,11 @@ abstract class GenJVM extends SubComponent {
def addGenericSignature(jmember: JMember, sym: Symbol, owner: Symbol) {
if (!sym.hasFlag(Flags.EXPANDEDNAME | Flags.SYNTHETIC)
- && !(sym.isMethod && sym.hasFlag(Flags.LIFTED))) {
+ && !(sym.isMethod && sym.hasFlag(Flags.LIFTED))
+ && !(sym.ownerChain exists (_.isImplClass))) { // @M don't generate java generics sigs for (members of) implementation classes, as they are monomorphic (TODO: ok?)
val memberTpe = atPhase(currentRun.erasurePhase)(owner.thisType.memberInfo(sym))
-// println("sym: " + sym.fullNameString + " : " + memberTpe + " sym.info: " + sym.info)
+ // println("addGenericSignature sym: " + sym.fullNameString + " : " + memberTpe + " sym.info: " + sym.info)
+ // println("addGenericSignature: "+ (sym.ownerChain map (x => (x.name, x.isImplClass))))
erasure.javaSig(sym, memberTpe) match {
case Some(sig) =>
val index = jmember.getConstantPool().addUtf8(sig).toShort
@@ -505,7 +510,7 @@ abstract class GenJVM extends SubComponent {
val innerClassesAttr = jclass.getInnerClasses()
// sort them so inner classes succeed their enclosing class
// to satisfy the Eclipse Java compiler
- for (innerSym <- innerClasses.toList.sort(_.name.length < _.name.length)) {
+ for (innerSym <- innerClasses.toList sortBy (_.name.length)) {
var outerName = javaName(innerSym.rawowner)
// remove the trailing '$'
if (outerName.endsWith("$") && isTopLevelModule(innerSym.rawowner))
@@ -556,6 +561,8 @@ abstract class GenJVM extends SubComponent {
}
def genMethod(m: IMethod) {
+ if (m.isStaticCtor) return
+
log("Generating method " + m.symbol.fullNameString)
method = m
endPC.clear
@@ -667,7 +674,7 @@ abstract class GenJVM extends SubComponent {
jclass.getType())
}
- def addStaticInit(cls: JClass) {
+ def addStaticInit(cls: JClass, mopt: Option[IMethod]) {
import JAccessFlags._
val clinitMethod = cls.addNewMethod(ACC_PUBLIC | ACC_STATIC,
"<clinit>",
@@ -675,6 +682,53 @@ abstract class GenJVM extends SubComponent {
JType.EMPTY_ARRAY,
new Array[String](0))
val clinit = clinitMethod.getCode().asInstanceOf[JExtendedCode]
+
+ mopt match {
+ case Some(m) =>
+ if (clasz.bootstrapClass.isDefined) legacyEmitBootstrapMethodInstall(clinit)
+
+ val oldLastBlock = m.code.blocks.last
+ val lastBlock = m.code.newBlock
+ oldLastBlock.replaceInstruction(oldLastBlock.length - 1, JUMP(lastBlock))
+
+ if (isStaticModule(clasz.symbol)) {
+ // call object's private ctor from static ctor
+ lastBlock.emit(NEW(REFERENCE(m.symbol.enclClass)))
+ lastBlock.emit(CALL_METHOD(m.symbol.enclClass.primaryConstructor, Static(true)))
+ }
+
+ // add serialVUID code
+ serialVUID match {
+ case Some(value) =>
+ import Flags._
+ import definitions._
+ val fieldName = "serialVersionUID"
+ val fieldSymbol = clasz.symbol.newValue(NoPosition, newTermName(fieldName))
+ .setFlag(STATIC | FINAL)
+ .setInfo(longType)
+ clasz.addField(new IField(fieldSymbol))
+ lastBlock.emit(CONSTANT(Constant(value)))
+ lastBlock.emit(STORE_FIELD(fieldSymbol, true))
+ case None => ()
+ }
+
+ if (clasz.bootstrapClass.isDefined) {
+ // emit bootstrap method install
+ //emitBootstrapMethodInstall(block)
+ }
+
+ lastBlock.emit(RETURN(UNIT))
+ lastBlock.close
+
+ method = m
+ jmethod = clinitMethod
+ genCode(m)
+ case None =>
+ legacyStaticInitializer(cls, clinit)
+ }
+ }
+
+ private def legacyStaticInitializer(cls: JClass, clinit: JExtendedCode) {
if (isStaticModule(clasz.symbol)) {
clinit.emitNEW(cls.getName())
clinit.emitINVOKESPECIAL(cls.getName(),
@@ -693,7 +747,7 @@ abstract class GenJVM extends SubComponent {
case None => ()
}
- if (clasz.bootstrapClass.isDefined) emitBootstrapMethodInstall(clinit)
+ if (clasz.bootstrapClass.isDefined) legacyEmitBootstrapMethodInstall(clinit)
clinit.emitRETURN()
}
@@ -701,7 +755,7 @@ abstract class GenJVM extends SubComponent {
/** Emit code that installs a boostrap method for invoke dynamic. It installs the default
* method, found in scala.runtime.DynamicDispatch.
*/
- def emitBootstrapMethodInstall(jcode: JExtendedCode) {
+ def legacyEmitBootstrapMethodInstall(jcode: JExtendedCode) {
jcode.emitPUSH(jclass.getType.asInstanceOf[JReferenceType])
jcode.emitPUSH(new JObjectType("scala.runtime.DynamicDispatch"))
jcode.emitPUSH("bootstrapInvokeDynamic")
@@ -822,9 +876,38 @@ abstract class GenJVM extends SubComponent {
}
var linearization: List[BasicBlock] = Nil
-
var isModuleInitialized = false
+ private def genConstant(jcode: JExtendedCode, const: Constant) {
+ const.tag match {
+ case UnitTag => ()
+ case BooleanTag => jcode.emitPUSH(const.booleanValue)
+ case ByteTag => jcode.emitPUSH(const.byteValue)
+ case ShortTag => jcode.emitPUSH(const.shortValue)
+ case CharTag => jcode.emitPUSH(const.charValue)
+ case IntTag => jcode.emitPUSH(const.intValue)
+ case LongTag => jcode.emitPUSH(const.longValue)
+ case FloatTag => jcode.emitPUSH(const.floatValue)
+ case DoubleTag => jcode.emitPUSH(const.doubleValue)
+ case StringTag => jcode.emitPUSH(const.stringValue)
+ case NullTag => jcode.emitACONST_NULL()
+ case ClassTag =>
+ val kind = toTypeKind(const.typeValue)
+ val toPush =
+ if (kind.isValueType) classLiteral(kind)
+ else javaType(kind).asInstanceOf[JReferenceType]
+
+ jcode emitPUSH toPush
+
+ case EnumTag =>
+ val sym = const.symbolValue
+ jcode.emitGETSTATIC(javaName(sym.owner),
+ javaName(sym),
+ javaType(sym.tpe.underlying))
+ case _ => abort("Unknown constant value: " + const);
+ }
+ }
+
/**
* @param m ...
*/
@@ -835,7 +918,7 @@ abstract class GenJVM extends SubComponent {
if (settings.debug.value)
log("Making labels for: " + method)
- HashMap(bs map (b => b -> jcode.newLabel) : _*)
+ HashMap(bs map (_ -> jcode.newLabel) : _*)
}
isModuleInitialized = false
@@ -847,12 +930,11 @@ abstract class GenJVM extends SubComponent {
var nextBlock: BasicBlock = linearization.head
- def genBlocks(l: List[BasicBlock]): Unit = l match {
- case Nil => ()
- case x :: Nil => nextBlock = null; genBlock(x)
- case x :: y :: ys => nextBlock = y; genBlock(x); genBlocks(y :: ys)
- }
-
+ def genBlocks(l: List[BasicBlock]): Unit = l match {
+ case Nil => ()
+ case x :: Nil => nextBlock = null; genBlock(x)
+ case x :: y :: ys => nextBlock = y; genBlock(x); genBlocks(y :: ys)
+ }
/** Generate exception handlers for the current method. */
def genExceptionHandlers {
@@ -867,30 +949,28 @@ abstract class GenJVM extends SubComponent {
var start = -1
var end = -1
- linearization foreach ((b) => {
+ linearization foreach { b =>
if (! (covered contains b) ) {
if (start >= 0) { // we're inside a handler range
end = labels(b).getAnchor()
- ranges = (start, end) :: ranges
+ ranges ::= (start, end)
start = -1
}
} else {
- if (start >= 0) { // we're inside a handler range
- end = endPC(b)
- } else {
+ if (start < 0) // we're not inside a handler range
start = labels(b).getAnchor()
- end = endPC(b)
- }
- covered = covered - b
+
+ end = endPC(b)
+ covered -= b
}
- });
+ }
/* Add the last interval. Note that since the intervals are
* open-ended to the right, we have to give a number past the actual
* code!
*/
if (start >= 0) {
- ranges = (start, jcode.getPC()) :: ranges;
+ ranges ::= (start, jcode.getPC())
}
if (!covered.isEmpty)
@@ -900,19 +980,16 @@ abstract class GenJVM extends SubComponent {
ranges
}
- this.method.exh foreach { e =>
- ranges(e).sort({ (p1, p2) => p1._1 < p2._1 })
- .foreach { p =>
- if (p._1 < p._2) {
- if (settings.debug.value)
- log("Adding exception handler " + e + "at block: " + e.startBlock + " for " + method +
- " from: " + p._1 + " to: " + p._2 + " catching: " + e.cls);
- jcode.addExceptionHandler(p._1, p._2,
- labels(e.startBlock).getAnchor(),
- if (e.cls == NoSymbol) null else javaName(e.cls))
- } else
- log("Empty exception range: " + p)
- }
+ for (e <- this.method.exh ; p <- ranges(e).sortBy(_._1)) {
+ if (p._1 < p._2) {
+ if (settings.debug.value)
+ log("Adding exception handler " + e + "at block: " + e.startBlock + " for " + method +
+ " from: " + p._1 + " to: " + p._2 + " catching: " + e.cls);
+ jcode.addExceptionHandler(p._1, p._2,
+ labels(e.startBlock).getAnchor(),
+ if (e.cls == NoSymbol) null else javaName(e.cls))
+ } else
+ log("Empty exception range: " + p)
}
}
@@ -944,31 +1021,7 @@ abstract class GenJVM extends SubComponent {
jcode.emitALOAD_0()
case CONSTANT(const) =>
- const.tag match {
- case UnitTag => ();
- case BooleanTag => jcode.emitPUSH(const.booleanValue)
- case ByteTag => jcode.emitPUSH(const.byteValue)
- case ShortTag => jcode.emitPUSH(const.shortValue)
- case CharTag => jcode.emitPUSH(const.charValue)
- case IntTag => jcode.emitPUSH(const.intValue)
- case LongTag => jcode.emitPUSH(const.longValue)
- case FloatTag => jcode.emitPUSH(const.floatValue)
- case DoubleTag => jcode.emitPUSH(const.doubleValue)
- case StringTag => jcode.emitPUSH(const.stringValue)
- case NullTag => jcode.emitACONST_NULL()
- case ClassTag =>
- val kind = toTypeKind(const.typeValue);
- if (kind.isValueType)
- jcode.emitPUSH(classLiteral(kind));
- else
- jcode.emitPUSH(javaType(kind).asInstanceOf[JReferenceType]);
- case EnumTag =>
- val sym = const.symbolValue
- jcode.emitGETSTATIC(javaName(sym.owner),
- javaName(sym),
- javaType(sym.tpe.underlying))
- case _ => abort("Unknown constant value: " + const);
- }
+ genConstant(jcode, const)
case LOAD_ARRAY_ITEM(kind) =>
jcode.emitALOAD(javaType(kind))
@@ -1029,46 +1082,36 @@ abstract class GenJVM extends SubComponent {
genPrimitive(primitive, instr.pos)
case call @ CALL_METHOD(method, style) =>
- val owner: String = javaName(method.owner);
- //reference the type of the receiver instead of the method owner (if not an interface!)
+ val owner: String = javaName(method.owner)
+ // reference the type of the receiver instead of the method owner (if not an interface!)
val dynamicOwner =
if (needsInterfaceCall(call.hostClass)) owner
else javaName(call.hostClass)
+ val jname = javaName(method)
+ val jtype = javaType(method).asInstanceOf[JMethodType]
style match {
case InvokeDynamic =>
- jcode.emitINVOKEINTERFACE("java.dyn.Dynamic",
- javaName(method),
- javaType(method).asInstanceOf[JMethodType])
+ jcode.emitINVOKEINTERFACE("java.dyn.Dynamic", jname, jtype)
case Dynamic =>
if (needsInterfaceCall(method.owner))
- jcode.emitINVOKEINTERFACE(owner,
- javaName(method),
- javaType(method).asInstanceOf[JMethodType])
+ jcode.emitINVOKEINTERFACE(owner, jname, jtype)
else
- jcode.emitINVOKEVIRTUAL(dynamicOwner,
- javaName(method),
- javaType(method).asInstanceOf[JMethodType]);
+ jcode.emitINVOKEVIRTUAL(dynamicOwner, jname, jtype)
case Static(instance) =>
- if (instance) {
- jcode.emitINVOKESPECIAL(owner,
- javaName(method),
- javaType(method).asInstanceOf[JMethodType]);
- } else
- jcode.emitINVOKESTATIC(owner,
- javaName(method),
- javaType(method).asInstanceOf[JMethodType]);
+ if (instance)
+ jcode.emitINVOKESPECIAL(owner, jname, jtype)
+ else
+ jcode.emitINVOKESTATIC(owner, jname, jtype)
case SuperCall(_) =>
- jcode.emitINVOKESPECIAL(owner,
- javaName(method),
- javaType(method).asInstanceOf[JMethodType]);
+ jcode.emitINVOKESPECIAL(owner, jname, jtype)
// we initialize the MODULE$ field immediately after the super ctor
if (isStaticModule(clasz.symbol) && !isModuleInitialized &&
jmethod.getName() == JMethod.INSTANCE_CONSTRUCTOR_NAME &&
- javaName(method) == JMethod.INSTANCE_CONSTRUCTOR_NAME) {
+ jname == JMethod.INSTANCE_CONSTRUCTOR_NAME) {
isModuleInitialized = true;
jcode.emitALOAD_0();
jcode.emitPUTSTATIC(jclass.getName(),
diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
index bbc11037ce..6bc87d082d 100644
--- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
+++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
@@ -561,7 +561,7 @@ abstract class GenMSIL extends SubComponent {
}
if (mcode != null) {
- for (local <- m.locals -- m.params) {
+ for (local <- m.locals ; if !(m.params contains local)) {
if (settings.debug.value)
log("add local var: " + local + ", of kind " + local.kind)
val t: MsilType = msilType(local.kind)
@@ -828,6 +828,15 @@ abstract class GenMSIL extends SubComponent {
// covering the same blocks
def orderBlocksForExh(blocks: List[BasicBlock], exH: List[ExceptionHandler]): List[BasicBlock] = {
+ def moveToFront[T](xs: List[T], x: T) = (xs indexOf x) match {
+ case -1 => x :: xs
+ case idx => x :: (xs take idx) ::: (xs drop (idx + 1))
+ }
+ def moveToEnd[T](xs: List[T], x: T) = (xs indexOf x) match {
+ case -1 => xs ::: List(x)
+ case idx => (xs take idx) ::: (xs drop (idx + 1)) ::: List(x)
+ }
+
var blocksToPut: List[BasicBlock] = blocks
var nextBlock: BasicBlock = null
var untreatedHandlers: List[ExceptionHandler] = exH
@@ -841,7 +850,7 @@ abstract class GenMSIL extends SubComponent {
// problem: block may already be added, and and needs to be moved.
// if nextblock NOT in b: check if nextblock in blocksToPut, if NOT, check if movable, else don't put
if (nextBlock != null && b.contains(nextBlock)) {
- val blocksToAdd = nextBlock :: (b - nextBlock)
+ val blocksToAdd = moveToFront(b, nextBlock)
nextBlock = null
addBlocks(blocksToAdd)
}
@@ -854,7 +863,7 @@ abstract class GenMSIL extends SubComponent {
{
// the block is not part of some catch or finally code
currentBlock.addBasicBlock(x)
- blocksToPut = blocksToPut - x
+ blocksToPut = moveToFront(blocksToPut, x)
if (settings.debug.value) log(" -> addBlocks(" + xs + ")")
addBlocks(xs)
} else {
@@ -865,7 +874,7 @@ abstract class GenMSIL extends SubComponent {
// is optimized by compiler (no try left)
if(untreatedHandlers.forall(h =>
(!h.blocks.contains(x) || h.covered.isEmpty))) {
- blocksToPut = blocksToPut - x
+ blocksToPut = moveToFront(blocksToPut, x)
addBlocks(xs)
} else
addBlocks(xs ::: List(x))
@@ -960,8 +969,9 @@ abstract class GenMSIL extends SubComponent {
firstBlockAfter(exh) = outside(0)
//else ()
//assert(firstBlockAfter(exh) == outside(0), "try/catch leaving to multiple targets: " + firstBlockAfter(exh) + ", new: " + outside(0))
+
val last = leaving(0)._1
- ((blocks - last) ::: List(last), None)
+ (moveToEnd(blocks, last), None)
} else {
val outside = leaving.flatMap(p => p._2)
//assert(outside.forall(b => b == outside(0)), "exception-block leaving to multiple targets")
@@ -981,9 +991,9 @@ abstract class GenMSIL extends SubComponent {
})
// shorter try-catch-finally last (the ones contained in another)
- affectedHandlers = affectedHandlers.sort({(h1, h2) => h1.covered.size > h2.covered.size})
+ affectedHandlers = affectedHandlers.sortWith(_.covered.size > _.covered.size)
affectedHandlers = affectedHandlers.filter(h => {h.covered.size == affectedHandlers(0).covered.size})
- untreatedHandlers = untreatedHandlers -- affectedHandlers
+ untreatedHandlers = untreatedHandlers filterNot (affectedHandlers contains)
// more than one catch produces more than one exh, but we only need one
var singleAffectedHandler: ExceptionHandler = affectedHandlers(0) // List[ExceptionHandler] = Nil
@@ -997,7 +1007,7 @@ abstract class GenMSIL extends SubComponent {
h1.addBlock(block)
case None => ()
}
- val orderedCatchBlocks = h1.startBlock :: (adaptedBlocks - h1.startBlock)
+ val orderedCatchBlocks = moveToFront(adaptedBlocks, h1.startBlock)
exceptionBlock match {
case Some(excBlock) =>
@@ -1028,7 +1038,7 @@ abstract class GenMSIL extends SubComponent {
singleAffectedHandler.finalizer.addBlock(block)
case None => ()
}
- val blocks = singleAffectedHandler.finalizer.startBlock :: (blocks0 - singleAffectedHandler.finalizer.startBlock)
+ val blocks = moveToFront(blocks0, singleAffectedHandler.finalizer.startBlock)
currentBlock = excBlock.finallyBlock
addBlocks(blocks)
}
@@ -1128,15 +1138,14 @@ abstract class GenMSIL extends SubComponent {
"untreated exception handlers left: " + untreatedHandlers)
// remove catch blocks from empty handlers (finally-blocks remain)
untreatedHandlers.foreach((h) => {
- orderedBlocks = orderedBlocks -- h.blocks
+ orderedBlocks = orderedBlocks filterNot (h.blocks contains)
})
// take care of order in which exHInstructions are executed (BeginExceptionBlock as last)
bb2exHInstructions.keysIterator.foreach((b) => {
- bb2exHInstructions(b).sort((i1, i2) => (!i1.isInstanceOf[BeginExceptionBlock]))
+ bb2exHInstructions(b).sortBy(x => x.isInstanceOf[BeginExceptionBlock])
})
-
if (settings.debug.value) {
log("after: " + orderedBlocks)
log(" exhInstr: " + bb2exHInstructions)
@@ -1791,7 +1800,7 @@ abstract class GenMSIL extends SubComponent {
idx += 1 // sizeOf(l.kind)
}
- val locvars = m.locals -- params
+ val locvars = m.locals filterNot (params contains)
idx = 0
for (l <- locvars) {
diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
index 248b24bc43..1e53627273 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
@@ -105,7 +105,7 @@ abstract class ClosureElimination extends SubComponent {
var info = cpp.in(bb)
log("Cpp info at entry to block " + bb + ": " + info)
- for (i <- bb.toList) {
+ for (i <- bb) {
i match {
case LOAD_LOCAL(l) if (info.bindings.isDefinedAt(LocalVar(l))) =>
val t = info.getBinding(l)
diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
index 321b27b030..194c99f800 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
@@ -23,6 +23,18 @@ abstract class Inliners extends SubComponent {
val phaseName = "inliner"
+ /** Debug - for timing the inliner. */
+ private def timed[T](s: String, body: => T): T = {
+ val t1 = System.currentTimeMillis()
+ val res = body
+ val t2 = System.currentTimeMillis()
+ val ms = (t2 - t1).toInt
+ if (ms >= 2000)
+ println("%s: %d milliseconds".format(s, ms))
+
+ res
+ }
+
/** The maximum size in basic blocks of methods considered for inlining. */
final val MAX_INLINE_SIZE = 16
@@ -269,9 +281,9 @@ abstract class Inliners extends SubComponent {
def analyzeClass(cls: IClass): Unit = if (settings.inline.value) {
if (settings.debug.value)
log("Analyzing " + cls);
- cls.methods.foreach { m => if (!m.symbol.isConstructor) analyzeMethod(m)
- }}
+ cls.methods filterNot (_.symbol.isConstructor) foreach analyzeMethod
+ }
val tfa = new analysis.MethodTFA();
tfa.stat = settings.Ystatistics.value
@@ -281,7 +293,7 @@ abstract class Inliners extends SubComponent {
override def default(k: Symbol) = 0
}
- def analyzeMethod(m: IMethod): Unit = {//try {
+ def analyzeMethod(m: IMethod): Unit = {
var retry = false
var count = 0
fresh.clear
@@ -290,13 +302,12 @@ abstract class Inliners extends SubComponent {
do {
retry = false;
if (m.code ne null) {
- if (settings.debug.value)
- log("Analyzing " + m + " count " + count + " with " + m.code.blocks.length + " blocks");
+ log("Analyzing " + m + " count " + count + " with " + m.code.blocks.length + " blocks");
tfa.init(m)
tfa.run
for (bb <- linearizer.linearize(m)) {
var info = tfa.in(bb);
- for (i <- bb.toList) {
+ for (i <- bb) {
if (!retry) {
i match {
case CALL_METHOD(msym, Dynamic) =>
@@ -308,11 +319,11 @@ abstract class Inliners extends SubComponent {
if (receiver != msym.owner && receiver != NoSymbol) {
if (settings.debug.value)
log("" + i + " has actual receiver: " + receiver);
- }
- if (!concreteMethod.isFinal && receiver.isFinal) {
- concreteMethod = lookupImpl(concreteMethod, receiver)
- if (settings.debug.value)
- log("\tlooked up method: " + concreteMethod.fullNameString)
+ if (!concreteMethod.isFinal && receiver.isFinal) {
+ concreteMethod = lookupImpl(concreteMethod, receiver)
+ if (settings.debug.value)
+ log("\tlooked up method: " + concreteMethod.fullNameString)
+ }
}
if (shouldLoad(receiver, concreteMethod)) {
@@ -372,7 +383,7 @@ abstract class Inliners extends SubComponent {
// e.printStackTrace();
// m.dump
// throw e
- }
+ }
def isMonadMethod(method: Symbol): Boolean =
@@ -427,7 +438,7 @@ abstract class Inliners extends SubComponent {
callsNonPublic = b
case None =>
breakable {
- for (b <- callee.code.blocks; i <- b.toList)
+ for (b <- callee.code.blocks; i <- b)
i match {
case CALL_METHOD(m, style) =>
if (m.hasFlag(Flags.PRIVATE) ||
diff --git a/src/compiler/scala/tools/nsc/dependencies/Changes.scala b/src/compiler/scala/tools/nsc/dependencies/Changes.scala
index 80a068dcdf..3c6184bc24 100644
--- a/src/compiler/scala/tools/nsc/dependencies/Changes.scala
+++ b/src/compiler/scala/tools/nsc/dependencies/Changes.scala
@@ -92,15 +92,9 @@ abstract class Changes {
tp1.isInstanceOf[ImplicitMethodType] == tp2.isInstanceOf[ImplicitMethodType])
case (PolyType(tparams1, res1), PolyType(tparams2, res2)) =>
- (tparams1.length == tparams2.length &&
- List.forall2(tparams1, tparams2)
- ((p1, p2) => sameType(p1.info, p2.info)) &&
- sameType(res1, res2))
+ sameTypeParams(tparams1, tparams2) && sameType(res1, res2)
case (ExistentialType(tparams1, res1), ExistentialType(tparams2, res2)) =>
- (tparams1.length == tparams2.length &&
- List.forall2(tparams1, tparams2)
- ((p1, p2) => sameType(p1.info, p2.info)) &&
- sameType(res1, res2))
+ sameTypeParams(tparams1, tparams2) && sameType(res1, res2)
case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) =>
sameType(lo1, lo2) && sameType(hi1, hi2)
case (BoundedWildcardType(bounds), _) =>
@@ -133,9 +127,11 @@ abstract class Changes {
((tp1n ne tp1) || (tp2n ne tp2)) && sameType(tp1n, tp2n)
}
+ private def sameTypeParams(tparams1: List[Symbol], tparams2: List[Symbol]) =
+ sameTypes(tparams1 map (_.info), tparams2 map (_.info))
+
def sameTypes(tps1: List[Type], tps2: List[Type]): Boolean =
- (tps1.length == tps2.length
- && List.forall2(tps1, tps2)(sameType))
+ (tps1.length == tps2.length) && ((tps1, tps2).zipped forall sameType)
/** Return the list of changes between 'from' and 'to'.
*/
diff --git a/src/compiler/scala/tools/nsc/dependencies/Files.scala b/src/compiler/scala/tools/nsc/dependencies/Files.scala
index 501936ee4e..2165855ac9 100644
--- a/src/compiler/scala/tools/nsc/dependencies/Files.scala
+++ b/src/compiler/scala/tools/nsc/dependencies/Files.scala
@@ -4,11 +4,13 @@ package dependencies;
import java.io.{InputStream, OutputStream, PrintStream, InputStreamReader, BufferedReader}
import io.{AbstractFile, PlainFile}
-import scala.collection._;
+import scala.collection._;import scala.tools.nsc.io.VirtualFile
+
trait Files { self : SubComponent =>
class FileDependencies(val classpath : String) {
+ import FileDependencies._
class Tracker extends mutable.OpenHashMap[AbstractFile, mutable.Set[AbstractFile]]{
override def default(key: AbstractFile) = {
@@ -30,8 +32,10 @@ trait Files { self : SubComponent =>
def reset(file: AbstractFile) = dependencies -= file;
def cleanEmpty() = {
- dependencies.foreach({case (key, value) => value.retain(_.exists)})
+ dependencies foreach {case (key, value) => value.retain(x => x.exists && (x ne RemovedFile))}
dependencies.retain((key, value) => key.exists && !value.isEmpty)
+ targets foreach {case (key, value) => value.retain(_.exists)}
+ targets.retain((key, value) => key.exists && !value.isEmpty)
}
def containsFile(f: AbstractFile) = targets.contains(f.absolute)
@@ -50,7 +54,7 @@ trait Files { self : SubComponent =>
val indirect = dependentFiles(maxDepth, direct)
for ((source, targets) <- targets;
- if direct(source) || indirect(source)){
+ if direct(source) || indirect(source) || (source eq RemovedFile)){
targets.foreach(_.delete);
targets -= source;
}
@@ -65,7 +69,7 @@ trait Files { self : SubComponent =>
val indirect = new mutable.HashSet[AbstractFile];
val newInvalidations = new mutable.HashSet[AbstractFile];
- def invalid(file: AbstractFile) = indirect(file) || changed(file);
+ def invalid(file: AbstractFile) = indirect(file) || changed(file) || (file eq RemovedFile)
def go(i : Int) : Unit = if(i > 0){
newInvalidations.clear;
@@ -108,6 +112,7 @@ trait Files { self : SubComponent =>
object FileDependencies{
val Separator = "-------";
+ private val RemovedFile = new VirtualFile("removed")
def readFrom(file: AbstractFile, toFile : String => AbstractFile): Option[FileDependencies] = readFromFile(file) { in =>
val reader = new BufferedReader(new InputStreamReader(in))
@@ -116,14 +121,26 @@ trait Files { self : SubComponent =>
var line : String = null
while ({line = reader.readLine; (line != null) && (line != Separator)}){
line.split(" -> ") match {
- case Array(from, on) => it.depends(toFile(from), toFile(on));
+ case Array(from, on) =>
+ (toFile(from), toFile(on)) match {
+ case (null, _) => // fromFile is removed, it's ok
+ case (fromFile, null) => it.depends(fromFile, RemovedFile) // onFile is removed, should recompile fromFile
+ case (fromFile, onFile) => it.depends(fromFile, onFile)
+ }
case x => global.inform("Parse error: Unrecognised string " + line); return None
}
}
while ({line = reader.readLine; (line != null) && (line != Separator)}){
line.split(" -> ") match {
- case Array(source, target) => it.emits(toFile(source), toFile(target));
+ case Array(source, target) =>
+ val targetFile = toFile(target)
+ (toFile(source), toFile(target)) match {
+ case (null, null) => // source and target are all removed, it's ok
+ case (null, targetFile) => it.emits(RemovedFile, targetFile) // source is removed, should remove relative target later
+ case (_, null) => // it may has been cleaned outside, or removed during last phase
+ case (sourceFile, targetFile) => it.emits(sourceFile, targetFile)
+ }
case x => global.inform("Parse error: Unrecognised string " + line); return None
}
}
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index be3af86d53..b8a219fb4d 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -334,6 +334,16 @@ self =>
def stabilizedType(tree: Tree): Type = tree match {
case Ident(_) if tree.symbol.isStable => singleType(NoPrefix, tree.symbol)
case Select(qual, _) if tree.symbol.isStable => singleType(qual.tpe, tree.symbol)
+ case Import(expr, selectors) =>
+ tree.symbol.info match {
+ case analyzer.ImportType(expr) => expr match {
+ case s@Select(qual, name) => singleType(qual.tpe, s.symbol)
+ case i : Ident => i.tpe
+ case _ => tree.tpe
+ }
+ case _ => tree.tpe
+ }
+
case _ => tree.tpe
}
@@ -388,7 +398,16 @@ self =>
}
def typeMembers(pos: Position): List[TypeMember] = {
- val tree = typedTreeAt(pos)
+ val tree1 = typedTreeAt(pos)
+ val tree0 = tree1 match {
+ case tt : TypeTree => tt.original
+ case t => t
+ }
+ val tree = tree0 match {
+ case s@Select(qual, name) if s.tpe == ErrorType => qual
+ case t => t
+ }
+
println("typeMembers at "+tree+" "+tree.tpe)
val context = doLocateContext(pos)
val superAccess = tree.isInstanceOf[Super]
@@ -415,12 +434,13 @@ self =>
}
}
val pre = stabilizedType(tree)
- for (sym <- tree.tpe.decls)
+ val ownerTpe = if (tree.tpe != null) tree.tpe else pre
+ for (sym <- ownerTpe.decls)
addTypeMember(sym, pre, false, NoSymbol)
- for (sym <- tree.tpe.members)
+ for (sym <- ownerTpe.members)
addTypeMember(sym, pre, true, NoSymbol)
val applicableViews: List[SearchResult] =
- new ImplicitSearch(tree, functionType(List(tree.tpe), AnyClass.tpe), true, context.makeImplicit(false))
+ new ImplicitSearch(tree, functionType(List(ownerTpe), AnyClass.tpe), true, context.makeImplicit(false))
.allImplicits
for (view <- applicableViews) {
val vtree = viewApply(view)
@@ -443,24 +463,6 @@ self =>
}
}
- /** A traverser that resets all type and symbol attributes in a tree
- object ResetAttrs extends Transformer {
- override def transform(t: Tree): Tree = {
- if (t.hasSymbol) t.symbol = NoSymbol
- t match {
- case EmptyTree =>
- t
- case tt: TypeTree =>
- if (tt.original != null) tt.original
- else t
- case _ =>
- t.tpe = null
- super.transform(t)
- }
- }
- }
- */
-
/** The typer run */
class TyperRun extends Run {
// units is always empty
diff --git a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
index 2e6041f4c4..78d3b55a3b 100644
--- a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
+++ b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
@@ -71,7 +71,7 @@ self: scala.tools.nsc.Global =>
Range(new RangePosition(null, lo, lo, hi), EmptyTree)
/** The maximal free range */
- private lazy val maxFree: Range = free(0, Math.MAX_INT)
+ private lazy val maxFree: Range = free(0, Int.MaxValue)
/** A singleton list of a non-empty range from `lo` to `hi`, or else the empty List */
private def maybeFree(lo: Int, hi: Int) =
diff --git a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala
index fdc2fd3a24..6af23f8fde 100644
--- a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala
+++ b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala
@@ -118,7 +118,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana
}
}
// Create a change for the top level classes that were removed
- val removed = definitions(src) remove ((s: Symbol) =>
+ val removed = definitions(src) filterNot ((s: Symbol) =>
syms.find(_.fullNameString == s.fullNameString) match {
case None => false
case _ => true
@@ -131,7 +131,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana
println("Changes: " + changesOf)
updateDefinitions(files)
val compiled = updated ++ files
- val invalid = invalidated(files, changesOf, additionalDefs ++ compiled)
+ val invalid = invalidated(files, changesOf, additionalDefs.clone() ++= compiled)
update0(invalid -- compiled, compiled)
}
@@ -224,7 +224,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana
if (buf.isEmpty)
processed
else
- invalidated(buf -- processed, newChangesOf, processed ++ buf)
+ invalidated(buf.clone() --= processed, newChangesOf, processed ++ buf)
}
/** Update the map of definitions per source file */
diff --git a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
index cf41852652..02df1d7318 100644
--- a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
@@ -7,7 +7,7 @@ package scala.tools.nsc
package interpreter
import scala.tools.nsc.io.AbstractFile
-import scala.util.ScalaClassLoader
+import util.ScalaClassLoader
/**
* A class loader that loads files from a {@link scala.tools.nsc.io.AbstractFile}.
diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
index fed2a6c5c1..7c8c6e6ef4 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
@@ -62,7 +62,7 @@ class Completion(val interpreter: Interpreter) extends Completor {
def filt(xs: List[String]) = xs filter (_ startsWith stub)
case class Result(candidates: List[String], position: Int) {
- def getCandidates() = (candidates map (_.trim) removeDuplicates) sort (_ < _)
+ def getCandidates() = (candidates map (_.trim) removeDuplicates) sortWith (_ < _)
}
// work out completion candidates and position
diff --git a/src/compiler/scala/tools/nsc/io/File.scala b/src/compiler/scala/tools/nsc/io/File.scala
index 294139ba44..1fbe384bfa 100644
--- a/src/compiler/scala/tools/nsc/io/File.scala
+++ b/src/compiler/scala/tools/nsc/io/File.scala
@@ -90,7 +90,7 @@ with Streamable.Chars
val dest = destPath.toFile
if (!isValid) fail("Source %s is not a valid file." format name)
if (this.normalize == dest.normalize) fail("Source and destination are the same.")
- if (!dest.parent.map(_.exists).getOrElse(false)) fail("Destination cannot be created.")
+ if (!dest.parent.exists) fail("Destination cannot be created.")
if (dest.exists && !dest.canWrite) fail("Destination exists but is not writable.")
if (dest.isDirectory) fail("Destination exists but is a directory.")
diff --git a/src/compiler/scala/tools/nsc/io/Path.scala b/src/compiler/scala/tools/nsc/io/Path.scala
index 37cc64cf75..64a313b00f 100644
--- a/src/compiler/scala/tools/nsc/io/Path.scala
+++ b/src/compiler/scala/tools/nsc/io/Path.scala
@@ -66,6 +66,7 @@ import Path._
class Path private[io] (val jfile: JFile)
{
val separator = JFile.separatorChar
+ val separatorStr = JFile.separator
// Validation: this verifies that the type of this object and the
// contents of the filesystem are in agreement. All objects are
@@ -83,7 +84,7 @@ class Path private[io] (val jfile: JFile)
/** Creates a new Path with the specified path appended. Assumes
* the type of the new component implies the type of the result.
*/
- def /(child: Path): Path = new Path(new JFile(jfile, child.path))
+ def /(child: Path): Path = if (isEmpty) child else new Path(new JFile(jfile, child.path))
def /(child: Directory): Directory = /(child: Path).toDirectory
def /(child: File): File = /(child: Path).toFile
@@ -91,17 +92,42 @@ class Path private[io] (val jfile: JFile)
def name: String = jfile.getName()
def path: String = jfile.getPath()
def normalize: Path = Path(jfile.getCanonicalPath())
- // todo -
- // def resolve(other: Path): Path
- // def relativize(other: Path): Path
+
+ def resolve(other: Path) = if (other.isAbsolute || isEmpty) other else /(other)
+ def relativize(other: Path) = {
+ assert(isAbsolute == other.isAbsolute, "Paths not of same type: "+this+", "+other)
+
+ def createRelativePath(baseSegs: List[String], otherSegs: List[String]) : String = {
+ (baseSegs, otherSegs) match {
+ case (b :: bs, o :: os) if b == o => createRelativePath(bs, os)
+ case (bs, os) => ((".."+separator)*bs.length)+os.mkString(separatorStr)
+ }
+ }
+
+ Path(createRelativePath(segments, other.segments))
+ }
// derived from identity
def root: Option[Path] = roots find (this startsWith _)
- def segments: List[String] = (path split separator).toList filterNot (_.isEmpty)
- def parent: Option[Path] = Option(jfile.getParent()) map Path.apply
- def parents: List[Path] = parent match {
- case None => Nil
- case Some(p) => p :: p.parents
+ def segments: List[String] = (path split separator).toList filterNot (_.length == 0)
+ /**
+ * @return The path of the parent directory, or root if path is already root
+ */
+ def parent: Path = {
+ val p = path match {
+ case "" | "." => ".."
+ case _ if path endsWith ".." => path + separator + ".." // the only solution
+ case _ => jfile.getParent match {
+ case null if isAbsolute => path // it should be a root. BTW, don't need to worry about relative pathed root
+ case null => "." // a file ot dir under pwd
+ case x => x
+ }
+ }
+ new Directory(new JFile(p))
+ }
+ def parents: List[Path] = {
+ val p = parent
+ if (p isSame this) Nil else p :: p.parents
}
// if name ends with an extension (e.g. "foo.jpg") returns the extension ("jpg"), otherwise ""
def extension: String = (name lastIndexOf '.') match {
@@ -119,10 +145,11 @@ class Path private[io] (val jfile: JFile)
def isDirectory = jfile.isDirectory()
def isAbsolute = jfile.isAbsolute()
def isHidden = jfile.isHidden()
- def isSymlink = parent.isDefined && {
- val x = parent.get / name
+ def isSymlink = {
+ val x = parent / name
x.normalize != x.toAbsolute
}
+ def isEmpty = path.length == 0
// Information
def lastModified = jfile.lastModified()
@@ -132,7 +159,7 @@ class Path private[io] (val jfile: JFile)
// Boolean path comparisons
def endsWith(other: Path) = segments endsWith other.segments
def startsWith(other: Path) = segments startsWith other.segments
- def isSame(other: Path) = toAbsolute == other.toAbsolute
+ def isSame(other: Path) = normalize == other.normalize
def isFresher(other: Path) = lastModified > other.lastModified
// creations
diff --git a/src/compiler/scala/tools/nsc/io/PlainFile.scala b/src/compiler/scala/tools/nsc/io/PlainFile.scala
index 926f5ee042..ef10b6d6bd 100644
--- a/src/compiler/scala/tools/nsc/io/PlainFile.scala
+++ b/src/compiler/scala/tools/nsc/io/PlainFile.scala
@@ -38,7 +38,7 @@ class PlainFile(val givenPath: Path) extends AbstractFile {
/** The absolute file. */
def absolute = new PlainFile(givenPath.normalize)
- override def container: AbstractFile = new PlainFile(givenPath.parent.get)
+ override def container: AbstractFile = new PlainFile(givenPath.parent)
override def input = givenPath.toFile.inputStream()
override def output = givenPath.toFile.outputStream()
override def sizeOption = Some(givenPath.length.toInt)
diff --git a/src/compiler/scala/tools/nsc/io/VirtualFile.scala b/src/compiler/scala/tools/nsc/io/VirtualFile.scala
index 90769d7086..65e7e34d88 100644
--- a/src/compiler/scala/tools/nsc/io/VirtualFile.scala
+++ b/src/compiler/scala/tools/nsc/io/VirtualFile.scala
@@ -68,7 +68,7 @@ class VirtualFile(val name: String, _path: String) extends AbstractFile
def isDirectory: Boolean = false
/** Returns the time that this abstract file was last modified. */
- def lastModified: Long = Math.MIN_LONG
+ def lastModified: Long = Long.MinValue
/** Returns all abstract subfiles of this abstract directory. */
def iterator: Iterator[AbstractFile] = {
diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala
index 2ffea32307..9d7889ccc2 100644
--- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala
+++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala
@@ -836,7 +836,7 @@ trait JavaScanners {
var value: Long = 0
val divider = if (base == 10) 1 else 2
val limit: Long =
- if (token == LONGLIT) Math.MAX_LONG else Math.MAX_INT
+ if (token == LONGLIT) Long.MaxValue else Int.MaxValue
var i = 0
val len = name.length
while (i < len) {
@@ -864,7 +864,7 @@ trait JavaScanners {
*/
def floatVal(negated: Boolean): Double = {
val limit: Double =
- if (token == DOUBLELIT) Math.MAX_DOUBLE else Math.MAX_FLOAT
+ if (token == DOUBLELIT) Double.MaxValue else Float.MaxValue
try {
val value: Double = java.lang.Double.valueOf(name.toString()).doubleValue()
if (value > limit)
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index d87eb29cf1..57a49cd461 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -53,20 +53,19 @@ trait ParallelMatching extends ast.TreeDSL
-shortCuts.length
}
- // XXX transitional.
- final def requestBody(bx: Int, subst: Bindings): Tree =
- requestBody(bx, PatternVarGroup.fromBindings(subst.get(), targets(bx).freeVars))
-
/** first time bx is requested, a LabelDef is returned. next time, a jump.
* the function takes care of binding
*/
- final def requestBody(bx: Int, pvgroup: PatternVarGroup): Tree = {
+ final def requestBody(bx: Int, subst: Bindings): Tree = {
+ // shortcut
+ if (bx < 0)
+ return Apply(ID(shortCuts(-bx-1)), Nil)
+
+ val pvgroup = PatternVarGroup.fromBindings(subst.get(), targets(bx).freeVars)
val target = targets(bx)
- // shortcut
- if (bx < 0) Apply(ID(shortCuts(-bx-1)), Nil)
// first time this bx is requested - might be bound elsewhere
- else if (target.isNotReached) target.createLabelBody(bx, pvgroup)
+ if (target.isNotReached) target.createLabelBody(bx, pvgroup)
// call label "method" if possible
else target.getLabelBody(pvgroup)
}
@@ -454,17 +453,17 @@ trait ParallelMatching extends ast.TreeDSL
private lazy val rowsplit = {
require(scrut.tpe <:< head.tpe)
- List.unzip(
- for ((c, rows) <- pmatch pzip rest.rows) yield {
- def canSkip = pivot canSkipSubsequences c
- def passthrough(skip: Boolean) = if (skip) None else Some(rows insert c)
+ val res = for ((c, rows) <- pmatch pzip rest.rows) yield {
+ def canSkip = pivot canSkipSubsequences c
+ def passthrough(skip: Boolean) = if (skip) None else Some(rows insert c)
- pivot.subsequences(c, scrut.seqType) match {
- case Some(ps) => (Some(rows insert ps), passthrough(canSkip))
- case None => (None, passthrough(false))
- }
+ pivot.subsequences(c, scrut.seqType) match {
+ case Some(ps) => (Some(rows insert ps), passthrough(canSkip))
+ case None => (None, passthrough(false))
}
- ) match { case (l1, l2) => (l1.flatten, l2.flatten) }
+ }
+
+ res.unzip match { case (l1, l2) => (l1.flatten, l2.flatten) }
}
lazy val cond = (pivot precondition pmatch).get // length check
@@ -477,7 +476,7 @@ trait ParallelMatching extends ast.TreeDSL
// @todo: equals test for same constant
class MixEquals(val pmatch: PatternMatch, val rest: Rep) extends RuleApplication {
private lazy val labelBody =
- remake(List.map2(rest.rows.tail, pmatch.tail)(_ insert _)).toTree
+ remake((rest.rows.tail, pmatch.tail).zipped map (_ insert _)).toTree
private lazy val rhs =
decodedEqualsType(head.tpe) match {
@@ -511,8 +510,11 @@ trait ParallelMatching extends ast.TreeDSL
case class Yes(bx: Int, moreSpecific: Pattern, subsumed: List[Pattern])
case class No(bx: Int, remaining: Pattern)
- val (yeses, noes) : (List[Yes], List[No]) = List.unzip(
- for ((pattern, j) <- pmatch.pzip()) yield {
+ val (yeses, noes) = {
+ val _ys = new ListBuffer[Yes]
+ val _ns = new ListBuffer[No]
+
+ for ((pattern, j) <- pmatch.pzip()) {
// scrutinee, head of pattern group
val (s, p) = (pattern.tpe, head.necessaryType)
@@ -530,7 +532,7 @@ trait ParallelMatching extends ast.TreeDSL
def typed(pp: Tree) = passl(ifEquiv(Pattern(pp)))
def subs() = passl(ifEquiv(NoPattern), pattern subpatterns pmatch)
- (pattern match {
+ val (oneY, oneN) = pattern match {
case Pattern(LIT(null), _) if !(p =:= s) => (None, passr) // (1)
case x if isObjectTest => (passl(), None) // (2)
case Pattern(Typed(pp, _), _) if sMatchesP => (typed(pp), None) // (4)
@@ -538,9 +540,12 @@ trait ParallelMatching extends ast.TreeDSL
case x if !x.isDefault && sMatchesP => (subs(), None)
case x if x.isDefault || pMatchesS => (passl(), passr)
case _ => (None, passr)
- }) : (Option[Yes], Option[No])
+ }
+ oneY map (_ys +=)
+ oneN map (_ns +=)
}
- ) match { case (x,y) => (x.flatten, y.flatten) }
+ (_ys.toList, _ns.toList)
+ }
val moreSpecific = yeses map (_.moreSpecific)
val subsumed = yeses map (x => (x.bx, x.subsumed))
@@ -739,12 +744,10 @@ trait ParallelMatching extends ast.TreeDSL
/** Cut out the column containing the non-default pattern. */
class Cut(index: Int) {
/** The first two separate out the 'i'th pattern in each row from the remainder. */
- private val (_column, _rows) =
- List.unzip(rows map (_ extractColumn index))
+ private val (_column, _rows) = rows map (_ extractColumn index) unzip
/** Now the 'i'th tvar is separated out and used as a new Scrutinee. */
- private val (_pv, _tvars) =
- tvars extractIndex index
+ private val (_pv, _tvars) = tvars extractIndex index
/** The non-default pattern (others.head) replaces the column head. */
private val (_ncol, _nrep) =
diff --git a/src/compiler/scala/tools/nsc/models/Signatures.scala b/src/compiler/scala/tools/nsc/models/Signatures.scala
index 98bfa142ff..0d75cf7101 100644
--- a/src/compiler/scala/tools/nsc/models/Signatures.scala
+++ b/src/compiler/scala/tools/nsc/models/Signatures.scala
@@ -25,14 +25,10 @@ class Signatures(val compiler: Compiler) {
def asString: String = name + "[" + asString0(children) + "]"
}
- def sort(sigs: List[Signature]) =
- sigs.sort((l0,l1) => l0.name.compareTo(l1.name) > 0)
+ def sort(sigs: List[Signature]) = sigs sortBy (_.name) reverse
- def asString0(sigs: List[Signature]): String = {
- var ret = ""
- for (sig <- sort(sigs)) ret = ret + sig.asString
- ret
- }
+ def asString0(sigs: List[Signature]): String =
+ sort(sigs) map (_.asString) mkString
def signature(unit: CompilationUnit): String =
asString0(signature(unit.body, Nil))
diff --git a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala
index 6c29ab5cf3..9bd2a79449 100644
--- a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala
+++ b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala
@@ -8,7 +8,7 @@ package symtab
// todo implement in terms of BitSet
import scala.collection.mutable.ListBuffer
import scala.collection.immutable.Map
-import Math.max
+import math.max
/** A base type sequence (BaseTypeSeq) is an ordered sequence spanning all the base types
* of a type. It characterized by the following two laws:
@@ -137,7 +137,7 @@ trait BaseTypeSeqs {
protected def maxDepthOfElems = {
var d = 0
- for (i <- 0 until length) d = Math.max(d, maxDpth(elems(i)))
+ for (i <- 0 until length) d = max(d, maxDpth(elems(i)))
d
}
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 25c60c32b8..c32a6fffd8 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -51,6 +51,25 @@ trait Definitions {
lazy val anyvalparam = List(AnyValClass.typeConstructor)
lazy val anyrefparam = List(AnyRefClass.typeConstructor)
+ // private parameter conveniences
+ private def booltype = BooleanClass.typeConstructor
+ private def boolparam = List(booltype)
+ private def bytetype = ByteClass.typeConstructor
+ private def byteparam = List(bytetype)
+ private def shorttype = ShortClass.typeConstructor
+ private def shortparam = List(shorttype)
+ private def inttype = IntClass.typeConstructor
+ private def intparam = List(inttype)
+ private def longtype = LongClass.typeConstructor
+ private def longparam = List(longtype)
+ private def floattype = FloatClass.typeConstructor
+ private def floatparam = List(floattype)
+ private def doubletype = DoubleClass.typeConstructor
+ private def doubleparam = List(doubletype)
+ private def chartype = CharClass.typeConstructor
+ private def charparam = List(chartype)
+ private def stringtype = StringClass.typeConstructor
+
// top types
lazy val AnyClass = newClass(ScalaPackageClass, nme.Any, Nil) setFlag (ABSTRACT)
lazy val AnyValClass = newClass(ScalaPackageClass, nme.AnyVal, anyparam) setFlag (ABSTRACT | SEALED)
@@ -76,6 +95,11 @@ trait Definitions {
def Boolean_and = getMember(BooleanClass, nme.ZAND)
def Boolean_or = getMember(BooleanClass, nme.ZOR)
+ def ScalaValueClasses = List(
+ UnitClass, ByteClass, ShortClass, IntClass, LongClass,
+ CharClass, FloatClass, DoubleClass, BooleanClass
+ )
+
// exceptions and other throwables
lazy val ThrowableClass = getClass(sn.Throwable)
lazy val NullPointerExceptionClass = getClass(sn.NPException)
@@ -106,6 +130,7 @@ trait Definitions {
// fundamental reference classes
lazy val ScalaObjectClass = getClass("scala.ScalaObject")
lazy val PartialFunctionClass = getClass("scala.PartialFunction")
+ lazy val SymbolClass = getClass("scala.Symbol")
lazy val StringClass = getClass(sn.String)
lazy val ClassClass = getClass(sn.Class)
def Class_getMethod = getMember(ClassClass, nme.getMethod_)
@@ -122,9 +147,8 @@ trait Definitions {
def Predef_conforms = getMember(PredefModule, nme.conforms)
lazy val ConsoleModule: Symbol = getModule("scala.Console")
lazy val ScalaRunTimeModule: Symbol = getModule("scala.runtime.ScalaRunTime")
+ lazy val SymbolModule: Symbol = getModule("scala.Symbol")
def SeqFactory = getMember(ScalaRunTimeModule, nme.Seq)
- def checkDefinedMethod = getMember(ScalaRunTimeModule, "checkDefined")
- def isArrayMethod = getMember(ScalaRunTimeModule, "isArray")
def arrayApplyMethod = getMember(ScalaRunTimeModule, "array_apply")
def arrayUpdateMethod = getMember(ScalaRunTimeModule, "array_update")
def arrayLengthMethod = getMember(ScalaRunTimeModule, "array_length")
@@ -227,6 +251,8 @@ trait Definitions {
def optionType(tp: Type) = typeRef(OptionClass.typeConstructor.prefix, OptionClass, List(tp))
def someType(tp: Type) = typeRef(SomeClass.typeConstructor.prefix, SomeClass, List(tp))
+ def symbolType = typeRef(SymbolClass.typeConstructor.prefix, SymbolClass, List())
+ def longType = typeRef(LongClass.typeConstructor.prefix, LongClass, List())
// Product, Tuple, Function
private def mkArityArray(name: String, arity: Int, countFrom: Int = 1) = {
@@ -351,8 +377,13 @@ trait Definitions {
var Object_== : Symbol = _
var Object_!= : Symbol = _
var Object_synchronized: Symbol = _
- var Object_isInstanceOf: Symbol = _
- var Object_asInstanceOf: Symbol = _
+ lazy val Object_isInstanceOf = newPolyMethod(
+ ObjectClass, "$isInstanceOf",
+ tparam => MethodType(List(), booltype)) setFlag FINAL
+ lazy val Object_asInstanceOf = newPolyMethod(
+ ObjectClass, "$asInstanceOf",
+ tparam => MethodType(List(), tparam.typeConstructor)) setFlag FINAL
+
def Object_getClass = getMember(ObjectClass, nme.getClass_)
def Object_clone = getMember(ObjectClass, nme.clone_)
def Object_finalize = getMember(ObjectClass, nme.finalize_)
@@ -367,9 +398,6 @@ trait Definitions {
// boxed classes
lazy val ObjectRefClass = getClass("scala.runtime.ObjectRef")
lazy val BoxesRunTimeClass = getModule("scala.runtime.BoxesRunTime")
- lazy val BoxedArrayClass = getClass("scala.runtime.BoxedArray")
- lazy val BoxedAnyArrayClass = getClass("scala.runtime.BoxedAnyArray")
- lazy val BoxedObjectArrayClass = getClass("scala.runtime.BoxedObjectArray")
lazy val BoxedNumberClass = getClass(sn.BoxedNumber)
lazy val BoxedCharacterClass = getClass(sn.BoxedCharacter)
lazy val BoxedBooleanClass = getClass(sn.BoxedBoolean)
@@ -380,6 +408,18 @@ trait Definitions {
lazy val BoxedFloatClass = getClass("java.lang.Float")
lazy val BoxedDoubleClass = getClass("java.lang.Double")
+ /** The various ways a boxed primitive might materialize at runtime. */
+ def isMaybeBoxed(sym: Symbol) =
+ if (forMSIL)
+ sym isNonBottomSubClass BoxedNumberClass
+ else {
+ (sym == ObjectClass) ||
+ (sym == SerializableClass) ||
+ (sym == ComparableClass) ||
+ (sym isNonBottomSubClass BoxedNumberClass) ||
+ (sym isNonBottomSubClass BoxedCharacterClass)
+ }
+
lazy val BoxedUnitClass = getClass("scala.runtime.BoxedUnit")
lazy val BoxedUnitModule = getModule("scala.runtime.BoxedUnit")
def BoxedUnit_UNIT = getMember(BoxedUnitModule, "UNIT")
@@ -525,7 +565,6 @@ trait Definitions {
val boxedModule = new HashMap[Symbol, Symbol]
val unboxMethod = new HashMap[Symbol, Symbol] // Type -> Method
val boxMethod = new HashMap[Symbol, Symbol] // Type -> Method
- val boxedArrayClass = new HashMap[Symbol, Symbol]
def isUnbox(m: Symbol) = (m.name == nme.unbox) && cond(m.tpe) {
case MethodType(_, restpe) => cond(unboxMethod get restpe.typeSymbol) {
@@ -550,7 +589,6 @@ trait Definitions {
val clazz = newClass(ScalaPackageClass, name, anyvalparam) setFlag (ABSTRACT | FINAL)
boxedClass(clazz) = getClass(boxedName)
boxedModule(clazz) = getModule(boxedName)
- boxedArrayClass(clazz) = getClass("scala.runtime.Boxed" + name + "Array")
refClass(clazz) = getClass("scala.runtime." + name + "Ref")
abbrvTag(clazz) = tag
if (width > 0) numericWidth(clazz) = width
@@ -572,26 +610,6 @@ trait Definitions {
/** Sets-up symbols etc. for value classes, and their boxed versions. This
* method is called once from within the body of init. */
private def initValueClasses() {
- val booltype = BooleanClass.typeConstructor
- val boolparam = List(booltype)
- val bytetype = ByteClass.typeConstructor
- val byteparam = List(bytetype)
- val chartype = CharClass.typeConstructor
- val charparam = List(chartype)
- val shorttype = ShortClass.typeConstructor
- val shortparam = List(shorttype)
- val inttype = IntClass.typeConstructor
- val intparam = List(inttype)
- val longtype = LongClass.typeConstructor
- val longparam = List(longtype)
-
- val floattype = FloatClass.typeConstructor
- val floatparam = List(floattype)
- val doubletype = DoubleClass.typeConstructor
- val doubleparam = List(doubletype)
-
- val stringtype = StringClass.typeConstructor
-
// init scala.Boolean
newParameterlessMethod(BooleanClass, nme.UNARY_!, booltype)
List(nme.EQ, nme.NE, nme.ZOR, nme.ZAND, nme.OR, nme.AND, nme.XOR) foreach {
@@ -619,7 +637,6 @@ trait Definitions {
newParameterlessMethod(clazz, nme.toChar, chartype)
newParameterlessMethod(clazz, nme.toInt, inttype)
newParameterlessMethod(clazz, nme.toLong, longtype)
-
newParameterlessMethod(clazz, nme.toFloat, floattype)
newParameterlessMethod(clazz, nme.toDouble, doubletype)
@@ -730,7 +747,7 @@ trait Definitions {
if (isInitialized) return
isInitialized = true
- EmptyPackageClass.setInfo(ClassInfoType(List(), new Scope, EmptyPackageClass))
+ EmptyPackageClass.setInfo(ClassInfoType(Nil, new Scope, EmptyPackageClass))
EmptyPackage.setInfo(EmptyPackageClass.tpe)
RootClass.info.decls.enter(EmptyPackage)
RootClass.info.decls.enter(RootPackage)
@@ -738,16 +755,13 @@ trait Definitions {
abbrvTag(UnitClass) = 'V'
initValueClasses()
- val booltype = BooleanClass.typeConstructor
// members of class scala.Any
Any_== = newMethod(AnyClass, nme.EQ, anyparam, booltype) setFlag FINAL
Any_!= = newMethod(AnyClass, nme.NE, anyparam, booltype) setFlag FINAL
Any_equals = newMethod(AnyClass, nme.equals_, anyparam, booltype)
- Any_hashCode = newMethod(
- AnyClass, nme.hashCode_, List(), IntClass.typeConstructor)
- Any_toString = newMethod(
- AnyClass, nme.toString_, List(), StringClass.typeConstructor)
+ Any_hashCode = newMethod(AnyClass, nme.hashCode_, Nil, inttype)
+ Any_toString = newMethod(AnyClass, nme.toString_, Nil, stringtype)
Any_isInstanceOf = newPolyMethod(
AnyClass, nme.isInstanceOf_, tparam => booltype) setFlag FINAL
@@ -762,16 +776,11 @@ trait Definitions {
Object_synchronized = newPolyMethodCon(
ObjectClass, nme.synchronized_,
tparam => msym => MethodType(msym.newSyntheticValueParams(List(tparam.typeConstructor)), tparam.typeConstructor)) setFlag FINAL
- Object_isInstanceOf = newPolyMethod(
- ObjectClass, "$isInstanceOf",
- tparam => MethodType(List(), booltype)) setFlag FINAL
- Object_asInstanceOf = newPolyMethod(
- ObjectClass, "$asInstanceOf",
- tparam => MethodType(List(), tparam.typeConstructor)) setFlag FINAL
+
String_+ = newMethod(
- StringClass, "+", anyparam, StringClass.typeConstructor) setFlag FINAL
+ StringClass, "+", anyparam, stringtype) setFlag FINAL
- val forced = List( // force initialization of every symbol that is enetred as a side effect
+ val forced = List( // force initialization of every symbol that is entered as a side effect
AnnotationDefaultAttr,
RepeatedParamClass,
JavaRepeatedParamClass,
@@ -791,7 +800,9 @@ trait Definitions {
NullClass,
NothingClass,
SingletonClass,
- EqualsPatternClass
+ EqualsPatternClass,
+ Object_isInstanceOf,
+ Object_asInstanceOf
)
// #2264
diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
index 3c5b866ba8..990d6dc463 100644
--- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala
+++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
@@ -268,8 +268,6 @@ trait StdNames {
val assume_ = newTermName("assume")
val asInstanceOf_ = newTermName("asInstanceOf")
val box = newTermName("box")
- val boxArray = newTermName("boxArray")
- val forceBoxedArray = newTermName("forceBoxedArray")
val canEqual_ = newTermName("canEqual")
val checkInitialized = newTermName("checkInitialized")
val classOf = newTermName("classOf")
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolWalker.scala b/src/compiler/scala/tools/nsc/symtab/SymbolWalker.scala
index 5f0574b525..f2e16b537a 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolWalker.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolWalker.scala
@@ -20,32 +20,35 @@ trait SymbolWalker {
def apply(pos : Position) : Symbol = map.apply(pos)
}
*/
+ private def validSym(t: Tree) = t.symbol != NoSymbol && t.symbol != null
+ private def validSym(tp: Type) = tp != null && tp.typeSymbol != NoSymbol && tp.typeSymbol != null
+ private def notNull(tp: Type) = tp.typeSymbol != null
+ private def isNoSymbol(t: Tree) = t.symbol eq NoSymbol
+
def walk(tree: Tree, visitor : Visitor)(fid : (util.Position) => Option[String]) : Unit = {
val visited = new LinkedHashSet[Tree]
def f(t : Tree) : Unit = {
if (visited.add(t)) return
- def fs(l : List[Tree]) : Unit = {
- val i = l.iterator
- while (i.hasNext) f(i.next)
- }
- def fss(l : List[List[Tree]]) : Unit = {
- val i = l.iterator
- while (i.hasNext) fs(i.next)
- }
+
+ def fs(l: List[Tree]) = l foreach f
+ def fss(l: List[List[Tree]]) = l foreach fs
+
if (t.isInstanceOf[StubTree]) return
- def asTypeRef = t.tpe.asInstanceOf[TypeRef]
- val sym = (t,t.tpe) match {
- case (Super(_,_),SuperType(_,supertp)) if supertp.typeSymbol != NoSymbol && supertp.typeSymbol != null => supertp.typeSymbol
- case _ if t.symbol != NoSymbol && t.symbol != null => t.symbol
- case (t : TypeTree, tp) if tp != null && tp.typeSymbol != null && tp.typeSymbol != NoSymbol => tp.typeSymbol
- case (t : TypeTree, tp) if tp != null && tp.resultType != null && tp.resultType.typeSymbol != null => tp.resultType.typeSymbol
- case (t, tpe : Type) if tpe != null && (t.symbol eq NoSymbol) && t.isTerm && tpe.termSymbol != null =>
- tpe.termSymbol
- case (t, tpe : Type) if tpe != null && (t.symbol eq NoSymbol) && tpe.typeSymbol != null =>
- if (t.tpe.isInstanceOf[TypeRef]) asTypeRef.sym // XXX: looks like a bug
- else tpe.typeSymbol
- case _ => NoSymbol
+
+ val sym = (t, t.tpe) match {
+ case (Super(_,_),SuperType(_,supertp)) if validSym(supertp) => supertp.typeSymbol
+ case _ if validSym(t) => t.symbol
+ case (t: TypeTree, tp) if validSym(tp) => tp.typeSymbol
+ case (t: TypeTree, tp) if validSym(tp.resultType) => tp.resultType.typeSymbol
+ case (t, tpe: Type) if isNoSymbol(t) && tpe.termSymbol != null =>
+ if (t.isTerm) tpe.termSymbol
+ else t.tpe match {
+ case x: TypeRef => x.sym // XXX: looks like a bug
+ case _ => tpe.typeSymbol
+ }
+ case _ => NoSymbol
}
+
if (sym != null && sym != NoSymbol /* && !sym.hasFlag(SYNTHETIC) */) {
var id = fid(t.pos)
val doAdd = if (id.isDefined) {
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index e4cbe159a1..1634e04025 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -112,7 +112,7 @@ trait Symbols {
* the annotations attached to member a definition (class, method, type, field).
*/
def annotations: List[AnnotationInfo] = {
- // .initialize: the type completer of the symbol parses the annotations,
+ // .initialize: the type completer o f the symbol parses the annotations,
// see "def typeSig" in Namers
val annots1 = initialize.rawannots map {
case LazyAnnotationInfo(annot) => annot()
@@ -563,14 +563,14 @@ trait Symbols {
final def isStaticOwner: Boolean =
isPackageClass || isModuleClass && isStatic
- /** Is this symbol final?*/
+ /** Is this symbol final? */
final def isFinal: Boolean = (
hasFlag(FINAL) ||
isTerm && (
hasFlag(PRIVATE) || isLocal || owner.isClass && owner.hasFlag(FINAL | MODULE))
)
- /** Is this symbol a sealed class?*/
+ /** Is this symbol a sealed class? */
final def isSealed: Boolean =
isClass && (hasFlag(SEALED) || isValueClass(this))
@@ -1166,9 +1166,10 @@ trait Symbols {
def renamedGetter = accessors find (_.originalName startsWith (getterName + "$"))
val accessorName = origGetter orElse renamedGetter
- accessorName getOrElse {
- throw new Error("Could not find case accessor for %s in %s".format(field, this))
- }
+ // This fails more gracefully rather than throw an Error as it used to because
+ // as seen in #2625, we can reach this point with an already erroneous tree.
+ accessorName getOrElse NoSymbol
+ // throw new Error("Could not find case accessor for %s in %s".format(field, this))
}
fields map findAccessor
@@ -1369,8 +1370,8 @@ trait Symbols {
/** The non-private member of `site' whose type and name match the type of this symbol
*/
- final def matchingSymbol(site: Type): Symbol =
- site.nonPrivateMember(name).filter(sym =>
+ final def matchingSymbol(site: Type, admit: Long = 0L): Symbol =
+ site.nonPrivateMemberAdmitting(name, admit).filter(sym =>
!sym.isTerm || (site.memberType(this) matches site.memberType(sym)))
/** The symbol overridden by this symbol in given class `ofclazz'.
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 6145c4a0d7..668f7149a9 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -1507,6 +1507,7 @@ trait Types {
private var baseTypeSeqPeriod = NoPeriod
override def isStable: Boolean = {
+ sym == NothingClass ||
sym == SingletonClass ||
sym.isAliasType && normalize.isStable ||
sym.isAbstractType && (bounds.hi.typeSymbol isSubClass SingletonClass)
@@ -1564,6 +1565,8 @@ A type's typeSymbol should never be inspected directly.
parentsPeriod = currentPeriod
if (!isValidForBaseClasses(period)) {
parentsCache = thisInfo.parents map transform
+ } else if (parentsCache == null) { // seems this can happen if things are currupted enough, see #2641
+ parentsCache = List(AnyClass.tpe)
}
}
parentsCache
@@ -1988,16 +1991,17 @@ A type's typeSymbol should never be inspected directly.
case class AntiPolyType(pre: Type, targs: List[Type]) extends Type {
override def safeToString =
pre.toString + targs.mkString("(with type arguments ", ",", ")");
- override def memberType(sym: Symbol) = pre.memberType(sym) match {
- case PolyType(tparams, restp) =>
- restp.subst(tparams, targs)
-/* I don't think this is needed, as existential types close only over value types
- case ExistentialType(tparams, qtpe) =>
- existentialAbstraction(tparams, qtpe.memberType(sym))
-*/
- case ErrorType =>
- ErrorType
- }
+ override def memberType(sym: Symbol) = appliedType(pre.memberType(sym), targs)
+// override def memberType(sym: Symbol) = pre.memberType(sym) match {
+// case PolyType(tparams, restp) =>
+// restp.subst(tparams, targs)
+// /* I don't think this is needed, as existential types close only over value types
+// case ExistentialType(tparams, qtpe) =>
+// existentialAbstraction(tparams, qtpe.memberType(sym))
+// */
+// case ErrorType =>
+// ErrorType
+// }
override def kind = "AntiPolyType"
}
@@ -2337,9 +2341,7 @@ A type's typeSymbol should never be inspected directly.
if (phase.erasedTypes)
if (parents.isEmpty) ObjectClass.tpe else parents.head
else {
- // having $anonfun as owner causes the pickler to break upon unpickling; see ticket #2323
- val nonAnonOwner = (owner.ownerChain dropWhile (_.isAnonymousFunction)).headOption getOrElse NoSymbol
- val clazz = nonAnonOwner.newRefinementClass(NoPosition)
+ val clazz = owner.newRefinementClass(NoPosition)
val result = refinementOfClass(clazz, parents, decls)
clazz.setInfo(result)
result
@@ -2520,16 +2522,19 @@ A type's typeSymbol should never be inspected directly.
else {
var occurCount = emptySymCount ++ (tparams map (_ -> 0))
val tpe = deAlias(tpe0)
- for (t <- tpe) {
- t match {
- case TypeRef(_, sym, _) =>
- occurCount get sym match {
- case Some(count) => occurCount += (sym -> (count + 1))
- case None =>
- }
- case _ =>
+ def countOccs(tp: Type) =
+ for (t <- tp) {
+ t match {
+ case TypeRef(_, sym, _) =>
+ occurCount get sym match {
+ case Some(count) => occurCount += (sym -> (count + 1))
+ case None =>
+ }
+ case _ =>
+ }
}
- }
+ countOccs(tpe)
+ for (tparam <- tparams) countOccs(tparam.info)
val extrapolate = new TypeMap {
variance = 1
@@ -2862,9 +2867,8 @@ A type's typeSymbol should never be inspected directly.
val clonedSyms = origSyms map (_.cloneSymbol)
val clonedInfos = clonedSyms map (_.info.substSym(origSyms, clonedSyms))
val transformedInfos = clonedInfos mapConserve (this)
- List.map2(clonedSyms, transformedInfos) {
- ((newSym, newInfo) => newSym.setInfo(newInfo))
- }
+ (clonedSyms, transformedInfos).zipped map (_ setInfo _)
+
clonedSyms
}
}
@@ -3287,8 +3291,10 @@ A type's typeSymbol should never be inspected directly.
class SubstWildcardMap(from: List[Symbol]) extends TypeMap {
def apply(tp: Type): Type = try {
tp match {
- case TypeRef(_, sym, _) if (from contains sym) => WildcardType
- case _ => mapOver(tp)
+ case TypeRef(_, sym, _) if (from contains sym) =>
+ BoundedWildcardType(sym.info.bounds)
+ case _ =>
+ mapOver(tp)
}
} catch {
case ex: MalformedType =>
@@ -3628,7 +3634,7 @@ A type's typeSymbol should never be inspected directly.
*/
def lubDepth(ts: List[Type]) = {
var d = 0
- for (tp <- ts) d = Math.max(d, tp.baseTypeSeqDepth)
+ for (tp <- ts) d = math.max(d, tp.baseTypeSeqDepth)
d + LubGlbMargin
}
@@ -3664,7 +3670,7 @@ A type's typeSymbol should never be inspected directly.
case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) =>
assert(sym1 == sym2)
pre1 =:= pre2 &&
- !(List.map3(args1, args2, sym1.typeParams) {
+ ((args1, args2, sym1.typeParams).zipped forall {
(arg1, arg2, tparam) =>
//if (tparam.variance == 0 && !(arg1 =:= arg2)) Console.println("inconsistent: "+arg1+"!="+arg2)//DEBUG
if (tparam.variance == 0) arg1 =:= arg2
@@ -3675,7 +3681,7 @@ A type's typeSymbol should never be inspected directly.
// also: think what happens if there are embedded typevars?
if (tparam.variance < 0) arg1 <:< arg2 else arg2 <:< arg1
else true
- } contains false)
+ })
case (et: ExistentialType, _) =>
et.withTypeVars(isConsistent(_, tp2))
case (_, et: ExistentialType) =>
@@ -3846,12 +3852,12 @@ A type's typeSymbol should never be inspected directly.
case (PolyType(tparams1, res1), PolyType(tparams2, res2)) =>
// assert((tparams1 map (_.typeParams.length)) == (tparams2 map (_.typeParams.length)))
(tparams1.length == tparams2.length &&
- List.forall2(tparams1, tparams2)
+ (tparams1, tparams2).zipped.forall
((p1, p2) => p1.info =:= p2.info.substSym(tparams2, tparams1)) && //@M looks like it might suffer from same problem as #2210
res1 =:= res2.substSym(tparams2, tparams1))
case (ExistentialType(tparams1, res1), ExistentialType(tparams2, res2)) =>
(tparams1.length == tparams2.length &&
- List.forall2(tparams1, tparams2)
+ (tparams1, tparams2).zipped.forall
((p1, p2) => p1.info =:= p2.info.substSym(tparams2, tparams1)) && //@M looks like it might suffer from same problem as #2210
res1 =:= res2.substSym(tparams2, tparams1))
case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) =>
@@ -3892,8 +3898,7 @@ A type's typeSymbol should never be inspected directly.
* types?
*/
def isSameTypes(tps1: List[Type], tps2: List[Type]): Boolean =
- tps1.length == tps2.length &&
- List.forall2(tps1, tps2)((tp1, tp2) => tp1 =:= tp2)
+ tps1.length == tps2.length && ((tps1, tps2).zipped forall (_ =:= _))
private var pendingSubTypes = new collection.mutable.HashSet[SubTypePair]
private var basetypeRecursions: Int = 0
@@ -3975,16 +3980,16 @@ A type's typeSymbol should never be inspected directly.
tparams1.length == tparams2.length && {
if(tparams1.isEmpty) res1 <:< res2 // fast-path: monomorphic nullary method type
else if(tparams1.head.owner.isMethod) { // fast-path: polymorphic method type -- type params cannot be captured
- List.forall2(tparams1, tparams2)((p1, p2) =>
- p2.info.substSym(tparams2, tparams1) <:< p1.info) &&
+ ((tparams1, tparams2).zipped forall ((p1, p2) =>
+ p2.info.substSym(tparams2, tparams1) <:< p1.info)) &&
res1 <:< res2.substSym(tparams2, tparams1)
} else { // normalized higher-kinded type
//@M for an example of why we need to generate fresh symbols, see neg/tcpoly_ticket2101.scala
val tpsFresh = cloneSymbols(tparams1) // @M cloneSymbols(tparams2) should be equivalent -- TODO: check
- (List.forall2(tparams1, tparams2)((p1, p2) =>
- p2.info.substSym(tparams2, tpsFresh) <:< p1.info.substSym(tparams1, tpsFresh)) &&
- res1.substSym(tparams1, tpsFresh) <:< res2.substSym(tparams2, tpsFresh))
+ ((tparams1, tparams2).zipped forall ((p1, p2) =>
+ p2.info.substSym(tparams2, tpsFresh) <:< p1.info.substSym(tparams1, tpsFresh))) &&
+ res1.substSym(tparams1, tpsFresh) <:< res2.substSym(tparams2, tpsFresh)
//@M the forall in the previous test could be optimised to the following,
// but not worth the extra complexity since it only shaves 1s from quick.comp
@@ -4030,7 +4035,7 @@ A type's typeSymbol should never be inspected directly.
/** First try, on the right:
* - unwrap Annotated types, BoundedWildcardTypes,
- * - bind TypeVars on the right, if lhs is not Annotated nor BoundedWildcard
+ * - bind TypeVars on the right, if lhs is not Annotated nor BoundedWildcard
* - handle common cases for first-kind TypeRefs on both sides as a fast path.
*/
def firstTry = tp2 match {
@@ -4201,8 +4206,7 @@ A type's typeSymbol should never be inspected directly.
* of `tps2'?
*/
def isSubTypes(tps1: List[Type], tps2: List[Type]): Boolean =
- tps1.length == tps2.length &&
- List.forall2(tps1, tps2)((tp1, tp2) => tp1 <:< tp2)
+ tps1.length == tps2.length && ((tps1, tps2).zipped forall (_ <:< _))
/** Does type `tp' implement symbol `sym' with same or
* stronger type? Exact only if `sym' is a member of some
@@ -4263,11 +4267,11 @@ A type's typeSymbol should never be inspected directly.
/** Are `tps1' and `tps2' lists of pairwise equivalent types? */
private def matchingParams(tps1: List[Type], tps2: List[Type], tps1isJava: Boolean, tps2isJava: Boolean): Boolean =
- tps1.length == tps2.length &&
- List.forall2(tps1, tps2)((tp1, tp2) =>
+ (tps1.length == tps2.length) &&
+ ((tps1, tps2).zipped forall ((tp1, tp2) =>
(tp1 =:= tp2) ||
tps1isJava && tp2.typeSymbol == ObjectClass && tp1.typeSymbol == AnyClass ||
- tps2isJava && tp1.typeSymbol == ObjectClass && tp2.typeSymbol == AnyClass)
+ tps2isJava && tp1.typeSymbol == ObjectClass && tp2.typeSymbol == AnyClass))
/** like map2, but returns list `xs' itself - instead of a copy - if function
* `f' maps all elements to themselves.
@@ -4318,15 +4322,21 @@ A type's typeSymbol should never be inspected directly.
if (bound.typeSymbol != AnyClass)
tvar addHiBound bound.instantiateTypeParams(tparams, tvars)
for (tparam2 <- tparams)
- if (tparam2.info.bounds.lo =:= tparam.tpe) // declaration tp2 :> tparam implies ?tparam <: tp2
- tvar addHiBound tparam2.tpe.instantiateTypeParams(tparams, tvars)
+ tparam2.info.bounds.lo.dealias match {
+ case TypeRef(_, `tparam`, _) =>
+ tvar addHiBound tparam2.tpe.instantiateTypeParams(tparams, tvars)
+ case _ =>
+ }
} else {
if (bound.typeSymbol != NothingClass && bound.typeSymbol != tparam) {
tvar addLoBound bound.instantiateTypeParams(tparams, tvars)
}
for (tparam2 <- tparams)
- if (tparam2.info.bounds.hi =:= tparam.tpe)
- tvar addLoBound tparam2.tpe.instantiateTypeParams(tparams, tvars)
+ tparam2.info.bounds.hi.dealias match {
+ case TypeRef(_, `tparam`, _) =>
+ tvar addLoBound tparam2.tpe.instantiateTypeParams(tparams, tvars)
+ case _ =>
+ }
}
}
tvar.constr.inst = NoType // necessary because hibounds/lobounds may contain tvar
@@ -4342,6 +4352,7 @@ A type's typeSymbol should never be inspected directly.
}
}
+ // println("solving "+tvars+"/"+tparams+"/"+(tparams map (_.info)))
for ((tvar, (tparam, variance)) <- config)
solveOne(tvar, tparam, variance)
@@ -4357,7 +4368,7 @@ A type's typeSymbol should never be inspected directly.
*/
def isWithinBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): Boolean = {
val bounds = instantiatedBounds(pre, owner, tparams, targs)
- !(List.map2(bounds, targs)((bound, targ) => bound containsType targ) contains false)
+ (bounds, targs).zipped forall (_ containsType _)
}
def instantiatedBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): List[TypeBounds] =
@@ -4481,9 +4492,9 @@ A type's typeSymbol should never be inspected directly.
(DoubleClass.tpe /: ts) ((t1, t2) => if (isNumericSubType(t1, t2)) t1 else t2)
def isWeakSubType(tp1: Type, tp2: Type) =
- tp1 match {
+ tp1.deconst.normalize match {
case TypeRef(_, sym1, _) if isNumericValueClass(sym1) =>
- tp2 match {
+ tp2.deconst.normalize match {
case TypeRef(_, sym2, _) if isNumericValueClass(sym2) =>
sym1 == sym2 || numericWidth(sym1) < numericWidth(sym2)
case tv2 @ TypeVar(_, _) =>
@@ -4492,7 +4503,7 @@ A type's typeSymbol should never be inspected directly.
isSubType(tp1, tp2)
}
case tv1 @ TypeVar(_, _) =>
- tp2 match {
+ tp2.deconst.normalize match {
case TypeRef(_, sym2, _) if isNumericValueClass(sym2) =>
tv1.registerBound(tp2, isLowerBound = false, numBound = true)
case _ =>
@@ -4515,7 +4526,7 @@ A type's typeSymbol should never be inspected directly.
case List(t) => t
case ts @ PolyType(tparams, _) :: _ =>
PolyType(
- List.map2(tparams, List.transpose(matchingBounds(ts, tparams)))
+ (tparams, matchingBounds(ts, tparams).transpose).zipped map
((tparam, bounds) => tparam.cloneSymbol.setInfo(glb(bounds, depth))),
lub0(matchingInstTypes(ts, tparams)))
case ts @ MethodType(params, _) :: rest =>
@@ -4543,8 +4554,7 @@ A type's typeSymbol should never be inspected directly.
if (syms contains NoSymbol) NoSymbol
else {
val symtypes =
- (List.map2(narrowts, syms)
- ((t, sym) => t.memberInfo(sym).substThis(t.typeSymbol, lubThisType)));
+ (narrowts, syms).zipped map ((t, sym) => t.memberInfo(sym).substThis(t.typeSymbol, lubThisType))
if (proto.isTerm) // possible problem: owner of info is still the old one, instead of new refinement class
proto.cloneSymbol(lubRefined.typeSymbol).setInfo(lub(symtypes, decr(depth)))
else if (symtypes.tail forall (symtypes.head =:=))
@@ -4616,7 +4626,7 @@ A type's typeSymbol should never be inspected directly.
case List(t) => t
case ts @ PolyType(tparams, _) :: _ =>
PolyType(
- List.map2(tparams, List.transpose(matchingBounds(ts, tparams)))
+ (tparams, matchingBounds(ts, tparams).transpose).zipped map
((tparam, bounds) => tparam.cloneSymbol.setInfo(lub(bounds, depth))),
glb0(matchingInstTypes(ts, tparams)))
case ts @ MethodType(params, _) :: rest =>
@@ -4699,15 +4709,9 @@ A type's typeSymbol should never be inspected directly.
else NothingClass.tpe
}
}
- if (settings.debug.value) {
- println(indent + "glb of " + ts + " at depth "+depth)//debug
- indent = indent + " "
- }
+ // if (settings.debug.value) { println(indent + "glb of " + ts + " at depth "+depth); indent = indent + " " } //DEBUG
val res = if (depth < 0) NothingClass.tpe else glb0(ts)
- if (settings.debug.value) {
- indent = indent.substring(0, indent.length() - 2)
- log(indent + "glb of " + ts + " is " + res)//debug
- }
+ // if (settings.debug.value) { indent = indent.substring(0, indent.length() - 2); log(indent + "glb of " + ts + " is " + res) }//DEBUG
if (ts exists (_.isNotNull)) res.notNull else res
}
@@ -4725,7 +4729,7 @@ A type's typeSymbol should never be inspected directly.
* of types.
*/
private def commonOwner(tps: List[Type]): Symbol = {
- if (settings.debug.value) log("computing common owner of types " + tps)//debug
+ // if (settings.debug.value) log("computing common owner of types " + tps)//DEBUG
commonOwnerMap.init
tps foreach { tp => commonOwnerMap.apply(tp); () }
commonOwnerMap.result
@@ -4745,7 +4749,7 @@ A type's typeSymbol should never be inspected directly.
val pre = if (variance == 1) lub(pres, depth) else glb(pres, depth)
val argss = tps map (_.typeArgs)
val capturedParams = new ListBuffer[Symbol]
- val args = List.map2(sym.typeParams, List.transpose(argss)) {
+ val args = (sym.typeParams, argss.transpose).zipped map {
(tparam, as) =>
if (depth == 0)
if (tparam.variance == variance) AnyClass.tpe
@@ -4792,7 +4796,7 @@ A type's typeSymbol should never be inspected directly.
*/
def addMember(thistp: Type, tp: Type, sym: Symbol) {
assert(sym != NoSymbol)
- if (settings.debug.value) log("add member " + sym+":"+sym.info+" to "+thistp)
+ // if (settings.debug.value) log("add member " + sym+":"+sym.info+" to "+thistp) //DEBUG
if (!(thistp specializes sym)) {
if (sym.isTerm)
for (alt <- tp.nonPrivateDecl(sym.name).alternatives)
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
index 3e0681ccdf..694fc9fe91 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
@@ -34,8 +34,8 @@ abstract class ICodeReader extends ClassfileParser {
var method: IMethod = _ // the current IMethod
val OBJECT: TypeKind = REFERENCE(definitions.ObjectClass)
- val nothingName = newTermName("scala.runtime.Nothing$")
- val nullName = newTermName("scala.runtime.Null$")
+ val nothingName = newTermName(SCALA_NOTHING)
+ val nullName = newTermName(SCALA_NULL)
var isScalaModule = false
/** Read back bytecode for the given class symbol. It returns
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
index 84b08f1258..fb5e24b23d 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
@@ -72,12 +72,15 @@ abstract class Pickler extends SubComponent {
// private var boundSyms: List[Symbol] = Nil
+ private def isRootSym(sym: Symbol) =
+ sym.name.toTermName == rootName && sym.owner == rootOwner
+
/** Returns usually symbol's owner, but picks classfile root instead
* for existentially bound variables that have a non-local owner.
* Question: Should this be done for refinement class symbols as well?
*/
private def localizedOwner(sym: Symbol) =
- if (sym.isAbstractType && sym.hasFlag(EXISTENTIAL) && !isLocal(sym.owner)) root
+ if (isLocal(sym) && !isRootSym(sym) && !isLocal(sym.owner)) root
else sym.owner
/** Is root in symbol.owner*, or should it be treated as a local symbol
@@ -85,12 +88,12 @@ abstract class Pickler extends SubComponent {
* an existentially bound variable, or a higher-order type parameter.
*/
private def isLocal(sym: Symbol): Boolean =
- !sym.isPackageClass &&
- (sym.name.toTermName == rootName && sym.owner == rootOwner ||
- sym != NoSymbol && isLocal(sym.owner) ||
+ !sym.isPackageClass && sym != NoSymbol &&
+ (isRootSym(sym) ||
sym.isRefinementClass ||
sym.isAbstractType && sym.hasFlag(EXISTENTIAL) || // existential param
- (locals contains sym)) // higher-order type param
+ (locals contains sym) || // higher-order type param
+ isLocal(sym.owner))
private def staticAnnotations(annots: List[AnnotationInfo]) =
annots filter(ann =>
@@ -402,11 +405,8 @@ abstract class Pickler extends SubComponent {
}
}
- private def putTrees(trees: List[Tree]) =
- trees.foreach(putTree _)
-
- private def putTreess(treess: List[List[Tree]]) =
- treess.foreach(putTrees _)
+ private def putTrees(trees: List[Tree]) = trees foreach putTree
+ private def putTreess(treess: List[List[Tree]]) = treess foreach putTrees
/** only used when pickling trees, i.e. in an
* argument of some Annotation */
@@ -486,6 +486,10 @@ abstract class Pickler extends SubComponent {
*/
private def writeRef(ref: AnyRef) { writeNat(index(ref)) }
private def writeRefs(refs: List[AnyRef]) { refs foreach writeRef }
+ private def writeRefsWithLength(refs: List[AnyRef]) {
+ writeNat(refs.length)
+ writeRefs(refs)
+ }
/** Write name, owner, flags, and info of a symbol.
*/
@@ -623,9 +627,9 @@ abstract class Pickler extends SubComponent {
args foreach writeClassfileAnnotArg
ANNOTARGARRAY
- case (target: Symbol, children: List[Symbol]) =>
+ case (target: Symbol, children: List[_]) =>
writeRef(target)
- for (c <- children) writeRef(c.asInstanceOf[Symbol])
+ writeRefs(children.asInstanceOf[List[Symbol]])
CHILDREN
case EmptyTree =>
@@ -676,13 +680,9 @@ abstract class Pickler extends SubComponent {
writeRef(tree.symbol)
writeRef(mods)
writeRef(name)
- writeNat(tparams.length)
- writeRefs(tparams)
+ writeRefsWithLength(tparams)
writeNat(vparamss.length)
- for(vparams <- vparamss) {
- writeNat(vparams.length)
- writeRefs(vparams)
- }
+ vparamss foreach writeRefsWithLength
writeRef(tpt)
writeRef(rhs)
TREE
@@ -728,8 +728,7 @@ abstract class Pickler extends SubComponent {
writeNat(TEMPLATEtree)
writeRef(tree.tpe)
writeRef(tree.symbol)
- writeNat(parents.length)
- writeRefs(parents)
+ writeRefsWithLength(parents)
writeRef(self)
writeRefs(body)
TREE
@@ -783,7 +782,6 @@ abstract class Pickler extends SubComponent {
writeRefs(trees)
TREE
-
case tree@Function(vparams, body) =>
writeNat(FUNCTIONtree)
writeRef(tree.tpe)
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
index 909ecae77a..b6fdb28090 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
@@ -132,7 +132,8 @@ abstract class UnPickler {
val savedIndex = readIndex
readIndex = index(i)
val tag = readByte().toInt
- if (tag != CLASSsym) assert(false)
+ assert(tag == CLASSsym)
+
readNat(); // read length
val result = readNameRef() == nme.REFINE_CLASS_NAME.toTypeName
readIndex = savedIndex
@@ -350,7 +351,7 @@ abstract class UnPickler {
val len = readNat()
(tag: @switch) match {
case LITERALunit => Constant(())
- case LITERALboolean => Constant(if (readLong(len) == 0L) false else true)
+ case LITERALboolean => Constant(readLong(len) != 0L)
case LITERALbyte => Constant(readLong(len).toByte)
case LITERALshort => Constant(readLong(len).toShort)
case LITERALchar => Constant(readLong(len).toChar)
@@ -390,17 +391,15 @@ abstract class UnPickler {
/** Read a ClassfileAnnotArg (argument to a classfile annotation)
*/
- private def readClassfileAnnotArg(): ClassfileAnnotArg = {
- val b = peekByte()
- if (peekByte() == ANNOTINFO) {
+ private def readClassfileAnnotArg(): ClassfileAnnotArg = peekByte() match {
+ case ANNOTINFO =>
NestedAnnotArg(readAnnotation())
- } else if (peekByte() == ANNOTARGARRAY) {
+ case ANNOTARGARRAY =>
readByte()
val end = readNat() + readIndex
ArrayAnnotArg(until(end, readClassfileAnnotArgRef).toArray)
- } else {
+ case _ =>
LiteralAnnotArg(readConstant())
- }
}
/** Read an AnnotationInfo. Not to be called directly, use
@@ -420,7 +419,6 @@ abstract class UnPickler {
AnnotationInfo(atp, args.toList, assocs.toList)
}
-
/** Read an annotation and as a side effect store it into
* the symbol it requests. Called at top-level, for all
* (symbol, annotInfo) entries. */
@@ -450,212 +448,184 @@ abstract class UnPickler {
errorBadSignature("tree expected (" + outerTag + ")")
val end = readNat() + readIndex
val tag = readByte()
- val tpe =
- if (tag != EMPTYtree)
- readTypeRef()
- else
- NoType
+ val tpe = if (tag == EMPTYtree) NoType else readTypeRef()
+
+ // Set by the three functions to follow. If symbol is non-null
+ // after the the new tree 't' has been created, t has its Symbol
+ // set to symbol; and it always has its Type set to tpe.
+ var symbol: Symbol = null
+ var mods: Modifiers = null
+ var name: Name = null
+
+ /** Read a Symbol, Modifiers, and a Name */
+ def setSymModsName() {
+ symbol = readSymbolRef()
+ mods = readModifiersRef()
+ name = readNameRef()
+ }
+ /** Read a Symbol and a Name */
+ def setSymName() {
+ symbol = readSymbolRef()
+ name = readNameRef()
+ }
+ /** Read a Symbol */
+ def setSym() {
+ symbol = readSymbolRef()
+ }
- tag match {
+ val t = tag match {
case EMPTYtree =>
EmptyTree
case PACKAGEtree =>
- val symbol = readSymbolRef()
+ setSym()
+ // val discardedSymbol = readSymbolRef() // XXX is symbol intentionally not set?
val pid = readTreeRef().asInstanceOf[RefTree]
val stats = until(end, readTreeRef)
- PackageDef(pid, stats) setType tpe
+ PackageDef(pid, stats)
case CLASStree =>
- val symbol = readSymbolRef()
- val mods = readModifiersRef()
- val name = readNameRef()
+ setSymModsName()
val impl = readTemplateRef()
val tparams = until(end, readTypeDefRef)
- (ClassDef(mods, name, tparams, impl).
- setSymbol(symbol).
- setType(tpe))
+ ClassDef(mods, name, tparams, impl)
case MODULEtree =>
- val symbol = readSymbolRef()
- val mods = readModifiersRef()
- val name = readNameRef()
- val impl = readTemplateRef()
- (ModuleDef(mods, name, impl).
- setSymbol(symbol).
- setType(tpe))
+ setSymModsName()
+ ModuleDef(mods, name, readTemplateRef())
case VALDEFtree =>
- val symbol = readSymbolRef()
- val mods = readModifiersRef()
- val name = readNameRef()
+ setSymModsName()
val tpt = readTreeRef()
val rhs = readTreeRef()
-
- (ValDef(mods, name, tpt, rhs).
- setSymbol(symbol).
- setType(tpe))
+ ValDef(mods, name, tpt, rhs)
case DEFDEFtree =>
- val symbol = readSymbolRef()
- val mods = readModifiersRef()
- val name = readNameRef()
- val numTparams = readNat()
- val tparams = times(numTparams, readTypeDefRef)
- val numVparamss = readNat
- val vparamss = times(numVparamss, () => {
- val len = readNat()
- times(len, readValDefRef)})
+ setSymModsName()
+ val tparams = times(readNat(), readTypeDefRef)
+ val vparamss = times(readNat(), () => times(readNat(), readValDefRef))
val tpt = readTreeRef()
val rhs = readTreeRef()
- (DefDef(mods, name, tparams, vparamss, tpt, rhs).
- setSymbol(symbol).
- setType(tpe))
+ DefDef(mods, name, tparams, vparamss, tpt, rhs)
case TYPEDEFtree =>
- val symbol = readSymbolRef()
- val mods = readModifiersRef()
- val name = readNameRef()
+ setSymModsName()
val rhs = readTreeRef()
val tparams = until(end, readTypeDefRef)
-
- (TypeDef(mods, name, tparams, rhs).
- setSymbol(symbol).
- setType(tpe))
+ TypeDef(mods, name, tparams, rhs)
case LABELtree =>
- val symbol = readSymbolRef()
- val name = readNameRef()
+ setSymName()
val rhs = readTreeRef()
val params = until(end, readIdentRef)
- (LabelDef(name, params, rhs).
- setSymbol(symbol).
- setType(tpe))
+ LabelDef(name, params, rhs)
case IMPORTtree =>
- val symbol = readSymbolRef()
+ setSym()
val expr = readTreeRef()
val selectors = until(end, () => {
val from = readNameRef()
val to = readNameRef()
ImportSelector(from, -1, to, -1)
})
- (Import(expr, selectors).
- setSymbol(symbol).
- setType(tpe))
+
+ Import(expr, selectors)
case DOCDEFtree =>
val comment = readConstantRef match {
- case Constant(com: String) => com
- case other =>
- errorBadSignature("Document comment not a string (" + other + ")")
+ case Constant(com: String) => com
+ case other => errorBadSignature("Document comment not a string (" + other + ")")
}
val definition = readTreeRef()
- (DocDef(comment, definition).setType(tpe))
+ DocDef(comment, definition)
case TEMPLATEtree =>
- val symbol = readSymbolRef()
- val numParents = readNat()
- val parents = times(numParents, readTreeRef)
+ setSym()
+ val parents = times(readNat(), readTreeRef)
val self = readValDefRef()
val body = until(end, readTreeRef)
- (Template(parents, self, body).
- setSymbol(symbol).
- setType(tpe))
+ Template(parents, self, body)
case BLOCKtree =>
val expr = readTreeRef()
val stats = until(end, readTreeRef)
- Block(stats, expr).setType(tpe)
+ Block(stats, expr)
case CASEtree =>
val pat = readTreeRef()
val guard = readTreeRef()
val body = readTreeRef()
- CaseDef(pat, guard, body).setType(tpe)
+ CaseDef(pat, guard, body)
case ALTERNATIVEtree =>
- val trees = until(end, readTreeRef)
- Alternative(trees).setType(tpe)
+ Alternative(until(end, readTreeRef))
case STARtree =>
- val elem = readTreeRef()
- Star(elem).setType(tpe)
+ Star(readTreeRef())
case BINDtree =>
- val symbol = readSymbolRef()
- val name = readNameRef()
- val body = readTreeRef()
- (Bind(name, body).
- setSymbol(symbol).
- setType(tpe))
+ setSymName()
+ Bind(name, readTreeRef())
case UNAPPLYtree =>
val fun = readTreeRef()
val args = until(end, readTreeRef)
- (UnApply(fun: Tree, args).setType(tpe))
+ UnApply(fun, args)
case ARRAYVALUEtree =>
val elemtpt = readTreeRef()
val trees = until(end, readTreeRef)
- (ArrayValue(elemtpt, trees).setType(tpe))
+ ArrayValue(elemtpt, trees)
case FUNCTIONtree =>
- val symbol = readSymbolRef()
+ setSym()
val body = readTreeRef()
val vparams = until(end, readValDefRef)
- (Function(vparams, body).
- setSymbol(symbol).
- setType(tpe))
+ Function(vparams, body)
case ASSIGNtree =>
val lhs = readTreeRef()
val rhs = readTreeRef()
- Assign(lhs, rhs).setType(tpe)
+ Assign(lhs, rhs)
case IFtree =>
val cond = readTreeRef()
val thenp = readTreeRef()
val elsep = readTreeRef()
- If(cond, thenp, elsep).setType(tpe)
+ If(cond, thenp, elsep)
case MATCHtree =>
val selector = readTreeRef()
val cases = until(end, readCaseDefRef)
- Match(selector, cases).setType(tpe)
+ Match(selector, cases)
case RETURNtree =>
- val symbol = readSymbolRef()
- val expr = readTreeRef()
- (Return(expr).
- setSymbol(symbol).
- setType(tpe))
+ setSym()
+ Return(readTreeRef())
case TREtree =>
val block = readTreeRef()
val finalizer = readTreeRef()
val catches = until(end, readCaseDefRef)
- Try(block, catches, finalizer).setType(tpe)
+ Try(block, catches, finalizer)
case THROWtree =>
- val expr = readTreeRef()
- Throw(expr).setType(tpe)
+ Throw(readTreeRef())
case NEWtree =>
- val tpt = readTreeRef()
- New(tpt).setType(tpe)
+ New(readTreeRef())
case TYPEDtree =>
val expr = readTreeRef()
val tpt = readTreeRef()
- Typed(expr, tpt).setType(tpe)
+ Typed(expr, tpt)
case TYPEAPPLYtree =>
val fun = readTreeRef()
val args = until(end, readTreeRef)
- TypeApply(fun, args).setType(tpe)
+ TypeApply(fun, args)
case APPLYtree =>
val fun = readTreeRef()
@@ -664,79 +634,77 @@ abstract class UnPickler {
fun.setType(fun.symbol.info)
typer.infer.inferMethodAlternative(fun, Nil, args map (_.tpe), tpe)
}
- Apply(fun, args).setType(tpe)
+ Apply(fun, args)
case APPLYDYNAMICtree =>
- val symbol = readSymbolRef()
+ setSym()
val qual = readTreeRef()
val args = until(end, readTreeRef)
- ApplyDynamic(qual, args).setSymbol(symbol).setType(tpe)
+ ApplyDynamic(qual, args)
case SUPERtree =>
- val symbol = readSymbolRef()
+ setSym()
val qual = readNameRef()
val mix = readNameRef()
- Super(qual, mix).setSymbol(symbol).setType(tpe)
+ Super(qual, mix)
case THIStree =>
- val symbol = readSymbolRef()
- val qual = readNameRef()
- This(qual).setSymbol(symbol).setType(tpe)
+ setSym()
+ This(readNameRef())
case SELECTtree =>
- val symbol = readSymbolRef()
+ setSym()
val qualifier = readTreeRef()
val selector = readNameRef()
- Select(qualifier, selector).setSymbol(symbol).setType(tpe)
+ Select(qualifier, selector)
case IDENTtree =>
- val symbol = readSymbolRef()
- val name = readNameRef()
- Ident(name).setSymbol(symbol).setType(tpe)
+ setSymName()
+ Ident(name)
case LITERALtree =>
- val value = readConstantRef()
- Literal(value).setType(tpe)
+ Literal(readConstantRef())
case TYPEtree =>
- TypeTree().setType(tpe)
+ TypeTree()
case ANNOTATEDtree =>
val annot = readTreeRef()
val arg = readTreeRef()
- Annotated(annot, arg).setType(tpe)
+ Annotated(annot, arg)
case SINGLETONTYPEtree =>
- val ref = readTreeRef()
- SingletonTypeTree(ref).setType(tpe)
+ SingletonTypeTree(readTreeRef())
case SELECTFROMTYPEtree =>
val qualifier = readTreeRef()
val selector = readNameRef()
- SelectFromTypeTree(qualifier, selector).setType(tpe)
+ SelectFromTypeTree(qualifier, selector)
case COMPOUNDTYPEtree =>
- val templ = readTemplateRef()
- CompoundTypeTree(templ: Template).setType(tpe)
+ CompoundTypeTree(readTemplateRef())
case APPLIEDTYPEtree =>
val tpt = readTreeRef()
val args = until(end, readTreeRef)
- AppliedTypeTree(tpt, args).setType(tpe)
+ AppliedTypeTree(tpt, args)
case TYPEBOUNDStree =>
val lo = readTreeRef()
val hi = readTreeRef()
- TypeBoundsTree(lo, hi).setType(tpe)
+ TypeBoundsTree(lo, hi)
case EXISTENTIALTYPEtree =>
val tpt = readTreeRef()
val whereClauses = until(end, readTreeRef)
- ExistentialTypeTree(tpt, whereClauses).setType(tpe)
+ ExistentialTypeTree(tpt, whereClauses)
case _ =>
errorBadSignature("unknown tree type (" + tag + ")")
}
+
+ if (symbol == null) t setType tpe
+ else t setSymbol symbol setType tpe
}
def readModifiers(): Modifiers = {
@@ -799,7 +767,6 @@ abstract class UnPickler {
errorBadSignature("expected an TypeDef (" + other + ")")
}
-
private def errorBadSignature(msg: String) =
throw new RuntimeException("malformed Scala signature of " + classRoot.name + " at " + readIndex + "; " + msg)
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index dafec5e1c3..9bd8337106 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -1,5 +1,5 @@
/* NSC -- new Scala compiler
- * Copyright 2005-2009 LAMP/EPFL
+ * Copyrights 2005-2009 LAMP/EPFL
* @author Martin Odersky
*/
// $Id$
@@ -28,6 +28,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
private val newInits = new ListBuffer[Tree]
private val classConstantMeth = new HashMap[String, Symbol]
+ private val symbolStaticFields = new HashMap[String, (Symbol, Tree, Tree)]
private var localTyper: analyzer.Typer = null
@@ -52,7 +53,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
localTyper typed { atPos(pos)(tree) }
private def classConstantMethod(pos: Position, sig: String): Symbol =
- (classConstantMeth get sig) getOrElse {
+ classConstantMeth.getOrElseUpdate(sig, {
val forName = getMember(ClassClass.linkedModuleOfClass, nme.forName)
val owner = currentOwner.enclClass
@@ -69,9 +70,8 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
)
newDefs.append(cdef, mdef)
- classConstantMeth.update(sig, meth)
meth
- }
+ })
override def transformUnit(unit: CompilationUnit) =
unit.body = transform(unit.body)
@@ -79,7 +79,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
/** A value class is defined to be only Java-compatible values: unit is
* not part of it, as opposed to isValueClass in definitions. scala.Int is
* a value class, java.lang.Integer is not. */
- def isValueClass(sym: Symbol) = boxedClass contains sym
+ def isJavaValueClass(sym: Symbol) = boxedClass contains sym
override def transform(tree: Tree): Tree = tree match {
@@ -349,13 +349,16 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
}
val qualSym = qual.tpe.typeSymbol
val methSym = ad.symbol
+ def args = qual :: params
+
+ /** Normal non-Array call */
def defaultCall = {
// reflective method call machinery
- val invokeName = MethodClass.tpe member nme.invoke_ // reflect.Method.invoke(...)
- def cache = REF(reflectiveMethodCache(ad.symbol.name.toString, paramTypes)) // cache Symbol
- def lookup = Apply(cache, List(qual GETCLASS)) // get Method object from cache
- def args = ArrayValue(TypeTree(ObjectClass.tpe), params) // args for invocation
- def invocation = (lookup DOT invokeName)(qual, args) // .invoke(qual, ...)
+ val invokeName = MethodClass.tpe member nme.invoke_ // reflect.Method.invoke(...)
+ def cache = REF(reflectiveMethodCache(ad.symbol.name.toString, paramTypes)) // cache Symbol
+ def lookup = Apply(cache, List(qual GETCLASS)) // get Method object from cache
+ def invokeArgs = ArrayValue(TypeTree(ObjectClass.tpe), params) // args for invocation
+ def invocation = (lookup DOT invokeName)(qual, invokeArgs) // .invoke(qual, ...)
// exception catching machinery
val invokeExc = currentOwner.newValue(ad.pos, mkTerm()) setInfo InvocationTargetExceptionClass.tpe
@@ -363,50 +366,43 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
def catchBody = Throw(Apply(Select(Ident(invokeExc), nme.getCause), Nil))
// try { method.invoke } catch { case e: InvocationTargetExceptionClass => throw e.getCause() }
- TRY (invocation) CATCH { CASE (catchVar) ==> catchBody } ENDTRY
+ fixResult( TRY (invocation) CATCH { CASE (catchVar) ==> catchBody } ENDTRY )
}
- def useValueOperator = {
- def isBoxed(qualSym: Symbol): Boolean =
- (qualSym isNonBottomSubClass BoxedNumberClass) ||
- (!forMSIL && (qualSym isNonBottomSubClass BoxedCharacterClass))
- ((qualSym == definitions.ObjectClass) || isBoxed(qualSym)) && // may be a boxed value class
+
+ def useValueOperator =
+ isMaybeBoxed(qualSym) && // may be a boxed value class
(getPrimitiveReplacementForStructuralCall isDefinedAt methSym.name) &&
- ((resType :: paramTypes) forall (x => isValueClass(x.typeSymbol))) // issue #1110
- }
- def useArrayOperator =
- ((qualSym == definitions.ObjectClass) || (qualSym == definitions.ArrayClass)) &&
- ((methSym.name == nme.length) || (methSym.name == nme.update) || (methSym.name == nme.apply))
- val callCode = if (useValueOperator) {
- val (operator, test) = getPrimitiveReplacementForStructuralCall(methSym.name)
- def args = qual :: params
- fixResult((IF (test) THEN (REF(operator) APPLY args) ELSE defaultCall))
+ ((resType :: paramTypes) forall (x => isJavaValueClass(x.typeSymbol))) // issue #1110
+
+ def isArrayMethodSignature =
+ (methSym.name == nme.length && params.isEmpty) ||
+ (methSym.name == nme.update && (structResType.typeSymbol eq UnitClass)) ||
+ (methSym.name == nme.apply && params.size == 1)
+
+ def isDefinitelyArray = isArrayMethodSignature && (qualSym == ArrayClass)
+ def isMaybeArray = isArrayMethodSignature && (qualSym == ObjectClass) // precondition: !isDefinitelyArray
+
+ def genArrayCall = methSym.name match {
+ case nme.length => REF(boxMethod(IntClass)) APPLY (REF(arrayLengthMethod) APPLY args)
+ case nme.update => REF(arrayUpdateMethod) APPLY List(args(0), (REF(unboxMethod(IntClass)) APPLY args(1)), args(2))
+ case nme.apply => REF(arrayApplyMethod) APPLY List(args(0), (REF(unboxMethod(IntClass)) APPLY args(1)))
}
- else if (useArrayOperator) {
- val args = qual :: params
- val operatorCall = // what follows is incredibly ugly. this dirty fix should be deal with at the next cleanup of cleanup.
- if (methSym.name == nme.length)
- (REF(boxMethod(IntClass)) APPLY (REF(arrayLengthMethod) APPLY args))
- else if (methSym.name == nme.update)
- (REF(arrayUpdateMethod) APPLY List(args(0), (REF(unboxMethod(IntClass)) APPLY args(1)), args(2)))
- else
- (REF(arrayApplyMethod) APPLY List(args(0), (REF(unboxMethod(IntClass)) APPLY args(1))))
- (IF (qual IS_OBJ arrayType(ObjectClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(ByteClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(ShortClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(IntClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(LongClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(FloatClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(DoubleClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(CharClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(BooleanClass.tpe)) THEN operatorCall
- ELSE fixResult(defaultCall)
- )))))))))
+ def genArrayTest = {
+ def oneTest(s: Symbol) = qual IS_OBJ arrayType(s.tpe)
+ OR((ObjectClass :: ScalaValueClasses filterNot (_ eq UnitClass)) map oneTest: _*)
}
- else fixResult(defaultCall)
- localTyper.typed(callCode)
- }
- def getClass(q: Tree): Tree = (q DOT nme.getClass_)()
+ val callCode =
+ if (useValueOperator) {
+ val (operator, test) = getPrimitiveReplacementForStructuralCall(methSym.name)
+ IF (test) THEN fixResult(REF(operator) APPLY args) ELSE defaultCall
+ }
+ else if (isDefinitelyArray) genArrayCall
+ else if (isMaybeArray) IF (genArrayTest) THEN genArrayCall ELSE defaultCall
+ else defaultCall
+
+ localTyper typed callCode
+ }
if (settings.refinementMethodDispatch.value == "invoke-dynamic") {
/* val guardCallSite: Tree = {
@@ -452,7 +448,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
val sym = currentOwner.newValue(ad.pos, mkTerm("qual")) setInfo qual0.tpe
qual = REF(sym)
- def structResType = if (isValueClass(resType.typeSymbol)) boxedClass(resType.typeSymbol).tpe else resType
+ def structResType = if (isJavaValueClass(resType.typeSymbol)) boxedClass(resType.typeSymbol).tpe else resType
BLOCK(
VAL(sym) === qual0,
callAsReflective(mparams map (_.tpe), resType, structResType)
@@ -498,7 +494,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
* constructor. */
case Template(parents, self, body) =>
localTyper = typer.atOwner(tree, currentClass)
- if (!forMSIL) {
+ val transformedTemplate = if (!forMSIL) {
classConstantMeth.clear
newDefs.clear
newInits.clear
@@ -522,11 +518,12 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
treeCopy.Template(tree, parents, self, newBody)
}
else super.transform(tree)
+ applySymbolFieldInitsToStaticCtor(transformedTemplate.asInstanceOf[Template]) // postprocess to include static ctors
case Literal(c) if (c.tag == ClassTag) && !forMSIL=>
val tpe = c.typeValue
typedWithPos(tree.pos) {
- if (isValueClass(tpe.typeSymbol) || tpe.typeSymbol == definitions.UnitClass) {
+ if (isValueClass(tpe.typeSymbol)) {
if (tpe.typeSymbol == UnitClass)
Select(REF(BoxedUnit_TYPE), BoxedUnit_TYPE)
else
@@ -566,9 +563,124 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
}
super.transform(tree)
+ /*
+ * This transformation should identify Scala symbol invocations in the tree and replace them
+ * with references to a static member. Also, whenever a class has at least a single symbol invocation
+ * somewhere in its methods, a new static member should be created and initialized for that symbol.
+ * For instance, say we have a Scala class:
+ *
+ * class Cls {
+ * // ...
+ * def someSymbol = `symbolic
+ * // ...
+ * }
+ *
+ * After transformation, this class looks like this:
+ *
+ * class Cls {
+ * private "static" val <some_name>$symbolic = Symbol("symbolic")
+ * // ...
+ * def someSymbol = <some_name>$symbolic
+ * // ...
+ * }
+ *
+ * The reasoning behind this transformation is the following. Symbols get interned - they are stored
+ * in a global map which is protected with a lock. The reason for this is making equality checks
+ * quicker. But calling Symbol.apply, although it does return a unique symbol, accesses a locked object,
+ * making symbol access slow. To solve this, the unique symbol from the global symbol map in Symbol
+ * is accessed only once during class loading, and after that, the unique symbol is in the static
+ * member. Hence, it is cheap to both reach the unique symbol and do equality checks on it.
+ *
+ * And, finally, be advised - scala symbol literal and the Symbol class of the compiler
+ * have little in common.
+ */
+ case symapp @ Apply(Select(Select(a @ Ident(nme.scala_), b @ nme.Symbol), nme.apply),
+ List(Literal(Constant(symname: String)))) =>
+ // add the symbol name to a map if it's not there already
+ val rhs = gen.mkCast(Apply(gen.scalaDot(nme.Symbol), List(Literal(Constant(symname)))), symbolType)
+ val (staticFieldSym, sfdef, sfinit) = getSymbolStaticField(symapp.pos, symname, rhs, symapp)
+
+ // create a reference to a static field
+ val ntree = typedWithPos(symapp.pos)(REF(staticFieldSym))
+
+ super.transform(ntree)
case _ =>
super.transform(tree)
}
+
+ /* Returns the symbol and the tree for the symbol field interning a reference to a symbol 'synmname'.
+ * If it doesn't exist, i.e. the symbol is encountered the first time,
+ * it creates a new static field definition and initalization and returns it.
+ */
+ private def getSymbolStaticField(pos: Position, symname: String, rhs: Tree, tree: Tree): (Symbol, Tree, Tree) =
+ symbolStaticFields.getOrElseUpdate(symname, {
+ val freshname = unit.fresh.newName(pos, "symbol$")
+ val theTyper = typer.atOwner(tree, currentClass)
+
+ // create a symbol for the static field
+ val stfieldSym = currentClass.newVariable(pos, freshname)
+ .setFlag(PRIVATE | STATIC | SYNTHETIC | FINAL)
+ .setInfo(symbolType)
+ currentClass.info.decls enter stfieldSym
+
+ // create field definition and initialization
+ val stfieldDef = theTyper.typed { atPos(pos)(VAL(stfieldSym) === rhs) }
+ val stfieldInit = theTyper.typed { atPos(pos)(REF(stfieldSym) === rhs) }
+
+ // add field definition to new defs
+ newDefs append stfieldDef
+
+ (stfieldSym, stfieldDef, stfieldInit)
+ })
+
+ /* returns a list of all trees for symbol static fields, and clear the list */
+ private def flushSymbolFieldsInitializations: List[Tree] = {
+ val fields = (symbolStaticFields.valuesIterator map (_._3)).toList
+ symbolStaticFields.clear
+ fields
+ }
+
+ /* finds the static ctor DefDef tree within the template if it exists. */
+ def findStaticCtor(template: Template): Option[Tree] =
+ template.body find {
+ case defdef @ DefDef(mods, nme.CONSTRUCTOR, tparam, vparam, tp, rhs) => defdef.symbol hasFlag STATIC
+ case _ => false
+ }
+
+ /* changes the template for the class so that it contains a static constructor with symbol fields inits,
+ * augments an existing static ctor if one already existed.
+ */
+ def applySymbolFieldInitsToStaticCtor(template: Template): Template = {
+ val symbolInitTrees = flushSymbolFieldsInitializations
+ if (symbolInitTrees.isEmpty) template
+ else {
+ val theTyper = typer.atOwner(template, currentClass)
+ val newCtor = findStaticCtor(template) match {
+ // in case there already were static ctors - augment existing ones
+ // currently, however, static ctors aren't being generated anywhere else
+ case Some(ctor @ DefDef(mods, name, tparams, vparamss, tpt, rhs)) =>
+ // modify existing static ctor
+ val newBlock = rhs match {
+ case block @ Block(stats, expr) =>
+ // need to add inits to existing block
+ treeCopy.Block(block, symbolInitTrees ::: stats, expr)
+ case term: TermTree =>
+ // need to create a new block with inits and the old term
+ treeCopy.Block(term, symbolInitTrees, term)
+ }
+ treeCopy.DefDef(ctor, mods, name, tparams, vparamss, tpt, newBlock)
+ case None =>
+ // create new static ctor
+ val staticCtorSym = currentClass.newConstructor(template.pos)
+ .setFlag(STATIC)
+ .setInfo(UnitClass.tpe)
+ val rhs = Block(symbolInitTrees, Literal(()))
+ val staticCtorTree = DefDef(staticCtorSym, rhs)
+ theTyper.typed { atPos(template.pos)(staticCtorTree) }
+ }
+ treeCopy.Template(template, template.parents, template.self, newCtor :: template.body)
+ }
+ }
} // CleanUpTransformer
}
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 7c57b2e16f..af435c8c83 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -75,6 +75,13 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
case _ => 0
}
+ // @M #2585 when generating a java generic signature that includes a selection of an inner class p.I, (p = `pre`, I = `cls`)
+ // must rewrite to p'.I, where p' refers to the class that directly defines the nested class I
+ // see also #2585 marker in javaSig: there, type arguments must be included (use pre.baseType(cls.owner))
+ // requires cls.isClass
+ @inline private def rebindInnerClass(pre: Type, cls: Symbol): Type =
+ if(cls.owner.isClass) cls.owner.tpe else pre // why not cls.isNestedClass?
+
/** <p>
* The erasure <code>|T|</code> of a type <code>T</code>. This is:
* </p>
@@ -90,7 +97,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
* - For a typeref scala.Array+[T] where T is not an abstract type, scala.Array+[|T|].
* - For a typeref scala.Any or scala.AnyVal, java.lang.Object.
* - For a typeref scala.Unit, scala.runtime.BoxedUnit.
- * - For a typeref P.C[Ts] where C refers to a class, |P|.C.
+ * - For a typeref P.C[Ts] where C refers to a class, |P|.C. (Where P is first rebound to the class that directly defines C.)
* - For a typeref P.C[Ts] where C refers to an alias type, the erasure of C's alias.
* - For a typeref P.C[Ts] where C refers to an abstract type, the
* erasure of C's upper bound.
@@ -122,9 +129,8 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
else typeRef(apply(pre), sym, args map this)
else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass) erasedTypeRef(ObjectClass)
else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass)
- else if (sym.isClass)
- typeRef(apply(if (sym.owner.isClass) sym.owner.tpe else pre), sym, List())
- else apply(sym.info)
+ else if (sym.isClass) typeRef(apply(rebindInnerClass(pre, sym)), sym, List()) // #2585
+ else apply(sym.info) // alias type or abstract type
case PolyType(tparams, restpe) =>
apply(restpe)
case ExistentialType(tparams, restpe) =>
@@ -164,6 +170,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
case TypeRef(pre, sym, args) =>
if (sym == ArrayClass) args foreach traverse
else if (sym.isTypeParameterOrSkolem || sym.isExistential || !args.isEmpty) result = true
+ else if (sym.isClass) traverse(rebindInnerClass(pre, sym)) // #2585
else if (!sym.owner.isPackageClass) traverse(pre)
case PolyType(_, _) | ExistentialType(_, _) =>
result = true
@@ -243,8 +250,9 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
tagOfClass(sym).toString
else if (sym.isClass)
{
- if (needsJavaSig(pre)) {
- val s = jsig(pre)
+ val preRebound = pre.baseType(sym.owner) // #2585
+ if (needsJavaSig(preRebound)) {
+ val s = jsig(preRebound)
if (s.charAt(0) == 'L') s.substring(0, s.length - 1) + classSigSuffix
else classSig
} else classSig
@@ -277,6 +285,9 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
(parents map jsig).mkString
case AnnotatedType(_, atp, _) =>
jsig(atp)
+ case BoundedWildcardType(bounds) =>
+ println("something's wrong: "+sym+":"+sym.tpe+" has a bounded wildcard type")
+ jsig(bounds.hi)
case _ =>
val etp = erasure(tp)
if (etp eq tp) throw new UnknownSig
@@ -417,17 +428,6 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
})
}
- /** generate ScalaRuntime.boxArray(tree)
- * !!! todo: optimize this in case the runtime type is known
- */
- private def boxArray(tree: Tree): Tree = tree match {
- case LabelDef(name, params, rhs) =>
- val rhs1 = boxArray(rhs)
- treeCopy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe
- case _ =>
- typedPos(tree.pos) { gen.mkRuntimeCall(nme.boxArray, List(tree)) }
- }
-
/** Unbox <code>tree</code> of boxed type to expected type <code>pt</code>.
*
* @param tree the given tree
@@ -914,7 +914,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
List()),
isArrayTest(qual1()))
}
- }
+ }
case TypeApply(fun, args) if (fun.symbol.owner != AnyClass &&
fun.symbol != Object_asInstanceOf &&
fun.symbol != Object_isInstanceOf) =>
diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
index 16c5f8754d..b2f9489480 100644
--- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala
+++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
@@ -94,10 +94,11 @@ abstract class LazyVals extends Transform with ast.TreeDSL {
}
val bmps = bitmaps(methSym) map (ValDef(_, ZERO))
+ def isMatch(params: List[Ident]) = (params.tail, methSym.tpe.paramTypes).zipped forall (_.tpe == _)
+
if (bmps.isEmpty) rhs else rhs match {
case Block(assign, l @ LabelDef(name, params, rhs1))
- if (name.toString.equals("_" + methSym.name)
- && List.forall2(params.tail, methSym.tpe.paramTypes) { (ident, tpe) => ident.tpe == tpe }) =>
+ if name.toString == ("_" + methSym.name) && isMatch(params) =>
val sym = l.symbol
Block(assign, treeCopy.LabelDef(l, name, params, typed(prependStats(bmps, rhs1))))
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 0daad7f2a7..fa436a4305 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -671,7 +671,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
val bitmapSym = bitmapFor(clazz, offset)
val mask = LIT(1 << (offset % FLAGS_PER_WORD))
def cond = mkTest(clazz, mask, bitmapSym, true)
- val nulls = (lazyValNullables(lzyVal).toList.sort(_.id < _.id) map nullify)
+ val nulls = (lazyValNullables(lzyVal).toList sortBy (_.id) map nullify)
def syncBody = init ::: List(mkSetFlag(clazz, offset), UNIT)
log("nulling fields inside " + lzyVal + ": " + nulls)
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
index 93cb5baefa..3e4cbf8f24 100644
--- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala
+++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
@@ -344,12 +344,7 @@ abstract class TailCalls extends Transform
typed(t)
}
- private def isSameTypes(ts1: List[Symbol], ts2: List[Symbol]): Boolean = {
- def isSameType(t1: Symbol, t2: Symbol) = {
- t1 == t2
- }
- List.forall2(ts1, ts2)(isSameType)
- }
+ private def isSameTypes(ts1: List[Symbol], ts2: List[Symbol]) = ts1 sameElements ts2
/** Returns <code>true</code> if the fun tree refers to the same method as
* the one saved in <code>ctx</code>.
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 67c963acf5..5409a0fe45 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -297,11 +297,11 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
* new $anon()
*
* transform a function node (x => body) of type PartialFunction[T, R] where
- * body = x match { case P_i if G_i => E_i }_i=1..n
+ * body = expr match { case P_i if G_i => E_i }_i=1..n
* to:
*
* class $anon() extends Object() with PartialFunction[T, R] with ScalaObject {
- * def apply(x: T): R = (x: @unchecked) match {
+ * def apply(x: T): R = (expr: @unchecked) match {
* { case P_i if G_i => E_i }_i=1..n
* def isDefinedAt(x: T): boolean = (x: @unchecked) match {
* case P_1 if G_1 => true
@@ -361,8 +361,8 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
BooleanClass.tpe))
anonClass.info.decls enter isDefinedAtMethod
def idbody(idparam: Symbol) = fun.body match {
- case Match(_, cases) =>
- val substParam = new TreeSymSubstituter(List(fun.vparams.head.symbol), List(idparam));
+ case Match(selector, cases) =>
+ val substParam = new TreeSymSubstituter(List(fun.vparams.head.symbol), List(idparam))
def transformCase(cdef: CaseDef): CaseDef =
substParam(
resetLocalAttrs(
@@ -370,7 +370,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
if (cases exists treeInfo.isDefaultCase) Literal(true)
else
Match(
- Ident(idparam),
+ substParam(resetLocalAttrs(selector.duplicate)),
(cases map transformCase) :::
List(CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(false))))
}
@@ -467,7 +467,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
case _ =>
args
}
- List.map2(formals, args1) { (formal, arg) =>
+ (formals, args1).zipped map { (formal, arg) =>
if (formal.typeSymbol != ByNameParamClass) {
arg
} else if (isByNameRef(arg)) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala
index ba328b9f48..8d9cee7f03 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala
@@ -154,7 +154,7 @@ abstract class ConstantFolder {
private def foldBinop(op: Name, x: Constant, y: Constant): Constant = {
val optag =
if (x.tag == y.tag) x.tag
- else if (isNumeric(x.tag) && isNumeric(y.tag)) Math.max(x.tag, y.tag)
+ else if (isNumeric(x.tag) && isNumeric(y.tag)) math.max(x.tag, y.tag)
else NoTag
try optag match {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index b3e4666f35..596c11bcac 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -481,8 +481,7 @@ trait Contexts { self: Analyzer =>
}
impls
}
- if (settings.debug.value)
- log("collect implicit imports " + imp + "=" + collect(imp.tree.selectors))//debug
+ //if (settings.debug.value) log("collect implicit imports " + imp + "=" + collect(imp.tree.selectors))//DEBUG
collect(imp.tree.selectors)
}
@@ -499,17 +498,14 @@ trait Contexts { self: Analyzer =>
val newImplicits: List[ImplicitInfo] =
if (owner != nextOuter.owner && owner.isClass && !owner.isPackageClass && !inSelfSuperCall) {
if (!owner.isInitialized) return nextOuter.implicitss
- if (settings.debug.value)
- log("collect member implicits " + owner + ", implicit members = " +
- owner.thisType.implicitMembers)//debug
+ // if (settings.debug.value) log("collect member implicits " + owner + ", implicit members = " + owner.thisType.implicitMembers)//DEBUG
val savedEnclClass = enclClass
this.enclClass = this
val res = collectImplicits(owner.thisType.implicitMembers, owner.thisType)
this.enclClass = savedEnclClass
res
} else if (scope != nextOuter.scope && !owner.isPackageClass) {
- if (settings.debug.value)
- log("collect local implicits " + scope.toList)//debug
+ if (settings.debug.value) log("collect local implicits " + scope.toList)//DEBUG
collectImplicits(scope.toList, NoPrefix)
} else if (imports != nextOuter.imports) {
assert(imports.tail == nextOuter.imports)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
index c9a2a377c1..796d6f8134 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
@@ -241,6 +241,9 @@ abstract class Duplicators extends Analyzer {
super.typed(atPos(tree.pos)(tree1))
case _ =>
+ if (tree.hasSymbol && tree.symbol != NoSymbol && (tree.symbol.owner == definitions.AnyClass)) {
+ tree.symbol = NoSymbol // maybe we can find a more specific member in a subclass of Any
+ }
tree.tpe = null
super.typed(tree, mode, pt)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
index 7d75994ef3..375dd5a4a5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
@@ -20,12 +20,13 @@ trait EtaExpansion { self: Analyzer =>
import global._
object etaExpansion {
+ private def isMatch(vparam: ValDef, arg: Tree) = arg match {
+ case Ident(name) => vparam.name == name
+ case _ => false
+ }
+
def unapply(tree: Tree): Option[(List[ValDef], Tree, List[Tree])] = tree match {
- case Function(vparams, Apply(fn, args))
- if (List.forall2(vparams, args) {
- case (vparam, Ident(name)) => vparam.name == name
- case _ => false
- }) =>
+ case Function(vparams, Apply(fn, args)) if (vparams, args).zipped forall isMatch =>
Some((vparams, fn, args))
case _ =>
None
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 6bbacfa311..f577042024 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -368,21 +368,28 @@ self: Analyzer =>
* correspond to the HasMethodMatching type,
* or otherwise if `tp' is compatible with `pt'.
*/
- def matchesPt(tp: Type, pt: Type, undet: List[Symbol]) =
- isCompatible(tp, pt) || {
+ def matchesPt(tp: Type, pt: Type, undet: List[Symbol]) = {
+ isCompatible(tp, pt) ||
+ isView && {
pt match {
- case Function1(arg, HasMethodMatching(name, argtpes, restpe)) =>
+ case Function1(arg, res) =>
normalize(tp) match {
case Function1(arg1, res1) =>
- (arg <:< arg1) &&
- (res1.member(name) filter (m => isApplicableSafe(undet, m.tpe, argtpes, restpe))) != NoSymbol
- case _ =>
- false
+ (arg.deconst weak_<:< arg1) && {
+ res match {
+ case HasMethodMatching(name, argtpes, restpe) =>
+ (res1.member(name) filter (m =>
+ isApplicableSafe(undet, m.tpe, argtpes, restpe))) != NoSymbol
+ case _ =>
+ res1 <:< res
+ }
+ }
+ case _ => false
}
- case _ =>
- false
+ case _ => false
}
}
+ }
//if (traceImplicits) println("typed impl for "+wildPt+"? "+info.name+":"+depoly(info.tpe)+"/"+undetParams+"/"+isPlausiblyCompatible(info.tpe, wildPt)+"/"+matchesPt(depoly(info.tpe), wildPt, List()))
if (isPlausiblyCompatible(info.tpe, wildPt) &&
@@ -734,47 +741,50 @@ self: Analyzer =>
def findSubManifest(tp: Type) = findManifest(tp, if (full) FullManifestClass else OptManifestClass)
- def mot(tp0: Type): Tree = tp0.normalize match {
- case ThisType(_) | SingleType(_, _) =>
- manifestFactoryCall("singleType", tp, gen.mkAttributedQualifier(tp0))
- case ConstantType(value) =>
- manifestOfType(tp0.deconst, full)
- case TypeRef(pre, sym, args) =>
- if (isValueClass(sym) || isPhantomClass(sym)) {
- typed { atPos(tree.pos.focus) {
- Select(gen.mkAttributedRef(FullManifestModule), sym.name.toString)
- }}
- } else if (sym == ArrayClass && args.length == 1) {
- manifestFactoryCall("arrayType", args.head, findSubManifest(args.head))
- } else if (sym.isClass) {
- val suffix = gen.mkClassOf(tp0) :: (args map findSubManifest)
- manifestFactoryCall(
- "classType", tp,
- (if ((pre eq NoPrefix) || pre.typeSymbol.isStaticOwner) suffix
- else findSubManifest(pre) :: suffix): _*)
- } else if (sym.isAbstractType) {
- if (sym.isExistential)
- EmptyTree // todo: change to existential parameter manifest
- else if (sym.isTypeParameterOrSkolem)
- EmptyTree // a manifest should have been found by normal searchImplicit
- else
+ def mot(tp0: Type): Tree = {
+ val tp1 = tp0.normalize
+ tp1 match {
+ case ThisType(_) | SingleType(_, _) =>
+ manifestFactoryCall("singleType", tp, gen.mkAttributedQualifier(tp1))
+ case ConstantType(value) =>
+ manifestOfType(tp1.deconst, full)
+ case TypeRef(pre, sym, args) =>
+ if (isValueClass(sym) || isPhantomClass(sym)) {
+ typed { atPos(tree.pos.focus) {
+ Select(gen.mkAttributedRef(FullManifestModule), sym.name.toString)
+ }}
+ } else if (sym == ArrayClass && args.length == 1) {
+ manifestFactoryCall("arrayType", args.head, findSubManifest(args.head))
+ } else if (sym.isClass) {
+ val suffix = gen.mkClassOf(tp1) :: (args map findSubManifest)
manifestFactoryCall(
- "abstractType", tp,
- findSubManifest(pre) :: Literal(sym.name.toString) :: findManifest(tp0.bounds.hi) :: (args map findSubManifest): _*)
- } else {
- EmptyTree // a manifest should have been found by normal searchImplicit
- }
- case RefinedType(parents, decls) =>
- // refinement is not generated yet
- if (parents.length == 1) findManifest(parents.head)
- else manifestFactoryCall("intersectionType", tp, parents map (findSubManifest(_)): _*)
- case ExistentialType(tparams, result) =>
- existentialAbstraction(tparams, result) match {
- case ExistentialType(_, _) => mot(result)
- case t => mot(t)
- }
- case _ =>
- EmptyTree
+ "classType", tp,
+ (if ((pre eq NoPrefix) || pre.typeSymbol.isStaticOwner) suffix
+ else findSubManifest(pre) :: suffix): _*)
+ } else if (sym.isAbstractType) {
+ if (sym.isExistential)
+ EmptyTree // todo: change to existential parameter manifest
+ else if (sym.isTypeParameterOrSkolem)
+ EmptyTree // a manifest should have been found by normal searchImplicit
+ else
+ manifestFactoryCall(
+ "abstractType", tp,
+ findSubManifest(pre) :: Literal(sym.name.toString) :: findManifest(tp1.bounds.hi) :: (args map findSubManifest): _*)
+ } else {
+ EmptyTree // a manifest should have been found by normal searchImplicit
+ }
+ case RefinedType(parents, decls) =>
+ // refinement is not generated yet
+ if (parents.length == 1) findManifest(parents.head)
+ else manifestFactoryCall("intersectionType", tp, parents map (findSubManifest(_)): _*)
+ case ExistentialType(tparams, result) =>
+ existentialAbstraction(tparams, result) match {
+ case ExistentialType(_, _) => mot(result)
+ case t => mot(t)
+ }
+ case _ =>
+ EmptyTree
+ }
}
mot(tp)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 0c3e34f8c5..d11f263677 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -404,7 +404,7 @@ trait Infer {
val l = args.length - 1
l == formals.length &&
sym == FunctionClass(l) &&
- List.forall2(args, formals) (isPlausiblySubType) &&
+ ((args, formals).zipped forall isPlausiblySubType) &&
isPlausiblySubType(tp.resultApprox, args.last)
}
case _ =>
@@ -418,7 +418,8 @@ trait Infer {
case TypeRef(_, sym1, _) =>
!sym1.isClass || {
tp2.normalize match {
- case TypeRef(_, sym2, _) => !sym2.isClass || (sym1 isSubClass sym2)
+ case TypeRef(_, sym2, _) =>
+ !sym2.isClass || (sym1 isSubClass sym2) || isNumericSubType(tp1, tp2)
case _ => true
}
}
@@ -458,7 +459,7 @@ trait Infer {
def isCoercible(tp: Type, pt: Type): Boolean = false
def isCompatibleArgs(tps: List[Type], pts: List[Type]): Boolean =
- List.map2(tps, pts)((tp, pt) => isCompatibleArg(tp, pt)) forall (x => x)
+ (tps, pts).zipped forall isCompatibleArg
/* -- Type instantiation------------------------------------------------ */
@@ -495,9 +496,9 @@ trait Infer {
* @param pt ...
* @return ...
*/
- private def exprTypeArgs(tparams: List[Symbol], restpe: Type, pt: Type): List[Type] = {
+ private def exprTypeArgs(tparams: List[Symbol], restpe: Type, pt: Type, checkCompat: (Type, Type) => Boolean = isCompatible): List[Type] = {
val tvars = tparams map freshVar
- if (isCompatible(restpe.instantiateTypeParams(tparams, tvars), pt)) {
+ if (checkCompat(restpe.instantiateTypeParams(tparams, tvars), pt)) {
try {
// If the restpe is an implicit method, and the expected type is fully defined
// optimze type varianbles wrt to the implicit formals only; ignore the result type.
@@ -562,7 +563,7 @@ trait Infer {
}
val tvars = tparams map freshVar
if (isConservativelyCompatible(restpe.instantiateTypeParams(tparams, tvars), pt))
- List.map2(tparams, tvars) ((tparam, tvar) =>
+ (tparams, tvars).zipped map ((tparam, tvar) =>
instantiateToBound(tvar, varianceInTypes(formals)(tparam)))
else
tvars map (tvar => WildcardType)
@@ -582,7 +583,7 @@ trait Infer {
@inline def notCovariantIn(tparam: Symbol, restpe: Type) =
(varianceInType(restpe)(tparam) & COVARIANT) == 0 // tparam occurred non-covariantly (in invariant or contravariant position)
- List.map2(tparams, targs) {(tparam, targ) =>
+ (tparams, targs).zipped map { (tparam, targ) =>
if (targ.typeSymbol == NothingClass && (restpe == WildcardType || notCovariantIn(tparam, restpe))) {
uninstantiated += tparam
tparam.tpeHK //@M tparam.tpe was wrong: we only want the type constructor,
@@ -659,7 +660,7 @@ trait Infer {
if (!isFullyDefined(tvar)) tvar.constr.inst = NoType
// Then define remaining type variables from argument types.
- List.map2(argtpes, formals) {(argtpe, formal) =>
+ (argtpes, formals).zipped map { (argtpe, formal) =>
//@M isCompatible has side-effect: isSubtype0 will register subtype checks in the tvar's bounds
if (!isCompatibleArg(argtpe.deconst.instantiateTypeParams(tparams, tvars),
formal.instantiateTypeParams(tparams, tvars))) {
@@ -787,7 +788,8 @@ trait Infer {
try {
val uninstantiated = new ListBuffer[Symbol]
val targs = methTypeArgs(undetparams, formals, restpe, argtpes, pt, uninstantiated)
- (exprTypeArgs(uninstantiated.toList, restpe.instantiateTypeParams(undetparams, targs), pt) ne null) &&
+ // #2665: must use weak conformance, not regular one (follow the monorphic case above)
+ (exprTypeArgs(uninstantiated.toList, restpe.instantiateTypeParams(undetparams, targs), pt, isWeaklyCompatible) ne null) &&
isWithinBounds(NoPrefix, NoSymbol, undetparams, targs)
} catch {
case ex: NoInstance => false
@@ -1032,8 +1034,8 @@ trait Infer {
(tparams map (_.defString)).mkString("[", ",", "]"))
if (settings.explaintypes.value) {
val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, targs).bounds)
- List.map2(targs, bounds)((targ, bound) => explainTypes(bound.lo, targ))
- List.map2(targs, bounds)((targ, bound) => explainTypes(targ, bound.hi))
+ (targs, bounds).zipped foreach ((targ, bound) => explainTypes(bound.lo, targ))
+ (targs, bounds).zipped foreach ((targ, bound) => explainTypes(targ, bound.hi))
()
}
}
@@ -1620,7 +1622,7 @@ trait Infer {
* assignment expression.
*/
def inferMethodAlternative(tree: Tree, undetparams: List[Symbol],
- argtpes: List[Type], pt0: Type): Unit = tree.tpe match {
+ argtpes: List[Type], pt0: Type, varArgsOnly: Boolean = false): Unit = tree.tpe match {
case OverloadedType(pre, alts) =>
val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0
tryTwice {
@@ -1631,6 +1633,9 @@ trait Infer {
var allApplicable = alts filter (alt =>
isApplicable(undetparams, followApply(pre.memberType(alt)), argtpes, pt))
+ if (varArgsOnly)
+ allApplicable = allApplicable filter (alt => isVarArgs(alt.tpe.paramTypes))
+
// if there are multiple, drop those that use a default
// (keep those that use vararg / tupling conversion)
val applicable =
@@ -1736,7 +1741,7 @@ trait Infer {
if (sym.hasFlag(OVERLOADED)) {
val tparams = new AsSeenFromMap(pre, sym.alternatives.head.owner).mapOver(
sym.alternatives.head.typeParams)
- val bounds = tparams map (_.tpe) //@M TODO: might be affected by change to tpe in Symbol
+ val bounds = tparams map (_.tpeHK) // see e.g., #1236
val tpe =
PolyType(tparams,
OverloadedType(AntiPolyType(pre, bounds), sym.alternatives))
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index d4a7b9e1e7..f4216f7958 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -290,52 +290,55 @@ trait Namers { self: Analyzer =>
if (m.isModule && inCurrentScope(m) && currentRun.compiles(m)) m
else enterSyntheticSym(creator)
}
-
- def enterSym(tree: Tree): Context = try {
-
- def finishWith(tparams: List[TypeDef]) {
- val sym = tree.symbol
- if (settings.debug.value) log("entered " + sym + " in " + context.owner + ", scope-id = " + context.scope.hashCode());
- var ltype = namerOf(sym).typeCompleter(tree)
- if (!tparams.isEmpty) {
- //@M! TypeDef's type params are handled differently
- //@M e.g., in [A[x <: B], B], A and B are entered first as both are in scope in the definition of x
- //@M x is only in scope in `A[x <: B]'
- if(!sym.isAbstractType) //@M TODO: change to isTypeMember ?
- newNamer(context.makeNewScope(tree, sym)).enterSyms(tparams)
-
- ltype = new PolyTypeCompleter(tparams, ltype, tree, sym, context) //@M
- if (sym.isTerm) skolemize(tparams)
- }
- def copyIsSynthetic() = sym.owner.info.member(nme.copy).hasFlag(SYNTHETIC)
- if (sym.name == nme.copy && sym.hasFlag(SYNTHETIC) ||
- sym.name.startsWith(nme.copy + "$default$") && copyIsSynthetic()){
- // the 'copy' method of case classes needs a special type completer to make bug0054.scala (and others)
- // work. the copy method has to take exactly the same parameter types as the primary constructor.
- setInfo(sym)(mkTypeCompleter(tree)(copySym => {
- val constrType = copySym.owner.primaryConstructor.tpe
- val subst = new SubstSymMap(copySym.owner.typeParams, tparams map (_.symbol))
- for ((params, cparams) <- tree.asInstanceOf[DefDef].vparamss.zip(constrType.paramss);
- (param, cparam) <- params.zip(cparams)) {
- // need to clone the type cparam.tpe??? problem is: we don't have the new owner yet (the new param symbol)
- param.tpt.setType(subst(cparam.tpe))
- () // @LUC TODO workaround for #1996
- }
- ltype.complete(sym)
- }))
- } else setInfo(sym)(ltype)
+ private def enterSymFinishWith(tree: Tree, tparams: List[TypeDef]) {
+ val sym = tree.symbol
+ if (settings.debug.value) log("entered " + sym + " in " + context.owner + ", scope-id = " + context.scope.hashCode());
+ var ltype = namerOf(sym).typeCompleter(tree)
+ if (!tparams.isEmpty) {
+ //@M! TypeDef's type params are handled differently
+ //@M e.g., in [A[x <: B], B], A and B are entered first as both are in scope in the definition of x
+ //@M x is only in scope in `A[x <: B]'
+ if(!sym.isAbstractType) //@M TODO: change to isTypeMember ?
+ newNamer(context.makeNewScope(tree, sym)).enterSyms(tparams)
+
+ ltype = new PolyTypeCompleter(tparams, ltype, tree, sym, context) //@M
+ if (sym.isTerm) skolemize(tparams)
}
- def finish = finishWith(List())
+ def copyIsSynthetic() = sym.owner.info.member(nme.copy).hasFlag(SYNTHETIC)
+ if (sym.name == nme.copy && sym.hasFlag(SYNTHETIC) ||
+ sym.name.startsWith(nme.copy + "$default$") && copyIsSynthetic()){
+ // the 'copy' method of case classes needs a special type completer to make bug0054.scala (and others)
+ // work. the copy method has to take exactly the same parameter types as the primary constructor.
+ setInfo(sym)(mkTypeCompleter(tree)(copySym => {
+ val constrType = copySym.owner.primaryConstructor.tpe
+ val subst = new SubstSymMap(copySym.owner.typeParams, tparams map (_.symbol))
+ for ((params, cparams) <- tree.asInstanceOf[DefDef].vparamss.zip(constrType.paramss);
+ (param, cparam) <- params.zip(cparams)) {
+ // need to clone the type cparam.tpe??? problem is: we don't have the new owner yet (the new param symbol)
+ param.tpt.setType(subst(cparam.tpe))
+ () // @LUC TODO workaround for #1996
+ }
+ ltype.complete(sym)
+ }))
+ } else setInfo(sym)(ltype)
+ }
+
+ def enterSym(tree: Tree): Context = {
+ def finishWith(tparams: List[TypeDef]) { enterSymFinishWith(tree, tparams) }
+ def finish = finishWith(Nil)
+ def sym = tree.symbol
+ if (sym != NoSymbol)
+ return this.context
- if (tree.symbol == NoSymbol) {
+ try {
val owner = context.owner
tree match {
case PackageDef(pid, stats) =>
tree.symbol = enterPackageSymbol(tree.pos, pid,
if (context.owner == EmptyPackageClass) RootClass else context.owner)
- val namer = newNamer(
- context.make(tree, tree.symbol.moduleClass, tree.symbol.info.decls))
- namer.enterSyms(stats)
+ val namer = newNamer(context.make(tree, sym.moduleClass, sym.info.decls))
+ namer enterSyms stats
+
case tree @ ClassDef(mods, name, tparams, impl) =>
tree.symbol = enterClassSymbol(tree)
finishWith(tparams)
@@ -343,26 +346,23 @@ trait Namers { self: Analyzer =>
val m = ensureCompanionObject(tree, caseModuleDef(tree))
caseClassOfModuleClass(m.moduleClass) = tree
}
- val constrs = impl.body filter {
- case DefDef(_, name, _, _, _, _) => name == nme.CONSTRUCTOR
- case _ => false
- }
- val hasDefault = constrs.exists(c => {
- val DefDef(_, _, _, vparamss, _, _) = c
- vparamss.exists(_.exists(_.mods hasFlag DEFAULTPARAM))
- })
+ val hasDefault = impl.body flatMap {
+ case DefDef(_, nme.CONSTRUCTOR, _, vparamss, _, _) => vparamss.flatten
+ case _ => Nil
+ } exists (_.mods hasFlag DEFAULTPARAM)
+
if (hasDefault) {
val m = ensureCompanionObject(tree, companionModuleDef(tree, List(gen.scalaScalaObjectConstr)))
classAndNamerOfModule(m) = (tree, null)
}
case tree @ ModuleDef(mods, name, _) =>
tree.symbol = enterModuleSymbol(tree)
- tree.symbol.moduleClass.setInfo(namerOf(tree.symbol).moduleClassTypeCompleter((tree)))
+ sym.moduleClass setInfo namerOf(sym).moduleClassTypeCompleter(tree)
finish
case vd @ ValDef(mods, name, tp, rhs) =>
if ((!context.owner.isClass ||
- (mods.flags & (PRIVATE | LOCAL)) == (PRIVATE | LOCAL).toLong ||
+ (mods.flags & (PRIVATE | LOCAL | CASEACCESSOR)) == (PRIVATE | LOCAL) ||
name.endsWith(nme.OUTER, nme.OUTER.length) ||
context.unit.isJava) &&
!mods.isLazy) {
@@ -370,38 +370,44 @@ trait Namers { self: Analyzer =>
.setFlag(mods.flags))
finish
} else {
+ val mods1 =
+ if (mods.hasFlag(PRIVATE) && mods.hasFlag(LOCAL) && !mods.isLazy) {
+ context.error(tree.pos, "private[this] not allowed for case class parameters")
+ mods &~ LOCAL
+ } else mods
// add getter and possibly also setter
val accflags: Long = ACCESSOR |
- (if ((mods.flags & MUTABLE) != 0L) mods.flags & ~MUTABLE & ~PRESUPER
- else mods.flags & ~PRESUPER | STABLE)
+ (if (mods1.isVariable) mods1.flags & ~MUTABLE & ~PRESUPER
+ else mods1.flags & ~PRESUPER | STABLE)
if (nme.isSetterName(name))
context.error(tree.pos, "Names of vals or vars may not end in `_='")
// .isInstanceOf[..]: probably for (old) IDE hook. is this obsolete?
- val getter = enterAliasMethod(tree, name, accflags, mods)
+ val getter = enterAliasMethod(tree, name, accflags, mods1)
setInfo(getter)(namerOf(getter).getterTypeCompleter(vd))
- if ((mods.flags & MUTABLE) != 0L) {
+ if (mods1.isVariable) {
val setter = enterAliasMethod(tree, nme.getterToSetter(name),
accflags & ~STABLE & ~CASEACCESSOR,
- mods)
+ mods1)
setInfo(setter)(namerOf(setter).setterTypeCompleter(vd))
}
+
tree.symbol =
- if (mods.isDeferred) {
+ if (mods1.isDeferred) {
getter setPos tree.pos // unfocus getter position, because there won't be a separate value
} else {
val vsym =
if (!context.owner.isClass) {
- assert(mods.isLazy) // if not a field, it has to be a lazy val
- owner.newValue(tree.pos, name + "$lzy" ).setFlag(mods.flags | MUTABLE)
+ assert(mods1.isLazy) // if not a field, it has to be a lazy val
+ owner.newValue(tree.pos, name + "$lzy" ).setFlag(mods1.flags | MUTABLE)
} else {
- val mflag = if (mods.isLazy) MUTABLE else 0
- val newflags = mods.flags & FieldFlags | PRIVATE | LOCAL | mflag
-
+ val mFlag = if (mods1.isLazy) MUTABLE else 0
+ val lFlag = if (mods.hasFlag(PRIVATE) && mods.hasFlag(LOCAL)) 0 else LOCAL
+ val newflags = mods1.flags & FieldFlags | PRIVATE | lFlag | mFlag
owner.newValue(tree.pos, nme.getterToLocal(name)) setFlag newflags
}
enterInScope(vsym)
setInfo(vsym)(namerOf(vsym).typeCompleter(tree))
- if (mods.isLazy)
+ if (mods1.isLazy)
vsym.setLazyAccessor(getter)
vsym
@@ -427,17 +433,18 @@ trait Namers { self: Analyzer =>
enterSym(defn)
case imp @ Import(_, _) =>
tree.symbol = NoSymbol.newImport(tree.pos)
- setInfo(tree.symbol)(namerOf(tree.symbol).typeCompleter(tree))
+ setInfo(sym)(namerOf(sym).typeCompleter(tree))
return (context.makeNewImport(imp))
case _ =>
}
}
+ catch {
+ case ex: TypeError =>
+ //Console.println("caught " + ex + " in enterSym")//DEBUG
+ typer.reportTypeError(tree.pos, ex)
+ this.context
+ }
this.context
- } catch {
- case ex: TypeError =>
- //Console.println("caught " + ex + " in enterSym")//DEBUG
- typer.reportTypeError(tree.pos, ex)
- this.context
}
def enterSyntheticSym(tree: Tree): Symbol = {
@@ -615,7 +622,7 @@ trait Namers { self: Analyzer =>
clazz.typeOfThis = selfTypeCompleter(self.tpt)
self.symbol = clazz.thisSym.setPos(self.pos)
} else {
- self.tpt.tpe = NoType
+ self.tpt defineType NoType
if (self.name != nme.WILDCARD) {
clazz.typeOfThis = clazz.tpe
self.symbol = clazz.thisSym
@@ -747,7 +754,7 @@ trait Namers { self: Analyzer =>
var vparamSymss = enterValueParams(meth, vparamss)
if (tpt.isEmpty && meth.name == nme.CONSTRUCTOR) {
- tpt.tpe = context.enclClass.owner.tpe
+ tpt defineType context.enclClass.owner.tpe
tpt setPos meth.pos.focus
}
@@ -873,7 +880,7 @@ trait Namers { self: Analyzer =>
var pfs = resultPt.paramTypes
for (vparam <- vparams) {
if (vparam.tpt.isEmpty) {
- vparam.tpt.tpe = pfs.head
+ vparam.tpt defineType pfs.head
vparam.tpt setPos vparam.pos.focus
vparam.symbol setInfo pfs.head
}
@@ -900,7 +907,7 @@ trait Namers { self: Analyzer =>
}
for (vparams <- vparamss; vparam <- vparams if vparam.tpt.isEmpty) {
context.error(vparam.pos, "missing parameter type")
- vparam.tpt.tpe = ErrorType
+ vparam.tpt defineType ErrorType
}
addDefaultGetters(meth, vparamss, tparams, overriddenSymbol)
@@ -910,7 +917,7 @@ trait Namers { self: Analyzer =>
// replace deSkolemized symbols with skolemized ones (for resultPt computed by looking at overridden symbol, right?)
val pt = resultPt.substSym(tparamSyms, tparams map (_.symbol))
// compute result type from rhs
- tpt.tpe = widenIfNotFinal(meth, typer.computeType(rhs, pt), pt)
+ tpt defineType widenIfNotFinal(meth, typer.computeType(rhs, pt), pt)
tpt setPos meth.pos.focus
tpt.tpe
} else typer.typedType(tpt).tpe
@@ -1148,7 +1155,7 @@ trait Namers { self: Analyzer =>
context.error(tpt.pos, "missing parameter type");
ErrorType
} else {
- tpt.tpe = widenIfNotFinal(
+ tpt defineType widenIfNotFinal(
sym,
newTyper(typer1.context.make(vdef, sym)).computeType(rhs, WildcardType),
WildcardType)
@@ -1268,7 +1275,7 @@ trait Namers { self: Analyzer =>
context.error(sym.pos, "`lazy' definitions may not be initialized early")
if (sym.info.typeSymbol == FunctionClass(0) &&
sym.isValueParameter && sym.owner.isClass && sym.owner.hasFlag(CASE))
- context.error(sym.pos, "pass-by-name arguments not allowed for case class parameters");
+ context.error(sym.pos, "pass-by-name arguments not allowed for case class parameters")
if (sym hasFlag DEFERRED) { // virtual classes count, too
if (sym.hasAnnotation(definitions.NativeAttr))
sym.resetFlag(DEFERRED)
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index 773b2cf561..d36d68163f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -223,7 +223,7 @@ trait NamesDefaults { self: Analyzer =>
*/
def argValDefs(args: List[Tree], paramTypes: List[Type], blockTyper: Typer): List[ValDef] = {
val context = blockTyper.context
- val symPs = List.map2(args, paramTypes)((arg, tpe) => {
+ val symPs = (args, paramTypes).zipped map ((arg, tpe) => {
val byName = tpe.typeSymbol == ByNameParamClass
val s = context.owner.newValue(arg.pos, unit.fresh.newName(arg.pos, "x$"))
val valType = if (byName) functionType(List(), arg.tpe)
@@ -231,7 +231,7 @@ trait NamesDefaults { self: Analyzer =>
s.setInfo(valType)
(context.scope.enter(s), byName)
})
- List.map2(symPs, args)((symP, arg) => {
+ (symPs, args).zipped map ((symP, arg) => {
val (sym, byName) = symP
// resetAttrs required for #2290. given a block { val x = 1; x }, when wrapping into a function
// () => { val x = 1; x }, the owner of symbol x must change (to the apply method of the function).
@@ -270,7 +270,7 @@ trait NamesDefaults { self: Analyzer =>
reorderArgsInv(formals, argPos),
blockTyper)
// refArgs: definition-site order again
- val refArgs = List.map2(reorderArgs(valDefs, argPos), formals)((vDef, tpe) => {
+ val refArgs = (reorderArgs(valDefs, argPos), formals).zipped map ((vDef, tpe) => {
val ref = gen.mkAttributedRef(vDef.symbol)
atPos(vDef.pos.focus) {
// for by-name parameters, the local value is a nullary function returning the argument
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 9b8be2aaec..c4a3981a51 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -368,6 +368,9 @@ abstract class RefChecks extends InfoTransform {
"The kind of the right-hand side "+memberTp.normalize+" of "+member.keyString+" "+
member.varianceString + member.nameString+ " does not conform to its expected kind."+
kindErrors.toList.mkString("\n", ", ", ""))
+ } else if (member.isAbstractType) {
+ if (memberTp.isVolatile && !otherTp.bounds.hi.isVolatile)
+ overrideError("is a volatile type; cannot override a type with non-volatile upper bound")
}
} else if (other.isTerm) {
other.cookJavaRawInfo() // #2454
@@ -398,9 +401,7 @@ abstract class RefChecks extends InfoTransform {
else clazz.toString() + " needs to be abstract") + ", since " + msg);
clazz.setFlag(ABSTRACT)
}
- // Find a concrete Java method that overrides `sym' under the erasure model.
- // Bridge symbols qualify.
- // Used as a fall back if no overriding symbol of a Java abstract method can be found
+
def javaErasedOverridingSym(sym: Symbol): Symbol =
clazz.tpe.nonPrivateMemberAdmitting(sym.name, BRIDGE).filter(other =>
!other.isDeferred &&
@@ -410,10 +411,12 @@ abstract class RefChecks extends InfoTransform {
atPhase(currentRun.erasurePhase.next)(tp1 matches tp2)
})
+ def ignoreDeferred(member: Symbol) =
+ isAbstractTypeWithoutFBound(member) ||
+ ((member hasFlag JAVA) && javaErasedOverridingSym(member) != NoSymbol)
+
for (member <- clazz.tpe.nonPrivateMembersAdmitting(VBRIDGE))
- if (member.isDeferred && !(clazz hasFlag ABSTRACT) &&
- !isAbstractTypeWithoutFBound(member) &&
- !((member hasFlag JAVA) && javaErasedOverridingSym(member) != NoSymbol)) {
+ if (member.isDeferred && !(clazz hasFlag ABSTRACT) && !ignoreDeferred(member)) {
abstractClassError(
false, infoString(member) + " is not defined" + analyzer.varNotice(member))
} else if ((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz)) {
@@ -435,8 +438,8 @@ abstract class RefChecks extends InfoTransform {
// (3) is violated but not (2).
def checkNoAbstractDecls(bc: Symbol) {
for (decl <- bc.info.decls.iterator) {
- if (decl.isDeferred && !isAbstractTypeWithoutFBound(decl)) {
- val impl = decl.matchingSymbol(clazz.thisType)
+ if (decl.isDeferred && !ignoreDeferred(decl)) {
+ val impl = decl.matchingSymbol(clazz.thisType, admit = VBRIDGE)
if (impl == NoSymbol || (decl.owner isSubClass impl.owner)) {
abstractClassError(false, "there is a deferred declaration of "+infoString(decl)+
" which is not implemented in a subclass"+analyzer.varNotice(decl))
@@ -450,21 +453,25 @@ abstract class RefChecks extends InfoTransform {
if (!(clazz hasFlag ABSTRACT)) checkNoAbstractDecls(clazz)
}
- /** Does there exists a symbol declared in class `inclazz` with name `name` and
- * whose type seen as a member of `class.thisType` matches `tpe`?
+ /** Returns whether there is a symbol declared in class `inclazz`
+ * (which must be different from `clazz`) whose name and type
+ * seen as a member of `class.thisType` matches `member`'s.
*/
- def hasMatchingSym(inclazz: Symbol, name: Name, tpe: Type): Boolean =
- inclazz.info.nonPrivateDecl(name).filter(sym =>
- !sym.isTerm || (tpe matches clazz.thisType.memberType(sym))) != NoSymbol
+ def hasMatchingSym(inclazz: Symbol, member: Symbol): Boolean =
+ inclazz != clazz && {
+ val isVarargs = hasRepeatedParam(member.tpe)
+ inclazz.info.nonPrivateDecl(member.name).filter { sym =>
+ !sym.isTerm || {
+ val symtpe = clazz.thisType.memberType(sym)
+ (member.tpe matches symtpe) || isVarargs && (toJavaRepeatedParam(member.tpe) matches symtpe)
+ }
+ } != NoSymbol
+ }
// 4. Check that every defined member with an `override' modifier overrides some other member.
for (member <- clazz.info.decls.toList)
if ((member hasFlag (OVERRIDE | ABSOVERRIDE)) &&
- !(clazz.ancestors exists { bc =>
- hasMatchingSym(bc, member.name, member.tpe) ||
- hasRepeatedParam(member.tpe) &&
- hasMatchingSym(bc, member.name, toJavaRepeatedParam(member.tpe))
- })) {
+ !(clazz.thisType.baseClasses exists (hasMatchingSym(_, member)))) {
// for (bc <- clazz.info.baseClasses.tail) Console.println("" + bc + " has " + bc.info.decl(member.name) + ":" + bc.info.decl(member.name).tpe);//DEBUG
unit.error(member.pos, member.toString() + " overrides nothing");
member resetFlag OVERRIDE
@@ -665,7 +672,7 @@ abstract class RefChecks extends InfoTransform {
class LevelInfo(val outer: LevelInfo) {
val scope: Scope = if (outer eq null) new Scope else new Scope(outer.scope)
- var maxindex: Int = Math.MIN_INT
+ var maxindex: Int = Int.MinValue
var refpos: Position = _
var refsym: Symbol = _
}
@@ -839,7 +846,7 @@ abstract class RefChecks extends InfoTransform {
if (tree.symbol.hasFlag(LAZY)) {
assert(tree.symbol.isTerm, tree.symbol)
val vsym = tree.symbol
- val hasUnitType = (tree.symbol.tpe.typeSymbol == definitions.UnitClass)
+ val hasUnitType = (tree.symbol.tpe.typeSymbol == UnitClass)
val lazyDefSym = vsym.lazyAccessor
assert(lazyDefSym != NoSymbol, vsym)
val ownerTransformer = new ChangeOwnerTraverser(vsym, lazyDefSym)
@@ -870,135 +877,210 @@ abstract class RefChecks extends InfoTransform {
List(transform(tree))
}
- override def transform(tree: Tree): Tree = try {
+ /******** Begin transform inner function section ********/
- /* Check whether argument types conform to bounds of type parameters */
- def checkBounds(pre: Type, owner: Symbol, tparams: List[Symbol], argtps: List[Type]): Unit =
- checkBoundsWithPos(pre, owner, tparams, argtps, tree.pos)
- def checkBoundsWithPos(pre: Type, owner: Symbol, tparams: List[Symbol], argtps: List[Type], pos: Position): Unit = try {
- typer.infer.checkBounds(pos, pre, owner, tparams, argtps, "");
- } catch {
+ /** The private functions between here and 'transform' are conceptually
+ * inner functions to that method, but have been moved outside of it to
+ * ease the burden on the optimizer.
+ */
+
+ /* Check whether argument types conform to bounds of type parameters */
+ private def checkBounds(pre: Type, owner: Symbol, tparams: List[Symbol], argtps: List[Type], pos: Position): Unit =
+ try typer.infer.checkBounds(pos, pre, owner, tparams, argtps, "")
+ catch {
case ex: TypeError =>
unit.error(pos, ex.getMessage());
if (settings.explaintypes.value) {
val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, argtps).bounds)
- List.map2(argtps, bounds)((targ, bound) => explainTypes(bound.lo, targ))
- List.map2(argtps, bounds)((targ, bound) => explainTypes(targ, bound.hi))
+ (argtps, bounds).zipped map ((targ, bound) => explainTypes(bound.lo, targ))
+ (argtps, bounds).zipped map ((targ, bound) => explainTypes(targ, bound.hi))
()
}
}
+ private def isIrrefutable(pat: Tree, seltpe: Type): Boolean = {
+ val result = pat match {
+ case Apply(_, args) =>
+ val clazz = pat.tpe.typeSymbol;
+ clazz == seltpe.typeSymbol &&
+ clazz.isClass && (clazz hasFlag CASE) &&
+ ((args, clazz.primaryConstructor.tpe.asSeenFrom(seltpe, clazz).paramTypes).zipped forall isIrrefutable)
+ case Typed(pat, tpt) =>
+ seltpe <:< tpt.tpe
+ case Ident(nme.WILDCARD) =>
+ true
+ case Bind(_, pat) =>
+ isIrrefutable(pat, seltpe)
+ case _ =>
+ false
+ }
+ //Console.println("is irefutable? " + pat + ":" + pat.tpe + " against " + seltpe + ": " + result);//DEBUG
+ result
+ }
+ /** If symbol is deprecated and is not contained in a deprecated definition,
+ * issue a deprecated warning
+ */
+ private def checkDeprecated(sym: Symbol, pos: Position) {
+ if (sym.isDeprecated && !currentOwner.ownerChain.exists(_.isDeprecated)) {
+ val dmsg = sym.deprecationMessage
+ val msg = sym.toString + sym.locationString +" is deprecated"+
+ (if (dmsg.isDefined) ": "+ dmsg.get
+ else "")
+ unit.deprecationWarning(pos, msg)
+ }
+ }
+ /** Check that a deprecated val or def does not override a
+ * concrete, non-deprecated method. If it does, then
+ * deprecation is meaningless.
+ */
+ private def checkDeprecatedOvers(tree: Tree) {
+ val symbol = tree.symbol
+ if (symbol.isDeprecated) {
+ val concrOvers =
+ symbol.allOverriddenSymbols.filter(sym =>
+ !sym.isDeprecated && !sym.isDeferred)
+ if(!concrOvers.isEmpty)
+ unit.deprecationWarning(
+ tree.pos,
+ symbol.toString + " overrides concrete, non-deprecated symbol(s):" +
+ concrOvers.map(_.name.decode).mkString(" ", ", ", ""))
+ }
+ }
+ private def isRepeatedParamArg(tree: Tree) = currentApplication match {
+ case Apply(fn, args) =>
+ !args.isEmpty && (args.last eq tree) &&
+ fn.tpe.paramTypes.length == args.length && isRepeatedParamType(fn.tpe.paramTypes.last)
+ case _ =>
+ false
+ }
+ private def checkTypeRef(tp: Type, pos: Position) = tp match {
+ case TypeRef(pre, sym, args) =>
+ checkDeprecated(sym, pos)
+ if (!tp.isHigherKinded)
+ checkBounds(pre, sym.owner, sym.typeParams, args, pos)
+ case _ =>
+ }
- def isIrrefutable(pat: Tree, seltpe: Type): Boolean = {
- val result = pat match {
- case Apply(_, args) =>
- val clazz = pat.tpe.typeSymbol;
- clazz == seltpe.typeSymbol &&
- clazz.isClass && (clazz hasFlag CASE) &&
- List.forall2(
- args,
- clazz.primaryConstructor.tpe.asSeenFrom(seltpe, clazz).paramTypes)(isIrrefutable)
- case Typed(pat, tpt) =>
- seltpe <:< tpt.tpe
- case Ident(nme.WILDCARD) =>
- true
- case Bind(_, pat) =>
- isIrrefutable(pat, seltpe)
- case _ =>
- false
- }
- //Console.println("is irefutable? " + pat + ":" + pat.tpe + " against " + seltpe + ": " + result);//DEBUG
- result
+ private def checkAnnotations(tpes: List[Type], pos: Position) = tpes foreach (tp => checkTypeRef(tp, pos))
+ private def doTypeTraversal(tree: Tree)(f: Type => Unit) = if (!inPattern) tree.tpe foreach f
+
+ private def applyRefchecksToAnnotations(tree: Tree) = tree match {
+ case m: MemberDef =>
+ checkAnnotations(m.symbol.annotations map (_.atp), tree.pos)
+ transformTrees(m.symbol.annotations.flatMap(_.args))
+ case TypeTree() => doTypeTraversal(tree) {
+ case AnnotatedType(annots, _, _) =>
+ checkAnnotations(annots map (_.atp), tree.pos)
+ transformTrees(annots.flatMap(_.args))
+ case _ =>
}
+ case _ =>
+ }
- /** If symbol is deprecated and is not contained in a deprecated definition,
- * issue a deprecated warning
- */
- def checkDeprecated(sym: Symbol, pos: Position) {
- if (sym.isDeprecated && !currentOwner.ownerChain.exists(_.isDeprecated)) {
- val dmsg = sym.deprecationMessage
- val msg = sym.toString + sym.locationString +" is deprecated"+
- (if (dmsg.isDefined) ": "+ dmsg.get
- else "")
- unit.deprecationWarning(pos, msg)
- }
+ private def transformCaseApply(tree: Tree, ifNot: => Unit) = {
+ val sym = tree.symbol
+
+ if (sym.isSourceMethod && sym.hasFlag(CASE) && sym.name == nme.apply)
+ toConstructor(tree.pos, tree.tpe)
+ else {
+ ifNot
+ tree
}
+ }
- /** Check that a deprecated val or def does not override a
- * concrete, non-deprecated method. If it does, then
- * deprecation is meaningless.
- */
- def checkDeprecatedOvers() {
- val symbol = tree.symbol
- if (symbol.isDeprecated) {
- val concrOvers =
- symbol.allOverriddenSymbols.filter(sym =>
- !sym.isDeprecated && !sym.isDeferred)
- if(!concrOvers.isEmpty)
- unit.deprecationWarning(
- tree.pos,
- symbol.toString + " overrides concrete, non-deprecated symbol(s):" +
- concrOvers.map(_.name.decode).mkString(" ", ", ", ""))
+ private def transformApply(tree: Apply): Tree = tree match {
+ case Apply(
+ Select(qual, nme.filter),
+ List(Function(
+ List(ValDef(_, pname, tpt, _)),
+ Match(_, CaseDef(pat1, _, _) :: _))))
+ if ((pname startsWith nme.CHECK_IF_REFUTABLE_STRING) &&
+ isIrrefutable(pat1, tpt.tpe) && (qual.tpe <:< tree.tpe)) =>
+
+ qual
+
+ case Apply(Select(New(tpt), name), args)
+ if (tpt.tpe.typeSymbol == ArrayClass && args.length >= 2) =>
+ unit.deprecationWarning(tree.pos,
+ "new Array(...) with multiple dimensions has been deprecated; use Array.ofDim(...) instead")
+ val manif = {
+ var etpe = tpt.tpe
+ for (_ <- args) { etpe = etpe.typeArgs.headOption.getOrElse(NoType) }
+ if (etpe == NoType) {
+ unit.error(tree.pos, "too many dimensions for array creation")
+ Literal(Constant(null))
+ } else {
+ localTyper.getManifestTree(tree.pos, etpe, false)
+ }
}
- }
+ val newResult = localTyper.typedPos(tree.pos) {
+ Apply(Apply(Select(gen.mkAttributedRef(ArrayModule), nme.ofDim), args), List(manif))
+ }
+ currentApplication = tree
+ newResult
- def isRepeatedParamArg(tree: Tree) = currentApplication match {
- case Apply(fn, args) =>
- !args.isEmpty && (args.last eq tree) &&
- fn.tpe.paramTypes.length == args.length && isRepeatedParamType(fn.tpe.paramTypes.last)
- case _ =>
- false
+ case Apply(fn, args) =>
+ checkSensible(tree.pos, fn, args)
+ currentApplication = tree
+ tree
+ }
+ private def transformSelect(tree: Select): Tree = {
+ val Select(qual, name) = tree
+ val sym = tree.symbol
+ checkDeprecated(sym, tree.pos)
+
+ if (currentClass != sym.owner && (sym hasFlag LOCAL)) {
+ var o = currentClass
+ var hidden = false
+ while (!hidden && o != sym.owner && o != sym.owner.moduleClass && !o.isPackage) {
+ hidden = o.isTerm || o.isPrivateLocal
+ o = o.owner
+ }
+ if (!hidden) escapedPrivateLocals += sym
}
- def isCaseApply(sym : Symbol) = sym.isSourceMethod && sym.hasFlag(CASE) && sym.name == nme.apply
+ def checkSuper(mix: Name) =
+ // term should have been eliminated by super accessors
+ assert(!(qual.symbol.isTrait && sym.isTerm && mix == nme.EMPTY.toTypeName))
- def checkTypeRef(tp: Type, pos: Position) = tp match {
- case TypeRef(pre, sym, args) =>
- checkDeprecated(sym, pos)
- if (!tp.isHigherKinded)
- checkBoundsWithPos(pre, sym.owner, sym.typeParams, args, pos)
- case _ =>
- }
- def checkAnnotations(tpes: List[(Type, Position)]) {
- for ((tp, pos) <- tpes) checkTypeRef(tp, pos)
+ transformCaseApply(tree,
+ qual match {
+ case Super(_, mix) => checkSuper(mix)
+ case _ =>
+ }
+ )
+ }
+ private def transformIf(tree: If): Tree = {
+ val If(cond, thenpart, elsepart) = tree
+ def unitIfEmpty(t: Tree): Tree =
+ if (t == EmptyTree) Literal(()).setPos(tree.pos).setType(UnitClass.tpe) else t
+
+ cond.tpe match {
+ case ConstantType(value) =>
+ val res = if (value.booleanValue) thenpart else elsepart
+ unitIfEmpty(res)
+ case _ => tree
}
+ }
+ override def transform(tree: Tree): Tree = try {
val savedLocalTyper = localTyper
val savedCurrentApplication = currentApplication
val sym = tree.symbol
- var result = tree
-
- def doTypeTraversal(f: (Type) => Unit) =
- if (!inPattern) {
- for (tp <- tree.tpe) f(tp)
- }
// Apply RefChecks to annotations. Makes sure the annotations conform to
// type bounds (bug #935), issues deprecation warnings for symbols used
// inside annotations.
- tree match {
- case m: MemberDef =>
- checkAnnotations(m.symbol.annotations.map(a => (a.atp, tree.pos)))
- transformTrees(m.symbol.annotations.flatMap(_.args))
- case TypeTree() => doTypeTraversal {
- case AnnotatedType(annots, _, _) =>
- checkAnnotations(annots.map(a => (a.atp, tree.pos)))
- transformTrees(annots.flatMap(_.args))
- case _ =>
- }
- case _ =>
- }
+ applyRefchecksToAnnotations(tree)
- tree match {
- case DefDef(mods, name, tparams, vparams, tpt, EmptyTree) if tree.symbol.hasAnnotation(definitions.NativeAttr) =>
+ var result: Tree = tree match {
+ case DefDef(mods, name, tparams, vparams, tpt, EmptyTree) if tree.symbol.hasAnnotation(NativeAttr) =>
tree.symbol.resetFlag(DEFERRED)
- result = transform(treeCopy.DefDef(tree, mods, name, tparams, vparams, tpt,
- typed(Apply(gen.mkAttributedRef(definitions.Predef_error), List(Literal("native method stub"))))))
-
- case DefDef(_, _, _, _, _, _) =>
- checkDeprecatedOvers()
+ transform(treeCopy.DefDef(tree, mods, name, tparams, vparams, tpt,
+ typed(Apply(gen.mkAttributedRef(Predef_error), List(Literal("native method stub"))))))
- case ValDef(_, _, _, _) =>
- checkDeprecatedOvers()
+ case ValDef(_, _, _, _) | DefDef(_, _, _, _, _, _) =>
+ checkDeprecatedOvers(tree)
+ tree
case Template(parents, self, body) =>
localTyper = localTyper.atOwner(tree, currentOwner)
@@ -1006,12 +1088,13 @@ abstract class RefChecks extends InfoTransform {
checkDefaultsInOverloaded(currentOwner)
val bridges = addVarargBridges(currentOwner)
checkAllOverrides(currentOwner)
- if (bridges.nonEmpty)
- result = treeCopy.Template(tree, parents, self, body ::: bridges)
+
+ if (bridges.nonEmpty) treeCopy.Template(tree, parents, self, body ::: bridges)
+ else tree
case TypeTree() =>
val existentialParams = new ListBuffer[Symbol]
- doTypeTraversal { // check all bounds, except those that are
+ doTypeTraversal(tree) { // check all bounds, except those that are
// existential type parameters
case ExistentialType(tparams, tpe) =>
existentialParams ++= tparams
@@ -1021,88 +1104,39 @@ abstract class RefChecks extends InfoTransform {
checkTypeRef(t.subst(exparams, wildcards), tree.pos)
case _ =>
}
+ tree
case TypeApply(fn, args) =>
- checkBounds(NoPrefix, NoSymbol, fn.tpe.typeParams, args map (_.tpe))
- if (isCaseApply(sym)) result = toConstructor(tree.pos, tree.tpe)
-
- case Apply(
- Select(qual, nme.filter),
- List(Function(
- List(ValDef(_, pname, tpt, _)),
- Match(_, CaseDef(pat1, _, _) :: _))))
- if ((pname startsWith nme.CHECK_IF_REFUTABLE_STRING) &&
- isIrrefutable(pat1, tpt.tpe) && (qual.tpe <:< tree.tpe)) =>
- result = qual
-
- case Apply(Select(New(tpt), name), args)
- if (tpt.tpe.typeSymbol == ArrayClass && args.length >= 2) =>
- unit.deprecationWarning(tree.pos,
- "new Array(...) with multiple dimensions has been deprecated; use Array.ofDim(...) instead")
- val manif = {
- var etpe = tpt.tpe
- for (_ <- args) { etpe = etpe.typeArgs.headOption.getOrElse(NoType) }
- if (etpe == NoType) {
- unit.error(tree.pos, "too many dimensions for array creation")
- Literal(Constant(null))
- } else {
- localTyper.getManifestTree(tree.pos, etpe, false)
- }
- }
- result = localTyper.typedPos(tree.pos) {
- Apply(Apply(Select(gen.mkAttributedRef(ArrayModule), nme.ofDim), args), List(manif))
- }
- currentApplication = tree
+ checkBounds(NoPrefix, NoSymbol, fn.tpe.typeParams, args map (_.tpe), tree.pos)
+ transformCaseApply(tree, ())
- case Apply(fn, args) =>
- checkSensible(tree.pos, fn, args)
- currentApplication = tree
+ case x @ Apply(_, _) =>
+ transformApply(x)
- case If(cond, thenpart, elsepart) =>
- cond.tpe match {
- case ConstantType(value) =>
- result = if (value.booleanValue) thenpart else elsepart;
- if (result == EmptyTree) result = Literal(()).setPos(tree.pos).setType(UnitClass.tpe)
- case _ =>
- }
+ case x @ If(_, _, _) =>
+ transformIf(x)
case New(tpt) =>
enterReference(tree.pos, tpt.tpe.typeSymbol)
+ tree
- case Typed(expr, tpt @ Ident(name)) if (name == nme.WILDCARD_STAR.toTypeName) =>
- if (!isRepeatedParamArg(tree))
- unit.error(tree.pos, "no `: _*' annotation allowed here\n"+
- "(such annotations are only allowed in arguments to *-parameters)")
+ case Typed(expr, tpt @ Ident(name)) if name == nme.WILDCARD_STAR.toTypeName && !isRepeatedParamArg(tree) =>
+ unit.error(tree.pos, "no `: _*' annotation allowed here\n"+
+ "(such annotations are only allowed in arguments to *-parameters)")
+ tree
case Ident(name) =>
- if (isCaseApply(sym))
- result = toConstructor(tree.pos, tree.tpe)
- else if (name != nme.WILDCARD && name != nme.WILDCARD_STAR.toTypeName) {
- assert(sym != NoSymbol, tree)//debug
- enterReference(tree.pos, sym)
- }
-
- case Select(qual, name) =>
- checkDeprecated(sym, tree.pos)
- if (currentClass != sym.owner && (sym hasFlag LOCAL)) {
- var o = currentClass
- var hidden = false
- while (!hidden && o != sym.owner && o != sym.owner.moduleClass && !o.isPackage) {
- hidden = o.isTerm || o.isPrivateLocal
- o = o.owner
+ transformCaseApply(tree,
+ if (name != nme.WILDCARD && name != nme.WILDCARD_STAR.toTypeName) {
+ assert(sym != NoSymbol, tree) //debug
+ enterReference(tree.pos, sym)
}
- if (!hidden) escapedPrivateLocals += sym
- }
- if (isCaseApply(sym))
- result = toConstructor(tree.pos, tree.tpe)
- else qual match {
- case Super(qualifier, mix) =>
- val base = qual.symbol;
- //Console.println("super: " + tree + " in " + base);//DEBUG
- assert(!(base.isTrait && sym.isTerm && mix == nme.EMPTY.toTypeName)) // term should have been eliminated by super accessors
- case _ =>
- }
- case _ =>
+ )
+
+ case x @ Select(_, _) =>
+ transformSelect(x)
+
+ case _ => tree
}
result = result match {
case CaseDef(pat, guard, body) =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 5001f8b9bf..fac10bfd72 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -27,7 +27,6 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
// inherits abstract value `global' and class `Phase' from Transform
import global._
- import typer.typed
/** the following two members override abstract members in Transform */
val phaseName: String = "superaccessors"
@@ -38,7 +37,6 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
class SuperAccTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
private var validCurrentOwner = true
private var accDefs: List[(Symbol, ListBuffer[Tree])] = List()
- private val typer = analyzer.newTyper(analyzer.rootContext(unit))
private def accDefBuf(clazz: Symbol) = accDefs find (_._1 == clazz) match {
case Some((_, buf)) => buf
@@ -54,17 +52,17 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
*/
private def transformArgs(args: List[Tree], formals: List[Type]) =
- List.map2(args, formals){ (arg, formal) =>
+ ((args, formals).zipped map { (arg, formal) =>
if (formal.typeSymbol == definitions.ByNameParamClass)
withInvalidOwner { checkPackedConforms(transform(arg), formal.typeArgs.head) }
else transform(arg)
- } :::
+ }) :::
(args drop formals.length map transform)
private def checkPackedConforms(tree: Tree, pt: Type): Tree = {
if (tree.tpe exists (_.typeSymbol.isExistentialSkolem)) {
- val packed = typer.packedType(tree, NoSymbol)
- if (!(packed <:< pt)) typer.infer.typeError(tree.pos, packed, pt)
+ val packed = localTyper.packedType(tree, NoSymbol)
+ if (!(packed <:< pt)) localTyper.infer.typeError(tree.pos, packed, pt)
}
tree
}
@@ -115,7 +113,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
superAcc.setInfo(superAccTpe.cloneInfo(superAcc))
//println("creating super acc "+superAcc+":"+superAcc.tpe)//DEBUG
clazz.info.decls enter superAcc;
- accDefBuf(clazz) += typed(DefDef(superAcc, EmptyTree))
+ accDefBuf(clazz) += typers(clazz).typed(DefDef(superAcc, EmptyTree))
}
atPos(sup.pos) {
Select(gen.mkAttributedThis(clazz), superAcc) setType tree.tpe;
@@ -128,112 +126,107 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
tree
}
- override def transform(tree: Tree): Tree = try { tree match {
- case ClassDef(_, _, _, _) =>
- checkCompanionNameClashes(tree.symbol)
- val decls = tree.symbol.info.decls
- for (sym <- decls.toList) {
- if (sym.privateWithin.isClass && !sym.privateWithin.isModuleClass &&
- !sym.hasFlag(EXPANDEDNAME) && !sym.isConstructor) {
- decls.unlink(sym)
- sym.expandName(sym.privateWithin)
- decls.enter(sym)
- }
- }
- super.transform(tree)
- case ModuleDef(_, _, _) =>
- checkCompanionNameClashes(tree.symbol)
- super.transform(tree)
- case Template(parents, self, body) =>
- val ownAccDefs = new ListBuffer[Tree];
- accDefs = (currentOwner, ownAccDefs) :: accDefs;
-
- // ugly hack... normally, the following line should not be
- // necessary, the 'super' method taking care of that. but because
- // that one is iterating through parents (and we dont want that here)
- // we need to inline it.
- curTree = tree
- val body1 = atOwner(currentOwner) { transformTrees(body) }
- accDefs = accDefs.tail;
- treeCopy.Template(tree, parents, self, ownAccDefs.toList ::: body1);
-
- case TypeApply(sel @ Select(This(_), name), args) =>
- val sym = tree.symbol
- if (needsProtectedAccessor(sym, tree.pos)) {
- if (settings.debug.value) log("Adding protected accessor for " + tree);
- transform(makeAccessor(sel.asInstanceOf[Select], args))
- } else
- tree
+ override def transform(tree: Tree): Tree = {
+ val sym = tree.symbol
- case Select(qual @ This(_), name) =>
- val sym = tree.symbol
- if ((sym hasFlag PARAMACCESSOR) && (sym.alias != NoSymbol)) {
- val result = typed {
- Select(
- Super(qual.symbol, nme.EMPTY.toTypeName/*qual.symbol.info.parents.head.symbol.name*/) setPos qual.pos,
- sym.alias) setPos tree.pos
- }
+ def mayNeedProtectedAccessor(sel: Select, args: List[Tree], goToSuper: Boolean) =
+ if (needsProtectedAccessor(sym, tree.pos)) {
if (settings.debug.value)
- Console.println("alias replacement: " + tree + " ==> " + result);//debug
- transformSuperSelect(result)
- } else {
- if (needsProtectedAccessor(sym, tree.pos)) {
- if (settings.debug.value) log("Adding protected accessor for " + tree);
- transform(makeAccessor(tree.asInstanceOf[Select], List(EmptyTree)))
- } else
- tree
- }
- case Select(sup @ Super(_, mix), name) =>
- val sym = tree.symbol
- if (sym.isValue && !sym.isMethod || sym.hasFlag(ACCESSOR)) {
- unit.error(tree.pos, "super may be not be used on "+
- (if (sym.hasFlag(ACCESSOR)) sym.accessed else sym))
- }
- transformSuperSelect(tree)
+ log("Adding protected accessor for " + tree)
- case TypeApply(sel @ Select(qual, name), args) =>
- val sym = tree.symbol
- if (needsProtectedAccessor(sym, tree.pos)) {
- if (settings.debug.value) log("Adding protected accessor for tree: " + tree);
- transform(makeAccessor(sel.asInstanceOf[Select], args))
- } else
+ transform(makeAccessor(sel, args))
+ }
+ else if (goToSuper) super.transform(tree)
+ else tree
+
+ try tree match {
+ case ClassDef(_, _, _, _) =>
+ checkCompanionNameClashes(sym)
+ val decls = sym.info.decls
+ for (s <- decls.toList) {
+ if (s.privateWithin.isClass && !s.privateWithin.isModuleClass &&
+ !s.hasFlag(EXPANDEDNAME) && !s.isConstructor) {
+ decls.unlink(s)
+ s.expandName(s.privateWithin)
+ decls.enter(s)
+ }
+ }
super.transform(tree)
-
- case Select(qual, name) =>
- val sym = tree.symbol
- if (needsProtectedAccessor(sym, tree.pos)) {
- if (settings.debug.value) log("Adding protected accessor for tree: " + tree);
- transform(makeAccessor(tree.asInstanceOf[Select], List(EmptyTree)))
- } else
+ case ModuleDef(_, _, _) =>
+ checkCompanionNameClashes(sym)
super.transform(tree)
+ case Template(parents, self, body) =>
+ val ownAccDefs = new ListBuffer[Tree];
+ accDefs = (currentOwner, ownAccDefs) :: accDefs;
+
+ // ugly hack... normally, the following line should not be
+ // necessary, the 'super' method taking care of that. but because
+ // that one is iterating through parents (and we dont want that here)
+ // we need to inline it.
+ curTree = tree
+ val body1 = atOwner(currentOwner) { transformTrees(body) }
+ accDefs = accDefs.tail;
+ treeCopy.Template(tree, parents, self, ownAccDefs.toList ::: body1);
+
+ case TypeApply(sel @ Select(This(_), name), args) =>
+ mayNeedProtectedAccessor(sel, args, false)
+
+ case sel @ Select(qual @ This(_), name) =>
+ if ((sym hasFlag PARAMACCESSOR) && (sym.alias != NoSymbol)) {
+ val result = localTyper.typed {
+ Select(
+ Super(qual.symbol, nme.EMPTY.toTypeName/*qual.symbol.info.parents.head.symbol.name*/) setPos qual.pos,
+ sym.alias) setPos tree.pos
+ }
+ if (settings.debug.value)
+ Console.println("alias replacement: " + tree + " ==> " + result);//debug
+ transformSuperSelect(result)
+ }
+ else mayNeedProtectedAccessor(sel, List(EmptyTree), false)
- case Assign(lhs @ Select(qual, name), rhs) =>
- if (lhs.symbol.isVariable &&
- lhs.symbol.hasFlag(JAVA) &&
- needsProtectedAccessor(lhs.symbol, tree.pos)) {
- if (settings.debug.value) log("Adding protected setter for " + tree)
- val setter = makeSetter(lhs);
- if (settings.debug.value)
- log("Replaced " + tree + " with " + setter);
- transform(typed(Apply(setter, List(qual, rhs))))
- } else
+ case Select(sup @ Super(_, mix), name) =>
+ if (sym.isValue && !sym.isMethod || sym.hasFlag(ACCESSOR)) {
+ unit.error(tree.pos, "super may be not be used on "+
+ (if (sym.hasFlag(ACCESSOR)) sym.accessed else sym))
+ }
+ transformSuperSelect(tree)
+
+ case TypeApply(sel @ Select(qual, name), args) =>
+ mayNeedProtectedAccessor(sel, args, true)
+
+ case sel @ Select(qual, name) =>
+ mayNeedProtectedAccessor(sel, List(EmptyTree), true)
+
+ case Assign(lhs @ Select(qual, name), rhs) =>
+ if (lhs.symbol.isVariable &&
+ lhs.symbol.hasFlag(JAVA) &&
+ needsProtectedAccessor(lhs.symbol, tree.pos)) {
+ if (settings.debug.value) log("Adding protected setter for " + tree)
+ val setter = makeSetter(lhs);
+ if (settings.debug.value)
+ log("Replaced " + tree + " with " + setter);
+ transform(localTyper.typed(Apply(setter, List(qual, rhs))))
+ } else
+ super.transform(tree)
+
+ case Apply(fn, args) =>
+ assert(fn.tpe != null, tree)
+ treeCopy.Apply(tree, transform(fn), transformArgs(args, fn.tpe.paramTypes))
+ case Function(vparams, body) =>
+ withInvalidOwner {
+ treeCopy.Function(tree, vparams, transform(body))
+ }
+ case _ =>
super.transform(tree)
+ }
+ catch {
+ case ex : AssertionError =>
+ if (sym != null && sym != NoSymbol)
+ Console.println("TRANSFORM: " + tree.symbol.sourceFile)
- case Apply(fn, args) =>
- assert(fn.tpe != null, tree)
- treeCopy.Apply(tree, transform(fn), transformArgs(args, fn.tpe.paramTypes))
- case Function(vparams, body) =>
- withInvalidOwner {
- treeCopy.Function(tree, vparams, transform(body))
- }
- case _ =>
- super.transform(tree)
- }} catch {
- case ex : AssertionError =>
- if (tree.symbol != null && tree.symbol != NoSymbol)
- Console.println("TRANSFORM: " + tree.symbol.sourceFile)
- Console.println("TREE: " + tree)
- throw ex
+ Console.println("TREE: " + tree)
+ throw ex
+ }
}
override def atOwner[A](owner: Symbol)(trans: => A): A = {
@@ -295,7 +288,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
val obj = protAcc.paramss.head.head // receiver
protAcc.paramss.tail.zip(allParamTypes(sym.tpe)).foldLeft(Select(Ident(obj), sym): Tree) (
(fun, pvparams) => {
- Apply(fun, (List.map2(pvparams._1, pvparams._2) { (v, origTpe) => makeArg(v, obj, origTpe) } ))
+ Apply(fun, (pvparams._1, pvparams._2).zipped map (makeArg(_, obj, _)))
})
})
@@ -311,7 +304,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
if (settings.debug.value)
log("Replaced " + tree + " with " + res)
- if (hasArgs) typer.typedOperator(res) else typer.typed(res)
+ if (hasArgs) localTyper.typedOperator(res) else localTyper.typed(res)
}
/** Adapt the given argument in call to protected member.
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index a3f628ebb4..d6e6afdac0 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -182,7 +182,7 @@ trait SyntheticMethods extends ast.TreeDSL {
}
// Creates list of parameters and a guard for each
- val (guards, params) = List.map2(clazz.caseFieldAccessors, constrParamTypes)(makeTrees) unzip
+ val (guards, params) = (clazz.caseFieldAccessors, constrParamTypes).zipped map makeTrees unzip
// Verify with canEqual method before returning true.
def canEqualCheck() = {
diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
index 3e8e803c13..9eb89e26bb 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
@@ -42,7 +42,6 @@ abstract class TreeCheckers extends Analyzer {
override def newTyper(context: Context): Typer = new TreeChecker(context)
class TreeChecker(context0: Context) extends Typer(context0) {
-
import infer._
override def typed(tree: Tree, mode: Int, pt: Type): Tree = {
@@ -50,104 +49,80 @@ abstract class TreeCheckers extends Analyzer {
case EmptyTree | TypeTree() =>
;
case _ =>
- try {
- if (!tpeOfTree.contains(tree)) {
- tpeOfTree.update(tree, tree.tpe)
- tree.tpe = null
- }
- val newtree = super.typed(tree, mode, pt);
- if ((newtree ne tree) && !newtree.isInstanceOf[Literal])
- error(tree.pos, "trees differ\n old: " + tree + " [" + tree.getClass() +
- "]\n new: " + newtree + " [" + newtree.getClass() + "]")
- } catch {
- case ex: Throwable =>
- Console.println("exception while typing "+tree)
- throw ex
+ if (!tpeOfTree.contains(tree)) {
+ tpeOfTree.update(tree, tree.tpe)
+ tree.tpe = null
}
+ val newtree = super.typed(tree, mode, pt);
+ if ((newtree ne tree) && !newtree.isInstanceOf[Literal])
+ error(tree.pos, "trees differ\n old: " + tree + " [" + tree.getClass() +
+ "]\n new: " + newtree + " [" + newtree.getClass() + "]")
}
tree
}
object precheck extends Traverser {
override def traverse(tree: Tree) {
- try {
- tree match {
- case DefDef(_, _, _, _, _, _) =>
- if (tree.symbol.hasFlag(ACCESSOR) &&
- !tree.symbol.isDeferred &&
- !tree.symbol.tpe.resultType.isInstanceOf[ConstantType]) {
- assert(tree.symbol.accessed != NoSymbol, tree.symbol)
- assert(tree.symbol.accessed.getter(tree.symbol.owner) == tree.symbol ||
- tree.symbol.accessed.setter(tree.symbol.owner) == tree.symbol)
- }
- case ValDef(_, _, _, _) =>
- if (tree.symbol.hasGetter) {
- assert(tree.symbol.getter(tree.symbol.owner) != NoSymbol, tree.symbol)
- }
- case Apply(_, args) =>
- assert(args forall (EmptyTree !=))
- case Select(_, _) =>
- assert(tree.symbol != NoSymbol, tree)
- case This(_) =>
- if (!(tree.symbol.isStatic && (tree.symbol hasFlag MODULE))) {
- var o = currentOwner
- while (o != tree.symbol) {
- o = o.owner
- if (o == NoSymbol) {
- error(tree.pos, "tree symbol "+tree.symbol+" does not point to enclosing class; tree = "+tree)
- return
- }
- }
+ tree match {
+ case DefDef(_, _, _, _, _, _) =>
+ if (tree.symbol.hasFlag(ACCESSOR) &&
+ !tree.symbol.isDeferred &&
+ !tree.symbol.tpe.resultType.isInstanceOf[ConstantType]) {
+ assert(tree.symbol.accessed != NoSymbol, tree.symbol)
+ assert(tree.symbol.accessed.getter(tree.symbol.owner) == tree.symbol ||
+ tree.symbol.accessed.setter(tree.symbol.owner) == tree.symbol)
+ }
+ case ValDef(_, _, _, _) =>
+ if (tree.symbol.hasGetter) {
+ assert(tree.symbol.getter(tree.symbol.owner) != NoSymbol, tree.symbol)
+ }
+ case Apply(_, args) =>
+ assert(args forall (EmptyTree !=))
+ case Select(_, _) =>
+ assert(tree.symbol != NoSymbol, tree)
+ case This(_) =>
+ if (!(tree.symbol.isStatic && (tree.symbol hasFlag MODULE))) {
+ if (currentOwner.ownerChain takeWhile (_ != tree.symbol) exists (_ == NoSymbol)) {
+ error(tree.pos, "tree symbol "+tree.symbol+" does not point to enclosing class; tree = "+tree)
+ return
}
- case _ =>
- }
- if (tree.pos == NoPosition && tree != EmptyTree) {
- error(tree.pos, "tree without position: " + tree)
- } else if ((tree.tpe eq null) && phase.id >= currentRun.typerPhase.id) {
- error(tree.pos, "tree without type: " + tree)
- } else if (tree.isDef && tree.symbol.owner != currentOwner) {
- var owner = currentOwner
- while (owner.isTerm && !owner.isMethod && tree.symbol.owner != owner)
- owner = owner.owner;
- if (tree.symbol.owner != owner) {
- error(tree.pos, "" + tree.symbol + " has wrong owner: " + tree.symbol.owner +
- tree.symbol.owner.locationString + ", should be: " +
- currentOwner + currentOwner.locationString)
}
- } else {
- super.traverse(tree)
+ case _ =>
+ }
+ if (tree.pos == NoPosition && tree != EmptyTree) {
+ error(tree.pos, "tree without position: " + tree)
+ } else if ((tree.tpe eq null) && phase.id >= currentRun.typerPhase.id) {
+ error(tree.pos, "tree without type: " + tree)
+ } else if (tree.isDef && tree.symbol.owner != currentOwner) {
+ var owner = currentOwner
+ while (owner.isTerm && !owner.isMethod && tree.symbol.owner != owner)
+ owner = owner.owner;
+ if (tree.symbol.owner != owner) {
+ error(tree.pos, "" + tree.symbol + " has wrong owner: " + tree.symbol.owner +
+ tree.symbol.owner.locationString + ", should be: " +
+ currentOwner + currentOwner.locationString)
}
- } catch {
- case ex: Throwable =>
- if (settings.debug.value)
- Console.println("exception when traversing " + tree);
- throw(ex)
+ } else {
+ super.traverse(tree)
}
}
}
object postcheck extends Traverser {
override def traverse(tree: Tree) {
- try {
- tree match {
- case EmptyTree | TypeTree() =>
- ;
- case _ =>
- tpeOfTree.get(tree) match {
- case Some(oldtpe) =>
- if (!(oldtpe =:= tree.tpe))
- error(tree.pos, "types differ\n old: " + oldtpe +
- "\n new: " + tree.tpe + "\n tree: " + tree)
- tree.tpe = oldtpe
- super.traverse(tree)
- case None =>
- }
- }
- } catch {
- case ex: Throwable =>
- if (settings.debug.value)
- Console.println("exception when traversing " + tree);
- throw(ex)
+ tree match {
+ case EmptyTree | TypeTree() =>
+ ;
+ case _ =>
+ tpeOfTree.get(tree) match {
+ case Some(oldtpe) =>
+ if (!(oldtpe =:= tree.tpe))
+ error(tree.pos, "types differ\n old: " + oldtpe +
+ "\n new: " + tree.tpe + "\n tree: " + tree)
+ tree.tpe = oldtpe
+ super.traverse(tree)
+ case None =>
+ }
}
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 6e6fdd3c35..c3ca5d7e30 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1141,7 +1141,7 @@ trait Typers { self: Analyzer =>
if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments")
}
- List.map2(cstats1, treeInfo.preSuperFields(templ.body)) {
+ (cstats1, treeInfo.preSuperFields(templ.body)).zipped map {
(ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe
}
case _ =>
@@ -1314,16 +1314,34 @@ trait Typers { self: Analyzer =>
case ValDef(mods, name, tpt, rhs)
if (mods.flags & (PRIVATE | LOCAL)) != (PRIVATE | LOCAL).toLong && !stat.symbol.isModuleVar =>
+ /** The annotations amongst `annots` that should go on a member of class
+ * `memberClass` (field, getter, setter, beanGetter, beanSetter)
+ */
def memberAnnots(annots: List[AnnotationInfo], memberClass: Symbol) = {
+
+ def hasMatching(metaAnnots: List[AnnotationInfo], orElse: => Boolean) = {
+ // either one of the meta-annotations matches the `memberClass`
+ metaAnnots.exists(_.atp.typeSymbol == memberClass) ||
+ // else, if there is no `target` meta-annotation at all, use the default case
+ (metaAnnots.forall(ann => {
+ val annClass = ann.atp.typeSymbol
+ annClass != GetterClass && annClass != SetterClass &&
+ annClass != BeanGetterClass && annClass != BeanSetterClass
+ }) && orElse)
+ }
+
+ // there was no meta-annotation on `ann`. Look if the class annotations of
+ // `ann` has a `target` annotation, otherwise put `ann` only on fields.
+ def noMetaAnnot(ann: AnnotationInfo) = {
+ hasMatching(ann.atp.typeSymbol.annotations, memberClass == FieldClass)
+ }
+
annots.filter(ann => ann.atp match {
- case AnnotatedType(annots, _, _) =>
- annots.exists(_.atp.typeSymbol == memberClass) ||
- (memberClass == FieldClass && annots.forall(ann => {
- val annClass = ann.atp.typeSymbol
- annClass != GetterClass && annClass != SetterClass &&
- annClass != BeanGetterClass && annClass != BeanSetterClass
- }))
- case _ => memberClass == FieldClass
+ // the annotation type has meta-annotations, e.g. @(foo @getter)
+ case AnnotatedType(metaAnnots, _, _) =>
+ hasMatching(metaAnnots, noMetaAnnot(ann))
+ // there are no meta-annotations, e.g. @foo
+ case _ => noMetaAnnot(ann)
})
}
@@ -1555,7 +1573,7 @@ trait Typers { self: Analyzer =>
if (!superClazz.hasFlag(JAVA)) {
val superParamAccessors = superClazz.constrParamAccessors
if (superParamAccessors.length == superArgs.length) {
- List.map2(superParamAccessors, superArgs) { (superAcc, superArg) =>
+ (superParamAccessors, superArgs).zipped map { (superAcc, superArg) =>
superArg match {
case Ident(name) =>
if (vparamss.exists(_.exists(_.symbol == superArg.symbol))) {
@@ -1715,7 +1733,7 @@ trait Typers { self: Analyzer =>
ddef.tpt.setType(tpt1.tpe)
val typedMods = removeAnnotations(ddef.mods)
var rhs1 =
- if (ddef.name == nme.CONSTRUCTOR) {
+ if (ddef.name == nme.CONSTRUCTOR && !ddef.symbol.hasFlag(STATIC)) { // need this to make it possible to generate static ctors
if (!meth.isPrimaryConstructor &&
(!meth.owner.isClass ||
meth.owner.isModuleClass ||
@@ -1906,7 +1924,7 @@ trait Typers { self: Analyzer =>
if (fun.vparams.length != argpts.length)
errorTree(fun, "wrong number of parameters; expected = " + argpts.length)
else {
- val vparamSyms = List.map2(fun.vparams, argpts) { (vparam, argpt) =>
+ val vparamSyms = (fun.vparams, argpts).zipped map { (vparam, argpt) =>
if (vparam.tpt.isEmpty) {
vparam.tpt.tpe =
if (isFullyDefined(argpt)) argpt
@@ -2083,13 +2101,13 @@ trait Typers { self: Analyzer =>
val losym = tparam.info.bounds.lo.typeSymbol
losym != NothingClass && losym != NullClass
}
- List.exists2(formals, args) {
+ (formals, args).zipped exists {
case (formal, Function(vparams, _)) =>
(vparams exists (_.tpt.isEmpty)) &&
vparams.length <= MaxFunctionArity &&
(formal baseType FunctionClass(vparams.length) match {
case TypeRef(_, _, formalargs) =>
- List.exists2(formalargs, vparams) ((formalarg, vparam) =>
+ (formalargs, vparams).zipped.exists ((formalarg, vparam) =>
vparam.tpt.isEmpty && (tparams exists (formalarg contains))) &&
(tparams forall isLowerBounded)
case _ =>
@@ -2130,6 +2148,10 @@ trait Typers { self: Analyzer =>
val pre = fun.symbol.tpe.prefix
var sym = fun.symbol filter { alt =>
+ // must use pt as expected type, not WildcardType (a tempting quick fix to #2665)
+ // now fixed by using isWeaklyCompatible in exprTypeArgs
+ // TODO: understand why exactly -- some types were not inferred anymore (`ant clean quick.bin` failed)
+ // (I had expected inferMethodAlternative to pick up the slack introduced by using WildcardType here)
isApplicableSafe(context.undetparams, followApply(pre.memberType(alt)), argtypes, pt)
}
if (sym hasFlag OVERLOADED) {
@@ -2164,7 +2186,8 @@ trait Typers { self: Analyzer =>
arg1
}
context.undetparams = undetparams
- inferMethodAlternative(fun, undetparams, argtpes.toList, pt)
+ inferMethodAlternative(fun, undetparams, argtpes.toList, pt,
+ varArgsOnly = args.nonEmpty && treeInfo.isWildcardStarArg(args.last))
doTypedApply(tree, adapt(fun, funMode(mode), WildcardType), args1, mode, pt)
case mt @ MethodType(params, _) =>
@@ -2318,7 +2341,7 @@ trait Typers { self: Analyzer =>
} else {
assert((mode & PATTERNmode) == 0); // this case cannot arise for patterns
val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt)
- val strictTargs = List.map2(lenientTargs, tparams)((targ, tparam) =>
+ val strictTargs = (lenientTargs, tparams).zipped map ((targ, tparam) =>
if (targ == WildcardType) tparam.tpe else targ) //@M TODO: should probably be .tpeHK
def typedArgToPoly(arg: Tree, formal: Type): Tree = {
val lenientPt = formal.instantiateTypeParams(tparams, lenientTargs)
@@ -2330,7 +2353,7 @@ trait Typers { self: Analyzer =>
}
arg1
}
- val args1 = List.map2(args, formals)(typedArgToPoly)
+ val args1 = (args, formals).zipped map typedArgToPoly
if (args1 exists (_.tpe.isError)) setError(tree)
else {
if (settings.debug.value) log("infer method inst "+fun+", tparams = "+tparams+", args = "+args1.map(_.tpe)+", pt = "+pt+", lobounds = "+tparams.map(_.tpe.bounds.lo)+", parambounds = "+tparams.map(_.info));//debug
@@ -2843,7 +2866,7 @@ trait Typers { self: Analyzer =>
* class NPE[T <: NPE[T] @peer]
*
* (Note: -Yself-in-annots must be on to see the problem)
- **/
+ * */
val sym =
context.owner.newLocalDummy(ann.pos)
.newValue(ann.pos, nme.self)
@@ -3591,7 +3614,7 @@ trait Typers { self: Analyzer =>
// @M! added the latter condition
appliedType(tpt1.tpe, argtypes)
else tpt1.tpe.instantiateTypeParams(tparams, argtypes)
- List.map2(args, tparams) { (arg, tparam) => arg match {
+ (args, tparams).zipped map { (arg, tparam) => arg match {
// note: can't use args1 in selector, because Bind's got replaced
case Bind(_, _) =>
if (arg.symbol.isAbstractType)
@@ -3675,7 +3698,7 @@ trait Typers { self: Analyzer =>
case UnApply(fun, args) =>
val fun1 = typed(fun)
val tpes = formalTypes(unapplyTypeList(fun.symbol, fun1.tpe), args.length)
- val args1 = List.map2(args, tpes)(typedPattern(_, _))
+ val args1 = (args, tpes).zipped map (typedPattern(_, _))
treeCopy.UnApply(tree, fun1, args1) setType pt
case ArrayValue(elemtpt, elems) =>
diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala
index aab74d8c02..cb48e432cd 100644
--- a/src/compiler/scala/tools/nsc/util/ClassPath.scala
+++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala
@@ -308,7 +308,7 @@ abstract class MergedClassPath[T] extends ClassPath[T] {
def sourcepaths: List[AbstractFile] = entries.flatMap(_.sourcepaths)
private def addPackage(to: ClassPath[T], pkg: ClassPath[T]) = to match {
- case cp: MergedClassPath[T] =>
+ case cp: MergedClassPath[_] =>
newMergedClassPath(cp.entries ::: List(pkg))
case _ =>
newMergedClassPath(List(to, pkg))
diff --git a/src/compiler/scala/tools/nsc/util/HashSet.scala b/src/compiler/scala/tools/nsc/util/HashSet.scala
index ebc517266b..32aef80d25 100644
--- a/src/compiler/scala/tools/nsc/util/HashSet.scala
+++ b/src/compiler/scala/tools/nsc/util/HashSet.scala
@@ -24,7 +24,7 @@ class HashSet[T >: Null <: AnyRef](val label: String, initialCapacity: Int) exte
table = new Array[AnyRef](capacity)
}
- private def index(x: Int): Int = Math.abs(x % capacity)
+ private def index(x: Int): Int = math.abs(x % capacity)
def findEntry(x: T): T = {
var h = index(x.hashCode())
diff --git a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala
new file mode 100644
index 0000000000..fa1227a859
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala
@@ -0,0 +1,93 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2009 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package util
+
+import java.lang.{ ClassLoader => JavaClassLoader }
+import java.lang.reflect.{ Constructor, Modifier, Method }
+import java.net.URL
+import ScalaClassLoader._
+import scala.util.control.Exception.{ catching }
+
+trait ScalaClassLoader extends JavaClassLoader
+{
+ /** Executing an action with this classloader as context classloader */
+ def asContext[T](action: => T): T = {
+ val oldLoader = getContextLoader
+ try {
+ setContextLoader(this)
+ action
+ }
+ finally setContextLoader(oldLoader)
+ }
+ def setAsContext() { setContextLoader(this) }
+
+ /** Load and link a class with this classloader */
+ def tryToLoadClass[T <: AnyRef](path: String): Option[Class[T]] = tryClass(path, false)
+ /** Load, link and initialize a class with this classloader */
+ def tryToInitializeClass[T <: AnyRef](path: String): Option[Class[T]] = tryClass(path, true)
+
+ private def tryClass[T <: AnyRef](path: String, initialize: Boolean): Option[Class[T]] =
+ catching(classOf[ClassNotFoundException], classOf[SecurityException]) opt
+ Class.forName(path, initialize, this).asInstanceOf[Class[T]]
+
+ /** Create an instance of a class with this classloader */
+ def create(path: String): AnyRef = {
+ tryToInitializeClass(path) match {
+ case Some(clazz) => clazz.newInstance()
+ case None => null
+ }
+ }
+
+ /** Run the main method of a class to be loaded by this classloader */
+ def run(objectName: String, arguments: Seq[String]) {
+ val clsToRun = tryToInitializeClass(objectName) getOrElse (
+ throw new ClassNotFoundException(objectName)
+ )
+
+ val method = clsToRun.getMethod("main", classOf[Array[String]])
+ if (!Modifier.isStatic(method.getModifiers))
+ throw new NoSuchMethodException(objectName + ".main is not static")
+
+ asContext(method.invoke(null, Array(arguments.toArray: AnyRef): _*)) // !!! : AnyRef shouldn't be necessary
+ }
+}
+
+
+object ScalaClassLoader {
+ class URLClassLoader(urls: Seq[URL], parent: JavaClassLoader)
+ extends java.net.URLClassLoader(urls.toArray, parent)
+ with ScalaClassLoader {
+ /** Override to widen to public */
+ override def addURL(url: URL) = super.addURL(url)
+ }
+
+ def setContextLoader(cl: JavaClassLoader) = Thread.currentThread.setContextClassLoader(cl)
+ def getContextLoader() = Thread.currentThread.getContextClassLoader()
+ def getSystemLoader() = JavaClassLoader.getSystemClassLoader()
+ def defaultParentClassLoader() = findExtClassLoader()
+
+ def fromURLs(urls: Seq[URL]): URLClassLoader =
+ new URLClassLoader(urls.toList, defaultParentClassLoader())
+
+ /** True if supplied class exists in supplied path */
+ def classExists(urls: Seq[URL], name: String): Boolean =
+ (fromURLs(urls) tryToLoadClass name).isDefined
+
+ // we cannot use the app classloader here or we get what looks to
+ // be classloader deadlock, but if we pass null we bypass the extension
+ // classloader and our extensions, so we search the hierarchy to find
+ // the classloader whose parent is null. Resolves bug #857.
+ def findExtClassLoader(): JavaClassLoader = {
+ def search(cl: JavaClassLoader): JavaClassLoader = {
+ if (cl == null) null
+ else if (cl.getParent == null) cl
+ else search(cl.getParent)
+ }
+
+ search(getContextLoader())
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/util/TreeSet.scala b/src/compiler/scala/tools/nsc/util/TreeSet.scala
index 1862212467..059ffd26e4 100644
--- a/src/compiler/scala/tools/nsc/util/TreeSet.scala
+++ b/src/compiler/scala/tools/nsc/util/TreeSet.scala
@@ -43,14 +43,10 @@ class TreeSet[T >: Null <: AnyRef](less: (T, T) => Boolean) extends Set[T] {
def iterator = {
def elems(t: Tree): Iterator[T] = {
- var it = Iterator single t.elem
- if (t.l ne null) it = elems(t.l) append it
- if (t.r ne null) it = it append elems(t.r)
- // if (t.l ne null) it = elems(t.l) ++ it
- // if (t.r ne null) it = it ++ elems(t.r)
- it
+ if (t eq null) Iterator.empty
+ else elems(t.l) ++ (Iterator single t.elem) ++ elems(t.r)
}
- if (tree eq null) Iterator.empty else elems(tree)
+ elems(tree)
}
override def toString(): String = {