Skip to content

Commit

Permalink
Merge pull request #2343 from retronym/topic/merge-2.10.x-to-v2.11.0-…
Browse files Browse the repository at this point in the history
…M2-74-g00e6c8b

Merge 2.10.x to master
  • Loading branch information
adriaanm committed Apr 2, 2013
2 parents 00e6c8b + 51d96a3 commit c77dd12
Show file tree
Hide file tree
Showing 76 changed files with 1,862 additions and 2,495 deletions.
672 changes: 310 additions & 362 deletions build.xml

Large diffs are not rendered by default.

65 changes: 22 additions & 43 deletions src/compiler/scala/reflect/reify/utils/Extractors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -164,51 +164,30 @@ trait Extractors {
}
}

object FreeDef {
def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match {
case FreeTermDef(uref, name, binding, flags, origin) =>
Some((uref, name, binding, flags, origin))
case FreeTypeDef(uref, name, binding, flags, origin) =>
Some((uref, name, binding, flags, origin))
case _ =>
None
}
}

object FreeTermDef {
def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match {
case
ValDef(_, name, _, Apply(
Select(Select(uref1 @ Ident(_), build1), newFreeTerm),
List(
_,
_,
Apply(Select(Select(uref2 @ Ident(_), build2), flagsFromBits), List(Literal(Constant(flags: Long)))),
Literal(Constant(origin: String)))))
if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && newFreeTerm == nme.newFreeTerm &&
uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits =>
Some((uref1, name, reifyBinding(tree), flags, origin))
case _ =>
None
}
}

