aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/core/ConstraintHandling.scala2
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala115
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala4
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala4
-rw-r--r--src/dotty/tools/dotc/core/Types.scala39
5 files changed, 97 insertions, 67 deletions
diff --git a/src/dotty/tools/dotc/core/ConstraintHandling.scala b/src/dotty/tools/dotc/core/ConstraintHandling.scala
index f8eae186a..3b368ad5e 100644
--- a/src/dotty/tools/dotc/core/ConstraintHandling.scala
+++ b/src/dotty/tools/dotc/core/ConstraintHandling.scala
@@ -285,6 +285,8 @@ trait ConstraintHandling {
if (!addParamBound(bound)) NoType
else if (fromBelow) defn.NothingType
else defn.AnyType
+ case bound: RefinedType =>
+ bound.BetaReduce
case _ =>
bound
}
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index c270288b2..7b2d2c3b2 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -291,10 +291,9 @@ object TypeApplications {
TypeLambda.applyOBS(variances, bounds, body)
}
- private class InstMap(fullType: Type, shortLived: Boolean)(implicit ctx: Context) extends TypeMap {
+ private class InstMap(fullType: Type)(implicit ctx: Context) extends TypeMap {
var localRecs: Set[RecType] = Set.empty
var keptRefs: Set[Name] = Set.empty
- var isSafe: Boolean = true
var tyconIsHK: Boolean = true
def apply(tp: Type): Type = tp match {
case tp @ TypeRef(RecThis(rt), sel) if sel.isHkArgName && localRecs.contains(rt) =>
@@ -302,8 +301,13 @@ object TypeApplications {
case TypeAlias(alias) => apply(alias)
case _ => keptRefs += sel; tp
}
- case tp: TypeVar if !tp.inst.exists && !shortLived =>
- isSafe = false
+ case tp: TypeVar if !tp.inst.exists =>
+ val bounds = tp.instanceOpt.orElse(ctx.typeComparer.bounds(tp.origin))
+ bounds.foreachPart {
+ case TypeRef(RecThis(rt), sel) if sel.isHkArgName && localRecs.contains(rt) =>
+ keptRefs += sel
+ case _ =>
+ }
tp
case _ =>
mapOver(tp)
@@ -561,12 +565,12 @@ class TypeApplications(val self: Type) extends AnyVal {
assert(!isHK, self)
self match {
case self: TypeAlias =>
- self.derivedTypeAlias(expand(self.alias.BetaReduce()))
+ self.derivedTypeAlias(expand(self.alias.BetaReduce))
case self @ TypeBounds(lo, hi) =>
if (Config.newHK)
- self.derivedTypeBounds(lo, expand(hi.BetaReduce()))
+ self.derivedTypeBounds(lo, expand(hi.BetaReduce))
else
- self.derivedTypeBounds(lo, expand(TypeBounds.upper(hi.BetaReduce())))
+ self.derivedTypeBounds(lo, expand(TypeBounds.upper(hi.BetaReduce)))
case _ => expand(self)
}
}
@@ -594,57 +598,68 @@ class TypeApplications(val self: Type) extends AnyVal {
*
* A binding is top-level if it can be reached by
*
- * - following aliases
+ * - following aliases unless the type is a LazyRef
+ * (need to keep cycle breakers around, see i974.scala)
* - dropping refinements and rec-types
* - going from a wildcard type to its upper bound
- *
- * @param shortLived If `false` suppresses all rewritings where a type variable with
- * an unknown or uncommitted instance is rewritten. Reason: If the
- * type variable is finally instantiated to something else, the
- * reduction might not be valid anymore. However, when reducing
- * during `<:<` tests `shortLived` is true and the reduction
- * is never suppressed, because then we are only interested
- * in subtyping relative to the current context.
*/
- def BetaReduce(shortLived: Boolean = false)(implicit ctx: Context): Type = self.dealias match {
+ def BetaReduce(implicit ctx: Context): Type = self.strictDealias match {
case self1 @ RefinedType(_, rname, _) if Config.newHK && rname.isHkArgName && self1.typeParams.isEmpty =>
- val inst = new InstMap(self, shortLived)
- def instTop(tp: Type): Type =
- if (!inst.isSafe) tp
- else tp.dealias match {
- case tp: RecType =>
- inst.localRecs += tp
- tp.rebind(instTop(tp.parent))
- case tp @ RefinedType(parent, rname, rinfo) =>
- rinfo match {
- case TypeAlias(TypeRef(RecThis(rt), sel)) if sel.isHkArgName && inst.localRecs.contains(rt) =>
- val bounds @ TypeBounds(_, _) = self.member(sel).info
- instTop(tp.derivedRefinedType(parent, rname, bounds.withBindingKind(NoBinding)))
- case _ =>
- val parent1 = instTop(parent)
- if (rname.isHkArgName &&
- !inst.tyconIsHK &&
- !inst.keptRefs.contains(rname)) parent1
- else tp.derivedRefinedType(parent1, rname, inst(rinfo))
- }
- case tp @ WildcardType(bounds @ TypeBounds(lo, hi)) =>
- tp.derivedWildcardType(bounds.derivedTypeBounds(inst(lo), instTop(hi)))
- case tp =>
- inst.tyconIsHK = tp.isHK
- val res = inst(tp)
- tp match {
- case tp: WildcardType =>
- println(s"inst $tp --> $res")
- case _ =>
- }
- res
+ val inst = new InstMap(self)
+
+ def instTop(tp: Type): Type = tp.strictDealias match {
+ case tp: RecType =>
+ inst.localRecs += tp
+ tp.rebind(instTop(tp.parent))
+ case tp @ RefinedType(parent, rname, rinfo) =>
+ rinfo match {
+ case TypeAlias(TypeRef(RecThis(rt), sel)) if sel.isHkArgName && inst.localRecs.contains(rt) =>
+ val bounds @ TypeBounds(_, _) = self.member(sel).info
+ instTop(tp.derivedRefinedType(parent, rname, bounds.withBindingKind(NoBinding)))
+ case _ =>
+ val parent1 = instTop(parent)
+ if (rname.isHkArgName &&
+ !inst.tyconIsHK &&
+ !inst.keptRefs.contains(rname)) parent1
+ else tp.derivedRefinedType(parent1, rname, inst(rinfo))
+ }
+ case tp @ WildcardType(bounds @ TypeBounds(lo, hi)) =>
+ tp.derivedWildcardType(bounds.derivedTypeBounds(inst(lo), instTop(hi)))
+ case tp: LazyRef =>
+ instTop(tp.ref)
+ case tp =>
+ inst.tyconIsHK = tp.isHK
+ val res = inst(tp)
+ tp match {
+ case tp: WildcardType =>
+ println(s"inst $tp --> $res")
+ case _ =>
+ }
+ res
+ }
+
+ def isLazy(tp: Type): Boolean = tp.strictDealias match {
+ case tp: RefinedOrRecType => isLazy(tp.parent)
+ case tp @ WildcardType(bounds @ TypeBounds(lo, hi)) => isLazy(hi)
+ case tp: LazyRef => true
+ case _ => false
+ }
+
+ val reduced =
+ if (isLazy(self1)) {
+ // A strange dance is needed here to make 974.scala compile.
+ val res = LazyRef(() => instTop(self))
+ res.ref // without this line, pickling 974.scala fails with an assertion error
+ // saying that we address a RecThis outside its Rec (in the case of RecThis of pickleNewType)
+ res // without this line, typing 974.scala gives a stackoverflow in asSeenFrom.
}
- val reduced = instTop(self)
- if (inst.isSafe) reduced else self
+ else instTop(self)
+ if (reduced ne self) hk.println(i"reduce $self --> $reduced")
+ reduced
case _ => self
}
- /** A type ref is eta expandable if it refers to a non-lambda class.
+ /** A type ref is eta expandable if it refers to a non-lambda class.
* In that case we can look for parameterized base types of the type
* to eta expand them.
*/
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index b0c36ca58..c82dc6a39 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -661,7 +661,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
}
}
Config.newHK && app.isHKApply && !other.isHKApply && {
- val reduced = app.BetaReduce(shortLived = true)
+ val reduced = app.BetaReduce
if (reduced ne app)
if (inOrder) isSubType(reduced, other) else isSubType(other, reduced)
else tryInfer(app.typeConstructor.dealias)
@@ -1503,7 +1503,7 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
override def compareHkApply(app: RefinedType, other: Type, inOrder: Boolean) =
if (app.isHKApply)
- traceIndented(i"compareHkApply $app, $other, $inOrder, ${app.BetaReduce(shortLived = true)}") {
+ traceIndented(i"compareHkApply $app, $other, $inOrder, ${app.BetaReduce}") {
super.compareHkApply(app, other, inOrder)
}
else super.compareHkApply(app, other, inOrder)
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index 46771a5aa..c6a18f305 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -158,7 +158,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
tp
case tp: RefinedType =>
tp.derivedRefinedType(simplify(tp.parent, theMap), tp.refinedName, simplify(tp.refinedInfo, theMap))
- .BetaReduce()
+ .BetaReduce
case tp: TypeAlias =>
tp.derivedTypeAlias(simplify(tp.alias, theMap))
case AndType(l, r) =>
@@ -384,7 +384,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
var formals: SimpleMap[TypeName, Symbol] = SimpleMap.Empty // A map of all formal parent parameter
// Strip all refinements from parent type, populating `refinements` and `formals` maps.
- def normalizeToRef(tp: Type): TypeRef = tp.dealias.BetaReduce() match {
+ def normalizeToRef(tp: Type): TypeRef = tp.dealias.BetaReduce match {
case tp: TypeRef =>
tp
case tp @ RefinedType(tp1, name: TypeName, rinfo) =>
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 4f5bec56b..dadb5b95e 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -822,7 +822,16 @@ object Types {
/** Follow aliases and dereferences LazyRefs and instantiated TypeVars until type
* is no longer alias type, LazyRef, or instantiated type variable.
*/
- final def dealias(implicit ctx: Context): Type = this match {
+ final def dealias(implicit ctx: Context): Type = strictDealias match {
+ case tp: LazyRef => tp.ref.dealias
+ case tp => tp
+ }
+
+ /** Follow aliases and instantiated TypeVars until type
+ * is no longer alias type, or instantiated type variable.
+ * Do not follow LazyRefs
+ */
+ final def strictDealias(implicit ctx: Context): Type = this match {
case tp: TypeRef =>
if (tp.symbol.isClass) tp
else tp.info match {
@@ -832,19 +841,11 @@ object Types {
case tp: TypeVar =>
val tp1 = tp.instanceOpt
if (tp1.exists) tp1.dealias else tp
- case tp: LazyRef =>
- tp.ref.dealias
case tp: AnnotatedType =>
tp.derivedAnnotatedType(tp.tpe.dealias, tp.annot)
case tp => tp
}
- /** If this is a TypeAlias type, its alias otherwise this type itself */
- final def followTypeAlias(implicit ctx: Context): Type = this match {
- case TypeAlias(alias) => alias
- case _ => this
- }
-
/** Perform successive widenings and dealiasings until none can be applied anymore */
final def widenDealias(implicit ctx: Context): Type = {
val res = this.widen.dealias
@@ -859,6 +860,12 @@ object Types {
case _ => this
}
+ /** If this is a TypeAlias type, its alias otherwise this type itself */
+ final def followTypeAlias(implicit ctx: Context): Type = this match {
+ case TypeAlias(alias) => alias
+ case _ => this
+ }
+
/** If this is a (possibly aliased, annotated, and/or parameterized) reference to
* a class, the class type ref, otherwise NoType.
* @param refinementOK If `true` we also skip non-parameter refinements.
@@ -1579,14 +1586,20 @@ object Types {
// we might now get cycles over members that are in a refinement but that lack
// a symbol. Without the following precaution i974.scala stackoverflows when compiled
// with new hk scheme.
- val saved = lastDenotation
- if (name.isTypeName && lastDenotation != null && (lastDenotation.symbol ne NoSymbol))
+ val savedDenot = lastDenotation
+ val savedSymbol = lastSymbol
+ if (prefix.isInstanceOf[RecThis] && name.isTypeName) {
lastDenotation = ctx.anyTypeDenot
+ lastSymbol = NoSymbol
+ }
try
if (name.isShadowedName) prefix.nonPrivateMember(name.revertShadowed)
else prefix.member(name)
finally
- if (lastDenotation eq ctx.anyTypeDenot) lastDenotation = saved
+ if (lastDenotation eq ctx.anyTypeDenot) {
+ lastDenotation = savedDenot
+ lastSymbol = savedSymbol
+ }
}
/** (1) Reduce a type-ref `W # X` or `W { ... } # U`, where `W` is a wildcard type
@@ -2753,7 +2766,7 @@ object Types {
myRepr
}
- override def toString = s"Skolem($info)"
+ override def toString = s"Skolem($hashCode)"
}
final class CachedSkolemType(info: Type) extends SkolemType(info)