Skip to content

Commit a45a78a

Browse files
committed
Merge commit '644eb7078a' into wip/fresh-merge2
Conflicts: build.xml src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
2 parents 26de439 + 644eb70 commit a45a78a

File tree

34 files changed

+4357
-81
lines changed

34 files changed

+4357
-81
lines changed

build.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,6 +1252,7 @@ QUICK BUILD (QUICK)
12521252
<pathelement location="${build-quick.dir}/classes/partest"/>
12531253
<pathelement location="${ant.jar}"/>
12541254
<path refid="forkjoin.classpath"/>
1255+
<path refid="asm.classpath"/>
12551256
<pathelement location="${scalacheck.jar}"/>
12561257
</compilationpath>
12571258
</scalacfork>

src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ abstract class TreeBuilder {
249249

250250
/** Create tree representing a while loop */
251251
def makeWhile(lname: TermName, cond: Tree, body: Tree): Tree = {
252-
val continu = atPos(o2p(body.pos.endOrPoint)) { Apply(Ident(lname), Nil) }
252+
val continu = atPos(o2p(body.pos pointOrElse wrappingPos(List(cond, body)).pos.endOrPoint)) { Apply(Ident(lname), Nil) }
253253
val rhs = If(cond, Block(List(body), continu), Literal(Constant()))
254254
LabelDef(lname, Nil, rhs)
255255
}

src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1036,7 +1036,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
10361036
if (needsAnnotation) {
10371037
val c = Constant(RemoteExceptionClass.tpe)
10381038
val arg = Literal(c) setType c.tpe
1039-
meth.addAnnotation(ThrowsClass, arg)
1039+
meth.addAnnotation(appliedType(ThrowsClass, c.tpe), arg)
10401040
}
10411041
}
10421042

src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1038,7 +1038,13 @@ abstract class ClassfileParser {
10381038
val nClasses = in.nextChar
10391039
for (n <- 0 until nClasses) {
10401040
val cls = pool.getClassSymbol(in.nextChar.toInt)
1041-
sym.addAnnotation(definitions.ThrowsClass, Literal(Constant(cls.tpe)))
1041+
val tp = if (cls.isMonomorphicType) cls.tpe else {
1042+
debuglog(s"Encountered polymorphic exception `${cls.fullName}` while parsing class file.")
1043+
// in case we encounter polymorphic exception the best we can do is to convert that type to
1044+
// monomorphic one by introducing existientals, see SI-7009 for details
1045+
typer.packSymbols(cls.typeParams, cls.tpe)
1046+
}
1047+
sym.addAnnotation(appliedType(definitions.ThrowsClass, tp), Literal(Constant(tp)))
10421048
}
10431049
}
10441050

src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -742,26 +742,8 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
742742

743743
// reference the (i-1)th case accessor if it exists, otherwise the (i-1)th tuple component
744744
override protected def tupleSel(binder: Symbol)(i: Int): Tree = { import CODE._
745-
// caseFieldAccessors is messed up after typers (reversed, names mangled for non-public fields)
746-
// TODO: figure out why...
747745
val accessors = binder.caseFieldAccessors
748-
// luckily, the constrParamAccessors are still sorted properly, so sort the field-accessors using them
749-
// (need to undo name-mangling, including the sneaky trailing whitespace)
750-
val constrParamAccessors = binder.constrParamAccessors
751-
752-
def indexInCPA(acc: Symbol) =
753-
constrParamAccessors indexWhere { orig =>
754-
// patmatDebug("compare: "+ (orig, acc, orig.name, acc.name, (acc.name == orig.name), (acc.name startsWith (orig.name append "$"))))
755-
val origName = orig.name.toString.trim
756-
val accName = acc.name.toString.trim
757-
(accName == origName) || (accName startsWith (origName + "$"))
758-
}
759-
760-
// patmatDebug("caseFieldAccessors: "+ (accessors, binder.caseFieldAccessors map indexInCPA))
761-
// patmatDebug("constrParamAccessors: "+ constrParamAccessors)
762-
763-
val accessorsSorted = accessors sortBy indexInCPA
764-
if (accessorsSorted isDefinedAt (i-1)) REF(binder) DOT accessorsSorted(i-1)
746+
if (accessors isDefinedAt (i-1)) REF(binder) DOT accessors(i-1)
765747
else codegen.tupleSel(binder)(i) // this won't type check for case classes, as they do not inherit ProductN
766748
}
767749

