diff options
-rw-r--r-- | src/compiler/scala/reflect/internal/TreeInfo.scala | 24 | ||||
-rw-r--r-- | src/compiler/scala/reflect/internal/Types.scala | 25 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala | 7 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/LazyVals.scala | 5 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Mixin.scala | 14 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala | 11 | ||||
-rw-r--r-- | test/files/pos/t5384.scala | 7 | ||||
-rw-r--r-- | test/files/pos/t5796.scala | 8 | ||||
-rw-r--r-- | test/files/run/t5552.check | 2 | ||||
-rw-r--r-- | test/files/run/t5552.scala | 10 | ||||
-rw-r--r-- | test/files/run/t5676.check | 3 | ||||
-rw-r--r-- | test/files/run/t5676.flags (renamed from test/pending/run/t5676.flags) | 0 | ||||
-rw-r--r-- | test/files/run/t5676.scala | 24 | ||||
-rw-r--r-- | test/pending/run/t5676.scala | 25 |
15 files changed, 122 insertions, 49 deletions
diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala index 2251310f35..1528061adb 100644 --- a/src/compiler/scala/reflect/internal/TreeInfo.scala +++ b/src/compiler/scala/reflect/internal/TreeInfo.scala @@ -221,9 +221,29 @@ abstract class TreeInfo { case _ => false } + /** + * Named arguments can transform a constructor call into a block, e.g. + * <init>(b = foo, a = bar) + * is transformed to + * { val x$1 = foo + * val x$2 = bar + * <init>(x$2, x$1) + * } + */ + def stripNamedApplyBlock(tree: Tree) = tree match { + case Block(stats, expr) if stats.forall(_.isInstanceOf[ValDef]) => + expr + case _ => + tree + } + /** Is tree a self or super constructor call? */ - def isSelfOrSuperConstrCall(tree: Tree) = - isSelfConstrCall(tree) || isSuperConstrCall(tree) + def isSelfOrSuperConstrCall(tree: Tree) = { + // stripNamedApply for SI-3584: adaptToImplicitMethod in Typers creates a special context + // for implicit search in constructor calls, adaptToImplicitMethod(isSelfOrConstrCall) + val tree1 = stripNamedApplyBlock(tree) + isSelfConstrCall(tree1) || isSuperConstrCall(tree1) + } /** Is tree a variable pattern? */ def isVarPattern(pat: Tree): Boolean = pat match { diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 81582db5f2..808198598b 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -3068,7 +3068,8 @@ trait Types extends api.Types { self: SymbolTable => } def registerTypeEquality(tp: Type, typeVarLHS: Boolean): Boolean = { - //println("regTypeEq: "+(safeToString, debugString(tp), typeVarLHS)) //@MDEBUG +// println("regTypeEq: "+(safeToString, debugString(tp), tp.getClass, if (typeVarLHS) "in LHS" else "in RHS", if (suspended) "ZZ" else if (constr.instValid) "IV" else "")) //@MDEBUG +// println("constr: "+ constr) def checkIsSameType(tp: Type) = if(typeVarLHS) constr.inst =:= tp else tp =:= constr.inst @@ -3127,7 +3128,7 @@ trait Types extends api.Types { self: SymbolTable => } def originName = { val name = origin.typeSymbolDirect.decodedName - if (name contains "_$") origin.typeSymbolDirect.decodedName else name + if (name contains "_$") origin.typeSymbolDirect.decodedName else name // wait, what? - what? } def originLocation = { val sym = origin.typeSymbolDirect @@ -3146,7 +3147,7 @@ trait Types extends api.Types { self: SymbolTable => protected def typeVarString = originName override def safeToString = ( if ((constr eq null) || (constr.inst eq null)) "TVar<" + originName + "=null>" - else if (constr.inst ne NoType) "" + constr.inst + else if (constr.inst ne NoType) "=?" + constr.inst else (if(untouchable) "!?" else "?") + levelString + originName ) override def kind = "TypeVar" @@ -4925,7 +4926,23 @@ trait Types extends api.Types { self: SymbolTable => override def hashCode = tp1.hashCode * 41 + tp2.hashCode override def equals(other: Any) = other match { case stp: SubTypePair => - (tp1 =:= stp.tp1) && (tp2 =:= stp.tp2) + // suspend TypeVars in types compared by =:=, + // since we don't want to mutate them simply to check whether a subtype test is pending + // in addition to making subtyping "more correct" for type vars, + // it should avoid the stackoverflow that's been plaguing us (https://groups.google.com/d/topic/scala-internals/2gHzNjtB4xA/discussion) + // this method is only called when subtyping hits a recursion threshold (subsametypeRecursions >= LogPendingSubTypesThreshold) + @inline def suspend(tp: Type) = + if (tp.isGround) null else suspendTypeVarsInType(tp) + @inline def revive(suspension: List[TypeVar]) = + if (suspension ne null) suspension foreach (_.suspended = false) + + val suspensions = Array(tp1, stp.tp1, tp2, stp.tp2) map suspend + + val sameTypes = (tp1 =:= stp.tp1) && (tp2 =:= stp.tp2) + + suspensions foreach revive + + sameTypes case _ => false } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index aa8f469513..225afaf0fb 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -274,8 +274,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters { // we can exclude lateFINAL. Such symbols are eligible for inlining, but to
// avoid breaking proxy software which depends on subclassing, we do not
// emit ACC_FINAL.
+ // Nested objects won't receive ACC_FINAL in order to allow for their overloading.
+
val finalFlag = (
- ((sym.rawflags & (Flags.FINAL | Flags.MODULE)) != 0)
+ (sym.hasFlag(Flags.FINAL) || isTopLevelModule(sym))
&& !sym.enclClass.isInterface
&& !sym.isClassConstructor
&& !sym.isMutable // lazy vals and vars both
@@ -649,8 +651,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { val INNER_CLASSES_FLAGS =
(asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_PRIVATE | asm.Opcodes.ACC_PROTECTED |
- asm.Opcodes.ACC_STATIC | asm.Opcodes.ACC_FINAL |
- asm.Opcodes.ACC_INTERFACE | asm.Opcodes.ACC_ABSTRACT)
+ asm.Opcodes.ACC_STATIC | asm.Opcodes.ACC_INTERFACE | asm.Opcodes.ACC_ABSTRACT)
val PublicStatic = asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_STATIC
val PublicStaticFinal = asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_STATIC | asm.Opcodes.ACC_FINAL
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 7d3249a7d3..b5ce7588f6 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -191,7 +191,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with val MIN_SWITCH_DENSITY = 0.7 val INNER_CLASSES_FLAGS = - (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT) + (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_INTERFACE | ACC_ABSTRACT) val PublicStatic = ACC_PUBLIC | ACC_STATIC val PublicStaticFinal = ACC_PUBLIC | ACC_STATIC | ACC_FINAL @@ -1976,8 +1976,10 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with // we can exclude lateFINAL. Such symbols are eligible for inlining, but to // avoid breaking proxy software which depends on subclassing, we do not // emit ACC_FINAL. + // Nested objects won't receive ACC_FINAL in order to allow for their overloading. + val finalFlag = ( - ((sym.rawflags & (Flags.FINAL | Flags.MODULE)) != 0) + (sym.hasFlag(Flags.FINAL) || isTopLevelModule(sym)) && !sym.enclClass.isInterface && !sym.isClassConstructor && !sym.isMutable // lazy vals and vars both diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala index 2b26f1590d..e8387c80f5 100644 --- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala +++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala @@ -75,7 +75,8 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD val stats1 = stats.flatMap(_ match { case Block(List(d1@DefDef(_, n1, _, _, _, _)), d2@DefDef(_, n2, _, _, _, _)) if (nme.newLazyValSlowComputeName(n2) == n1) => List(d1, d2) - case stat => List(stat) + case stat => + List(stat) }) treeCopy.Block(block1, stats1, expr) @@ -138,7 +139,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD case ValDef(_, _, _, _) if !sym.owner.isModule && !sym.owner.isClass => deriveValDef(tree) { rhs0 => - val rhs = super.transform(rhs0) + val rhs = transform(rhs0) if (LocalLazyValFinder.find(rhs)) typed(addBitmapDefs(sym, rhs)) else rhs } diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 4ce5985af8..79b9317f20 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -903,14 +903,14 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { if (sym.isLazy && !isEmpty && !clazz.isImplClass) { assert(fieldOffset contains sym, sym) - deriveDefDef(stat)(rhs => - if (isUnit) - mkLazyDef(clazz, sym, List(rhs), UNIT, fieldOffset(sym)) - else { - val Block(stats, res) = rhs + deriveDefDef(stat) { + case t if isUnit => mkLazyDef(clazz, sym, List(t), UNIT, fieldOffset(sym)) + + case Block(stats, res) => mkLazyDef(clazz, sym, stats, Select(This(clazz), res.symbol), fieldOffset(sym)) - } - ) + + case t => t // pass specialized lazy vals through + } } else if (needsInitFlag(sym) && !isEmpty && !clazz.hasFlag(IMPLCLASS | TRAIT)) { assert(fieldOffset contains sym, sym) diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 7e780304e7..07a10ecb1f 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -666,16 +666,19 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { // log("other concrete " + m) forwardToOverload(m) - } else if (m.isValue && !m.isMethod) { // concrete value definition + } else if (m.isMethod && m.hasFlag(LAZY)) { + forwardToOverload(m) + + } else if (m.isValue && !m.isMethod && !m.hasFlag(LAZY)) { // concrete value definition def mkAccessor(field: Symbol, name: Name) = { - val newFlags = (SPECIALIZED | m.getter(clazz).flags) & ~(LOCAL | CASEACCESSOR | PARAMACCESSOR | LAZY) + val newFlags = (SPECIALIZED | m.getter(clazz).flags) & ~(LOCAL | CASEACCESSOR | PARAMACCESSOR) // we rely on the super class to initialize param accessors val sym = sClass.newMethod(name, field.pos, newFlags) info(sym) = SpecializedAccessor(field) sym } def overrideIn(clazz: Symbol, sym: Symbol) = { - val newFlags = (sym.flags | OVERRIDE | SPECIALIZED) & ~(DEFERRED | CASEACCESSOR | PARAMACCESSOR | LAZY) + val newFlags = (sym.flags | OVERRIDE | SPECIALIZED) & ~(DEFERRED | CASEACCESSOR | PARAMACCESSOR) val sym1 = sym.cloneSymbol(clazz, newFlags) sym1 modifyInfo (_ asSeenFrom (clazz.tpe, sym1.owner)) } @@ -881,7 +884,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** Return the specialized overload of `m`, in the given environment. */ private def specializedOverload(owner: Symbol, sym: Symbol, env: TypeEnv): Symbol = { - val newFlags = (sym.flags | SPECIALIZED) & ~(DEFERRED | CASEACCESSOR | ACCESSOR | LAZY) + val newFlags = (sym.flags | SPECIALIZED) & ~(DEFERRED | CASEACCESSOR) // this method properly duplicates the symbol's info ( sym.cloneSymbol(owner, newFlags, specializedName(sym, env)) modifyInfo (info => subst(env, info.asSeenFrom(owner.thisType, sym.owner))) diff --git a/test/files/pos/t5384.scala b/test/files/pos/t5384.scala new file mode 100644 index 0000000000..4e297d5935 --- /dev/null +++ b/test/files/pos/t5384.scala @@ -0,0 +1,7 @@ +class A(x: String, y: Int)(implicit o: String) +class B1(implicit o: String) extends A(y = 5, x = "a") +class B2(implicit o: String) extends A("a", 5) +class B3(implicit o: String) extends A(y = 5, x = "a")(o) + +class AM[E: Manifest](val x: Unit = (), y: Unit) +class BM[E: Manifest] extends AM[E](y = ()) diff --git a/test/files/pos/t5796.scala b/test/files/pos/t5796.scala new file mode 100644 index 0000000000..d05350c535 --- /dev/null +++ b/test/files/pos/t5796.scala @@ -0,0 +1,8 @@ +object Bug { + def foo() { + val v = { + lazy val s = 0 + s + } + } +} diff --git a/test/files/run/t5552.check b/test/files/run/t5552.check new file mode 100644 index 0000000000..a19a60840e --- /dev/null +++ b/test/files/run/t5552.check @@ -0,0 +1,2 @@ +(3,3) +(3.0,3.0) diff --git a/test/files/run/t5552.scala b/test/files/run/t5552.scala new file mode 100644 index 0000000000..afb8a1f0be --- /dev/null +++ b/test/files/run/t5552.scala @@ -0,0 +1,10 @@ +class C[@specialized(Int) A](a:A) { + lazy val b = (a, a) + def c = b +} +object Test { + def main(args:Array[String]) { + println(new C(3).c) + println(new C(3.0).c) + } +} diff --git a/test/files/run/t5676.check b/test/files/run/t5676.check new file mode 100644 index 0000000000..3b562d3046 --- /dev/null +++ b/test/files/run/t5676.check @@ -0,0 +1,3 @@ +ok +false +true diff --git a/test/pending/run/t5676.flags b/test/files/run/t5676.flags index e1b37447c9..e1b37447c9 100644 --- a/test/pending/run/t5676.flags +++ b/test/files/run/t5676.flags diff --git a/test/files/run/t5676.scala b/test/files/run/t5676.scala new file mode 100644 index 0000000000..b643c300ce --- /dev/null +++ b/test/files/run/t5676.scala @@ -0,0 +1,24 @@ +import java.lang.reflect.Modifier + +class Bar[T] + +class Foo[T] { + object A extends Bar[T] +} + +class Baz[S] extends Foo[S] { + override object A extends Bar[S] { + def foo(): String = "ok" + } +} + +object Test { + + def main(a: Array[String]) { + val b = new Baz[Any] + println(b.A.foo()) + println(Modifier.isFinal(classOf[Baz[Any]].getModifiers())) + println(Modifier.isFinal(Test.getClass.getModifiers())) + } + +} diff --git a/test/pending/run/t5676.scala b/test/pending/run/t5676.scala deleted file mode 100644 index 3ff498eaa2..0000000000 --- a/test/pending/run/t5676.scala +++ /dev/null @@ -1,25 +0,0 @@ - - - - -class Bar[T] - - -class Foo[T] { - object A extends Bar[T] -} - - -class Baz[S] extends Foo[S] { - override object A extends Bar[S] -} - - -object Test { - - def main(a: Array[String]) { - val b = new Baz[Any] - println(b) - } - -} |