aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-06-29 19:01:12 +0200
committerMartin Odersky <odersky@gmail.com>2016-07-11 13:34:58 +0200
commitd30f441ae986c144e739223be97b906b3bbd43dc (patch)
treeb7ba96597290a345dd9a92e3e0275f8a340fe766 /src
parent5866d0d16c79ca5c62507bdcb7d87669426e86d6 (diff)
downloaddotty-d30f441ae986c144e739223be97b906b3bbd43dc.tar.gz
dotty-d30f441ae986c144e739223be97b906b3bbd43dc.tar.bz2
dotty-d30f441ae986c144e739223be97b906b3bbd43dc.zip
Allow general recursion in refined types.
Treat parent like refinedInfo. Introduce isBinding convenience method in TypeBounds.
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala22
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala5
-rw-r--r--src/dotty/tools/dotc/core/TypeErasure.scala2
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala4
-rw-r--r--src/dotty/tools/dotc/core/Types.scala43
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreePickler.scala2
-rw-r--r--src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala4
-rw-r--r--src/dotty/tools/dotc/printing/PlainPrinter.scala2
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala4
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Variances.scala4
13 files changed, 59 insertions, 41 deletions
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index d73181fcb..8ab5fbf02 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -70,19 +70,19 @@ object TypeApplications {
}
def unapply(tp: Type)(implicit ctx: Context): Option[(List[Int], List[TypeBounds], Type)] = tp match {
- case app @ RefinedType(parent, tpnme.hkApply) =>
+ case app @ RefinedType(parent, tpnme.hkApply, refinedInfo) =>
val cls = parent.typeSymbol
val variances = cls.typeParams.map(_.variance)
def collectBounds(t: Type, acc: List[TypeBounds]): List[TypeBounds] = t match {
- case t @ RefinedType(p, rname) =>
+ case t @ RefinedType(p, rname, rinfo) =>
assert(rname.isHkArgName)
- collectBounds(p, t.refinedInfo.bounds :: acc)
+ collectBounds(p, rinfo.bounds :: acc)
case TypeRef(_, lname) =>
assert(lname.isLambdaTraitName)
acc
}
val argBounds = collectBounds(parent, Nil)
- Some((variances, argBounds, app.refinedInfo.argInfo))
+ Some((variances, argBounds, refinedInfo.argInfo))
case _ =>
None
}
@@ -153,9 +153,9 @@ object TypeApplications {
def stripArgs(tp: Type, n: Int): Type =
if (n == 0) tp
else tp match {
- case tp @ RefinedType(parent, pname) if pname == tparams(n - 1).name =>
+ case tp @ RefinedType(parent, pname, rinfo) if pname == tparams(n - 1).name =>
val res = stripArgs(parent, n - 1)
- if (res.exists) argBuf += tp.refinedInfo.argInfo
+ if (res.exists) argBuf += rinfo.argInfo
res
case _ =>
NoType
@@ -335,7 +335,7 @@ class TypeApplications(val self: Type) extends AnyVal {
/** The Lambda trait underlying a type lambda */
def LambdaTrait(implicit ctx: Context): Symbol = self.stripTypeVar match {
- case RefinedType(parent, tpnme.hkApply) =>
+ case RefinedType(_, tpnme.hkApply, _) =>
val sym = self.classSymbol
if (sym.isLambdaTrait) sym else NoSymbol
case TypeBounds(lo, hi) => hi.LambdaTrait
@@ -345,7 +345,7 @@ class TypeApplications(val self: Type) extends AnyVal {
/** Is receiver type higher-kinded (i.e. of kind != "*")? */
def isHK(implicit ctx: Context): Boolean = self.dealias match {
case self: TypeRef => self.info.isHK
- case RefinedType(_, name) => name == tpnme.hkApply
+ case RefinedType(_, tpnme.hkApply, _) => true
case TypeBounds(_, hi) => hi.isHK
case _ => false
}
@@ -580,7 +580,7 @@ class TypeApplications(val self: Type) extends AnyVal {
}
assert(args.nonEmpty)
matchParams(self, typParams, args) match {
- case refined @ RefinedType(_, pname) if pname.isHkArgName =>
+ case refined @ RefinedType(_, pname, _) if pname.isHkArgName =>
TypeRef(refined, tpnme.hkApply)
case refined =>
refined
@@ -671,7 +671,7 @@ class TypeApplications(val self: Type) extends AnyVal {
case TypeBounds(_, hi) => hi.baseTypeWithArgs(base)
case _ => default
}
- case tp @ RefinedType(parent, name) if !tp.member(name).symbol.is(ExpandedTypeParam) =>
+ case tp @ RefinedType(parent, name, _) if !tp.member(name).symbol.is(ExpandedTypeParam) =>
tp.wrapIfMember(parent.baseTypeWithArgs(base))
case tp: TermRef =>
tp.underlying.baseTypeWithArgs(base)
@@ -731,7 +731,7 @@ class TypeApplications(val self: Type) extends AnyVal {
*/
final def withoutArgs(typeArgs: List[Type]): Type = typeArgs match {
case _ :: typeArgs1 =>
- val RefinedType(tycon, _) = self
+ val RefinedType(tycon, _, _) = self
tycon.withoutArgs(typeArgs1)
case nil =>
self
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 2523c6b9a..d1dc4069d 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -465,7 +465,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
case _ =>
def isNullable(tp: Type): Boolean = tp.dealias match {
case tp: TypeRef => tp.symbol.isNullableClass
- case RefinedType(parent, _) => isNullable(parent)
+ case tp: RefinedType => isNullable(tp.parent)
case AndType(tp1, tp2) => isNullable(tp1) && isNullable(tp2)
case OrType(tp1, tp2) => isNullable(tp1) || isNullable(tp2)
case _ => false
@@ -738,9 +738,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
* @return The parent type of `tp2` after skipping the matching refinements.
*/
private def skipMatching(tp1: Type, tp2: RefinedType): Type = tp1 match {
- case tp1 @ RefinedType(parent1, name1)
+ case tp1 @ RefinedType(parent1, name1, rinfo1: TypeAlias)
if name1 == tp2.refinedName &&
- tp1.refinedInfo.isInstanceOf[TypeAlias] &&
!tp2.refinementRefersToThis &&
!tp1.refinementRefersToThis =>
tp2.parent match {
diff --git a/src/dotty/tools/dotc/core/TypeErasure.scala b/src/dotty/tools/dotc/core/TypeErasure.scala
index 39d02e069..a5aabe9c4 100644
--- a/src/dotty/tools/dotc/core/TypeErasure.scala
+++ b/src/dotty/tools/dotc/core/TypeErasure.scala
@@ -430,7 +430,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
// constructor method should not be semi-erased.
else if (isConstructor && isDerivedValueClass(sym)) eraseNormalClassRef(tp)
else this(tp)
- case RefinedType(parent, _) if !(parent isRef defn.ArrayClass) =>
+ case RefinedType(parent, _, _) if !(parent isRef defn.ArrayClass) =>
eraseResult(parent)
case _ =>
this(tp)
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index 1288c0b23..72b0c87c4 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -364,8 +364,8 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
def normalizeToRef(tp: Type): TypeRef = tp.dealias match {
case tp: TypeRef =>
tp
- case tp @ RefinedType(tp1, name: TypeName) =>
- tp.refinedInfo match {
+ case tp @ RefinedType(tp1, name: TypeName, rinfo) =>
+ rinfo match {
case TypeAlias(TypeRef(pre, name1)) if name1 == name && (pre =:= cls.thisType) =>
// Don't record refinements of the form X = this.X (These can arise using named parameters).
typr.println(s"dropping refinement $tp")
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 632ab823a..b26fd6373 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -1035,7 +1035,7 @@ object Types {
/** the self type of the underlying classtype */
def givenSelfType(implicit ctx: Context): Type = this match {
- case tp @ RefinedType(parent, name) => tp.wrapIfMember(parent.givenSelfType)
+ case tp: RefinedType => tp.wrapIfMember(tp.parent.givenSelfType)
case tp: ThisType => tp.tref.givenSelfType
case tp: TypeProxy => tp.underlying.givenSelfType
case _ => NoType
@@ -2029,10 +2029,11 @@ object Types {
* @param infoFn: A function that produces the info of the refinement declaration,
* given the refined type itself.
*/
- abstract case class RefinedType(parent: Type, refinedName: Name)
+ abstract case class RefinedType(private var myParent: Type, refinedName: Name, private var myRefinedInfo: Type)
extends CachedProxyType with BindingType with ValueType {
- val refinedInfo: Type
+ final def parent = myParent
+ final def refinedInfo = myRefinedInfo
private var refinementRefersToThisCache: Boolean = _
private var refinementRefersToThisKnown: Boolean = false
@@ -2053,7 +2054,7 @@ object Types {
def checkInst(implicit ctx: Context): this.type = {
if (refinedName == tpnme.hkApply)
parent.stripTypeVar match {
- case RefinedType(_, name) if name.isHkArgName => // ok
+ case RefinedType(_, name, _) if name.isHkArgName => // ok
case _ => badInst
}
this
@@ -2076,16 +2077,18 @@ object Types {
case _ =>
false
}
- override def computeHash = doHash(refinedName, refinedInfo, parent)
+ override def computeHash = {
+ assert(parent.exists)
+ doHash(refinedName, refinedInfo, parent)
+ }
+
override def toString = s"RefinedType($parent, $refinedName, $refinedInfo | $hashCode)"
}
- class CachedRefinedType(parent: Type, refinedName: Name, infoFn: RefinedType => Type) extends RefinedType(parent, refinedName) {
- val refinedInfo = infoFn(this)
- }
+ class CachedRefinedType(refinedName: Name) extends RefinedType(NoType, refinedName, NoType)
- class PreHashedRefinedType(parent: Type, refinedName: Name, override val refinedInfo: Type, hc: Int)
- extends RefinedType(parent, refinedName) {
+ class PreHashedRefinedType(parent: Type, refinedName: Name, refinedInfo: Type, hc: Int)
+ extends RefinedType(parent, refinedName, refinedInfo) {
myHash = hc
override def computeHash = unsupported("computeHash")
}
@@ -2095,9 +2098,22 @@ object Types {
if (names.isEmpty) parent
else make(RefinedType(parent, names.head, infoFns.head), names.tail, infoFns.tail)
+ def recursive(parentFn: RefinedType => Type, names: List[Name], infoFns: List[RefinedType => Type])(implicit ctx: Context): RefinedType = {
+ val refinements: List[RefinedType] = names.map(new CachedRefinedType(_))
+ val last = refinements.last
+ (refinements, infoFns).zipped.foreach((rt, infoFn) => rt.myRefinedInfo = infoFn(last))
+ (parentFn(last) /: refinements) { (parent, rt) =>
+ rt.myParent = parent
+ ctx.base.uniqueRefinedTypes.enterIfNew(rt).checkInst
+ }.asInstanceOf[RefinedType]
+ }
+
def apply(parent: Type, name: Name, infoFn: RefinedType => Type)(implicit ctx: Context): RefinedType = {
assert(!ctx.erasedTypes || ctx.mode.is(Mode.Printing))
- ctx.base.uniqueRefinedTypes.enterIfNew(new CachedRefinedType(parent, name, infoFn)).checkInst
+ val res: RefinedType = new CachedRefinedType(name)
+ res.myParent = parent
+ res.myRefinedInfo = infoFn(res)
+ ctx.base.uniqueRefinedTypes.enterIfNew(res).checkInst
}
def apply(parent: Type, name: Name, info: Type)(implicit ctx: Context): RefinedType = {
@@ -2668,8 +2684,8 @@ object Types {
}
def isOrType(tp: Type): Boolean = tp.stripTypeVar.dealias match {
case tp: OrType => true
+ case tp: RefinedType => isOrType(tp.parent)
case AndType(tp1, tp2) => isOrType(tp1) | isOrType(tp2)
- case RefinedType(parent, _) => isOrType(parent)
case WildcardType(bounds: TypeBounds) => isOrType(bounds.hi)
case _ => false
}
@@ -2860,6 +2876,7 @@ object Types {
assert(hi.isInstanceOf[TermType])
def variance: Int = 0
+ def isBinding = bindingKind != NoBinding
override def underlying(implicit ctx: Context): Type = hi
@@ -2876,6 +2893,8 @@ object Types {
case _ => this
}
+ def withBindingKind(bk: BindingKind)(implicit ctx: Context) = derivedTypeBounds(lo, hi, bk)
+
def contains(tp: Type)(implicit ctx: Context): Boolean = tp match {
case tp: TypeBounds => lo <:< tp.lo && tp.hi <:< hi
case tp: ClassInfo =>
diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
index 4cfd7727c..0cc08f2d9 100644
--- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
@@ -236,7 +236,7 @@ class TreePickler(pickler: TastyPickler) {
withLength {
pickleType(tpe.lo, richTypes)
pickleType(tpe.hi, richTypes)
- if (tpe.bindingKind != NoBinding) writeNat(tpe.bindingKind.n)
+ if (tpe.isBinding) writeNat(tpe.bindingKind.n)
}
case tpe: AnnotatedType =>
writeByte(ANNOTATED)
diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
index 71a919ca3..687e9279b 100644
--- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
+++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
@@ -620,9 +620,9 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
def removeSingleton(tp: Type): Type =
if (tp isRef defn.SingletonClass) defn.AnyType else tp
def elim(tp: Type): Type = tp match {
- case tp @ RefinedType(parent, name) =>
+ case tp @ RefinedType(parent, name, rinfo) =>
val parent1 = elim(tp.parent)
- tp.refinedInfo match {
+ rinfo match {
case TypeAlias(info: TypeRef) if isBound(info) =>
RefinedType(parent1, name, info.symbol.info)
case info: TypeRef if isBound(info) =>
diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala
index 1e2ba0b4d..bac180efe 100644
--- a/src/dotty/tools/dotc/printing/PlainPrinter.scala
+++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -110,7 +110,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
*/
private def refinementChain(tp: Type): List[Type] =
tp :: (tp match {
- case RefinedType(parent, _) => refinementChain(parent.stripTypeVar)
+ case tp: RefinedType => refinementChain(tp.parent.stripTypeVar)
case _ => Nil
})
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 614a274b4..e0fd47900 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -123,7 +123,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
def contains(tp1: Type, tp2: Type): Boolean =
tp1.eq(tp2) || {
tp1.stripTypeVar match {
- case RefinedType(parent, _) => contains(parent, tp2)
+ case tp1: RefinedType => contains(tp1.parent, tp2)
case _ => false
}
}
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index a9184c7e5..14071e27c 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -741,7 +741,7 @@ trait Applications extends Compatibility { self: Typer =>
def isSubTypeOfParent(subtp: Type, tp: Type)(implicit ctx: Context): Boolean =
if (subtp <:< tp) true
else tp match {
- case RefinedType(parent, _) => isSubTypeOfParent(subtp, parent)
+ case tp: RefinedType => isSubTypeOfParent(subtp, tp.parent)
case _ => false
}
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 22d2407bc..37753fe65 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -172,8 +172,8 @@ object Checking {
case tp: TermRef =>
this(tp.info)
mapOver(tp)
- case tp @ RefinedType(parent, name) =>
- tp.derivedRefinedType(this(parent), name, this(tp.refinedInfo, nestedCycleOK, nestedCycleOK))
+ case tp @ RefinedType(parent, name, rinfo) =>
+ tp.derivedRefinedType(this(parent), name, this(rinfo, nestedCycleOK, nestedCycleOK))
case tp @ TypeRef(pre, name) =>
try {
// A prefix is interesting if it might contain (transitively) a reference
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 995fa43ca..f439c4c99 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -98,9 +98,9 @@ trait TypeAssigner {
val base = apply(tycon)
val args = tp.baseArgInfos(base.typeSymbol)
if (base.typeParams.length == args.length) base.appliedTo(args) else base
- case tp @ RefinedType(parent, name) if variance > 0 =>
+ case tp @ RefinedType(parent, name, rinfo) if variance > 0 =>
val parent1 = apply(tp.parent)
- val refinedInfo1 = apply(tp.refinedInfo)
+ val refinedInfo1 = apply(rinfo)
if (toAvoid(refinedInfo1)) {
typr.println(s"dropping refinement from $tp")
parent1
diff --git a/src/dotty/tools/dotc/typer/Variances.scala b/src/dotty/tools/dotc/typer/Variances.scala
index 55e6b5232..bc9730140 100644
--- a/src/dotty/tools/dotc/typer/Variances.scala
+++ b/src/dotty/tools/dotc/typer/Variances.scala
@@ -75,8 +75,8 @@ object Variances {
case tp @ TypeBounds(lo, hi) =>
if (lo eq hi) compose(varianceInType(hi)(tparam), tp.variance)
else flip(varianceInType(lo)(tparam)) & varianceInType(hi)(tparam)
- case tp @ RefinedType(parent, _) =>
- varianceInType(parent)(tparam) & varianceInType(tp.refinedInfo)(tparam)
+ case tp @ RefinedType(parent, _, rinfo) =>
+ varianceInType(parent)(tparam) & varianceInType(rinfo)(tparam)
case tp @ MethodType(_, paramTypes) =>
flip(varianceInTypes(paramTypes)(tparam)) & varianceInType(tp.resultType)(tparam)
case ExprType(restpe) =>