Skip to content

Change : freeze bounds #805

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Oct 6, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
}

Expand Down
10 changes: 9 additions & 1 deletion src/dotty/tools/dotc/core/ConstraintHandling.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
*/
Expand Down
8 changes: 4 additions & 4 deletions src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 18 additions & 1 deletion src/dotty/tools/dotc/core/OrderingConstraint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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
}
}
1 change: 1 addition & 0 deletions src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/core/TypeApplications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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)
Expand Down
60 changes: 41 additions & 19 deletions src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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) =>
Expand Down Expand Up @@ -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 =>
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
Expand All @@ -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))
Expand Down
31 changes: 21 additions & 10 deletions src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
*/
Expand Down Expand Up @@ -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)
}
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/printing/PlainPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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) ~ ")"
}
Expand Down
22 changes: 12 additions & 10 deletions src/dotty/tools/dotc/reporting/Reporter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/transform/TreeChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/test/DeSugarTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class DeSugarTest extends ParserTest {
def transform(trees: List[Tree], mode: Mode)(implicit ctx: Context): List[Tree] = withMode(mode) { transform(trees) }

override def transform(tree: Tree)(implicit ctx: Context): Tree = {
val tree1 = desugar(tree)(ctx.withMode(curMode))
val tree1 = desugar(tree)(ctx.withModeBits(curMode))
tree1 match {
case TypedSplice(t) =>
tree1
Expand Down
File renamed without changes.
Loading