summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-02-01 17:38:56 -0800
committerPaul Phillips <paulp@improving.org>2013-02-01 17:38:56 -0800
commita45a78a1d4111709acdc0bca9a1ac869a8e53ea5 (patch)
tree5c909c41db2470c460cbb3c33672294c9342b914 /src
parent26de4394b19d6614b7d414b33f66ebf7adcb8833 (diff)
parent644eb7078a11613a06dcaaefb807cbcc44f65ea7 (diff)
downloadscala-a45a78a1d4111709acdc0bca9a1ac869a8e53ea5.tar.gz
scala-a45a78a1d4111709acdc0bca9a1ac869a8e53ea5.tar.bz2
scala-a45a78a1d4111709acdc0bca9a1ac869a8e53ea5.zip
Merge commit '644eb7078a' into wip/fresh-merge2
Conflicts: build.xml src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala49
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala9
-rw-r--r--src/partest/scala/tools/partest/BytecodeTest.scala61
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala38
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala18
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala12
-rw-r--r--src/reflect/scala/reflect/internal/util/Position.scala8
-rw-r--r--src/scalap/scala/tools/scalap/Main.scala2
11 files changed, 147 insertions, 62 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index 379261906a..5497719f89 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -249,7 +249,7 @@ abstract class TreeBuilder {
/** Create tree representing a while loop */
def makeWhile(lname: TermName, cond: Tree, body: Tree): Tree = {
- val continu = atPos(o2p(body.pos.endOrPoint)) { Apply(Ident(lname), Nil) }
+ val continu = atPos(o2p(body.pos pointOrElse wrappingPos(List(cond, body)).pos.endOrPoint)) { Apply(Ident(lname), Nil) }
val rhs = If(cond, Block(List(body), continu), Literal(Constant()))
LabelDef(lname, Nil, rhs)
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index c1bd7fd389..45c366cc69 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -1036,7 +1036,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
if (needsAnnotation) {
val c = Constant(RemoteExceptionClass.tpe)
val arg = Literal(c) setType c.tpe
- meth.addAnnotation(ThrowsClass, arg)
+ meth.addAnnotation(appliedType(ThrowsClass, c.tpe), arg)
}
}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index 19d03ad04d..5ce4466897 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -1038,7 +1038,13 @@ abstract class ClassfileParser {
val nClasses = in.nextChar
for (n <- 0 until nClasses) {
val cls = pool.getClassSymbol(in.nextChar.toInt)
- sym.addAnnotation(definitions.ThrowsClass, Literal(Constant(cls.tpe)))
+ val tp = if (cls.isMonomorphicType) cls.tpe else {
+ debuglog(s"Encountered polymorphic exception `${cls.fullName}` while parsing class file.")
+ // in case we encounter polymorphic exception the best we can do is to convert that type to
+ // monomorphic one by introducing existientals, see SI-7009 for details
+ typer.packSymbols(cls.typeParams, cls.tpe)
+ }
+ sym.addAnnotation(appliedType(definitions.ThrowsClass, tp), Literal(Constant(tp)))
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
index 6d5eff460f..24f406236f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -742,26 +742,8 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// reference the (i-1)th case accessor if it exists, otherwise the (i-1)th tuple component
override protected def tupleSel(binder: Symbol)(i: Int): Tree = { import CODE._
- // caseFieldAccessors is messed up after typers (reversed, names mangled for non-public fields)
- // TODO: figure out why...
val accessors = binder.caseFieldAccessors
- // luckily, the constrParamAccessors are still sorted properly, so sort the field-accessors using them
- // (need to undo name-mangling, including the sneaky trailing whitespace)
- val constrParamAccessors = binder.constrParamAccessors
-
- def indexInCPA(acc: Symbol) =
- constrParamAccessors indexWhere { orig =>
- // patmatDebug("compare: "+ (orig, acc, orig.name, acc.name, (acc.name == orig.name), (acc.name startsWith (orig.name append "$"))))
- val origName = orig.name.toString.trim
- val accName = acc.name.toString.trim
- (accName == origName) || (accName startsWith (origName + "$"))
- }
-
- // patmatDebug("caseFieldAccessors: "+ (accessors, binder.caseFieldAccessors map indexInCPA))
- // patmatDebug("constrParamAccessors: "+ constrParamAccessors)
-
- val accessorsSorted = accessors sortBy indexInCPA
- if (accessorsSorted isDefinedAt (i-1)) REF(binder) DOT accessorsSorted(i-1)
+ if (accessors isDefinedAt (i-1)) REF(binder) DOT accessors(i-1)
else codegen.tupleSel(binder)(i) // this won't type check for case classes, as they do not inherit ProductN
}
@@ -1887,17 +1869,24 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
case object False extends Prop
// symbols are propositions
- case class Sym(val variable: Var, val const: Const) extends Prop {
- private[this] val id = nextSymId
+ abstract case class Sym(val variable: Var, val const: Const) extends Prop {
+ private[this] val id = Sym.nextSymId
+
override def toString = variable +"="+ const +"#"+ id
}
- private def nextSymId = {_symId += 1; _symId}; private var _symId = 0
-
+ class UniqueSym(variable: Var, const: Const) extends Sym(variable, const)
+ object Sym {
+ private val uniques: util.HashSet[Sym] = new util.HashSet("uniques", 512)
+ def apply(variable: Var, const: Const): Sym = {
+ val newSym = new UniqueSym(variable, const)
+ (uniques findEntryOrUpdate newSym)
+ }
+ private def nextSymId = {_symId += 1; _symId}; private var _symId = 0
+ }
def /\(props: Iterable[Prop]) = if (props.isEmpty) True else props.reduceLeft(And(_, _))
def \/(props: Iterable[Prop]) = if (props.isEmpty) False else props.reduceLeft(Or(_, _))
-
trait PropTraverser {
def apply(x: Prop): Unit = x match {
case And(a, b) => apply(a); apply(b)
@@ -2053,6 +2042,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
import scala.collection.mutable.ArrayBuffer
type FormulaBuilder = ArrayBuffer[Clause]
def formulaBuilder = ArrayBuffer[Clause]()
+ def formulaBuilderSized(init: Int) = new ArrayBuffer[Clause](init)
def addFormula(buff: FormulaBuilder, f: Formula): Unit = buff ++= f
def toFormula(buff: FormulaBuilder): Formula = buff
@@ -2157,7 +2147,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
class Lit(val sym: Sym, val pos: Boolean) {
override def toString = if (!pos) "-"+ sym.toString else sym.toString
override def equals(o: Any) = o match {
- case o: Lit => (o.sym == sym) && (o.pos == pos)
+ case o: Lit => (o.sym eq sym) && (o.pos == pos)
case _ => false
}
override def hashCode = sym.hashCode + pos.hashCode
@@ -2206,13 +2196,18 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
private def withLit(res: Model, l: Lit): Model = if (res eq NoModel) NoModel else res + (l.sym -> l.pos)
- private def dropUnit(f: Formula, unitLit: Lit) = {
+ private def dropUnit(f: Formula, unitLit: Lit): Formula = {
val negated = -unitLit
// drop entire clauses that are trivially true
// (i.e., disjunctions that contain the literal we're making true in the returned model),
// and simplify clauses by dropping the negation of the literal we're making true
// (since False \/ X == X)
- f.filterNot(_.contains(unitLit)).map(_ - negated)
+ val dropped = formulaBuilderSized(f.size)
+ for {
+ clause <- f
+ if !(clause contains unitLit)
+ } dropped += (clause - negated)
+ dropped
}
def findModelFor(f: Formula): Model = {
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index ff3e856471..9949e9181b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -76,14 +76,7 @@ trait SyntheticMethods extends ast.TreeDSL {
else templ
}
- val originalAccessors = clazz.caseFieldAccessors
- // private ones will have been renamed -- make sure they are entered
- // in the original order.
- def accessors = clazz.caseFieldAccessors sortBy { acc =>
- originalAccessors indexWhere { orig =>
- (acc.name == orig.name) || (acc.name startsWith (orig.name append "$"))
- }
- }
+ def accessors = clazz.caseFieldAccessors
val arity = accessors.size
// If this is ProductN[T1, T2, ...], accessorLub is the lub of T1, T2, ..., .
// !!! Hidden behind -Xexperimental due to bummer type inference bugs.
diff --git a/src/partest/scala/tools/partest/BytecodeTest.scala b/src/partest/scala/tools/partest/BytecodeTest.scala
new file mode 100644
index 0000000000..93183c2095
--- /dev/null
+++ b/src/partest/scala/tools/partest/BytecodeTest.scala
@@ -0,0 +1,61 @@
+package scala.tools.partest
+
+import scala.tools.nsc.util.JavaClassPath
+import scala.collection.JavaConverters._
+import scala.tools.asm
+import asm.ClassReader
+import asm.tree.{ClassNode, MethodNode, InsnList}
+import java.io.InputStream
+
+/**
+ * Providies utilities for inspecting bytecode using ASM library.
+ *
+ * HOW TO USE
+ * 1. Create subdirectory in test/files/jvm for your test. Let's name it $TESTDIR.
+ * 2. Create $TESTDIR/BytecodeSrc_1.scala that contains Scala source file which you
+ * want to inspect the bytecode for. The '_1' suffix signals to partest that it
+ * should compile this file first.
+ * 3. Create $TESTDIR/Test.scala:
+ * import scala.tools.partest.BytecodeTest
+ * object Test extends BytecodeTest {
+ * def show {
+ * // your code that inspect ASM trees and prints values
+ * }
+ * }
+ * 4. Create corresponding check file.
+ *
+ * EXAMPLE
+ * See test/files/jvm/bytecode-test-example for an example of bytecode test.
+ *
+ */
+abstract class BytecodeTest {
+
+ /** produce the output to be compared against a checkfile */
+ protected def show(): Unit
+
+ def main(args: Array[String]): Unit = show
+
+ protected def getMethod(classNode: ClassNode, name: String): MethodNode =
+ classNode.methods.asScala.find(_.name == name) getOrElse
+ sys.error(s"Didn't find method '$name' in class '${classNode.name}'")
+
+ protected def loadClassNode(name: String): ClassNode = {
+ val classBytes: InputStream = (for {
+ classRep <- classpath.findClass(name)
+ binary <- classRep.binary
+ } yield binary.input) getOrElse sys.error(s"failed to load class '$name'; classpath = $classpath")
+
+ val cr = new ClassReader(classBytes)
+ val cn = new ClassNode()
+ cr.accept(cn, 0)
+ cn
+ }
+
+ protected lazy val classpath: JavaClassPath = {
+ import scala.tools.nsc.util.ClassPath.DefaultJavaContext
+ import scala.tools.util.PathResolver.Defaults
+ // logic inspired by scala.tools.util.PathResolver implementation
+ val containers = DefaultJavaContext.classesInExpandedPath(Defaults.javaUserClassPath)
+ new JavaClassPath(containers, DefaultJavaContext)
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 6894c68062..bd9c1576a1 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -1611,8 +1611,21 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
setAnnotations(annot :: annotations)
// Convenience for the overwhelmingly common case
- def addAnnotation(sym: Symbol, args: Tree*): this.type =
+ def addAnnotation(sym: Symbol, args: Tree*): this.type = {
+ // The assertion below is meant to prevent from issues like SI-7009 but it's disabled
+ // due to problems with cycles while compiling Scala library. It's rather shocking that
+ // just checking if sym is monomorphic type introduces nasty cycles. We are definitively
+ // forcing too much because monomorphism is a local property of a type that can be checked
+ // syntactically
+ // assert(sym.initialize.isMonomorphicType, sym)
addAnnotation(AnnotationInfo(sym.tpe, args.toList, Nil))
+ }
+
+ /** Use that variant if you want to pass (for example) an applied type */
+ def addAnnotation(tp: Type, args: Tree*): this.type = {
+ assert(tp.typeParams.isEmpty, tp)
+ addAnnotation(AnnotationInfo(tp, args.toList, Nil))
+ }
// ------ comparisons ----------------------------------------------------------------
@@ -1769,8 +1782,27 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** For a case class, the symbols of the accessor methods, one for each
* argument in the first parameter list of the primary constructor.
* The empty list for all other classes.
- */
- final def caseFieldAccessors: List[Symbol] =
+ *
+ * This list will be sorted to correspond to the declaration order
+ * in the constructor parameter
+ */
+ final def caseFieldAccessors: List[Symbol] = {
+ // We can't rely on the ordering of the case field accessors within decls --
+ // handling of non-public parameters seems to change the order (see SI-7035.)
+ //
+ // Luckily, the constrParamAccessors are still sorted properly, so sort the field-accessors using them
+ // (need to undo name-mangling, including the sneaky trailing whitespace)
+ //
+ // The slightly more principled approach of using the paramss of the
+ // primary constructor leads to cycles in, for example, pos/t5084.scala.
+ val primaryNames = constrParamAccessors.map(acc => nme.dropLocalSuffix(acc.name))
+ caseFieldAccessorsUnsorted.sortBy { acc =>
+ primaryNames indexWhere { orig =>
+ (acc.name == orig) || (acc.name startsWith (orig append "$"))
+ }
+ }
+ }
+ private final def caseFieldAccessorsUnsorted: List[Symbol] =
(info.decls filter (_.isCaseAccessorMethod)).toList
final def constrParamAccessors: List[Symbol] =
diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala
index 4c67771485..9b8f86751e 100644
--- a/src/reflect/scala/reflect/internal/TreeInfo.scala
+++ b/src/reflect/scala/reflect/internal/TreeInfo.scala
@@ -253,22 +253,24 @@ abstract class TreeInfo {
* in the position `for { <tree> <- expr }` based only
* on information at the `parser` phase? To qualify, there
* may be no subtree that will be interpreted as a
- * Stable Identifier Pattern.
+ * Stable Identifier Pattern, nor any type tests, even
+ * on TupleN. See SI-6968.
*
* For instance:
*
* {{{
- * foo @ (bar, (baz, quux))
+ * (foo @ (bar @ _)) = 0
* }}}
*
- * is a variable pattern; if the structure matches,
- * then the remainder is inevitable.
+ * is a not a variable pattern; if only binds names.
*
* The following are not variable patterns.
*
* {{{
- * foo @ (bar, (`baz`, quux)) // back quoted ident, not at top level
- * foo @ (bar, Quux) // UpperCase ident, not at top level
+ * `bar`
+ * Bar
+ * (a, b)
+ * _: T
* }}}
*
* If the pattern is a simple identifier, it is always
@@ -297,10 +299,6 @@ abstract class TreeInfo {
tree match {
case Bind(name, pat) => isVarPatternDeep0(pat)
case Ident(name) => isVarPattern(tree)
- case Apply(sel, args) =>
- ( isReferenceToScalaMember(sel, TupleClass(args.size).name.toTermName)
- && (args forall isVarPatternDeep0)
- )
case _ => false
}
}
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 0dfa3abf29..71343cfce2 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -732,7 +732,7 @@ trait Types extends api.Types { self: SymbolTable =>
val trivial = (
this.isTrivial
|| phase.erasedTypes && pre.typeSymbol != ArrayClass
- || pre.normalize.isTrivial && !isPossiblePrefix(clazz)
+ || skipPrefixOf(pre, clazz)
)
if (trivial) this
else {
@@ -4341,14 +4341,15 @@ trait Types extends api.Types { self: SymbolTable =>
*/
def isPossiblePrefix(clazz: Symbol) = clazz.isClass && !clazz.isPackageClass
+ private def skipPrefixOf(pre: Type, clazz: Symbol) = (
+ (pre eq NoType) || (pre eq NoPrefix) || !isPossiblePrefix(clazz)
+ )
+
/** A map to compute the asSeenFrom method */
class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap with KeepOnlyTypeConstraints {
var capturedSkolems: List[Symbol] = List()
var capturedParams: List[Symbol] = List()
- private def skipPrefixOf(pre: Type, clazz: Symbol) = (
- (pre eq NoType) || (pre eq NoPrefix) || !isPossiblePrefix(clazz)
- )
override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = {
object annotationArgRewriter extends TypeMapTransformer {
private def canRewriteThis(sym: Symbol) = (
@@ -4381,8 +4382,7 @@ trait Types extends api.Types { self: SymbolTable =>
}
def apply(tp: Type): Type =
- if (skipPrefixOf(pre, clazz)) tp
- else tp match {
+ tp match {
case ThisType(sym) =>
def toPrefix(pre: Type, clazz: Symbol): Type =
if (skipPrefixOf(pre, clazz)) tp
diff --git a/src/reflect/scala/reflect/internal/util/Position.scala b/src/reflect/scala/reflect/internal/util/Position.scala
index 1c29cabe24..f0185372c5 100644
--- a/src/reflect/scala/reflect/internal/util/Position.scala
+++ b/src/reflect/scala/reflect/internal/util/Position.scala
@@ -91,7 +91,7 @@ abstract class Position extends scala.reflect.api.Position { self =>
/** An optional value containing the source file referred to by this position, or
* None if not defined.
*/
- def source: SourceFile = throw new UnsupportedOperationException("Position.source")
+ def source: SourceFile = throw new UnsupportedOperationException(s"Position.source on ${this.getClass}")
/** Is this position neither a NoPosition nor a FakePosition?
* If isDefined is true, offset and source are both defined.
@@ -111,19 +111,19 @@ abstract class Position extends scala.reflect.api.Position { self =>
def makeTransparent: Position = this
/** The start of the position's range, error if not a range position */
- def start: Int = throw new UnsupportedOperationException("Position.start")
+ def start: Int = throw new UnsupportedOperationException(s"Position.start on ${this.getClass}")
/** The start of the position's range, or point if not a range position */
def startOrPoint: Int = point
/** The point (where the ^ is) of the position */
- def point: Int = throw new UnsupportedOperationException("Position.point")
+ def point: Int = throw new UnsupportedOperationException(s"Position.point on ${this.getClass}")
/** The point (where the ^ is) of the position, or else `default` if undefined */
def pointOrElse(default: Int): Int = default
/** The end of the position's range, error if not a range position */
- def end: Int = throw new UnsupportedOperationException("Position.end")
+ def end: Int = throw new UnsupportedOperationException(s"Position.end on ${this.getClass}")
/** The end of the position's range, or point if not a range position */
def endOrPoint: Int = point
diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala
index 7c84279699..90f8cb8d71 100644
--- a/src/scalap/scala/tools/scalap/Main.scala
+++ b/src/scalap/scala/tools/scalap/Main.scala
@@ -184,7 +184,7 @@ object Main extends Main {
val cparg = List("-classpath", "-cp") map (arguments getArgument _) reduceLeft (_ orElse _)
val path = cparg match {
case Some(cp) => new JavaClassPath(DefaultJavaContext.classesInExpandedPath(cp), DefaultJavaContext)
- case _ => PathResolver.fromPathString("")
+ case _ => PathResolver.fromPathString(".") // include '.' in the default classpath SI-6669
}
// print the classpath if output is verbose
if (verbose)