aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorodersky <odersky@gmail.com>2015-10-06 20:59:12 +0200
committerodersky <odersky@gmail.com>2015-10-06 20:59:12 +0200
commitadc4a54d81746e9c77cf2ac3f5f6c439b421b76c (patch)
tree4d98527470498e93d4bdd1648e6f86cfc92488bd /src
parent5f7e2901b0d13d0201874ada72a107820870e274 (diff)
parent3b60c3bfd675c9c650a006a302fb35163181db89 (diff)
downloaddotty-adc4a54d81746e9c77cf2ac3f5f6c439b421b76c.tar.gz
dotty-adc4a54d81746e9c77cf2ac3f5f6c439b421b76c.tar.bz2
dotty-adc4a54d81746e9c77cf2ac3f5f6c439b421b76c.zip
Merge pull request #805 from dotty-staging/change-freeze-bounds
Change : freeze bounds
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala4
-rw-r--r--src/dotty/tools/dotc/core/ConstraintHandling.scala10
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala8
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala4
-rw-r--r--src/dotty/tools/dotc/core/OrderingConstraint.scala19
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala1
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala4
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala60
-rw-r--r--src/dotty/tools/dotc/core/Types.scala31
-rw-r--r--src/dotty/tools/dotc/printing/PlainPrinter.scala2
-rw-r--r--src/dotty/tools/dotc/reporting/Reporter.scala22
-rw-r--r--src/dotty/tools/dotc/transform/TreeChecker.scala2
12 files changed, 114 insertions, 53 deletions
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index 29a31375b..14a36f398 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -626,7 +626,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
loop(from.owner, from :: froms, to :: tos)
else {
//println(i"change owner ${from :: froms}%, % ==> $tos of $tree")
- new TreeTypeMap(oldOwners = from :: froms, newOwners = tos)(ctx.withMode(Mode.FutureDefsOK)).apply(tree)
+ new TreeTypeMap(oldOwners = from :: froms, newOwners = tos)(ctx.addMode(Mode.FutureDefsOK)).apply(tree)
}
}
loop(from, Nil, to :: Nil)
@@ -652,7 +652,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
traverseChildren(tree)
}
}
- traverser.traverse(tree)(ctx.withMode(Mode.FutureDefsOK))
+ traverser.traverse(tree)(ctx.addMode(Mode.FutureDefsOK))
tree
}
diff --git a/src/dotty/tools/dotc/core/ConstraintHandling.scala b/src/dotty/tools/dotc/core/ConstraintHandling.scala
index 544304e8a..577b958c8 100644
--- a/src/dotty/tools/dotc/core/ConstraintHandling.scala
+++ b/src/dotty/tools/dotc/core/ConstraintHandling.scala
@@ -23,6 +23,7 @@ trait ConstraintHandling {
implicit val ctx: Context
protected def isSubType(tp1: Type, tp2: Type): Boolean
+ protected def isSameType(tp1: Type, tp2: Type): Boolean
val state: TyperState
import state.constraint
@@ -104,13 +105,20 @@ trait ConstraintHandling {
up.forall(addOneBound(_, lo, isUpper = false))
}
- protected final def isSubTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
+ final def isSubTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
val saved = frozenConstraint
frozenConstraint = true
try isSubType(tp1, tp2)
finally frozenConstraint = saved
}
+ final def isSameTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
+ val saved = frozenConstraint
+ frozenConstraint = true
+ try isSameType(tp1, tp2)
+ finally frozenConstraint = saved
+ }
+
/** Test whether the lower bounds of all parameters in this
* constraint are a solution to the constraint.
*/
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index 206ef9d8b..f9d64b2cc 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -439,12 +439,12 @@ object Contexts {
}
implicit class ModeChanges(val c: Context) extends AnyVal {
- final def withMode(mode: Mode): Context =
+ final def withModeBits(mode: Mode): Context =
if (mode != c.mode) c.fresh.setMode(mode) else c
- final def addMode(mode: Mode): Context = withMode(c.mode | mode)
- final def maskMode(mode: Mode): Context = withMode(c.mode & mode)
- final def retractMode(mode: Mode): Context = withMode(c.mode &~ mode)
+ final def addMode(mode: Mode): Context = withModeBits(c.mode | mode)
+ final def maskMode(mode: Mode): Context = withModeBits(c.mode & mode)
+ final def retractMode(mode: Mode): Context = withModeBits(c.mode &~ mode)
}
implicit class FreshModeChanges(val c: FreshContext) extends AnyVal {
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index fff447803..b223a8086 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -339,8 +339,8 @@ object Denotations {
val info1 = denot1.info
val info2 = denot2.info
val sameSym = sym1 eq sym2
- if (sameSym && info1 <:< info2) denot2
- else if (sameSym && info2 <:< info1) denot1
+ if (sameSym && (info1 frozen_<:< info2)) denot2
+ else if (sameSym && (info2 frozen_<:< info1)) denot1
else {
val jointSym =
if (sameSym) sym1
diff --git a/src/dotty/tools/dotc/core/OrderingConstraint.scala b/src/dotty/tools/dotc/core/OrderingConstraint.scala
index 7e27ee628..e818862cb 100644
--- a/src/dotty/tools/dotc/core/OrderingConstraint.scala
+++ b/src/dotty/tools/dotc/core/OrderingConstraint.scala
@@ -129,7 +129,6 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
type This = OrderingConstraint
-
// ----------- Basic indices --------------------------------------------------
/** The number of type parameters in the given entry array */
@@ -576,4 +575,22 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
}
Text.lines(List(header, uninstVarsText, constrainedText, boundsText, orderingText, ")"))
}
+
+ override def toString: String = {
+ def entryText(tp: Type): String = tp match {
+ case tp: TypeBounds => tp.toString
+ case _ =>" := " + tp
+ }
+ val constrainedText =
+ " constrained types = " + domainPolys.mkString("\n")
+ val boundsText =
+ " bounds = " + {
+ val assocs =
+ for (param <- domainParams)
+ yield
+ param.binder.paramNames(param.paramNum) + ": " + entryText(entry(param))
+ assocs.mkString("\n")
+ }
+ constrainedText + "\n" + boundsText
+ }
}
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 2ce2b8d20..d5ab09930 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -1587,6 +1587,7 @@ object SymDenotations {
if (isCachable(tp)) baseTypeRefCache.put(tp, basetp)
else baseTypeRefCache.remove(tp)
} else if (basetp == NoPrefix) {
+ baseTypeRefCache.put(tp, null)
throw CyclicReference(this)
}
basetp
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index 927c4fcc5..47935f79e 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -497,7 +497,7 @@ class TypeApplications(val self: Type) extends AnyVal {
val boundss = new mutable.ListBuffer[TypeBounds]
for (sym <- boundSyms) {
val bounds = sym.info.bounds
- if (!(TypeBounds.empty <:< bounds)) {
+ if (!(TypeBounds.empty frozen_<:< bounds)) {
boundNames += sym.name
boundss += bounds
}
@@ -574,7 +574,7 @@ class TypeApplications(val self: Type) extends AnyVal {
// we have a binding T = Lambda$XYZ{...}.this.hk$i where hk$i names the current `tparam`.
val pcore = etaCore(tp.parent, otherParams)
val hkBounds = self.member(rname).info.bounds
- if (TypeBounds.empty <:< hkBounds) pcore
+ if (TypeBounds.empty frozen_<:< hkBounds) pcore
else tp.derivedRefinedType(pcore, tp.refinedName, hkBounds)
case _ =>
val pcore = etaCore(tp.parent, tparams)
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index e3e5f3960..5fbffe6e9 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -154,24 +154,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
case tp1: NamedType =>
val sym1 = tp1.symbol
(if ((sym1 ne NoSymbol) && (sym1 eq tp2.symbol))
- ctx.erasedTypes || sym1.isStaticOwner ||
- { // Implements: A # X <: B # X
- // if either A =:= B (i.e. A <: B and B <: A), or the following three conditions hold:
- // 1. X is a class type,
- // 2. B is a class type without abstract type members.
- // 3. A <: B.
- // Dealiasing is taken care of elsewhere.
- val pre1 = tp1.prefix
- val pre2 = tp2.prefix
- isSameType(pre1, pre2) ||
- sym1.isClass &&
- pre2.classSymbol.exists &&
- pre2.abstractTypeMembers.isEmpty &&
- isSubType(pre1, pre2)
- }
+ ctx.erasedTypes || sym1.isStaticOwner || isSubType(tp1.prefix, tp2.prefix)
else
(tp1.name eq tp2.name) &&
- isSameType(tp1.prefix, tp2.prefix) &&
+ isSubType(tp1.prefix, tp2.prefix) &&
(tp1.signature == tp2.signature) &&
!tp1.isInstanceOf[WithFixedSym] &&
!tp2.isInstanceOf[WithFixedSym]
@@ -229,6 +215,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
compareSuper
case AndType(tp21, tp22) =>
isSubType(tp1, tp21) && isSubType(tp1, tp22)
+ case OrType(tp21, tp22) =>
+ if (tp21.stripTypeVar eq tp22.stripTypeVar) isSubType(tp1, tp21)
+ else secondTry(tp1, tp2)
case TypeErasure.ErasedValueType(cls2, underlying2) =>
def compareErasedValueType = tp1 match {
case TypeErasure.ErasedValueType(cls1, underlying1) =>
@@ -291,6 +280,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
isSubType(tp1.ref, tp2)
case tp1: AnnotatedType =>
isSubType(tp1.tpe, tp2)
+ case AndType(tp11, tp12) =>
+ if (tp11.stripTypeVar eq tp12.stripTypeVar) isSubType(tp11, tp2)
+ else thirdTry(tp1, tp2)
case OrType(tp11, tp12) =>
isSubType(tp11, tp2) && isSubType(tp12, tp2)
case ErrorType =>
@@ -353,6 +345,21 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
}
compareRefined
case OrType(tp21, tp22) =>
+ // Rewrite T1 <: (T211 & T212) | T22 to T1 <: (T211 | T22) and T1 <: (T212 | T22)
+ // and analogously for T1 <: T21 | (T221 & T222)
+ // `|' types to the right of <: are problematic, because
+ // we have to choose one constraint set or another, which might cut off
+ // solutions. The rewriting delays the point where we have to choose.
+ tp21 match {
+ case AndType(tp211, tp212) =>
+ return isSubType(tp1, OrType(tp211, tp22)) && isSubType(tp1, OrType(tp212, tp22))
+ case _ =>
+ }
+ tp22 match {
+ case AndType(tp221, tp222) =>
+ return isSubType(tp1, OrType(tp21, tp221)) && isSubType(tp1, OrType(tp21, tp222))
+ case _ =>
+ }
eitherIsSubType(tp1, tp21, tp1, tp22) || fourthTry(tp1, tp2)
case tp2 @ MethodType(_, formals2) =>
def compareMethod = tp1 match {
@@ -454,6 +461,21 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
isNewSubType(tp1.parent, tp2) ||
needsEtaLift(tp2, tp1) && tp2.testLifted(tp1.typeParams, isSubType(tp1, _), Nil)
case AndType(tp11, tp12) =>
+ // Rewrite (T111 | T112) & T12 <: T2 to (T111 & T12) <: T2 and (T112 | T12) <: T2
+ // and analogously for T11 & (T121 | T122) & T12 <: T2
+ // `&' types to the left of <: are problematic, because
+ // we have to choose one constraint set or another, which might cut off
+ // solutions. The rewriting delays the point where we have to choose.
+ tp11 match {
+ case OrType(tp111, tp112) =>
+ return isSubType(AndType(tp111, tp12), tp2) && isSubType(AndType(tp112, tp12), tp2)
+ case _ =>
+ }
+ tp12 match {
+ case OrType(tp121, tp122) =>
+ return isSubType(AndType(tp11, tp121), tp2) && isSubType(AndType(tp11, tp122), tp2)
+ case _ =>
+ }
eitherIsSubType(tp11, tp2, tp12, tp2)
case JavaArrayType(elem1) =>
def compareJavaArray = tp2 match {
@@ -693,7 +715,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
case formal1 :: rest1 =>
formals2 match {
case formal2 :: rest2 =>
- (isSameType(formal1, formal2)
+ (isSameTypeWhenFrozen(formal1, formal2)
|| isJava1 && (formal2 isRef ObjectClass) && (formal1 isRef AnyClass)
|| isJava2 && (formal1 isRef ObjectClass) && (formal2 isRef AnyClass)) &&
matchingParams(rest1, rest2, isJava1, isJava2)
@@ -1067,7 +1089,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
case tp1: ClassInfo =>
tp2 match {
case tp2: ClassInfo =>
- isSubType(tp1.prefix, tp2.prefix) || (tp1.cls.owner derivesFrom tp2.cls.owner)
+ isSubTypeWhenFrozen(tp1.prefix, tp2.prefix) || (tp1.cls.owner derivesFrom tp2.cls.owner)
case _ =>
false
}
@@ -1083,7 +1105,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
tp2 match {
case tp2: MethodType =>
def asGoodParams(formals1: List[Type], formals2: List[Type]) =
- (formals2 corresponds formals1)(isSubType)
+ (formals2 corresponds formals1)(isSubTypeWhenFrozen)
asGoodParams(tp1.paramTypes, tp2.paramTypes) &&
(!asGoodParams(tp2.paramTypes, tp1.paramTypes) ||
isAsGood(tp1.resultType, tp2.resultType))
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index bce57ae23..e4f228915 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -595,6 +595,11 @@ object Types {
ctx.typeComparer.topLevelSubType(this, that)
}
+ /** Is this type a subtype of that type? */
+ final def frozen_<:<(that: Type)(implicit ctx: Context): Boolean = track("frozen_<:<") {
+ ctx.typeComparer.isSubTypeWhenFrozen(this, that)
+ }
+
/** Is this type the same as that type?
* This is the case iff `this <:< that` and `that <:< this`.
*/
@@ -625,9 +630,9 @@ object Types {
case ExprType(_) | MethodType(Nil, _) => tp.resultType
case _ => tp
}
- this <:< that || {
+ (this frozen_<:< that) || {
val rthat = result(that)
- (rthat ne that) && result(this) <:< rthat
+ (rthat ne that) && (result(this) frozen_<:< rthat)
}
}
@@ -801,12 +806,18 @@ object Types {
case _ => NoType
}
- /** The chain of underlying types as long as type is a TypeProxy.
+ /** The iterator of underlying types as long as type is a TypeProxy.
* Useful for diagnostics
*/
- def underlyingChain(implicit ctx: Context): List[Type] = this match {
- case tp: TypeProxy => tp :: tp.underlying.underlyingChain
- case _ => Nil
+ def underlyingIterator(implicit ctx: Context): Iterator[Type] = new Iterator[Type] {
+ var current = Type.this
+ var hasNext = true
+ def next = {
+ val res = current
+ hasNext = current.isInstanceOf[TypeProxy]
+ if (hasNext) current = current.asInstanceOf[TypeProxy].underlying
+ res
+ }
}
/** A prefix-less refined this or a termRef to a new skolem symbol
@@ -2652,13 +2663,13 @@ object Types {
}
def & (that: TypeBounds)(implicit ctx: Context): TypeBounds =
- if (this.lo <:< that.lo && that.hi <:< this.hi) that
- else if (that.lo <:< this.lo && this.hi <:< that.hi) this
+ if ((this.lo frozen_<:< that.lo) && (that.hi frozen_<:< this.hi)) that
+ else if ((that.lo frozen_<:< this.lo) && (this.hi frozen_<:< that.hi)) this
else TypeBounds(this.lo | that.lo, this.hi & that.hi)
def | (that: TypeBounds)(implicit ctx: Context): TypeBounds =
- if (this.lo <:< that.lo && that.hi <:< this.hi) this
- else if (that.lo <:< this.lo && this.hi <:< that.hi) that
+ if ((this.lo frozen_<:< that.lo) && (that.hi frozen_<:< this.hi)) this
+ else if ((that.lo frozen_<:< this.lo) && (this.hi frozen_<:< that.hi)) that
else TypeBounds(this.lo & that.lo, this.hi | that.hi)
override def & (that: Type)(implicit ctx: Context) = that match {
diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala
index 45928af4b..5daef9fb8 100644
--- a/src/dotty/tools/dotc/printing/PlainPrinter.scala
+++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -166,7 +166,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
else {
val constr = ctx.typerState.constraint
val bounds =
- if (constr.contains(tp)) constr.fullBounds(tp.origin)
+ if (constr.contains(tp)) constr.fullBounds(tp.origin)(ctx.addMode(Mode.Printing))
else TypeBounds.empty
"(" ~ toText(tp.origin) ~ "?" ~ toText(bounds) ~ ")"
}
diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala
index 7adeeac1c..086575fb4 100644
--- a/src/dotty/tools/dotc/reporting/Reporter.scala
+++ b/src/dotty/tools/dotc/reporting/Reporter.scala
@@ -149,16 +149,18 @@ trait Reporting { this: Context =>
else traceIndented[T](s"==> $question?", (res: Any) => s"<== $question = ${resStr(res)}")(op)
}
- def traceIndented[T](leading: => String, trailing: Any => String)(op: => T): T = {
- var finalized = false
- var logctx = this
- while (logctx.reporter.isInstanceOf[StoreReporter]) logctx = logctx.outer
- def finalize(result: Any, note: String) =
- if (!finalized) {
- base.indent -= 1
- logctx.log(s"${base.indentTab * base.indent}${trailing(result)}$note")
- finalized = true
- }
+ def traceIndented[T](leading: => String, trailing: Any => String)(op: => T): T =
+ if (ctx.mode.is(Mode.Printing)) op
+ else {
+ var finalized = false
+ var logctx = this
+ while (logctx.reporter.isInstanceOf[StoreReporter]) logctx = logctx.outer
+ def finalize(result: Any, note: String) =
+ if (!finalized) {
+ base.indent -= 1
+ logctx.log(s"${base.indentTab * base.indent}${trailing(result)}$note")
+ finalized = true
+ }
try {
logctx.log(s"${base.indentTab * base.indent}$leading")
base.indent += 1
diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala
index f046226d1..2296ae658 100644
--- a/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -66,7 +66,7 @@ class TreeChecker extends Phase with SymTransformer {
val cur = symd.linkedClass
val prev = ctx.atPhase(ctx.phase.prev) {
ct => {
- implicit val ctx: Context = ct.withMode(Mode.FutureDefsOK)
+ implicit val ctx: Context = ct.addMode(Mode.FutureDefsOK)
symd.symbol.linkedClass
}
}