summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala4
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala14
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala14
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeComparers.scala18
-rw-r--r--test/files/neg/t7834neg.check41
-rw-r--r--test/files/neg/t7834neg.scala76
-rw-r--r--test/files/pos/t7834.scala6
-rw-r--r--test/files/run/t7801.check11
-rw-r--r--test/files/run/t7801.scala12
9 files changed, 178 insertions, 18 deletions
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 32f0571e83..b37d0ba283 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -182,7 +182,6 @@ trait ScalaSettings extends AbsScalaSettings
*/
val Ydocdebug = BooleanSetting("-Ydoc-debug", "Trace all scaladoc activity.")
val Yidedebug = BooleanSetting("-Yide-debug", "Generate, validate and output trees using the interactive compiler.")
- val Yinferdebug = BooleanSetting("-Yinfer-debug", "Trace type inference and implicit search.")
val Yissuedebug = BooleanSetting("-Yissue-debug", "Print stack traces when a context issues an error.")
val YmacrodebugLite = BooleanSetting("-Ymacro-debug-lite", "Trace essential macro-related activities.")
val YmacrodebugVerbose = BooleanSetting("-Ymacro-debug-verbose", "Trace all macro-related activities: compilation, generation of synthetics, classloading, expansion, exceptions.")
@@ -193,6 +192,9 @@ trait ScalaSettings extends AbsScalaSettings
val Ypatmatdebug = BooleanSetting("-Ypatmat-debug", "Trace pattern matching translation.")
val Yquasiquotedebug = BooleanSetting("-Yquasiquote-debug", "Trace quasiquote-related activities.")
+ // TODO 2.12 Remove
+ val Yinferdebug = BooleanSetting("-Yinfer-debug", "Trace type inference and implicit search.") withDeprecationMessage("Use -Ytyper-debug") enabling(List(Ytyperdebug))
+
/** Groups of Settings.
*/
val future = BooleanSetting("-Xfuture", "Turn on future language features.") enabling futureSettings
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index d3a0ffb744..d58ea09386 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -1435,6 +1435,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
assert(isCompilerUniverse)
if (infos == null || runId(infos.validFrom) == currentRunId) {
infos
+ } else if (isPackageClass) {
+ // SI-7801 early phase package scopes are mutated in new runs (Namers#enterPackage), so we have to
+ // discard transformed infos, rather than just marking them as from this run.
+ val oldest = infos.oldest
+ oldest.validFrom = validTo
+ this.infos = oldest
+ oldest
} else {
val prev1 = adaptInfos(infos.prev)
if (prev1 ne infos.prev) prev1
@@ -1444,10 +1451,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
_validTo = period(currentRunId, pid)
phase = phaseWithId(pid)
- val info1 = (
- if (isPackageClass) infos.info
- else adaptToNewRunMap(infos.info)
- )
+ val info1 = adaptToNewRunMap(infos.info)
if (info1 eq infos.info) {
infos.validFrom = validTo
infos
@@ -3473,6 +3477,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
"TypeHistory(" + phaseOf(validFrom)+":"+runId(validFrom) + "," + info + "," + prev + ")"
def toList: List[TypeHistory] = this :: ( if (prev eq null) Nil else prev.toList )
+
+ def oldest: TypeHistory = if (prev == null) this else prev.oldest
}
// ----- Hoisted closures and convenience methods, for compile time reductions -------
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index ca01a4b8e3..ad9001ca4e 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -4013,15 +4013,11 @@ trait Types
* type selections with the same name of equal (as determined by `=:=`) prefixes are
* considered equal in regard to `=:=`.
*/
- def beginsWithTypeVarOrIsRefined(tp: Type): Boolean = tp match {
- case SingleType(pre, sym) =>
- !(sym hasFlag PACKAGE) && beginsWithTypeVarOrIsRefined(pre)
- case tv@TypeVar(_, constr) =>
- !tv.instValid || beginsWithTypeVarOrIsRefined(constr.inst)
- case RefinedType(_, _) =>
- true
- case _ =>
- false
+ def isEligibleForPrefixUnification(tp: Type): Boolean = tp match {
+ case SingleType(pre, sym) => !(sym hasFlag PACKAGE) && isEligibleForPrefixUnification(pre)
+ case tv@TypeVar(_, constr) => !tv.instValid || isEligibleForPrefixUnification(constr.inst)
+ case RefinedType(_, _) => true
+ case _ => false
}
def isErrorOrWildcard(tp: Type) = (tp eq ErrorType) || (tp eq WildcardType)
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
index d8b3b04d0e..152c689c56 100644
--- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
+++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
@@ -35,8 +35,10 @@ trait TypeComparers {
private var subsametypeRecursions: Int = 0
- private def isUnifiable(pre1: Type, pre2: Type) =
- (beginsWithTypeVarOrIsRefined(pre1) || beginsWithTypeVarOrIsRefined(pre2)) && (pre1 =:= pre2)
+ private def isUnifiable(pre1: Type, pre2: Type) = (
+ (isEligibleForPrefixUnification(pre1) || isEligibleForPrefixUnification(pre2))
+ && (pre1 =:= pre2)
+ )
/** Returns true iff we are past phase specialize,
* sym1 and sym2 are two existential skolems with equal names and bounds,
@@ -64,7 +66,6 @@ trait TypeComparers {
(sym1.name == sym2.name) && isUnifiable(pre1, pre2)
)
-
def isDifferentType(tp1: Type, tp2: Type): Boolean = try {
subsametypeRecursions += 1
undoLog undo { // undo type constraints that arise from operations in this block
@@ -207,6 +208,7 @@ trait TypeComparers {
}
case _ => false
}
+
/* Those false cases certainly are ugly. There's a proposed SIP to deuglify it.
* https://docs.google.com/a/improving.org/document/d/1onPrzSqyDpHScc9PS_hpxJwa3FlPtthxw-bAuuEe8uA
*/
@@ -334,6 +336,14 @@ trait TypeComparers {
(tparams1 corresponds tparams2)(cmp) && (sub1(res1) <:< sub2(res2))
}
}
+ // This is looking for situations such as B.this.x.type <:< B.super.x.type.
+ // If it's a ThisType on the lhs and a SuperType on the right, and they originate
+ // in the same class, and the 'x' in the ThisType has in its override chain
+ // the 'x' in the SuperType, then the types conform.
+ private def isThisAndSuperSubtype(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match {
+ case (SingleType(ThisType(lpre), v1), SingleType(SuperType(ThisType(rpre), _), v2)) => (lpre == rpre) && (v1.overrideChain contains v2)
+ case _ => false
+ }
// @assume tp1.isHigherKinded || tp2.isHigherKinded
def isHKSubType(tp1: Type, tp2: Type, depth: Depth): Boolean = {
@@ -359,7 +369,7 @@ trait TypeComparers {
def retry(lhs: Type, rhs: Type) = ((lhs ne tp1) || (rhs ne tp2)) && isSubType(lhs, rhs, depth)
if (isSingleType(tp1) && isSingleType(tp2) || isConstantType(tp1) && isConstantType(tp2))
- return (tp1 =:= tp2) || retry(tp1.underlying, tp2)
+ return (tp1 =:= tp2) || isThisAndSuperSubtype(tp1, tp2) || retry(tp1.underlying, tp2)
if (tp1.isHigherKinded || tp2.isHigherKinded)
return isHKSubType(tp1, tp2, depth)
diff --git a/test/files/neg/t7834neg.check b/test/files/neg/t7834neg.check
new file mode 100644
index 0000000000..569df4b8ce
--- /dev/null
+++ b/test/files/neg/t7834neg.check
@@ -0,0 +1,41 @@
+t7834neg.scala:48: error: type mismatch;
+ found : C.super.q.type (with underlying type M2)
+ required: C.super.q.type
+ x1 = x2 // fail
+ ^
+t7834neg.scala:50: error: type mismatch;
+ found : C.super.q.type (with underlying type M1)
+ required: C.super.q.type
+ x2 = x1 // fail
+ ^
+t7834neg.scala:53: error: type mismatch;
+ found : C.super.q.type (with underlying type M1)
+ required: C.this.q.type
+ x3 = x1 // fail
+ ^
+t7834neg.scala:54: error: type mismatch;
+ found : C.super.q.type (with underlying type M2)
+ required: C.this.q.type
+ x3 = x2 // fail
+ ^
+t7834neg.scala:69: error: type mismatch;
+ found : C.super.q.type (with underlying type M2)
+ required: C.super.q.type
+ x1 = super[S2].q // fail
+ ^
+t7834neg.scala:71: error: type mismatch;
+ found : C.super.q.type (with underlying type M1)
+ required: C.super.q.type
+ x2 = super[S1].q // fail
+ ^
+t7834neg.scala:74: error: type mismatch;
+ found : C.super.q.type (with underlying type M1)
+ required: C.this.q.type
+ x3 = super[S1].q // fail
+ ^
+t7834neg.scala:75: error: type mismatch;
+ found : C.super.q.type (with underlying type M2)
+ required: C.this.q.type
+ x3 = super[S2].q // fail
+ ^
+8 errors found
diff --git a/test/files/neg/t7834neg.scala b/test/files/neg/t7834neg.scala
new file mode 100644
index 0000000000..d35a84eadd
--- /dev/null
+++ b/test/files/neg/t7834neg.scala
@@ -0,0 +1,76 @@
+class M1
+class M2 extends M1
+class M3 extends M2
+
+trait S1 { val q = new M1 ; val q1: q.type = q }
+trait S2 { val q = new M2 ; val q2: q.type = q }
+
+class B extends S1 with S2 {
+ override val q = new M3
+ val q3: q.type = q
+
+ var x1: B.super[S1].q1.type = null
+ var x2: B.super[S2].q2.type = null
+ var x3: B.this.q3.type = null
+
+ x1 = x1
+ x1 = x2
+ x1 = x3
+ x2 = x1
+ x2 = x2
+ x2 = x3
+ x3 = x1
+ x3 = x2
+ x3 = x3
+
+ x1 = q1
+ x1 = q2
+ x1 = q3
+ x2 = q1
+ x2 = q2
+ x2 = q3
+ x3 = q1
+ x3 = q2
+ x3 = x3
+}
+
+class C extends S1 with S2 {
+ override val q = new M3
+ val q3: q.type = q
+
+ // x1's type and x2's type are incompatible
+ // x3's is assignable to x1 or x2, but not vice versa
+ var x1: C.super[S1].q.type = null
+ var x2: C.super[S2].q.type = null
+ var x3: C.this.q.type = null
+
+ x1 = x1
+ x1 = x2 // fail
+ x1 = x3
+ x2 = x1 // fail
+ x2 = x2
+ x2 = x3
+ x3 = x1 // fail
+ x3 = x2 // fail
+ x3 = x3
+
+ x1 = q1
+ x1 = q2
+ x1 = q3
+ x2 = q1
+ x2 = q2
+ x2 = q3
+ x3 = q1
+ x3 = q2
+ x3 = x3
+
+ x1 = q
+ x1 = super[S1].q
+ x1 = super[S2].q // fail
+ x2 = q
+ x2 = super[S1].q // fail
+ x2 = super[S2].q
+ x3 = q
+ x3 = super[S1].q // fail
+ x3 = super[S2].q // fail
+}
diff --git a/test/files/pos/t7834.scala b/test/files/pos/t7834.scala
new file mode 100644
index 0000000000..fc9a0aa09d
--- /dev/null
+++ b/test/files/pos/t7834.scala
@@ -0,0 +1,6 @@
+class S { val q = "" }
+
+class B extends S {
+ val x1: B.super.q.type = q
+ val x2: B.this.q.type = q
+}
diff --git a/test/files/run/t7801.check b/test/files/run/t7801.check
new file mode 100644
index 0000000000..d72060c684
--- /dev/null
+++ b/test/files/run/t7801.check
@@ -0,0 +1,11 @@
+Type in expressions to have them evaluated.
+Type :help for more information.
+
+scala> val g: scala.reflect.internal.SymbolTable = null; import g.abort
+g: scala.reflect.internal.SymbolTable = null
+import g.abort
+
+scala> class C(val a: Any) extends AnyVal
+defined class C
+
+scala>
diff --git a/test/files/run/t7801.scala b/test/files/run/t7801.scala
new file mode 100644
index 0000000000..3a3cc97a51
--- /dev/null
+++ b/test/files/run/t7801.scala
@@ -0,0 +1,12 @@
+import scala.tools.partest.ReplTest
+
+// was crashing due to a subtle interaction of the Namer entering packages into
+// enclosing packages by mutating the scope in place without invalidating later
+// entries in the enclosing package class symbols type history.
+//
+// Sadly, I couldn't whittle the test case down further.
+object Test extends ReplTest {
+ override def code = """val g: scala.reflect.internal.SymbolTable = null; import g.abort
+ |class C(val a: Any) extends AnyVal""".stripMargin
+
+}