aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-10-09 12:36:43 +0200
committerMartin Odersky <odersky@gmail.com>2013-10-09 12:36:43 +0200
commit0fc19e0e1ef7b56f9ca0649fde35765892cf1a53 (patch)
treed037ee483a3c89218acf35983006dd8bc4336b46 /src/dotty/tools/dotc
parent16c1ddd3bb86c61890418b8394d44486e7bbd9dd (diff)
downloaddotty-0fc19e0e1ef7b56f9ca0649fde35765892cf1a53.tar.gz
dotty-0fc19e0e1ef7b56f9ca0649fde35765892cf1a53.tar.bz2
dotty-0fc19e0e1ef7b56f9ca0649fde35765892cf1a53.zip
Cleanup of new scheme for handling local type parameters and type members.
If a type parameter or local type member is co/contravariant, its instantiation is a special alias type that remembers the variance. These alias types can be refined with subtypes in subclasses and intersection and union translate to their bounds.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala4
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala12
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala29
-rw-r--r--src/dotty/tools/dotc/core/Types.scala56
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala2
5 files changed, 69 insertions, 34 deletions
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index 17ff18b73..593fb2bbb 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -458,10 +458,10 @@ object Flags {
final val ParamOrAccessor = Param | Accessor
/** A covariant type parameter instance */
- final val CovariantExpanded = allOf(ExpandedName, Covariant)
+ final val LocalCovariant = allOf(Local, Covariant)
/** A contravariant type parameter instance */
- final val ContravariantExpanded = allOf(ExpandedName, Contravariant)
+ final val LocalContravariant = allOf(Local, Contravariant)
/** A covariant type parameter instance */
final val TypeParamOrInstance = TypeParam | TypeParamInstance
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 8a4cdf1e5..9142e3185 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -117,7 +117,7 @@ object SymDenotations {
}
protected[dotc] final def info_=(tp: Type) = {
- def illegal: String = s"illegal type for module $this: $tp"
+ def illegal: String = s"illegal type for $this: $tp"
/*
if (this is Module) // make sure module invariants that allow moduleClass and sourceModule to work are kept.
tp match {
@@ -646,7 +646,7 @@ object SymDenotations {
def symRef(implicit ctx: Context): NamedType =
NamedType.withSym(owner.thisType, symbol)
- /** The variance of this type parameter as an Int, with
+ /** The variance of this type parameter or type member as an Int, with
* +1 = Covariant, -1 = Contravariant, 0 = Nonvariant, or not a type parameter
*/
final def variance: Int =
@@ -654,6 +654,14 @@ object SymDenotations {
else if (this is Contravariant) -1
else 0
+ /** If this is a privatye[this] or protected[this] type parameter or type member,
+ * its variance, otherwise 0.
+ */
+ final def localVariance: Int =
+ if (this is LocalCovariant) 1
+ else if (this is LocalContravariant) -1
+ else 0
+
override def toString = {
val kindString =
if (this is ModuleClass) "module class"
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 14b0413ec..c54312e01 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -254,11 +254,12 @@ class TypeComparer(initctx: Context) extends DotClass {
case _ =>
isSubType(tp1, restpe2)
}
- case TypeBounds(lo2, hi2) =>
+ case tp2 @ TypeBounds(lo2, hi2) =>
tp1 match {
- case TypeBounds(lo1, hi1) =>
- ((lo2 isRef NothingClass) || isSubType(lo2, lo1)) &&
- ((hi2 isRef AnyClass) || isSubType(hi1, hi2))
+ case tp1 @ TypeBounds(lo1, hi1) =>
+ val v = tp1.variance + tp2.variance
+ ((v > 0) || (lo2 isRef NothingClass) || isSubType(lo2, lo1)) &&
+ ((v < 0) || (hi2 isRef AnyClass) || isSubType(hi1, hi2))
case tp1: ClassInfo =>
val tt = tp1.typeConstructor // was typeTemplate
isSubType(lo2, tt) && isSubType(tt, hi2)
@@ -434,7 +435,7 @@ class TypeComparer(initctx: Context) extends DotClass {
}
}
}
-
+
/** The greatest lower bound of a list types */
final def glb(tps: List[Type]): Type =
(defn.AnyType /: tps)(glb)
@@ -552,9 +553,14 @@ class TypeComparer(initctx: Context) extends DotClass {
/** Try to distribute `&` inside type, detect and handle conflicts */
private def distributeAnd(tp1: Type, tp2: Type): Type = tp1 match {
- case TypeBounds(lo1, hi1) =>
+ case tp1 @ TypeBounds(lo1, hi1) =>
tp2 match {
- case TypeBounds(lo2, hi2) =>
+ case tp2 @ TypeBounds(lo2, hi2) =>
+ if ((lo1 eq hi1) && (lo2 eq hi2)) {
+ val v = (tp1.variance + tp2.variance) / 2
+ if (v > 0) return TypeAlias(hi1 & hi2, v)
+ if (v < 0) return TypeAlias(lo1 | lo2, v)
+ }
TypeBounds(lo1 | lo2, hi1 & hi2)
case _ =>
andConflict(tp1, tp2)
@@ -615,9 +621,14 @@ class TypeComparer(initctx: Context) extends DotClass {
/** Try to distribute `|` inside type, detect and handle conflicts */
private def distributeOr(tp1: Type, tp2: Type): Type = tp1 match {
- case TypeBounds(lo1, hi1) =>
+ case tp1 @ TypeBounds(lo1, hi1) =>
tp2 match {
- case TypeBounds(lo2, hi2) =>
+ case tp2 @ TypeBounds(lo2, hi2) =>
+ if ((lo1 eq hi1) && (lo2 eq hi2)) {
+ val v = (tp1.variance + tp2.variance) / 2
+ if (v > 0) return TypeAlias(hi1 | hi2, v)
+ if (v < 0) return TypeAlias(lo1 & lo2, v)
+ }
TypeBounds(lo1 & lo2, hi1 | hi2)
case _ =>
orConflict(tp1, tp2)
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 978c39cc9..b5cd8c3ee 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -843,9 +843,9 @@ object Types {
*/
final def toBounds(tparam: Symbol)(implicit ctx: Context): TypeBounds = {
val v = tparam.variance
- if (v > 0) TypeBounds.upper(this)
- else if (v < 0) TypeBounds.lower(this)
- else TypeAlias(this)
+ if (v > 0 && !(tparam is Local)) TypeBounds.upper(this)
+ else if (v < 0 && !(tparam is Local)) TypeBounds.lower(this)
+ else TypeAlias(this, v)
}
/** The type arguments of the base type instance wrt `base` of this type */
@@ -893,11 +893,13 @@ object Types {
*/
final def argType(tparam: Symbol)(implicit ctx: Context): Type = this match {
case TypeBounds(lo, hi) =>
- val v = tparam.variance
- if (v > 0 && (lo isRef defn.NothingClass)) hi
- else if (v < 0 && (hi isRef defn.AnyClass)) lo
- else if (v == 0 && (lo eq hi)) lo
- else NoType
+ if (lo eq hi) hi
+ else {
+ val v = tparam.variance
+ if (v > 0 && (lo isRef defn.NothingClass)) hi
+ else if (v < 0 && (hi isRef defn.AnyClass)) lo
+ else NoType
+ }
case _ =>
NoType
}
@@ -1978,31 +1980,34 @@ object Types {
assert(lo.isInstanceOf[TermType], lo+" "+lo.getClass)
assert(hi.isInstanceOf[TermType], hi+" "+hi.getClass)
+ def variance: Int = 0
+
override def underlying(implicit ctx: Context): Type = hi
- def derivedTypeBounds(lo: Type, hi: Type)(implicit ctx: Context) =
- if ((lo eq this.lo) && (hi eq this.hi)) this
- else TypeBounds(lo, hi)
+ def derivedTypeBounds(lo: Type, hi: Type, variance: Int = this.variance)(implicit ctx: Context) =
+ if ((lo eq this.lo) && (hi eq this.hi) && (variance == this.variance)) this
+ else TypeBounds(lo, hi, variance)
def contains(tp: Type)(implicit ctx: Context) = lo <:< tp && tp <:< hi
def &(that: TypeBounds)(implicit ctx: Context): TypeBounds =
- derivedTypeBounds(this.lo | that.lo, this.hi & that.hi)
+ derivedTypeBounds(this.lo | that.lo, this.hi & that.hi, (this.variance + that.variance) / 2)
def | (that: TypeBounds)(implicit ctx: Context): TypeBounds =
- derivedTypeBounds(this.lo & that.lo, this.hi | that.hi)
+ derivedTypeBounds(this.lo & that.lo, this.hi | that.hi, (this.variance + that.variance) / 2)
override def & (that: Type)(implicit ctx: Context) = that match {
case that: TypeBounds => this & that
- case that: ClassInfo => this & that.bounds
+ case _ => super.& (that)
}
override def | (that: Type)(implicit ctx: Context) = that match {
case that: TypeBounds => this | that
+ case _ => super.| (that)
}
def map(f: Type => Type)(implicit ctx: Context): TypeBounds =
- TypeBounds(f(lo), f(hi))
+ derivedTypeBounds(f(lo), f(hi))
/** Given a higher-kinded abstract type
*
@@ -2051,17 +2056,28 @@ object Types {
}
final class CachedTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi)
+ final class CoTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi) {
+ override def variance = 1
+ }
+ final class ContraTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi) {
+ override def variance = -1
+ }
object TypeBounds {
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)
- def apply(lo: Type, hi: Type)(implicit ctx: Context) =
- unique(new CachedTypeBounds(lo, hi))
+ def upper(hi: Type, variance: Int = 0)(implicit ctx: Context) = apply(defn.NothingType, hi, variance)
+ def lower(lo: Type, variance: Int = 0)(implicit ctx: Context) = apply(lo, defn.AnyType, variance)
+ //def apply(lo: Type, hi: Type)(implicit ctx: Context): TypeBounds = apply(lo, hi, 0)
+ def apply(lo: Type, hi: Type, variance: Int = 0)(implicit ctx: Context): TypeBounds =
+ unique(
+ if (variance == 0) new CachedTypeBounds(lo, hi)
+ else if (variance == 1) new CoTypeBounds(lo, hi)
+ else new ContraTypeBounds(lo, hi)
+ )
}
object TypeAlias {
- def apply(tp: Type)(implicit ctx: Context) = TypeBounds(tp, tp)
+ def apply(tp: Type, variance: Int = 0)(implicit ctx: Context) = TypeBounds(tp, tp, variance)
def unapply(tp: Type): Option[Type] = tp match {
case TypeBounds(lo, hi) if lo eq hi => Some(lo)
case _ => None
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index e9eb7df0b..72ed20454 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -431,7 +431,7 @@ class Namer { typer: Typer =>
else rhsType
case _ =>
if (tparamSyms.nonEmpty) rhsType.LambdaAbstract(tparamSyms)(ctx.error(_, _))
- else TypeBounds(rhsType, rhsType)
+ else TypeAlias(rhsType, sym.localVariance)
}
}
} \ No newline at end of file