aboutsummaryrefslogtreecommitdiff
path: root/src/dotty
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-05-24 15:57:44 +0200
committerMartin Odersky <odersky@gmail.com>2016-07-11 13:34:58 +0200
commit5866d0d16c79ca5c62507bdcb7d87669426e86d6 (patch)
tree8bdce25a51cb7c36656e77abce59c6f9132807ca /src/dotty
parent6ca5b9d4675c20002ca65dab3cacf32caade3933 (diff)
downloaddotty-5866d0d16c79ca5c62507bdcb7d87669426e86d6.tar.gz
dotty-5866d0d16c79ca5c62507bdcb7d87669426e86d6.tar.bz2
dotty-5866d0d16c79ca5c62507bdcb7d87669426e86d6.zip
Allow refinements of new types
Previously a refinement could only apply to a type bound in the parent. This restriction needs to be dropped for the new encoding of hk type parameters.
Diffstat (limited to 'src/dotty')
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala2
-rw-r--r--src/dotty/tools/dotc/core/Types.scala52
-rw-r--r--src/dotty/tools/dotc/core/tasty/TastyFormat.scala3
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreePickler.scala6
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala5
5 files changed, 50 insertions, 18 deletions
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index 3ed1798ed..d73181fcb 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -50,7 +50,7 @@ object TypeApplications {
*
* [v1 X1: B1, ..., vn Xn: Bn] -> T
* ==>
- * Lambda$_v1...vn { type $hk_i: B_i, type $Apply = [X_i := this.$Arg_i] T }
+ * ([X_i := this.$hk_i] T) { type v_i $hk_i: (new)B_i }
*/
object TypeLambda {
def apply(variances: List[Int],
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index f514a329e..632ab823a 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -2849,8 +2849,12 @@ object Types {
unique(new CachedClassInfo(prefix, cls, classParents, decls, selfInfo))
}
- /** Type bounds >: lo <: hi */
- abstract case class TypeBounds(lo: Type, hi: Type) extends CachedProxyType with TypeType {
+ /** Type bounds >: lo <: hi
+ * @param bindingKind: If != NoBinding, it indicates that this is
+ * an introduction of a higher-kinded type parameter.
+ * In that case it also defines the variance of the parameter.
+ */
+ abstract case class TypeBounds(lo: Type, hi: Type)(val bindingKind: BindingKind) extends CachedProxyType with TypeType {
assert(lo.isInstanceOf[TermType])
assert(hi.isInstanceOf[TermType])
@@ -2860,9 +2864,9 @@ object Types {
override def underlying(implicit ctx: Context): Type = hi
/** The non-alias type bounds type with given bounds */
- def derivedTypeBounds(lo: Type, hi: Type)(implicit ctx: Context) =
- if ((lo eq this.lo) && (hi eq this.hi) && (variance == 0)) this
- else TypeBounds(lo, hi)
+ def derivedTypeBounds(lo: Type, hi: Type, bk: BindingKind = this.bindingKind)(implicit ctx: Context) =
+ if ((lo eq this.lo) && (hi eq this.hi) && (bk == this.bindingKind) && (variance == 0)) this
+ else TypeBounds(lo, hi, bk)
/** If this is an alias, a derived alias with the new variance,
* Otherwise the type itself.
@@ -2884,12 +2888,12 @@ object Types {
def & (that: TypeBounds)(implicit ctx: Context): TypeBounds =
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)
+ else TypeBounds(this.lo | that.lo, this.hi & that.hi, this.bindingKind join that.bindingKind)
def | (that: TypeBounds)(implicit ctx: Context): TypeBounds =
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)
+ else TypeBounds(this.lo & that.lo, this.hi | that.hi, this.bindingKind join that.bindingKind)
override def & (that: Type)(implicit ctx: Context) = that match {
case that: TypeBounds => this & that
@@ -2909,6 +2913,7 @@ object Types {
/** If this type and that type have the same variance, this variance, otherwise 0 */
final def commonVariance(that: TypeBounds): Int = (this.variance + that.variance) / 2
+ override def computeHash = doHash(variance, lo, hi)
override def equals(that: Any): Boolean = that match {
case that: TypeBounds =>
(this.lo eq that.lo) && (this.hi eq that.hi) && this.variance == that.variance
@@ -2920,11 +2925,9 @@ object Types {
if (lo eq hi) s"TypeAlias($lo, $variance)" else s"TypeBounds($lo, $hi)"
}
- class RealTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi) {
- override def computeHash = doHash(variance, lo, hi)
- }
+ class RealTypeBounds(lo: Type, hi: Type, bk: BindingKind) extends TypeBounds(lo, hi)(bk)
- abstract class TypeAlias(val alias: Type, override val variance: Int) extends TypeBounds(alias, alias) {
+ abstract class TypeAlias(val alias: Type, override val variance: Int) extends TypeBounds(alias, alias)(NoBinding) {
/** pre: this is a type alias */
def derivedTypeAlias(alias: Type, variance: Int = this.variance)(implicit ctx: Context) =
if ((alias eq this.alias) && (variance == this.variance)) this
@@ -2952,12 +2955,11 @@ object Types {
class CachedTypeAlias(alias: Type, variance: Int, hc: Int) extends TypeAlias(alias, variance) {
myHash = hc
- override def computeHash = doHash(variance, lo, hi)
}
object TypeBounds {
- def apply(lo: Type, hi: Type)(implicit ctx: Context): TypeBounds =
- unique(new RealTypeBounds(lo, hi))
+ def apply(lo: Type, hi: Type, bk: BindingKind = NoBinding)(implicit ctx: Context): TypeBounds =
+ unique(new RealTypeBounds(lo, hi, bk))
def empty(implicit ctx: Context) = apply(defn.NothingType, defn.AnyType)
def upper(hi: Type)(implicit ctx: Context) = apply(defn.NothingType, hi)
def lower(lo: Type)(implicit ctx: Context) = apply(lo, defn.AnyType)
@@ -2969,6 +2971,28 @@ object Types {
def unapply(tp: TypeAlias): Option[Type] = Some(tp.alias)
}
+ /** A value class defining the interpretation of a TypeBounds
+ * as either a regular type bounds or a binding (i.e. introduction) of a
+ * higher-kinded type parameter.
+ */
+ class BindingKind(val n: Byte) extends AnyVal {
+ def join(that: BindingKind) =
+ if (this == that) this
+ else if (this == NoBinding) that
+ else if (that == NoBinding) this
+ else NonvariantBinding
+ }
+
+ val NoBinding = new BindingKind(0) // Regular type bounds
+ val ContravariantBinding = new BindingKind(1) // Bounds for contravariant hk type param
+ val NonvariantBinding = new BindingKind(2) // Bounds for nonvariant hk type param
+ val CovariantBinding = new BindingKind(3) // Bounds for covariant hk type param
+
+ object BindingKind {
+ def fromVariance(v: Int): BindingKind = new BindingKind((v + NonvariantBinding.n).toByte)
+ def toVariance(bk: BindingKind): Int = bk.n
+ }
+
// ----- Annotated and Import types -----------------------------------------------
/** An annotated type tpe @ annot */
diff --git a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
index 221170622..a42958e75 100644
--- a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
+++ b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
@@ -129,7 +129,7 @@ Standard-Section: "ASTs" TopLevelStat*
SUPERtype Length this_Type underlying_Type
REFINEDtype Length underlying_Type refinement_NameRef info_Type
APPLIEDtype Length tycon_Type arg_Type*
- TYPEBOUNDS Length low_Type high_Type
+ TYPEBOUNDS Length low_Type high_Type bindingKind_Nat?
TYPEALIAS Length alias_Type (COVARIANT | CONTRAVARIANT)?
ANNOTATED Length underlying_Type fullAnnotation_Term
ANDtype Length left_Type right_Type
@@ -494,6 +494,7 @@ object TastyFormat {
SELFDEF | REFINEDtype => 1
case RENAMED | PARAMtype => 2
case POLYtype | METHODtype => -1
+ case TYPEBOUNDS => -2
case _ => 0
}
}
diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
index 37b9341eb..4cfd7727c 100644
--- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
@@ -233,7 +233,11 @@ class TreePickler(pickler: TastyPickler) {
}
case tpe: TypeBounds =>
writeByte(TYPEBOUNDS)
- withLength { pickleType(tpe.lo, richTypes); pickleType(tpe.hi, richTypes) }
+ withLength {
+ pickleType(tpe.lo, richTypes)
+ pickleType(tpe.hi, richTypes)
+ if (tpe.bindingKind != NoBinding) writeNat(tpe.bindingKind.n)
+ }
case tpe: AnnotatedType =>
writeByte(ANNOTATED)
withLength { pickleType(tpe.tpe, richTypes); pickleTree(tpe.annot.tree) }
diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
index 91ac4ea3e..2b8e5f019 100644
--- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
@@ -266,7 +266,10 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
case APPLIEDtype =>
readType().appliedTo(until(end)(readType()))
case TYPEBOUNDS =>
- TypeBounds(readType(), readType())
+ val lo = readType()
+ val hi = readType()
+ val bk = ifBefore(end)(new BindingKind(readNat().toByte), NoBinding)
+ TypeBounds(lo, hi, bk)
case TYPEALIAS =>
val alias = readType()
val variance =