diff options
-rw-r--r-- | src/dotty/tools/dotc/core/TypeApplications.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 52 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TastyFormat.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TreePickler.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 5 |
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 = |