@@ -1887,17 +1869,24 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
18871869
case object False extends Prop
18881870

18891871
// symbols are propositions
1890-
case class Sym(val variable: Var, val const: Const) extends Prop {
1891-
private[this] val id = nextSymId
1872+
abstract case class Sym(val variable: Var, val const: Const) extends Prop {
1873+
private[this] val id = Sym.nextSymId
1874+
18921875
override def toString = variable +"="+ const +"#"+ id
18931876
}
1894-
private def nextSymId = {_symId += 1; _symId}; private var _symId = 0
1895-
1877+
class UniqueSym(variable: Var, const: Const) extends Sym(variable, const)
1878+
object Sym {
1879+
private val uniques: util.HashSet[Sym] = new util.HashSet("uniques", 512)
1880+
def apply(variable: Var, const: Const): Sym = {
1881+
val newSym = new UniqueSym(variable, const)
1882+
(uniques findEntryOrUpdate newSym)
1883+
}
1884+
private def nextSymId = {_symId += 1; _symId}; private var _symId = 0
1885+
}
18961886

18971887
def /\(props: Iterable[Prop]) = if (props.isEmpty) True else props.reduceLeft(And(_, _))
18981888
def \/(props: Iterable[Prop]) = if (props.isEmpty) False else props.reduceLeft(Or(_, _))
18991889

1900-
19011890
trait PropTraverser {
19021891
def apply(x: Prop): Unit = x match {
19031892
case And(a, b) => apply(a); apply(b)
@@ -2053,6 +2042,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
20532042
import scala.collection.mutable.ArrayBuffer
20542043
type FormulaBuilder = ArrayBuffer[Clause]
20552044
def formulaBuilder = ArrayBuffer[Clause]()
2045+
def formulaBuilderSized(init: Int) = new ArrayBuffer[Clause](init)
20562046
def addFormula(buff: FormulaBuilder, f: Formula): Unit = buff ++= f
20572047
def toFormula(buff: FormulaBuilder): Formula = buff
20582048

@@ -2157,7 +2147,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
21572147
class Lit(val sym: Sym, val pos: Boolean) {
21582148
override def toString = if (!pos) "-"+ sym.toString else sym.toString
21592149
override def equals(o: Any) = o match {
2160-
case o: Lit => (o.sym == sym) && (o.pos == pos)
2150+
case o: Lit => (o.sym eq sym) && (o.pos == pos)
21612151
case _ => false
21622152
}
21632153
override def hashCode = sym.hashCode + pos.hashCode
@@ -2206,13 +2196,18 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
22062196
}
22072197

22082198
private def withLit(res: Model, l: Lit): Model = if (res eq NoModel) NoModel else res + (l.sym -> l.pos)
2209-
private def dropUnit(f: Formula, unitLit: Lit) = {
2199+
private def dropUnit(f: Formula, unitLit: Lit): Formula = {
22102200
val negated = -unitLit
22112201
// drop entire clauses that are trivially true
22122202
// (i.e., disjunctions that contain the literal we're making true in the returned model),
22132203
// and simplify clauses by dropping the negation of the literal we're making true
22142204
// (since False \/ X == X)
2215-
f.filterNot(_.contains(unitLit)).map(_ - negated)
2205+
val dropped = formulaBuilderSized(f.size)
2206+
for {
2207+
clause <- f
2208+
if !(clause contains unitLit)
2209+
} dropped += (clause - negated)
2210+
dropped
22162211
}
22172212

22182213
def findModelFor(f: Formula): Model = {

src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,7 @@ trait SyntheticMethods extends ast.TreeDSL {
7676
else templ
7777
}
7878

79-
val originalAccessors = clazz.caseFieldAccessors
80-
// private ones will have been renamed -- make sure they are entered
81-
// in the original order.
82-
def accessors = clazz.caseFieldAccessors sortBy { acc =>
83-
originalAccessors indexWhere { orig =>
84-
(acc.name == orig.name) || (acc.name startsWith (orig.name append "$"))
85-
}
86-
}
79+
def accessors = clazz.caseFieldAccessors
8780
val arity = accessors.size
8881
// If this is ProductN[T1, T2, ...], accessorLub is the lub of T1, T2, ..., .
8982
// !!! Hidden behind -Xexperimental due to bummer type inference bugs.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package scala.tools.partest
2+
3+
import scala.tools.nsc.util.JavaClassPath
4+
import scala.collection.JavaConverters._
5+
import scala.tools.asm
6+
import asm.ClassReader
7+
import asm.tree.{ClassNode, MethodNode, InsnList}
8+
import java.io.InputStream
9+
10+
/**
11+
* Providies utilities for inspecting bytecode using ASM library.
12+
*
13+
* HOW TO USE
14+
* 1. Create subdirectory in test/files/jvm for your test. Let's name it $TESTDIR.
15+
* 2. Create $TESTDIR/BytecodeSrc_1.scala that contains Scala source file which you
16+
* want to inspect the bytecode for. The '_1' suffix signals to partest that it
17+
* should compile this file first.
18+
* 3. Create $TESTDIR/Test.scala:
19+
* import scala.tools.partest.BytecodeTest
20+
* object Test extends BytecodeTest {
21+
* def show {
22+
* // your code that inspect ASM trees and prints values
23+
* }
24+
* }
25+
* 4. Create corresponding check file.
26+
*
27+
* EXAMPLE
28+
* See test/files/jvm/bytecode-test-example for an example of bytecode test.
29+
*
30+
*/
31+
abstract class BytecodeTest {
32+
33+
/** produce the output to be compared against a checkfile */
34+
protected def show(): Unit
35+
36+
def main(args: Array[String]): Unit = show
37+
38+
protected def getMethod(classNode: ClassNode, name: String): MethodNode =
39+
classNode.methods.asScala.find(_.name == name) getOrElse
40+
sys.error(s"Didn't find method '$name' in class '${classNode.name}'")
41+
42+
protected def loadClassNode(name: String): ClassNode = {
43+
val classBytes: InputStream = (for {
44+
classRep <- classpath.findClass(name)
45+
binary <- classRep.binary
46+
} yield binary.input) getOrElse sys.error(s"failed to load class '$name'; classpath = $classpath")
47+
48+
val cr = new ClassReader(classBytes)
49+
val cn = new ClassNode()
50+
cr.accept(cn, 0)
51+
cn
52+
}
53+
54+
protected lazy val classpath: JavaClassPath = {
55+
import scala.tools.nsc.util.ClassPath.DefaultJavaContext
56+
import scala.tools.util.PathResolver.Defaults
57+
// logic inspired by scala.tools.util.PathResolver implementation
58+
val containers = DefaultJavaContext.classesInExpandedPath(Defaults.javaUserClassPath)
59+
new JavaClassPath(containers, DefaultJavaContext)
60+
}
61+
}

src/reflect/scala/reflect/internal/Symbols.scala

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,8 +1611,21 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
16111611
setAnnotations(annot :: annotations)
16121612

16131613
// Convenience for the overwhelmingly common case
1614-
def addAnnotation(sym: Symbol, args: Tree*): this.type =
1614+
def addAnnotation(sym: Symbol, args: Tree*): this.type = {
1615+
// The assertion below is meant to prevent from issues like SI-7009 but it's disabled
1616+
// due to problems with cycles while compiling Scala library. It's rather shocking that
1617+
// just checking if sym is monomorphic type introduces nasty cycles. We are definitively
1618+
// forcing too much because monomorphism is a local property of a type that can be checked
1619+
// syntactically
1620+
// assert(sym.initialize.isMonomorphicType, sym)
16151621
addAnnotation(AnnotationInfo(sym.tpe, args.toList, Nil))
1622+
}
1623+
1624+
/** Use that variant if you want to pass (for example) an applied type */
1625+
def addAnnotation(tp: Type, args: Tree*): this.type = {
1626+
assert(tp.typeParams.isEmpty, tp)
1627+
addAnnotation(AnnotationInfo(tp, args.toList, Nil))
1628+
}
16161629

16171630
// ------ comparisons ----------------------------------------------------------------
16181631

@@ -1769,8 +1782,27 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
17691782
/** For a case class, the symbols of the accessor methods, one for each
17701783
* argument in the first parameter list of the primary constructor.
17711784
* The empty list for all other classes.
1772-
*/
1773-
final def caseFieldAccessors: List[Symbol] =
1785+
*
1786+
* This list will be sorted to correspond to the declaration order
1787+
* in the constructor parameter
1788+
*/
1789+
final def caseFieldAccessors: List[Symbol] = {
1790+
// We can't rely on the ordering of the case field accessors within decls --
1791+
// handling of non-public parameters seems to change the order (see SI-7035.)
1792+
//
1793+
// Luckily, the constrParamAccessors are still sorted properly, so sort the field-accessors using them
1794+
// (need to undo name-mangling, including the sneaky trailing whitespace)
1795+
//
1796+
// The slightly more principled approach of using the paramss of the
1797+
// primary constructor leads to cycles in, for example, pos/t5084.scala.
1798+
val primaryNames = constrParamAccessors.map(acc => nme.dropLocalSuffix(acc.name))
1799+
caseFieldAccessorsUnsorted.sortBy { acc =>
1800+
primaryNames indexWhere { orig =>
1801+
(acc.name == orig) || (acc.name startsWith (orig append "$"))
1802+
}
1803+
}
1804+
}
1805+
private final def caseFieldAccessorsUnsorted: List[Symbol] =
17741806
(info.decls filter (_.isCaseAccessorMethod)).toList
17751807

17761808
final def constrParamAccessors: List[Symbol] =

src/reflect/scala/reflect/internal/TreeInfo.scala

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -253,22 +253,24 @@ abstract class TreeInfo {
253253
* in the position `for { <tree> <- expr }` based only
254254
* on information at the `parser` phase? To qualify, there
255255
* may be no subtree that will be interpreted as a
256-
* Stable Identifier Pattern.
256+
* Stable Identifier Pattern, nor any type tests, even
257+
* on TupleN. See SI-6968.
257258
*
258259
* For instance:
259260
*
260261
* {{{
261-
* foo @ (bar, (baz, quux))
262+
* (foo @ (bar @ _)) = 0
262263
* }}}
263264
*
264-
* is a variable pattern; if the structure matches,
265-
* then the remainder is inevitable.
265+
* is a not a variable pattern; if only binds names.
266266
*
267267
* The following are not variable patterns.
268268
*
269269
* {{{
270-
* foo @ (bar, (`baz`, quux)) // back quoted ident, not at top level
271-
* foo @ (bar, Quux) // UpperCase ident, not at top level
270+
* `bar`
271+
* Bar
272+
* (a, b)
273+
* _: T
272274
* }}}
273275
*
274276
* If the pattern is a simple identifier, it is always
@@ -297,10 +299,6 @@ abstract class TreeInfo {
297299
tree match {
298300
case Bind(name, pat) => isVarPatternDeep0(pat)
299301
case Ident(name) => isVarPattern(tree)
300-
case Apply(sel, args) =>
301-
( isReferenceToScalaMember(sel, TupleClass(args.size).name.toTermName)
302-
&& (args forall isVarPatternDeep0)
303-
)
304302
case _ => false
305303
}
306304
}

src/reflect/scala/reflect/internal/Types.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@ trait Types extends api.Types { self: SymbolTable =>
732732
val trivial = (
733733
this.isTrivial
734734
|| phase.erasedTypes && pre.typeSymbol != ArrayClass
735-
|| pre.normalize.isTrivial && !isPossiblePrefix(clazz)
735+
|| skipPrefixOf(pre, clazz)
736736
)
737737
if (trivial) this
738738
else {
@@ -4341,14 +4341,15 @@ trait Types extends api.Types { self: SymbolTable =>
43414341
*/
43424342
def isPossiblePrefix(clazz: Symbol) = clazz.isClass && !clazz.isPackageClass
43434343

4344+
private def skipPrefixOf(pre: Type, clazz: Symbol) = (
4345+
(pre eq NoType) || (pre eq NoPrefix) || !isPossiblePrefix(clazz)
4346+
)
4347+
43444348
/** A map to compute the asSeenFrom method */
43454349
class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap with KeepOnlyTypeConstraints {
43464350
var capturedSkolems: List[Symbol] = List()
43474351
var capturedParams: List[Symbol] = List()
43484352

4349-
private def skipPrefixOf(pre: Type, clazz: Symbol) = (
4350-
(pre eq NoType) || (pre eq NoPrefix) || !isPossiblePrefix(clazz)
4351-
)
43524353
override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = {
43534354
object annotationArgRewriter extends TypeMapTransformer {
43544355
private def canRewriteThis(sym: Symbol) = (
@@ -4381,8 +4382,7 @@ trait Types extends api.Types { self: SymbolTable =>
43814382
}
43824383

43834384
def apply(tp: Type): Type =
4384-
if (skipPrefixOf(pre, clazz)) tp
4385-
else tp match {
4385+
tp match {
43864386
case ThisType(sym) =>
43874387
def toPrefix(pre: Type, clazz: Symbol): Type =
43884388
if (skipPrefixOf(pre, clazz)) tp

0 commit comments

Comments
 (0)