object FreeTypeDef {
def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match {
case
ValDef(_, name, _, Apply(
Select(Select(uref1 @ Ident(_), build1), newFreeType),
List(
_,
Apply(Select(Select(uref2 @ Ident(_), build2), flagsFromBits), List(Literal(Constant(flags: Long)))),
Literal(Constant(origin: String)))))
if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && newFreeType == nme.newFreeType &&
uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits =>
Some((uref1, name, reifyBinding(tree), flags, origin))
case _ =>
None
sealed abstract class FreeDefExtractor(acceptTerms: Boolean, acceptTypes: Boolean) {
def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = {
def acceptFreeTermFactory(name: Name) = {
(acceptTerms && name == nme.newFreeTerm) ||
(acceptTypes && name == nme.newFreeType)
}
tree match {
case
ValDef(_, name, _, Apply(
Select(Select(uref1 @ Ident(_), build1), freeTermFactory),
_ :+
Apply(Select(Select(uref2 @ Ident(_), build2), flagsFromBits), List(Literal(Constant(flags: Long)))) :+
Literal(Constant(origin: String))))
if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && acceptFreeTermFactory(freeTermFactory) &&
uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits =>
Some((uref1, name, reifyBinding(tree), flags, origin))
case _ =>
None
}
}
}
object FreeDef extends FreeDefExtractor(acceptTerms = true, acceptTypes = true)
object FreeTermDef extends FreeDefExtractor(acceptTerms = true, acceptTypes = false)
object FreeTypeDef extends FreeDefExtractor(acceptTerms = false, acceptTypes = true)

object FreeRef {
def unapply(tree: Tree): Option[(Tree, TermName)] = tree match {
Expand Down
1 change: 1 addition & 0 deletions src/compiler/scala/tools/nsc/backend/icode/Members.scala
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ trait Members {
var returnType: TypeKind = _
var recursive: Boolean = false
var bytecodeHasEHs = false // set by ICodeReader only, used by Inliner to prevent inlining (SI-6188)
var bytecodeHasInvokeDynamic = false // set by ICodeReader only, used by Inliner to prevent inlining until we have proper invoke dynamic support

/** local variables and method parameters */
var locals: List[Local] = Nil
Expand Down
19 changes: 19 additions & 0 deletions src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,25 @@ trait Opcodes { self: ICodes =>

override def category = mthdsCat
}

/**
* A place holder entry that allows us to parse class files with invoke dynamic
* instructions. Because the compiler doesn't yet really understand the
* behavior of invokeDynamic, this op acts as a poison pill. Any attempt to analyze
* this instruction will cause a failure. The only optimization that
* should ever look at non-Scala generated icode is the inliner, and it
* has been modified to not examine any method with invokeDynamic
* instructions. So if this poison pill ever causes problems then
* there's been a serious misunderstanding
*/
// TODO do the real thing
case class INVOKE_DYNAMIC(poolEntry: Char) extends Instruction {
private def error = sys.error("INVOKE_DYNAMIC is not fully implemented and should not be analyzed")
override def consumed = error
override def produced = error
override def producedTypes = error
override def category = error
}

case class BOX(boxType: TypeKind) extends Instruction {
assert(boxType.isValueType && (boxType ne UNIT)) // documentation
Expand Down
18 changes: 9 additions & 9 deletions src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2251,16 +2251,16 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
// info calls so that types are up to date; erasure may add lateINTERFACE to traits
hostSymbol.info ; methodOwner.info

def isInterfaceCall(sym: Symbol) = (
sym.isInterface && methodOwner != ObjectClass
def needsInterfaceCall(sym: Symbol) = (
sym.isInterface
|| sym.isJavaDefined && sym.isNonBottomSubClass(ClassfileAnnotationClass)
)
// whether to reference the type of the receiver or
// the type of the method owner (if not an interface!)
// the type of the method owner
val useMethodOwner = (
style != Dynamic
|| !isInterfaceCall(hostSymbol) && isAccessibleFrom(methodOwner, siteSymbol)
|| hostSymbol.isBottomClass
|| methodOwner == ObjectClass
)
val receiver = if (useMethodOwner) methodOwner else hostSymbol
val jowner = javaName(receiver)
Expand All @@ -2283,11 +2283,11 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
}

style match {
case Static(true) => dbg("invokespecial"); jcode.invokespecial (jowner, jname, jtype)
case Static(false) => dbg("invokestatic"); jcode.invokestatic (jowner, jname, jtype)
case Dynamic if isInterfaceCall(receiver) => dbg("invokinterface"); jcode.invokeinterface(jowner, jname, jtype)
case Dynamic => dbg("invokevirtual"); jcode.invokevirtual (jowner, jname, jtype)
case SuperCall(_) =>
case Static(true) => dbg("invokespecial"); jcode.invokespecial (jowner, jname, jtype)
case Static(false) => dbg("invokestatic"); jcode.invokestatic (jowner, jname, jtype)
case Dynamic if needsInterfaceCall(receiver) => dbg("invokinterface"); jcode.invokeinterface(jowner, jname, jtype)
case Dynamic => dbg("invokevirtual"); jcode.invokevirtual (jowner, jname, jtype)
case SuperCall(_) =>
dbg("invokespecial")
jcode.invokespecial(jowner, jname, jtype)
initModule()
Expand Down
1 change: 1 addition & 0 deletions src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,7 @@ abstract class Inliners extends SubComponent {
if(isInlineForbidden) { rs ::= "is annotated @noinline" }
if(inc.isSynchronized) { rs ::= "is synchronized method" }
if(inc.m.bytecodeHasEHs) { rs ::= "bytecode contains exception handlers / finally clause" } // SI-6188
if(inc.m.bytecodeHasInvokeDynamic) { rs ::= "bytecode contains invoke dynamic" }
if(rs.isEmpty) null else rs.mkString("", ", and ", "")
}

Expand Down
8 changes: 1 addition & 7 deletions src/compiler/scala/tools/nsc/javac/JavaParsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -755,13 +755,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners {
val pos = in.currentPos
val name = identForType()
val (statics, body) = typeBody(AT, name)
def getValueMethodType(tree: Tree) = tree match {
case DefDef(_, nme.value, _, _, tpt, _) => Some(tpt.duplicate)
case _ => None
}
var templ = makeTemplate(annotationParents, body)
for (stat <- templ.body; tpt <- getValueMethodType(stat))
templ = makeTemplate(annotationParents, makeConstructor(List(tpt)) :: templ.body)
val templ = makeTemplate(annotationParents, body)
addCompanionObject(statics, atPos(pos) {
ClassDef(mods, name, List(), templ)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,13 @@ abstract class ClassfileParser {
(in.nextByte.toInt: @switch) match {
case CONSTANT_UTF8 | CONSTANT_UNICODE =>
in.skip(in.nextChar)
case CONSTANT_CLASS | CONSTANT_STRING =>
case CONSTANT_CLASS | CONSTANT_STRING | CONSTANT_METHODTYPE=>
in.skip(2)
case CONSTANT_METHODHANDLE =>
in.skip(3)
case CONSTANT_FIELDREF | CONSTANT_METHODREF | CONSTANT_INTFMETHODREF
| CONSTANT_NAMEANDTYPE | CONSTANT_INTEGER | CONSTANT_FLOAT =>
| CONSTANT_NAMEANDTYPE | CONSTANT_INTEGER | CONSTANT_FLOAT
| CONSTANT_INVOKEDYNAMIC =>
in.skip(4)
case CONSTANT_LONG | CONSTANT_DOUBLE =>
in.skip(8)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,13 @@ abstract class ICodeReader extends ClassfileParser {
code.emit(UNBOX(toTypeKind(m.info.resultType)))
else
code.emit(CALL_METHOD(m, Static(onInstance = false)))
case JVM.invokedynamic =>
// TODO, this is just a place holder. A real implementation must parse the class constant entry
debuglog("Found JVM invokedynamic instructionm, inserting place holder ICode INVOKE_DYNAMIC.")
containsInvokeDynamic = true
val poolEntry = in.nextChar
in.skip(2)
code.emit(INVOKE_DYNAMIC(poolEntry))

case JVM.new_ =>
code.emit(NEW(REFERENCE(pool.getClassSymbol(in.nextChar))))
Expand Down Expand Up @@ -639,6 +646,7 @@ abstract class ICodeReader extends ClassfileParser {
var containsDUPX = false
var containsNEW = false
var containsEHs = false
var containsInvokeDynamic = false

def emit(i: Instruction) {
instrs += ((pc, i))
Expand All @@ -657,6 +665,7 @@ abstract class ICodeReader extends ClassfileParser {
val code = new Code(method)
method.setCode(code)
method.bytecodeHasEHs = containsEHs
method.bytecodeHasInvokeDynamic = containsInvokeDynamic
var bb = code.startBlock

def makeBasicBlocks: mutable.Map[Int, BasicBlock] =
Expand Down
64 changes: 45 additions & 19 deletions src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,26 +41,24 @@ abstract class ExplicitOuter extends InfoTransform
private def isInner(clazz: Symbol) =
!clazz.isPackageClass && !clazz.outerClass.isStaticOwner

private def haveSameOuter(parent: Type, clazz: Symbol) = parent match {
case TypeRef(pre, sym, _) =>
val owner = clazz.owner
private def haveSameOuter(parent: Type, clazz: Symbol) = {
val owner = clazz.owner
val parentSym = parent.typeSymbol

//println(s"have same outer $parent $clazz $sym ${sym.owner} $owner $pre")

sym.isClass && owner.isClass &&
(owner isSubClass sym.owner) &&
owner.thisType =:= pre

case _ => false
parentSym.isClass && owner.isClass &&
(owner isSubClass parentSym.owner) &&
owner.thisType =:= parent.prefix
}

/** Does given clazz define an outer field? */
def hasOuterField(clazz: Symbol) = {
val parents = clazz.info.parents
val parent = clazz.info.firstParent

isInner(clazz) && !clazz.isTrait && {
parents.isEmpty || !haveSameOuter(parents.head, clazz)
}
// space optimization: inherit the $outer pointer from the parent class if
// we know that it will point to the correct instance.
def canReuseParentOuterField = !parent.typeSymbol.isJavaDefined && haveSameOuter(parent, clazz)

isInner(clazz) && !clazz.isTrait && !canReuseParentOuterField
}

private def outerField(clazz: Symbol): Symbol = {
Expand Down Expand Up @@ -100,6 +98,29 @@ abstract class ExplicitOuter extends InfoTransform
sym setInfo clazz.outerClass.thisType
}

/**
* Will the outer accessor of the `clazz` subsume the outer accessor of
* `mixin`?
*
* This arises when an inner object mixes in its companion trait.
*
* {{{
* class C {
* trait T { C.this } // C$T$$$outer$ : C
* object T extends T { C.this } // C$T$$$outer$ : C.this.type
* }
* }}}
*
* See SI-7242.
}}
*/
private def skipMixinOuterAccessor(clazz: Symbol, mixin: Symbol) = {
// Reliant on the current scheme for name expansion, the expanded name
// of the outer accessors in a trait and its companion object are the same.
// If the assumption is one day falsified, run/t7424.scala will let us know.
clazz.fullName == mixin.fullName
}

/** <p>
* The type transformation method:
* </p>
Expand Down Expand Up @@ -162,10 +183,14 @@ abstract class ExplicitOuter extends InfoTransform
for (mc <- clazz.mixinClasses) {
val mixinOuterAcc: Symbol = exitingExplicitOuter(outerAccessor(mc))
if (mixinOuterAcc != NoSymbol) {
if (decls1 eq decls) decls1 = decls.cloneScope
val newAcc = mixinOuterAcc.cloneSymbol(clazz, mixinOuterAcc.flags & ~DEFERRED)
newAcc setInfo (clazz.thisType memberType mixinOuterAcc)
decls1 enter newAcc
if (skipMixinOuterAccessor(clazz, mc))
debuglog(s"Reusing outer accessor symbol of $clazz for the mixin outer accessor of $mc")
else {
if (decls1 eq decls) decls1 = decls.cloneScope
val newAcc = mixinOuterAcc.cloneSymbol(clazz, mixinOuterAcc.flags & ~DEFERRED)
newAcc setInfo (clazz.thisType memberType mixinOuterAcc)
decls1 enter newAcc
}
}
}
}
Expand Down Expand Up @@ -370,6 +395,7 @@ abstract class ExplicitOuter extends InfoTransform
val outerAcc = outerAccessor(mixinClass) overridingSymbol currentClass
def mixinPrefix = (currentClass.thisType baseType mixinClass).prefix
assert(outerAcc != NoSymbol, "No outer accessor for inner mixin " + mixinClass + " in " + currentClass)
assert(outerAcc.alternatives.size == 1, s"Multiple outer accessors match inner mixin $mixinClass in $currentClass : ${outerAcc.alternatives.map(_.defString)}")
// I added the mixinPrefix.typeArgs.nonEmpty condition to address the
// crash in SI-4970. I feel quite sure this can be improved.
val path = (
Expand Down Expand Up @@ -404,7 +430,7 @@ abstract class ExplicitOuter extends InfoTransform
}
if (!currentClass.isTrait)
for (mc <- currentClass.mixinClasses)
if (outerAccessor(mc) != NoSymbol)
if (outerAccessor(mc) != NoSymbol && !skipMixinOuterAccessor(currentClass, mc))
newDefs += mixinOuterAccessorDef(mc)
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/compiler/scala/tools/nsc/transform/UnCurry.scala
Original file line number Diff line number Diff line change
Expand Up @@ -347,10 +347,14 @@ abstract class UnCurry extends InfoTransform
}
else {
log(s"Argument '$arg' at line ${arg.pos.safeLine} is $formal from ${fun.fullName}")
def canUseDirectly(recv: Tree) = (
recv.tpe.typeSymbol.isSubClass(FunctionClass(0))
&& treeInfo.isExprSafeToInline(recv)
)
arg match {
// don't add a thunk for by-name argument if argument already is an application of
// a Function0. We can then remove the application and use the existing Function0.
case Apply(Select(recv, nme.apply), Nil) if recv.tpe.typeSymbol isSubClass FunctionClass(0) =>
case Apply(Select(recv, nme.apply), Nil) if canUseDirectly(recv) =>
recv
case _ =>
newFunction0(arg)
Expand Down
1 change: 1 addition & 0 deletions src/compiler/scala/tools/nsc/transform/patmat/Logic.scala
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis {
assert(tp.isInstanceOf[SingletonType])
val toString = tp match {
case ConstantType(c) => c.escapedStringValue
case _ if tp.typeSymbol.isModuleClass => tp.typeSymbol.name.toString
case _ => tp.toString
}
Const.unique(tp, new ValueConst(tp, tp.widen, toString))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import scala.reflect.internal.util.Position
/** Optimize and analyze matches based on their TreeMaker-representation.
*
* The patmat translation doesn't rely on this, so it could be disabled in principle.
*
* TODO: split out match analysis
* - well, not quite: the backend crashes if we emit duplicates in switches (e.g. SI-7290)
*/
// TODO: split out match analysis
trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {
import global._
import global.definitions._
Expand Down Expand Up @@ -435,7 +435,7 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {
case SwitchableTreeMaker(pattern) :: GuardAndBodyTreeMakers(guard, body) =>
Some(CaseDef(pattern, guard, body))
// alternatives
case AlternativesTreeMaker(_, altss, _) :: GuardAndBodyTreeMakers(guard, body) if alternativesSupported =>
case AlternativesTreeMaker(_, altss, pos) :: GuardAndBodyTreeMakers(guard, body) if alternativesSupported =>
val switchableAlts = altss map {
case SwitchableTreeMaker(pattern) :: Nil =>
Some(pattern)
Expand All @@ -445,7 +445,17 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {

// succeed if they were all switchable
sequence(switchableAlts) map { switchableAlts =>
CaseDef(Alternative(switchableAlts), guard, body)
def extractConst(t: Tree) = t match {
case Literal(const) => const
case _ => t
}
// SI-7290 Discard duplicate alternatives that would crash the backend
val distinctAlts = distinctBy(switchableAlts)(extractConst)
if (distinctAlts.size < switchableAlts.size) {
val duplicated = switchableAlts.groupBy(extractConst).flatMap(_._2.drop(1).take(1)) // report the first duplicated
global.currentUnit.warning(pos, s"Pattern contains duplicate alternatives: ${duplicated.mkString(", ")}")
}
CaseDef(Alternative(distinctAlts), guard, body)
}
case _ =>
// debug.patmat("can't emit switch for "+ makers)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ trait NamesDefaults { self: Analyzer =>
// disable conforms as a view...
val errsBefore = reporter.ERROR.count
try typer.silent { tpr =>
val res = tpr.typed(arg, subst(paramtpe))
val res = tpr.typed(arg.duplicate, subst(paramtpe))
// better warning for SI-5044: if `silent` was not actually silent give a hint to the user
// [H]: the reason why `silent` is not silent is because the cyclic reference exception is
// thrown in a context completely different from `context` here. The exception happens while
Expand Down
Loading

0 comments on commit c77dd12

Please sign in to comment.