aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/core/Types.scala
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/src/dotty/tools/dotc/core/Types.scala')
-rw-r--r--compiler/src/dotty/tools/dotc/core/Types.scala173
1 files changed, 103 insertions, 70 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index 6ff896110..8e852a9a9 100644
--- a/compiler/src/dotty/tools/dotc/core/Types.scala
+++ b/compiler/src/dotty/tools/dotc/core/Types.scala
@@ -19,6 +19,7 @@ import util.Positions.{Position, NoPosition}
import util.Stats._
import util.{DotClass, SimpleMap}
import reporting.diagnostic.Message
+import reporting.diagnostic.messages.CyclicReferenceInvolving
import ast.tpd._
import ast.TreeTypeMap
import printing.Texts._
@@ -216,14 +217,14 @@ object Types {
*/
def isVarArgsMethod(implicit ctx: Context): Boolean = this match {
case tp: PolyType => tp.resultType.isVarArgsMethod
- case MethodType(_, paramTypes) => paramTypes.nonEmpty && paramTypes.last.isRepeatedParam
+ case mt: MethodType => mt.paramTypes.nonEmpty && mt.paramTypes.last.isRepeatedParam
case _ => false
}
/** Is this the type of a method with a leading empty parameter list?
*/
def isNullaryMethod(implicit ctx: Context): Boolean = this match {
- case MethodType(Nil, _) => true
+ case MethodType(Nil) => true
case tp: PolyType => tp.resultType.isNullaryMethod
case _ => false
}
@@ -549,13 +550,7 @@ object Types {
def goThis(tp: ThisType) = {
val d = go(tp.underlying)
- if (d.exists)
- if ((pre eq tp) && d.symbol.is(NamedTypeParam) && (d.symbol.owner eq tp.cls))
- // If we look for a named type parameter `P` in `C.this.P`, looking up
- // the fully applied self type of `C` will give as an info the alias type
- // `P = this.P`. We need to return a denotation with the underlying bounds instead.
- d.symbol.denot
- else d
+ if (d.exists) d
else
// There is a special case to handle:
// trait Super { this: Sub => private class Inner {} println(this.Inner) }
@@ -737,7 +732,7 @@ object Types {
*/
final def overrides(that: Type)(implicit ctx: Context) = {
def result(tp: Type): Type = tp match {
- case ExprType(_) | MethodType(Nil, _) => tp.resultType
+ case ExprType(_) | MethodType(Nil) => tp.resultType
case _ => tp
}
(this frozen_<:< that) || {
@@ -1223,8 +1218,8 @@ object Types {
* when forming the function type.
*/
def toFunctionType(dropLast: Int = 0)(implicit ctx: Context): Type = this match {
- case mt @ MethodType(_, formals) if !mt.isDependent || ctx.mode.is(Mode.AllowDependentFunctions) =>
- val formals1 = if (dropLast == 0) formals else formals dropRight dropLast
+ case mt: MethodType if !mt.isDependent || ctx.mode.is(Mode.AllowDependentFunctions) =>
+ val formals1 = if (dropLast == 0) mt.paramTypes else mt.paramTypes dropRight dropLast
defn.FunctionOf(
formals1 mapConserve (_.underlyingIfRepeated(mt.isJava)), mt.resultType, mt.isImplicit && !ctx.erasedTypes)
}
@@ -1279,10 +1274,14 @@ object Types {
def underlying(implicit ctx: Context): Type
/** The closest supertype of this type. This is the same as `underlying`,
- * except for TypeRefs where the upper bound is returned, and HKApplys,
- * where the upper bound of the constructor is re-applied to the arguments.
+ * except that
+ * - instead of a TyperBounds type it returns its upper bound, and
+ * - for HKApplys it returns the upper bound of the constructor re-applied to the arguments.
*/
- def superType(implicit ctx: Context): Type = underlying
+ def superType(implicit ctx: Context): Type = underlying match {
+ case TypeBounds(_, hi) => hi
+ case st => st
+ }
}
// Every type has to inherit one of the following four abstract type classes.,
@@ -1686,7 +1685,10 @@ object Types {
}
else newLikeThis(prefix)
}
- else newLikeThis(prefix)
+ else prefix match {
+ case _: WildcardType => WildcardType
+ case _ => newLikeThis(prefix)
+ }
/** Create a NamedType of the same kind as this type, but with a new prefix.
*/
@@ -1768,11 +1770,6 @@ object Types {
type ThisType = TypeRef
override def underlying(implicit ctx: Context): Type = info
-
- override def superType(implicit ctx: Context): Type = info match {
- case TypeBounds(_, hi) => hi
- case _ => info
- }
}
final class TermRefWithSignature(prefix: Type, name: TermName, override val sig: Signature) extends TermRef(prefix, name) {
@@ -2066,6 +2063,9 @@ object Types {
*/
abstract case class RefinedType(parent: Type, refinedName: Name, refinedInfo: Type) extends RefinedOrRecType {
+ if (refinedName.isTermName) assert(refinedInfo.isInstanceOf[TermType])
+ else assert(refinedInfo.isInstanceOf[TypeType])
+
override def underlying(implicit ctx: Context) = parent
private def badInst =
@@ -2312,14 +2312,16 @@ object Types {
trait MethodOrPoly extends MethodicType
- abstract case class MethodType(paramNames: List[TermName], paramTypes: List[Type])
- (resultTypeExp: MethodType => Type)
+ abstract case class MethodType(paramNames: List[TermName])(
+ paramTypesExp: MethodType => List[Type],
+ resultTypeExp: MethodType => Type)
extends CachedGroundType with BindingType with TermType with MethodOrPoly with NarrowCached { thisMethodType =>
import MethodType._
def isJava = false
def isImplicit = false
+ val paramTypes = paramTypesExp(this)
private[core] val resType = resultTypeExp(this)
assert(resType.exists)
@@ -2329,7 +2331,7 @@ object Types {
def apply(tp: Type) = tp match {
case tp @ TypeRef(pre, name) =>
tp.info match {
- case TypeAlias(alias) if depStatus(pre) == TrueDeps => apply(alias)
+ case TypeAlias(alias) if depStatus(NoDeps, pre) == TrueDeps => apply(alias)
case _ => mapOver(tp)
}
case _ =>
@@ -2341,8 +2343,9 @@ object Types {
else resType
var myDependencyStatus: DependencyStatus = Unknown
+ var myParamDependencyStatus: DependencyStatus = Unknown
- private def depStatus(tp: Type)(implicit ctx: Context): DependencyStatus = {
+ private def depStatus(initial: DependencyStatus, tp: Type)(implicit ctx: Context): DependencyStatus = {
def combine(x: DependencyStatus, y: DependencyStatus) = {
val status = (x & StatusMask) max (y & StatusMask)
val provisional = (x | y) & Provisional
@@ -2366,7 +2369,7 @@ object Types {
case _ => foldOver(status, tp)
}
}
- depStatusAcc(NoDeps, tp)
+ depStatusAcc(initial, tp)
}
/** The dependency status of this method. Some examples:
@@ -2380,17 +2383,36 @@ object Types {
private def dependencyStatus(implicit ctx: Context): DependencyStatus = {
if (myDependencyStatus != Unknown) myDependencyStatus
else {
- val result = depStatus(resType)
+ val result = depStatus(NoDeps, resType)
if ((result & Provisional) == 0) myDependencyStatus = result
(result & StatusMask).toByte
}
}
+ /** The parameter dependency status of this method. Analogous to `dependencyStatus`,
+ * but tracking dependencies in same parameter list.
+ */
+ private def paramDependencyStatus(implicit ctx: Context): DependencyStatus = {
+ if (myParamDependencyStatus != Unknown) myParamDependencyStatus
+ else {
+ val result =
+ if (paramTypes.isEmpty) NoDeps
+ else (NoDeps /: paramTypes.tail)(depStatus(_, _))
+ if ((result & Provisional) == 0) myParamDependencyStatus = result
+ (result & StatusMask).toByte
+ }
+ }
+
/** Does result type contain references to parameters of this method type,
* which cannot be eliminated by de-aliasing?
*/
def isDependent(implicit ctx: Context): Boolean = dependencyStatus == TrueDeps
+ /** Does one of the parameter types contain references to earlier parameters
+ * of this method type which cannot be eliminated by de-aliasing?
+ */
+ def isParamDependent(implicit ctx: Context): Boolean = paramDependencyStatus == TrueDeps
+
protected def computeSignature(implicit ctx: Context): Signature =
resultSignature.prepend(paramTypes, isJava)
@@ -2399,10 +2421,11 @@ object Types {
resType: Type = this.resType)(implicit ctx: Context) =
if ((paramNames eq this.paramNames) && (paramTypes eq this.paramTypes) && (resType eq this.resType)) this
else {
+ val paramTypesFn = (x: MethodType) => paramTypes.map(_.subst(this, x))
val resTypeFn = (x: MethodType) => resType.subst(this, x)
- if (isJava) JavaMethodType(paramNames, paramTypes)(resTypeFn)
- else if (isImplicit) ImplicitMethodType(paramNames, paramTypes)(resTypeFn)
- else MethodType(paramNames, paramTypes)(resTypeFn)
+ if (isJava) JavaMethodType(paramNames)(paramTypesFn, resTypeFn)
+ else if (isImplicit) ImplicitMethodType(paramNames)(paramTypesFn, resTypeFn)
+ else MethodType(paramNames)(paramTypesFn, resTypeFn)
}
def instantiate(argTypes: => List[Type])(implicit ctx: Context): Type =
@@ -2424,21 +2447,21 @@ object Types {
override def toString = s"$prefixString($paramNames, $paramTypes, $resType)"
}
- final class CachedMethodType(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)
- extends MethodType(paramNames, paramTypes)(resultTypeExp) {
+ final class CachedMethodType(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)
+ extends MethodType(paramNames)(paramTypesExp, resultTypeExp) {
override def equals(that: Any) = super.equals(that) && that.isInstanceOf[CachedMethodType]
}
- final class JavaMethodType(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)
- extends MethodType(paramNames, paramTypes)(resultTypeExp) {
+ final class JavaMethodType(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)
+ extends MethodType(paramNames)(paramTypesExp, resultTypeExp) {
override def isJava = true
override def equals(that: Any) = super.equals(that) && that.isInstanceOf[JavaMethodType]
override def computeHash = addDelta(super.computeHash, 1)
override protected def prefixString = "JavaMethodType"
}
- final class ImplicitMethodType(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)
- extends MethodType(paramNames, paramTypes)(resultTypeExp) {
+ final class ImplicitMethodType(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)
+ extends MethodType(paramNames)(paramTypesExp, resultTypeExp) {
override def isImplicit = true
override def equals(that: Any) = super.equals(that) && that.isInstanceOf[ImplicitMethodType]
override def computeHash = addDelta(super.computeHash, 2)
@@ -2446,11 +2469,11 @@ object Types {
}
abstract class MethodTypeCompanion {
- def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType
+ def apply(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType
def apply(paramNames: List[TermName], paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType =
- apply(paramNames, paramTypes)(_ => resultType)
+ apply(paramNames)(_ => paramTypes, _ => resultType)
def apply(paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType =
- apply(nme.syntheticParamNames(paramTypes.length), paramTypes)(resultTypeExp)
+ apply(nme.syntheticParamNames(paramTypes.length))(_ => paramTypes, resultTypeExp)
def apply(paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType =
apply(nme.syntheticParamNames(paramTypes.length), paramTypes, resultType)
@@ -2473,19 +2496,31 @@ object Types {
case _: ExprType => tp
case _ => AnnotatedType(tp, Annotation(defn.InlineParamAnnot))
}
+ def integrate(tp: Type, mt: MethodType) =
+ tp.subst(params, (0 until params.length).toList.map(MethodParam(mt, _)))
def paramInfo(param: Symbol): Type = {
val paramType = translateRepeated(param.info)
if (param.is(Inline)) translateInline(paramType) else paramType
}
- def transformResult(mt: MethodType) =
- resultType.subst(params, (0 until params.length).toList map (MethodParam(mt, _)))
- apply(params map (_.name.asTermName), params map paramInfo)(transformResult _)
+ apply(params.map(_.name.asTermName))(
+ mt => params.map(param => integrate(paramInfo(param), mt)),
+ mt => integrate(resultType, mt))
+ }
+
+ def checkValid(mt: MethodType)(implicit ctx: Context): mt.type = {
+ if (Config.checkMethodTypes)
+ for ((paramType, idx) <- mt.paramTypes.zipWithIndex)
+ paramType.foreachPart {
+ case MethodParam(`mt`, j) => assert(j < idx, mt)
+ case _ =>
+ }
+ mt
}
}
object MethodType extends MethodTypeCompanion {
- def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context) =
- unique(new CachedMethodType(paramNames, paramTypes)(resultTypeExp))
+ def apply(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType =
+ checkValid(unique(new CachedMethodType(paramNames)(paramTypesExp, resultTypeExp)))
private type DependencyStatus = Byte
private final val Unknown: DependencyStatus = 0 // not yet computed
@@ -2497,13 +2532,19 @@ object Types {
}
object JavaMethodType extends MethodTypeCompanion {
- def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context) =
- unique(new JavaMethodType(paramNames, paramTypes)(resultTypeExp))
+ def apply(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType =
+ unique(new JavaMethodType(paramNames)(paramTypesExp, resultTypeExp))
}
object ImplicitMethodType extends MethodTypeCompanion {
- def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context) =
- unique(new ImplicitMethodType(paramNames, paramTypes)(resultTypeExp))
+ def apply(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType =
+ checkValid(unique(new ImplicitMethodType(paramNames)(paramTypesExp, resultTypeExp)))
+ }
+
+ /** A ternary extractor for MethodType */
+ object MethodTpe {
+ def unapply(mt: MethodType)(implicit ctx: Context) =
+ Some((mt.paramNames, mt.paramTypes, mt.resultType))
}
/** A by-name parameter type of the form `=> T`, or the type of a method with no parameter list. */
@@ -2547,11 +2588,6 @@ object Types {
case _ => false
}
- /** Is this polytype a higher-kinded type lambda as opposed to a polymorphic?
- * method type? Only type lambdas get created with variances, that's how we can tell.
- */
- def isTypeLambda: Boolean = variances.nonEmpty
-
/** PolyParam references to all type parameters of this type */
lazy val paramRefs: List[PolyParam] = paramNames.indices.toList.map(PolyParam(this, _))
@@ -2928,20 +2964,8 @@ object Types {
* instantiation can be a singleton type only if the upper bound
* is also a singleton type.
*/
- def instantiate(fromBelow: Boolean)(implicit ctx: Context): Type = {
- val inst = ctx.typeComparer.instanceType(origin, fromBelow)
- if (ctx.typerState.isGlobalCommittable)
- inst match {
- case inst: PolyParam =>
- assert(inst.binder.isTypeLambda, i"bad inst $this := $inst, constr = ${ctx.typerState.constraint}")
- // If this fails, you might want to turn on Config.debugCheckConstraintsClosed
- // to help find the root of the problem.
- // Note: Parameters of type lambdas are excluded from the assertion because
- // they might arise from ill-kinded code. See #1652
- case _ =>
- }
- instantiateWith(inst)
- }
+ def instantiate(fromBelow: Boolean)(implicit ctx: Context): Type =
+ instantiateWith(ctx.typeComparer.instanceType(origin, fromBelow))
/** Unwrap to instance (if instantiated) or origin (if not), until result
* is no longer a TypeVar
@@ -3328,6 +3352,8 @@ object Types {
zeroParamClass(tp.underlying)
case tp: TypeVar =>
zeroParamClass(tp.underlying)
+ case tp: HKApply =>
+ zeroParamClass(tp.superType)
case _ =>
NoType
}
@@ -3546,6 +3572,13 @@ object Types {
def apply(tp: Type) = tp
}
+ /** A type map that approximates NoTypes by upper or lower known bounds depending on
+ * variance.
+ *
+ * if variance > 0 : approximate by upper bound
+ * variance < 0 : approximate by lower bound
+ * variance = 0 : propagate NoType to next outer level
+ */
abstract class ApproximatingTypeMap(implicit ctx: Context) extends TypeMap { thisMap =>
def approx(lo: Type = defn.NothingType, hi: Type = defn.AnyType) =
if (variance == 0) NoType
@@ -3651,9 +3684,9 @@ object Types {
this(y, hi)
}
- case tp @ MethodType(pnames, ptypes) =>
+ case tp: MethodType =>
variance = -variance
- val y = foldOver(x, ptypes)
+ val y = foldOver(x, tp.paramTypes)
variance = -variance
this(y, tp.resultType)
@@ -3856,7 +3889,7 @@ object Types {
class CyclicReference private (val denot: SymDenotation)
extends TypeError(s"cyclic reference involving $denot") {
- def show(implicit ctx: Context) = s"cyclic reference involving ${denot.show}"
+ def toMessage(implicit ctx: Context) = CyclicReferenceInvolving(denot)
}
object CyclicReference {