diff options
author | Antonio Cunei <antonio.cunei@epfl.ch> | 2009-11-24 17:30:44 +0000 |
---|---|---|
committer | Antonio Cunei <antonio.cunei@epfl.ch> | 2009-11-24 17:30:44 +0000 |
commit | 839d0ee5ec9c27e2e5da6bab6f03c8a95e90a109 (patch) | |
tree | 613ed692570fb5891f57e76854d9ff4af8ed13d1 /src/compiler | |
parent | 5f71b9208404015f425f30a0b4b3f4b3df4ec83f (diff) | |
download | scala-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')
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 = { |