aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/Types.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/dotty/tools/dotc/core/Types.scala')
-rw-r--r--src/dotty/tools/dotc/core/Types.scala138
1 files changed, 115 insertions, 23 deletions
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index c3e15d94c..8df651180 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -150,7 +150,8 @@ object Types {
}
/** Does this type occur as a part of type `that`? */
- final def occursIn(that: Type): Boolean = that.existsPart(this == _)
+ final def occursIn(that: Type)(implicit ctx: Context): Boolean =
+ that.existsPart(this == _)
def isRepeatedParam(implicit ctx: Context): Boolean =
defn.RepeatedParamAliases contains typeSymbol
@@ -159,16 +160,21 @@ object Types {
/** Returns true if there is a part of this type that satisfies predicate `p`.
*/
- final def existsPart(p: Type => Boolean): Boolean =
- new ExistsAccumulator(p)(false, this)
+ final def existsPart(p: Type => Boolean)(implicit ctx: Context): Boolean =
+ new ExistsAccumulator(p).apply(false, this)
/** Returns true if all parts of this type satisfy predicate `p`.
*/
- final def forallParts(p: Type => Boolean): Boolean = !existsPart(!p(_))
+ final def forallParts(p: Type => Boolean)(implicit ctx: Context): Boolean = !existsPart(!p(_))
/** The parts of this type which are type or term refs */
final def namedParts(implicit ctx: Context): Set[NamedType] =
- new PartsAccumulator().apply(Set(), this)
+ namedPartsWith(Function.const(true))
+
+ final def namedPartsWith(p: NamedType => Boolean)(implicit ctx: Context): Set[NamedType] =
+ new NamedPartsAccumulator(p).apply(Set(), this)
+
+ final def foreach(f: Type => Unit): Unit = ???
/** Map function over elements of an AndType, rebuilding with & */
def mapAnd(f: Type => Type)(implicit ctx: Context): Type = thisInstance match {
@@ -498,7 +504,7 @@ object Types {
/** Map a TypeVar to either its instance if it is instantiated, or its origin,
* if not. Identity on all other types.
*/
- def thisInstance: Type = this
+ def thisInstance(implicit ctx: Context): Type = this
/** Widen from singleton type to its underlying non-singleton
* base type by applying one or more `underlying` dereferences,
@@ -535,7 +541,7 @@ object Types {
/** If this is a refinement type, the unrefined parent,
* else the type itself.
*/
- final def unrefine: Type = thisInstance match {
+ final def unrefine(implicit ctx: Context): Type = thisInstance match {
case tp @ RefinedType(tycon, _) => tycon.unrefine
case tp => tp
}
@@ -594,6 +600,15 @@ object Types {
case pt: PolyType => pt.resultType.paramTypess
case _ => Nil
}
+
+ /** Is this either not a method at all, or a parameterless method? */
+ final def isParameterless: Boolean = this match {
+ case mt: MethodType => false
+ case pt: PolyType => pt.resultType.isParameterless
+ case _ => true
+ }
+
+
/* Not sure whether we'll need this
final def firstParamTypes: List[Type] = this match {
case mt: MethodType => mt.paramTypes
@@ -908,6 +923,12 @@ object Types {
def toText(printer: Printer): Text = printer.toText(this)
+ /** `tp` is either a type variable or poly param. Returns
+ * Covariant if all occurrences of `tp` in this type are covariant
+ * Contravariant if all occurrences of `tp` in this type are contravariant
+ * Covariant | Contravariant if there are no occurrences of `tp` in this type
+ * EmptyFlags if `tp` occurs noon-variantly in this type
+ */
def varianceOf(tp: Type): FlagSet = ???
// ----- hashing ------------------------------------------------------
@@ -1403,9 +1424,18 @@ object Types {
def isJava = false
def isImplicit = false
- lazy val isDependent = resultType existsPart {
- case MethodParam(mt, _) => mt eq this
- case _ => false
+ private[this] var myIsDependent: Boolean = _
+ private[this] var isDepKnown = false
+
+ def isDependent(implicit ctx: Context) = {
+ if (!isDepKnown) {
+ myIsDependent = resultType existsPart {
+ case MethodParam(mt, _) => mt eq this
+ case _ => false
+ }
+ isDepKnown = true
+ }
+ myIsDependent
}
private[this] var _signature: Signature = _
@@ -1623,14 +1653,76 @@ object Types {
override def toString = s"RefinedThis(${binder.hashCode})"
}
- final case class TypeVar(origin: PolyParam) extends UncachedProxyType with ValueType {
- private var inst: Type = NoType
- def isInstantiated = inst ne NoType
- def instantiateWith(tp: Type) = inst = tp
- override def thisInstance = if (isInstantiated) inst else origin
+ /** A type variable is essentially a switch that models some part of a substitution.
+ * It is first linked to `origin`, a poly param that's in the current constraint set.
+ * It can then be (once) instantiated to some other type. The instantiation is
+ * recorded in the type variable itself, or else, if the current type state
+ * is different from the variable's creation state (meaning unrolls are possible)
+ * in the current typer state. Every type variable is referred to by exactly
+ * one inferred type parameter in a TypeApply tree.
+ *
+ * @param origin The parameter that's tracked by the type variable.
+ * @param creatorState The typer state in which the variable was created.
+ * @param pos The position of the TypeApply tree that introduces
+ * the type variable.
+ */
+ final class TypeVar(val origin: PolyParam, creatorState: TyperState, val pos: Position) extends UncachedProxyType with ValueType {
+
+ /** The permanent instance type of the the variable, or NoType is none is given yet */
+ private[core] var inst: Type = NoType
+
+ /** The state owning the variable. This is at first creationState, but it can
+ * be changed to an enclosing state on a commit
+ */
+ private[core] var owningState = creatorState
+
+ assert(!(creatorState.undetVars contains this))
+ creatorState.undetVars += this
+
+ /** The instance type of this variable, or NoType if the variable is currently
+ * uninstantiated
+ */
+ def instanceOpt(implicit ctx: Context): Type =
+ if (inst.exists) inst
+ else {
+ val i = ctx.typerState.instType(this)
+ if (i == null) NoType else i
+ }
+
+ /** Is the variable already instantiated? */
+ def isInstantiated(implicit ctx: Context) = instanceOpt.exists
+
+ /** Instantiate variable with given type */
+ def instantiateWith(tp: Type)(implicit ctx: Context): Type = {
+ assert(owningState.undetVars contains this)
+ owningState.undetVars -= this
+ if (ctx.typerState eq creatorState) inst = tp
+ else ctx.typerState.instType = ctx.typerState.instType.updated(this, tp)
+ tp
+ }
+
+ /** Instantiate variable from the constraints over its `origin`.
+ * If `fromBelow` is true, the variable is instantiated to the lub
+ * of its lower bounds in the current constraint; otherwie it is
+ * instantiated to the glb of its upper bounds.
+ */
+ def instantiate(fromBelow: Boolean)(implicit ctx: Context): Type =
+ instantiateWith(ctx.typeComparer.approximate(origin, fromBelow))
+
+ /** If the variable is instantiated, its instance, otherwise its origin */
+ override def thisInstance(implicit ctx: Context) = {
+ val inst = instanceOpt
+ if (inst.exists) inst else origin
+ }
+
+ /** Same as `thisInstance` */
override def underlying(implicit ctx: Context): Type = thisInstance
+
+ override def hashCode: Int = System.identityHashCode(this)
override def equals(that: Any) = this eq that.asInstanceOf[AnyRef]
- override def toString = thisInstance.toString
+
+ override def toString =
+ if (inst.exists) inst.toString else s"TypeVar($origin)"
}
// ------ ClassInfo, Type Bounds ------------------------------------------------------------
@@ -1871,12 +1963,12 @@ object Types {
case _ =>
false
}
- def unapply(tp: Type)(implicit ctx: Context): Option[(SingleDenotation, List[Type], Type)] =
+ def unapply(tp: Type)(implicit ctx: Context): Option[SingleDenotation] =
if (isInstantiatable(tp)) {
val absMems = tp.abstractTermMembers
if (absMems.size == 1)
absMems.head.info match {
- case mt: MethodType if !mt.isDependent => Some((absMems.head, mt.paramTypes, mt.resultType))
+ case mt: MethodType if !mt.isDependent => Some(absMems.head)
case _=> None
}
else None
@@ -1927,7 +2019,7 @@ object Types {
case tp @ AnnotatedType(annot, underlying) =>
tp.derivedAnnotatedType(mapOver(annot), this(underlying))
- case tp @ TypeVar(_) =>
+ case tp: TypeVar =>
apply(tp.thisInstance)
case tp @ WildcardType =>
@@ -1980,7 +2072,7 @@ object Types {
// ----- TypeAccumulators ----------------------------------------------------
- abstract class TypeAccumulator[T] extends ((T, Type) => T) {
+ abstract class TypeAccumulator[T](implicit ctx: Context) extends ((T, Type) => T) {
def apply(x: T, tp: Type): T
protected def apply(x: T, annot: Annotation): T = x // don't go into annotations
@@ -2024,13 +2116,13 @@ object Types {
}
}
- class ExistsAccumulator(p: Type => Boolean) extends TypeAccumulator[Boolean] {
+ class ExistsAccumulator(p: Type => Boolean)(implicit ctx: Context) extends TypeAccumulator[Boolean] {
def apply(x: Boolean, tp: Type) = x || p(tp) || foldOver(x, tp)
}
- class PartsAccumulator(implicit ctx: Context) extends TypeAccumulator[Set[NamedType]] {
+ class NamedPartsAccumulator(p: NamedType => Boolean)(implicit ctx: Context) extends TypeAccumulator[Set[NamedType]] {
def apply(x: Set[NamedType], tp: Type): Set[NamedType] = tp match {
- case tp: NamedType =>
+ case tp: NamedType if (p(tp)) =>
foldOver(x + tp, tp)
case tp: ThisType =>
apply(x, tp.underlying)