aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/core
diff options
context:
space:
mode:
authorodersky <odersky@gmail.com>2017-04-06 14:12:22 +0200
committerGitHub <noreply@github.com>2017-04-06 14:12:22 +0200
commit09cc23726069fa04cbfeec55a9fa4bb8e4a02ff9 (patch)
tree604b5580371851334c05566986538f209ad55544 /compiler/src/dotty/tools/dotc/core
parent62c2a1e2d6265cf7f096e4c4e51e4e883bce1514 (diff)
parente800987c671c101a3643bfbaf93873db80ced9f3 (diff)
downloaddotty-09cc23726069fa04cbfeec55a9fa4bb8e4a02ff9.tar.gz
dotty-09cc23726069fa04cbfeec55a9fa4bb8e4a02ff9.tar.bz2
dotty-09cc23726069fa04cbfeec55a9fa4bb8e4a02ff9.zip
Merge pull request #2121 from dotty-staging/change-merge-method-poly
Refactor lambda types
Diffstat (limited to 'compiler/src/dotty/tools/dotc/core')
-rw-r--r--compiler/src/dotty/tools/dotc/core/Constants.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/core/Constraint.scala60
-rw-r--r--compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala58
-rw-r--r--compiler/src/dotty/tools/dotc/core/Definitions.scala12
-rw-r--r--compiler/src/dotty/tools/dotc/core/Denotations.scala56
-rw-r--r--compiler/src/dotty/tools/dotc/core/Mode.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/NameOps.scala26
-rw-r--r--compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala154
-rw-r--r--compiler/src/dotty/tools/dotc/core/ParamInfo.scala (renamed from compiler/src/dotty/tools/dotc/core/TypeParamInfo.scala)22
-rw-r--r--compiler/src/dotty/tools/dotc/core/StdNames.scala7
-rw-r--r--compiler/src/dotty/tools/dotc/core/Substituters.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/core/SymDenotations.scala7
-rw-r--r--compiler/src/dotty/tools/dotc/core/Symbols.scala12
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeApplications.scala65
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeComparer.scala146
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeErasure.scala22
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeOps.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/TyperState.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/core/Types.scala760
-rw-r--r--compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala21
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala34
-rw-r--r--compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala39
-rw-r--r--compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala16
25 files changed, 805 insertions, 742 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Constants.scala b/compiler/src/dotty/tools/dotc/core/Constants.scala
index 1892e4bdc..ed388b7ec 100644
--- a/compiler/src/dotty/tools/dotc/core/Constants.scala
+++ b/compiler/src/dotty/tools/dotc/core/Constants.scala
@@ -169,12 +169,12 @@ object Constants {
def convertTo(pt: Type)(implicit ctx: Context): Constant = {
def classBound(pt: Type): Type = pt.dealias.stripTypeVar match {
case tref: TypeRef if !tref.symbol.isClass => classBound(tref.info.bounds.lo)
- case param: PolyParam =>
+ case param: TypeParamRef =>
ctx.typerState.constraint.entry(param) match {
case TypeBounds(lo, hi) =>
if (hi.classSymbol.isPrimitiveValueClass) hi //constrain further with high bound
else classBound(lo)
- case NoType => classBound(param.binder.paramBounds(param.paramNum).lo)
+ case NoType => classBound(param.binder.paramInfos(param.paramNum).lo)
case inst => classBound(inst)
}
case pt => pt
diff --git a/compiler/src/dotty/tools/dotc/core/Constraint.scala b/compiler/src/dotty/tools/dotc/core/Constraint.scala
index 50136a26c..a6c21c0d1 100644
--- a/compiler/src/dotty/tools/dotc/core/Constraint.scala
+++ b/compiler/src/dotty/tools/dotc/core/Constraint.scala
@@ -13,20 +13,20 @@ import config.Printers.constr
/** Constraint over undetermined type parameters. Constraints are built
* over values of the following types:
*
- * - PolyType A constraint constrains the type parameters of a set of PolyTypes
- * - PolyParam The parameters of the constrained polytypes
- * - TypeVar Every constrained parameter might be associated with a TypeVar
- * that has the PolyParam as origin.
+ * - TypeLambda A constraint constrains the type parameters of a set of TypeLambdas
+ * - TypeParamRef The parameters of the constrained type lambdas
+ * - TypeVar Every constrained parameter might be associated with a TypeVar
+ * that has the TypeParamRef as origin.
*/
abstract class Constraint extends Showable {
type This <: Constraint
/** Does the constraint's domain contain the type parameters of `pt`? */
- def contains(pt: PolyType): Boolean
+ def contains(pt: TypeLambda): Boolean
/** Does the constraint's domain contain the type parameter `param`? */
- def contains(param: PolyParam): Boolean
+ def contains(param: TypeParamRef): Boolean
/** Does this constraint contain the type variable `tvar` and is it uninstantiated? */
def contains(tvar: TypeVar): Boolean
@@ -34,43 +34,43 @@ abstract class Constraint extends Showable {
/** The constraint entry for given type parameter `param`, or NoType if `param` is not part of
* the constraint domain. Note: Low level, implementation dependent.
*/
- def entry(param: PolyParam): Type
+ def entry(param: TypeParamRef): Type
/** The type variable corresponding to parameter `param`, or
* NoType, if `param` is not in constrained or is not paired with a type variable.
*/
- def typeVarOfParam(param: PolyParam): Type
+ def typeVarOfParam(param: TypeParamRef): Type
/** Is it known that `param1 <:< param2`? */
- def isLess(param1: PolyParam, param2: PolyParam): Boolean
+ def isLess(param1: TypeParamRef, param2: TypeParamRef): Boolean
/** The parameters that are known to be smaller wrt <: than `param` */
- def lower(param: PolyParam): List[PolyParam]
+ def lower(param: TypeParamRef): List[TypeParamRef]
/** The parameters that are known to be greater wrt <: than `param` */
- def upper(param: PolyParam): List[PolyParam]
+ def upper(param: TypeParamRef): List[TypeParamRef]
/** lower(param) \ lower(butNot) */
- def exclusiveLower(param: PolyParam, butNot: PolyParam): List[PolyParam]
+ def exclusiveLower(param: TypeParamRef, butNot: TypeParamRef): List[TypeParamRef]
/** upper(param) \ upper(butNot) */
- def exclusiveUpper(param: PolyParam, butNot: PolyParam): List[PolyParam]
+ def exclusiveUpper(param: TypeParamRef, butNot: TypeParamRef): List[TypeParamRef]
/** The constraint bounds for given type parameter `param`.
* Poly params that are known to be smaller or greater than `param`
* are not contained in the return bounds.
* @pre `param` is not part of the constraint domain.
*/
- def nonParamBounds(param: PolyParam): TypeBounds
+ def nonParamBounds(param: TypeParamRef): TypeBounds
/** The lower bound of `param` including all known-to-be-smaller parameters */
- def fullLowerBound(param: PolyParam)(implicit ctx: Context): Type
+ def fullLowerBound(param: TypeParamRef)(implicit ctx: Context): Type
/** The upper bound of `param` including all known-to-be-greater parameters */
- def fullUpperBound(param: PolyParam)(implicit ctx: Context): Type
+ def fullUpperBound(param: TypeParamRef)(implicit ctx: Context): Type
/** The bounds of `param` including all known-to-be-smaller and -greater parameters */
- def fullBounds(param: PolyParam)(implicit ctx: Context): TypeBounds
+ def fullBounds(param: TypeParamRef)(implicit ctx: Context): TypeBounds
/** A new constraint which is derived from this constraint by adding
* entries for all type parameters of `poly`.
@@ -79,7 +79,7 @@ abstract class Constraint extends Showable {
* satisfiability but will solved to give instances of
* type variables.
*/
- def add(poly: PolyType, tvars: List[TypeVar])(implicit ctx: Context): This
+ def add(poly: TypeLambda, tvars: List[TypeVar])(implicit ctx: Context): This
/** A new constraint which is derived from this constraint by updating
* the entry for parameter `param` to `tp`.
@@ -90,18 +90,18 @@ abstract class Constraint extends Showable {
*
* @pre `this contains param`.
*/
- def updateEntry(param: PolyParam, tp: Type)(implicit ctx: Context): This
+ def updateEntry(param: TypeParamRef, tp: Type)(implicit ctx: Context): This
/** A constraint that includes the relationship `p1 <: p2`.
* `<:` relationships between parameters ("edges") are propagated, but
* non-parameter bounds are left alone.
*/
- def addLess(p1: PolyParam, p2: PolyParam)(implicit ctx: Context): This
+ def addLess(p1: TypeParamRef, p2: TypeParamRef)(implicit ctx: Context): This
/** A constraint resulting from adding p2 = p1 to this constraint, and at the same
* time transferring all bounds of p2 to p1
*/
- def unify(p1: PolyParam, p2: PolyParam)(implicit ctx: Context): This
+ def unify(p1: TypeParamRef, p2: TypeParamRef)(implicit ctx: Context): This
/** A new constraint which is derived from this constraint by removing
* the type parameter `param` from the domain and replacing all top-level occurrences
@@ -109,25 +109,25 @@ abstract class Constraint extends Showable {
* approximation of it if that is needed to avoid cycles.
* Occurrences nested inside a refinement or prefix are not affected.
*/
- def replace(param: PolyParam, tp: Type)(implicit ctx: Context): This
+ def replace(param: TypeParamRef, tp: Type)(implicit ctx: Context): This
/** Is entry associated with `pt` removable? This is the case if
* all type parameters of the entry are associated with type variables
* which have their `inst` fields set.
*/
- def isRemovable(pt: PolyType): Boolean
+ def isRemovable(pt: TypeLambda): Boolean
/** A new constraint with all entries coming from `pt` removed. */
- def remove(pt: PolyType)(implicit ctx: Context): This
+ def remove(pt: TypeLambda)(implicit ctx: Context): This
- /** The polytypes constrained by this constraint */
- def domainPolys: List[PolyType]
+ /** The type lambdas constrained by this constraint */
+ def domainLambdas: List[TypeLambda]
- /** The polytype parameters constrained by this constraint */
- def domainParams: List[PolyParam]
+ /** The type lambda parameters constrained by this constraint */
+ def domainParams: List[TypeParamRef]
/** Check whether predicate holds for all parameters in constraint */
- def forallParams(p: PolyParam => Boolean): Boolean
+ def forallParams(p: TypeParamRef => Boolean): Boolean
/** Perform operation `op` on all typevars, or only on uninstantiated
* typevars, depending on whether `uninstOnly` is set or not.
@@ -143,6 +143,6 @@ abstract class Constraint extends Showable {
/** Check that no constrained parameter contains itself as a bound */
def checkNonCyclic()(implicit ctx: Context): Unit
- /** Check that constraint only refers to PolyParams bound by itself */
+ /** Check that constraint only refers to TypeParamRefs bound by itself */
def checkClosed()(implicit ctx: Context): Unit
}
diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
index a12936c58..de96f644a 100644
--- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
+++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
@@ -42,12 +42,12 @@ trait ConstraintHandling {
*/
protected var homogenizeArgs = false
- /** We are currently comparing polytypes. Used as a flag for
+ /** We are currently comparing type lambdas. Used as a flag for
* optimization: when `false`, no need to do an expensive `pruneLambdaParams`
*/
- protected var comparedPolyTypes: Set[PolyType] = Set.empty
+ protected var comparedTypeLambdas: Set[TypeLambda] = Set.empty
- private def addOneBound(param: PolyParam, bound: Type, isUpper: Boolean): Boolean =
+ private def addOneBound(param: TypeParamRef, bound: Type, isUpper: Boolean): Boolean =
!constraint.contains(param) || {
def occursIn(bound: Type): Boolean = {
val b = bound.dealias
@@ -75,7 +75,7 @@ trait ConstraintHandling {
* If `isUpper` is true, ensure that `param <: `bound`, otherwise ensure
* that `param >: bound`.
*/
- def narrowedBound(param: PolyParam, bound: Type, isUpper: Boolean)(implicit ctx: Context): TypeBounds = {
+ def narrowedBound(param: TypeParamRef, bound: Type, isUpper: Boolean)(implicit ctx: Context): TypeBounds = {
val oldBounds @ TypeBounds(lo, hi) = constraint.nonParamBounds(param)
val saved = homogenizeArgs
homogenizeArgs = Config.alignArgsInAnd
@@ -85,7 +85,7 @@ trait ConstraintHandling {
finally homogenizeArgs = saved
}
- protected def addUpperBound(param: PolyParam, bound: Type): Boolean = {
+ protected def addUpperBound(param: TypeParamRef, bound: Type): Boolean = {
def description = i"constraint $param <: $bound to\n$constraint"
if (bound.isRef(defn.NothingClass) && ctx.typerState.isGlobalCommittable) {
def msg = s"!!! instantiated to Nothing: $param, constraint = ${constraint.show}"
@@ -101,7 +101,7 @@ trait ConstraintHandling {
res
}
- protected def addLowerBound(param: PolyParam, bound: Type): Boolean = {
+ protected def addLowerBound(param: TypeParamRef, bound: Type): Boolean = {
def description = i"constraint $param >: $bound to\n$constraint"
constr.println(i"adding $description")
val upper = constraint.upper(param)
@@ -112,7 +112,7 @@ trait ConstraintHandling {
res
}
- protected def addLess(p1: PolyParam, p2: PolyParam): Boolean = {
+ protected def addLess(p1: TypeParamRef, p2: TypeParamRef): Boolean = {
def description = i"ordering $p1 <: $p2 to\n$constraint"
val res =
if (constraint.isLess(p2, p1)) unify(p2, p1)
@@ -133,7 +133,7 @@ trait ConstraintHandling {
/** Make p2 = p1, transfer all bounds of p2 to p1
* @pre less(p1)(p2)
*/
- private def unify(p1: PolyParam, p2: PolyParam): Boolean = {
+ private def unify(p1: TypeParamRef, p2: TypeParamRef): Boolean = {
constr.println(s"unifying $p1 $p2")
assert(constraint.isLess(p1, p2))
val down = constraint.exclusiveLower(p2, p1)
@@ -191,7 +191,7 @@ trait ConstraintHandling {
* @return the instantiating type
* @pre `param` is in the constraint's domain.
*/
- final def approximation(param: PolyParam, fromBelow: Boolean): Type = {
+ final def approximation(param: TypeParamRef, fromBelow: Boolean): Type = {
val avoidParam = new TypeMap {
override def stopAtStatic = true
def apply(tp: Type) = mapOver {
@@ -235,7 +235,7 @@ trait ConstraintHandling {
* a lower bound instantiation can be a singleton type only if the upper bound
* is also a singleton type.
*/
- def instanceType(param: PolyParam, fromBelow: Boolean): Type = {
+ def instanceType(param: TypeParamRef, fromBelow: Boolean): Type = {
def upperBound = constraint.fullUpperBound(param)
def isSingleton(tp: Type): Boolean = tp match {
case tp: SingletonType => true
@@ -301,26 +301,26 @@ trait ConstraintHandling {
}
/** The current bounds of type parameter `param` */
- final def bounds(param: PolyParam): TypeBounds = {
+ final def bounds(param: TypeParamRef): TypeBounds = {
val e = constraint.entry(param)
- if (e.exists) e.bounds else param.binder.paramBounds(param.paramNum)
+ if (e.exists) e.bounds else param.binder.paramInfos(param.paramNum)
}
- /** Add polytype `pt`, possibly with type variables `tvars`, to current constraint
+ /** Add type lambda `tl`, possibly with type variables `tvars`, to current constraint
* and propagate all bounds.
* @param tvars See Constraint#add
*/
- def addToConstraint(pt: PolyType, tvars: List[TypeVar]): Unit =
+ def addToConstraint(tl: TypeLambda, tvars: List[TypeVar]): Unit =
assert {
- checkPropagated(i"initialized $pt") {
- constraint = constraint.add(pt, tvars)
- pt.paramNames.indices.forall { i =>
- val param = PolyParam(pt, i)
+ checkPropagated(i"initialized $tl") {
+ constraint = constraint.add(tl, tvars)
+ tl.paramNames.indices.forall { i =>
+ val param = TypeParamRef(tl, i)
val bounds = constraint.nonParamBounds(param)
val lower = constraint.lower(param)
val upper = constraint.upper(param)
if (lower.nonEmpty && !bounds.lo.isRef(defn.NothingClass) ||
- upper.nonEmpty && !bounds.hi.isRef(defn.AnyClass)) constr.println(i"INIT*** $pt")
+ upper.nonEmpty && !bounds.hi.isRef(defn.AnyClass)) constr.println(i"INIT*** $tl")
lower.forall(addOneBound(_, bounds.hi, isUpper = true)) &&
upper.forall(addOneBound(_, bounds.lo, isUpper = false))
}
@@ -328,7 +328,7 @@ trait ConstraintHandling {
}
/** Can `param` be constrained with new bounds? */
- final def canConstrain(param: PolyParam): Boolean =
+ final def canConstrain(param: TypeParamRef): Boolean =
!frozenConstraint && (constraint contains param)
/** Add constraint `param <: bound` if `fromBelow` is false, `param >: bound` otherwise.
@@ -338,7 +338,7 @@ trait ConstraintHandling {
* not be AndTypes and lower bounds may not be OrTypes. This is assured by the
* way isSubType is organized.
*/
- protected def addConstraint(param: PolyParam, bound: Type, fromBelow: Boolean): Boolean = {
+ protected def addConstraint(param: TypeParamRef, bound: Type, fromBelow: Boolean): Boolean = {
def description = i"constr $param ${if (fromBelow) ">:" else "<:"} $bound:\n$constraint"
//checkPropagated(s"adding $description")(true) // DEBUG in case following fails
checkPropagated(s"added $description") {
@@ -357,12 +357,12 @@ trait ConstraintHandling {
* missing.
*/
def pruneLambdaParams(tp: Type) =
- if (comparedPolyTypes.nonEmpty) {
+ if (comparedTypeLambdas.nonEmpty) {
val approx = new ApproximatingTypeMap {
def apply(t: Type): Type = t match {
- case t @ PolyParam(pt: PolyType, n) if comparedPolyTypes contains pt =>
+ case t @ TypeParamRef(tl: TypeLambda, n) if comparedTypeLambdas contains tl =>
val effectiveVariance = if (fromBelow) -variance else variance
- val bounds = pt.paramBounds(n)
+ val bounds = tl.paramInfos(n)
if (effectiveVariance > 0) bounds.lo
else if (effectiveVariance < 0) bounds.hi
else NoType
@@ -374,7 +374,7 @@ trait ConstraintHandling {
}
else tp
- def addParamBound(bound: PolyParam) =
+ def addParamBound(bound: TypeParamRef) =
if (fromBelow) addLess(bound, param) else addLess(param, bound)
/** Drop all constrained parameters that occur at the toplevel in `bound` and
@@ -419,7 +419,7 @@ trait ConstraintHandling {
else NoType
case bound: TypeVar if constraint contains bound.origin =>
prune(bound.underlying)
- case bound: PolyParam =>
+ case bound: TypeParamRef =>
constraint.entry(bound) match {
case NoType => pruneLambdaParams(bound)
case _: TypeBounds =>
@@ -434,7 +434,7 @@ trait ConstraintHandling {
}
try bound match {
- case bound: PolyParam if constraint contains bound =>
+ case bound: TypeParamRef if constraint contains bound =>
addParamBound(bound)
case _ =>
val pbound = prune(bound)
@@ -446,7 +446,7 @@ trait ConstraintHandling {
}
/** Instantiate `param` to `tp` if the constraint stays satisfiable */
- protected def tryInstantiate(param: PolyParam, tp: Type): Boolean = {
+ protected def tryInstantiate(param: TypeParamRef, tp: Type): Boolean = {
val saved = constraint
constraint =
if (addConstraint(param, tp, fromBelow = true) &&
@@ -461,7 +461,7 @@ trait ConstraintHandling {
val saved = frozenConstraint
frozenConstraint = true
for (p <- constraint.domainParams) {
- def check(cond: => Boolean, q: PolyParam, ordering: String, explanation: String): Unit =
+ def check(cond: => Boolean, q: TypeParamRef, ordering: String, explanation: String): Unit =
assert(cond, i"propagation failure for $p $ordering $q: $explanation\n$msg")
for (u <- constraint.upper(p))
check(bounds(p).hi <:< bounds(u).hi, u, "<:", "upper bound not propagated")
diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala
index 39b46cbfe..b70fcb093 100644
--- a/compiler/src/dotty/tools/dotc/core/Definitions.scala
+++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala
@@ -150,9 +150,9 @@ class Definitions {
private def enterPolyMethod(cls: ClassSymbol, name: TermName, typeParamCount: Int,
resultTypeFn: PolyType => Type, flags: FlagSet = EmptyFlags) = {
- val tparamNames = tpnme.syntheticTypeParamNames(typeParamCount)
- val tparamBounds = tparamNames map (_ => TypeBounds.empty)
- val ptype = PolyType(tparamNames, tparamNames.map(alwaysZero))(_ => tparamBounds, resultTypeFn)
+ val tparamNames = PolyType.syntheticParamNames(typeParamCount)
+ val tparamInfos = tparamNames map (_ => TypeBounds.empty)
+ val ptype = PolyType(tparamNames)(_ => tparamInfos, resultTypeFn)
enterMethod(cls, name, ptype, flags)
}
@@ -242,7 +242,7 @@ class Definitions {
lazy val Any_## = enterMethod(AnyClass, nme.HASHHASH, ExprType(IntType), Final)
lazy val Any_getClass = enterMethod(AnyClass, nme.getClass_, MethodType(Nil, ClassClass.typeRef.appliedTo(TypeBounds.empty)), Final)
lazy val Any_isInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final)
- lazy val Any_asInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, PolyParam(_, 0), Final)
+ lazy val Any_asInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, TypeParamRef(_, 0), Final)
def AnyMethods = List(Any_==, Any_!=, Any_equals, Any_hashCode,
Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_asInstanceOf)
@@ -268,7 +268,7 @@ class Definitions {
lazy val Object_eq = enterMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final)
lazy val Object_ne = enterMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final)
lazy val Object_synchronized = enterPolyMethod(ObjectClass, nme.synchronized_, 1,
- pt => MethodType(List(PolyParam(pt, 0)), PolyParam(pt, 0)), Final)
+ pt => MethodType(List(TypeParamRef(pt, 0)), TypeParamRef(pt, 0)), Final)
lazy val Object_clone = enterMethod(ObjectClass, nme.clone_, MethodType(Nil, ObjectType), Protected)
lazy val Object_finalize = enterMethod(ObjectClass, nme.finalize_, MethodType(Nil, UnitType), Protected)
lazy val Object_notify = enterMethod(ObjectClass, nme.notify_, MethodType(Nil, UnitType))
@@ -283,7 +283,7 @@ class Definitions {
/** Dummy method needed by elimByName */
lazy val dummyApply = enterPolyMethod(
OpsPackageClass, nme.dummyApply, 1,
- pt => MethodType(List(FunctionOf(Nil, PolyParam(pt, 0))), PolyParam(pt, 0)))
+ pt => MethodType(List(FunctionOf(Nil, TypeParamRef(pt, 0))), TypeParamRef(pt, 0)))
/** Method representing a throw */
lazy val throwMethod = enterMethod(OpsPackageClass, nme.THROWkw,
diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala
index f726cd0d1..7341b96af 100644
--- a/compiler/src/dotty/tools/dotc/core/Denotations.scala
+++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala
@@ -213,7 +213,7 @@ object Denotations {
def requiredMethod(name: PreName, argTypes: List[Type])(implicit ctx: Context): TermSymbol =
info.member(name.toTermName).requiredSymbol(x=>
- (x is Method) && x.info.paramTypess == List(argTypes)
+ (x is Method) && x.info.paramInfoss == List(argTypes)
).asTerm
def requiredMethodRef(name: PreName, argTypes: List[Type])(implicit ctx: Context): TermRef =
requiredMethod(name, argTypes).termRef
@@ -252,13 +252,12 @@ object Denotations {
else throw new Error(s"cannot merge ${showType(tp1)} with ${showType(tp2)}") // flip condition for debugging
}
- /** Merge two lists of names. If names in corresponding positions match, keep them,
+ /** Merge parameter names of lambda types. If names in corresponding positions match, keep them,
* otherwise generate new synthetic names.
*/
- def mergeNames[N <: Name](names1: List[N], names2: List[N], syntheticName: Int => N): List[N] = {
- for ((name1, name2, idx) <- (names1, names2, 0 until names1.length).zipped)
- yield if (name1 == name2) name1 else syntheticName(idx)
- }.toList
+ private def mergeParamNames(tp1: LambdaType, tp2: LambdaType): List[tp1.ThisName] =
+ (for ((name1, name2, idx) <- (tp1.paramNames, tp2.paramNames, tp1.paramNames.indices).zipped)
+ yield if (name1 == name2) name1 else tp1.companion.syntheticParamName(idx)).toList
/** Form a denotation by conjoining with denotation `that`.
*
@@ -308,27 +307,17 @@ object Denotations {
case tp2: TypeBounds if tp2 contains tp1 => tp1
case _ => mergeConflict(tp1, tp2)
}
- case tp1: MethodType if isTerm =>
+ case tp1: MethodOrPoly =>
tp2 match {
- case tp2: MethodType if ctx.typeComparer.matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) &&
- tp1.isImplicit == tp2.isImplicit =>
- tp1.derivedMethodType(
- mergeNames(tp1.paramNames, tp2.paramNames, nme.syntheticParamName),
- tp1.paramTypes,
+ case tp2: MethodOrPoly
+ if ctx.typeComparer.matchingParams(tp1, tp2) &&
+ tp1.isImplicit == tp2.isImplicit =>
+ tp1.derivedLambdaType(
+ mergeParamNames(tp1, tp2), tp1.paramInfos,
infoMeet(tp1.resultType, tp2.resultType.subst(tp2, tp1)))
case _ =>
mergeConflict(tp1, tp2)
}
- case tp1: PolyType if isTerm =>
- tp2 match {
- case tp2: PolyType if ctx.typeComparer.matchingTypeParams(tp1, tp2) =>
- tp1.derivedPolyType(
- mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName),
- tp1.paramBounds,
- infoMeet(tp1.resultType, tp2.resultType.subst(tp2, tp1)))
- case _: MethodicType =>
- mergeConflict(tp1, tp2)
- }
case _ =>
tp1 & tp2
}
@@ -471,23 +460,14 @@ object Denotations {
case tp2: TypeBounds if tp2 contains tp1 => tp2
case _ => mergeConflict(tp1, tp2)
}
- case tp1: MethodType =>
- tp2 match {
- case tp2: MethodType
- if ctx.typeComparer.matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) &&
- tp1.isImplicit == tp2.isImplicit =>
- tp1.derivedMethodType(
- mergeNames(tp1.paramNames, tp2.paramNames, nme.syntheticParamName),
- tp1.paramTypes, tp1.resultType | tp2.resultType.subst(tp2, tp1))
- case _ =>
- mergeConflict(tp1, tp2)
- }
- case tp1: PolyType =>
+ case tp1: MethodOrPoly =>
tp2 match {
- case tp2: PolyType if ctx.typeComparer.matchingTypeParams(tp1, tp2) =>
- tp1.derivedPolyType(
- mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName),
- tp1.paramBounds, tp1.resultType | tp2.resultType.subst(tp2, tp1))
+ case tp2: MethodOrPoly
+ if ctx.typeComparer.matchingParams(tp1, tp2) &&
+ tp1.isImplicit == tp2.isImplicit =>
+ tp1.derivedLambdaType(
+ mergeParamNames(tp1, tp2), tp1.paramInfos,
+ tp1.resultType | tp2.resultType.subst(tp2, tp1))
case _ =>
mergeConflict(tp1, tp2)
}
diff --git a/compiler/src/dotty/tools/dotc/core/Mode.scala b/compiler/src/dotty/tools/dotc/core/Mode.scala
index 406a84af6..c835f677e 100644
--- a/compiler/src/dotty/tools/dotc/core/Mode.scala
+++ b/compiler/src/dotty/tools/dotc/core/Mode.scala
@@ -34,7 +34,7 @@ object Mode {
* context with typerstate and constraint. This is typically done when we
* cache the eligibility of implicits. Caching needs to be done across different constraints.
* Therefore, if TypevarsMissContext is set, subtyping becomes looser, and assumes
- * that PolyParams can be sub- and supertypes of anything. See TypeComparer.
+ * that TypeParamRefs can be sub- and supertypes of anything. See TypeComparer.
*/
val TypevarsMissContext = newMode(4, "TypevarsMissContext")
val CheckCyclic = newMode(5, "CheckCyclic")
diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala
index ea905c19f..240ad359b 100644
--- a/compiler/src/dotty/tools/dotc/core/NameOps.scala
+++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala
@@ -196,6 +196,31 @@ object NameOps {
if (name.isModuleClassName) name.stripModuleClassSuffix.freshened.moduleClassName
else likeTyped(ctx.freshName(name ++ NameTransformer.NAME_JOIN_STRING)))
+ /** Name with variance prefix: `+` for covariant, `-` for contravariant */
+ def withVariance(v: Int): N =
+ if (hasVariance) dropVariance.withVariance(v)
+ else v match {
+ case -1 => likeTyped('-' +: name)
+ case 1 => likeTyped('+' +: name)
+ case 0 => name
+ }
+
+ /** Does name have a `+`/`-` variance prefix? */
+ def hasVariance: Boolean =
+ name.nonEmpty && name.head == '+' || name.head == '-'
+
+ /** Drop variance prefix if name has one */
+ def dropVariance: N = if (hasVariance) likeTyped(name.tail) else name
+
+ /** The variance as implied by the variance prefix, or 0 if there is
+ * no variance prefix.
+ */
+ def variance = name.head match {
+ case '-' => -1
+ case '+' => 1
+ case _ => 0
+ }
+
/** Translate a name into a list of simple TypeNames and TermNames.
* In all segments before the last, type/term is determined by whether
* the following separator char is '.' or '#'. The last segment
@@ -271,7 +296,6 @@ object NameOps {
else -1
}
-
/** The number of hops specified in an outer-select name */
def outerSelectHops: Int = {
require(isOuterSelect)
diff --git a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala
index 61dd5a445..84b0bfc6d 100644
--- a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala
+++ b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala
@@ -14,13 +14,13 @@ import annotation.tailrec
object OrderingConstraint {
- type ArrayValuedMap[T] = SimpleMap[PolyType, Array[T]]
+ type ArrayValuedMap[T] = SimpleMap[TypeLambda, Array[T]]
/** The type of `OrderingConstraint#boundsMap` */
type ParamBounds = ArrayValuedMap[Type]
/** The type of `OrderingConstraint#lowerMap`, `OrderingConstraint#upperMap` */
- type ParamOrdering = ArrayValuedMap[List[PolyParam]]
+ type ParamOrdering = ArrayValuedMap[List[TypeParamRef]]
/** A new constraint with given maps */
private def newConstraint(boundsMap: ParamBounds, lowerMap: ParamOrdering, upperMap: ParamOrdering)(implicit ctx: Context) : OrderingConstraint = {
@@ -32,11 +32,11 @@ object OrderingConstraint {
/** A lens for updating a single entry array in one of the three constraint maps */
abstract class ConstraintLens[T <: AnyRef: ClassTag] {
- def entries(c: OrderingConstraint, poly: PolyType): Array[T]
- def updateEntries(c: OrderingConstraint, poly: PolyType, entries: Array[T])(implicit ctx: Context): OrderingConstraint
+ def entries(c: OrderingConstraint, poly: TypeLambda): Array[T]
+ def updateEntries(c: OrderingConstraint, poly: TypeLambda, entries: Array[T])(implicit ctx: Context): OrderingConstraint
def initial: T
- def apply(c: OrderingConstraint, poly: PolyType, idx: Int) = {
+ def apply(c: OrderingConstraint, poly: TypeLambda, idx: Int) = {
val es = entries(c, poly)
if (es == null) initial else es(idx)
}
@@ -47,7 +47,7 @@ object OrderingConstraint {
* parts of `current` which are not shared by `prev`.
*/
def update(prev: OrderingConstraint, current: OrderingConstraint,
- poly: PolyType, idx: Int, entry: T)(implicit ctx: Context): OrderingConstraint = {
+ poly: TypeLambda, idx: Int, entry: T)(implicit ctx: Context): OrderingConstraint = {
var es = entries(current, poly)
if (es != null && (es(idx) eq entry)) current
else {
@@ -68,38 +68,38 @@ object OrderingConstraint {
}
def update(prev: OrderingConstraint, current: OrderingConstraint,
- param: PolyParam, entry: T)(implicit ctx: Context): OrderingConstraint =
+ param: TypeParamRef, entry: T)(implicit ctx: Context): OrderingConstraint =
update(prev, current, param.binder, param.paramNum, entry)
def map(prev: OrderingConstraint, current: OrderingConstraint,
- poly: PolyType, idx: Int, f: T => T)(implicit ctx: Context): OrderingConstraint =
+ poly: TypeLambda, idx: Int, f: T => T)(implicit ctx: Context): OrderingConstraint =
update(prev, current, poly, idx, f(apply(current, poly, idx)))
def map(prev: OrderingConstraint, current: OrderingConstraint,
- param: PolyParam, f: T => T)(implicit ctx: Context): OrderingConstraint =
+ param: TypeParamRef, f: T => T)(implicit ctx: Context): OrderingConstraint =
map(prev, current, param.binder, param.paramNum, f)
}
val boundsLens = new ConstraintLens[Type] {
- def entries(c: OrderingConstraint, poly: PolyType): Array[Type] =
+ def entries(c: OrderingConstraint, poly: TypeLambda): Array[Type] =
c.boundsMap(poly)
- def updateEntries(c: OrderingConstraint, poly: PolyType, entries: Array[Type])(implicit ctx: Context): OrderingConstraint =
+ def updateEntries(c: OrderingConstraint, poly: TypeLambda, entries: Array[Type])(implicit ctx: Context): OrderingConstraint =
newConstraint(c.boundsMap.updated(poly, entries), c.lowerMap, c.upperMap)
def initial = NoType
}
- val lowerLens = new ConstraintLens[List[PolyParam]] {
- def entries(c: OrderingConstraint, poly: PolyType): Array[List[PolyParam]] =
+ val lowerLens = new ConstraintLens[List[TypeParamRef]] {
+ def entries(c: OrderingConstraint, poly: TypeLambda): Array[List[TypeParamRef]] =
c.lowerMap(poly)
- def updateEntries(c: OrderingConstraint, poly: PolyType, entries: Array[List[PolyParam]])(implicit ctx: Context): OrderingConstraint =
+ def updateEntries(c: OrderingConstraint, poly: TypeLambda, entries: Array[List[TypeParamRef]])(implicit ctx: Context): OrderingConstraint =
newConstraint(c.boundsMap, c.lowerMap.updated(poly, entries), c.upperMap)
def initial = Nil
}
- val upperLens = new ConstraintLens[List[PolyParam]] {
- def entries(c: OrderingConstraint, poly: PolyType): Array[List[PolyParam]] =
+ val upperLens = new ConstraintLens[List[TypeParamRef]] {
+ def entries(c: OrderingConstraint, poly: TypeLambda): Array[List[TypeParamRef]] =
c.upperMap(poly)
- def updateEntries(c: OrderingConstraint, poly: PolyType, entries: Array[List[PolyParam]])(implicit ctx: Context): OrderingConstraint =
+ def updateEntries(c: OrderingConstraint, poly: TypeLambda, entries: Array[List[TypeParamRef]])(implicit ctx: Context): OrderingConstraint =
newConstraint(c.boundsMap, c.lowerMap, c.upperMap.updated(poly, entries))
def initial = Nil
}
@@ -109,20 +109,20 @@ import OrderingConstraint._
/** Constraint over undetermined type parameters that keeps separate maps to
* reflect parameter orderings.
- * @param boundsMap a map from PolyType to arrays.
+ * @param boundsMap a map from TypeLambda to arrays.
* Each array contains twice the number of entries as there a type parameters
- * in the PolyType. The first half of the array contains the type bounds that constrain the
- * polytype's type parameters. The second half might contain type variables that
+ * in the TypeLambda. The first half of the array contains the type bounds that constrain the
+ * lambda's type parameters. The second half might contain type variables that
* track the corresponding parameters, or is left empty (filled with nulls).
* An instantiated type parameter is represented by having its instance type in
* the corresponding array entry. The dual use of arrays for poly params
* and typevars is to save space and hopefully gain some speed.
*
- * @param lowerMap a map from PolyTypes to arrays. Each array entry corresponds
- * to a parameter P of the polytype; it contains all constrained parameters
+ * @param lowerMap a map from TypeLambdas to arrays. Each array entry corresponds
+ * to a parameter P of the type lambda; it contains all constrained parameters
* Q that are known to be smaller than P, i.e. Q <: P.
- * @param upperMap a map from PolyTypes to arrays. Each array entry corresponds
- * to a parameter P of the polytype; it contains all constrained parameters
+ * @param upperMap a map from TypeLambdas to arrays. Each array entry corresponds
+ * to a parameter P of the type lambda; it contains all constrained parameters
* Q that are known to be greater than P, i.e. P <: Q.
*/
class OrderingConstraint(private val boundsMap: ParamBounds,
@@ -141,7 +141,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
entries(paramCount(entries) + n)
/** The `boundsMap` entry corresponding to `param` */
- def entry(param: PolyParam): Type = {
+ def entry(param: TypeParamRef): Type = {
val entries = boundsMap(param.binder)
if (entries == null) NoType
else entries(param.paramNum)
@@ -149,9 +149,9 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
// ----------- Contains tests --------------------------------------------------
- def contains(pt: PolyType): Boolean = boundsMap(pt) != null
+ def contains(pt: TypeLambda): Boolean = boundsMap(pt) != null
- def contains(param: PolyParam): Boolean = {
+ def contains(param: TypeParamRef): Boolean = {
val entries = boundsMap(param.binder)
entries != null && isBounds(entries(param.paramNum))
}
@@ -167,43 +167,43 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
// ---------- Dependency handling ----------------------------------------------
- def lower(param: PolyParam): List[PolyParam] = lowerLens(this, param.binder, param.paramNum)
- def upper(param: PolyParam): List[PolyParam] = upperLens(this, param.binder, param.paramNum)
+ def lower(param: TypeParamRef): List[TypeParamRef] = lowerLens(this, param.binder, param.paramNum)
+ def upper(param: TypeParamRef): List[TypeParamRef] = upperLens(this, param.binder, param.paramNum)
- def minLower(param: PolyParam): List[PolyParam] = {
+ def minLower(param: TypeParamRef): List[TypeParamRef] = {
val all = lower(param)
all.filterNot(p => all.exists(isLess(p, _)))
}
- def minUpper(param: PolyParam): List[PolyParam] = {
+ def minUpper(param: TypeParamRef): List[TypeParamRef] = {
val all = upper(param)
all.filterNot(p => all.exists(isLess(_, p)))
}
- def exclusiveLower(param: PolyParam, butNot: PolyParam): List[PolyParam] =
+ def exclusiveLower(param: TypeParamRef, butNot: TypeParamRef): List[TypeParamRef] =
lower(param).filterNot(isLess(_, butNot))
- def exclusiveUpper(param: PolyParam, butNot: PolyParam): List[PolyParam] =
+ def exclusiveUpper(param: TypeParamRef, butNot: TypeParamRef): List[TypeParamRef] =
upper(param).filterNot(isLess(butNot, _))
-// ---------- Info related to PolyParams -------------------------------------------
+// ---------- Info related to TypeParamRefs -------------------------------------------
- def isLess(param1: PolyParam, param2: PolyParam): Boolean =
+ def isLess(param1: TypeParamRef, param2: TypeParamRef): Boolean =
upper(param1).contains(param2)
- def nonParamBounds(param: PolyParam): TypeBounds =
+ def nonParamBounds(param: TypeParamRef): TypeBounds =
entry(param).asInstanceOf[TypeBounds]
- def fullLowerBound(param: PolyParam)(implicit ctx: Context): Type =
+ def fullLowerBound(param: TypeParamRef)(implicit ctx: Context): Type =
(nonParamBounds(param).lo /: minLower(param))(_ | _)
- def fullUpperBound(param: PolyParam)(implicit ctx: Context): Type =
+ def fullUpperBound(param: TypeParamRef)(implicit ctx: Context): Type =
(nonParamBounds(param).hi /: minUpper(param))(_ & _)
- def fullBounds(param: PolyParam)(implicit ctx: Context): TypeBounds =
+ def fullBounds(param: TypeParamRef)(implicit ctx: Context): TypeBounds =
nonParamBounds(param).derivedTypeBounds(fullLowerBound(param), fullUpperBound(param))
- def typeVarOfParam(param: PolyParam): Type = {
+ def typeVarOfParam(param: TypeParamRef): Type = {
val entries = boundsMap(param.binder)
if (entries == null) NoType
else {
@@ -212,15 +212,15 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
}
}
-// ---------- Adding PolyTypes --------------------------------------------------
+// ---------- Adding TypeLambdas --------------------------------------------------
/** The list of parameters P such that, for a fresh type parameter Q:
*
* Q <: tp implies Q <: P and isUpper = true, or
* tp <: Q implies P <: Q and isUpper = false
*/
- def dependentParams(tp: Type, isUpper: Boolean): List[PolyParam] = tp match {
- case param: PolyParam if contains(param) =>
+ def dependentParams(tp: Type, isUpper: Boolean): List[TypeParamRef] = tp match {
+ case param: TypeParamRef if contains(param) =>
param :: (if (isUpper) upper(param) else lower(param))
case tp: AndOrType =>
val ps1 = dependentParams(tp.tp1, isUpper)
@@ -255,9 +255,9 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
*
* @param isUpper If true, `bound` is an upper bound, else a lower bound.
*/
- private def stripParams(tp: Type, paramBuf: mutable.ListBuffer[PolyParam],
+ private def stripParams(tp: Type, paramBuf: mutable.ListBuffer[TypeParamRef],
isUpper: Boolean)(implicit ctx: Context): Type = tp match {
- case param: PolyParam if contains(param) =>
+ case param: TypeParamRef if contains(param) =>
if (!paramBuf.contains(param)) paramBuf += param
NoType
case tp: AndOrType if isUpper == tp.isAnd =>
@@ -275,16 +275,16 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
* A top or bottom type if type consists only of dependent parameters.
* @param isUpper If true, `bound` is an upper bound, else a lower bound.
*/
- private def normalizedType(tp: Type, paramBuf: mutable.ListBuffer[PolyParam],
+ private def normalizedType(tp: Type, paramBuf: mutable.ListBuffer[TypeParamRef],
isUpper: Boolean)(implicit ctx: Context): Type =
stripParams(tp, paramBuf, isUpper)
.orElse(if (isUpper) defn.AnyType else defn.NothingType)
- def add(poly: PolyType, tvars: List[TypeVar])(implicit ctx: Context): This = {
+ def add(poly: TypeLambda, tvars: List[TypeVar])(implicit ctx: Context): This = {
assert(!contains(poly))
val nparams = poly.paramNames.length
val entries1 = new Array[Type](nparams * 2)
- poly.paramBounds.copyToArray(entries1, 0)
+ poly.paramInfos.copyToArray(entries1, 0)
tvars.copyToArray(entries1, nparams)
newConstraint(boundsMap.updated(poly, entries1), lowerMap, upperMap).init(poly)
}
@@ -293,12 +293,12 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
* Update all bounds to be normalized and update ordering to account for
* dependent parameters.
*/
- private def init(poly: PolyType)(implicit ctx: Context): This = {
+ private def init(poly: TypeLambda)(implicit ctx: Context): This = {
var current = this
- val loBuf, hiBuf = new mutable.ListBuffer[PolyParam]
+ val loBuf, hiBuf = new mutable.ListBuffer[TypeParamRef]
var i = 0
while (i < poly.paramNames.length) {
- val param = PolyParam(poly, i)
+ val param = TypeParamRef(poly, i)
val bounds = nonParamBounds(param)
val lo = normalizedType(bounds.lo, loBuf, isUpper = false)
val hi = normalizedType(bounds.hi, hiBuf, isUpper = true)
@@ -318,7 +318,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
/** Add the fact `param1 <: param2` to the constraint `current` and propagate
* `<:<` relationships between parameters ("edges") but not bounds.
*/
- private def order(current: This, param1: PolyParam, param2: PolyParam)(implicit ctx: Context): This =
+ private def order(current: This, param1: TypeParamRef, param2: TypeParamRef)(implicit ctx: Context): This =
if (param1 == param2 || current.isLess(param1, param2)) this
else {
assert(contains(param1))
@@ -330,10 +330,10 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
current2
}
- def addLess(param1: PolyParam, param2: PolyParam)(implicit ctx: Context): This =
+ def addLess(param1: TypeParamRef, param2: TypeParamRef)(implicit ctx: Context): This =
order(this, param1, param2)
- def updateEntry(current: This, param: PolyParam, tp: Type)(implicit ctx: Context): This = {
+ def updateEntry(current: This, param: TypeParamRef, tp: Type)(implicit ctx: Context): This = {
var current1 = boundsLens.update(this, current, param, tp)
tp match {
case TypeBounds(lo, hi) =>
@@ -346,10 +346,10 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
current1
}
- def updateEntry(param: PolyParam, tp: Type)(implicit ctx: Context): This =
+ def updateEntry(param: TypeParamRef, tp: Type)(implicit ctx: Context): This =
updateEntry(this, param, tp)
- def unify(p1: PolyParam, p2: PolyParam)(implicit ctx: Context): This = {
+ def unify(p1: TypeParamRef, p2: TypeParamRef)(implicit ctx: Context): This = {
val p1Bounds = (nonParamBounds(p1) & nonParamBounds(p2)).substParam(p2, p1)
updateEntry(p1, p1Bounds).replace(p2, p1)
}
@@ -381,7 +381,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
* would not find out where we need to approximate. Occurrences of parameters
* that are not top-level are not affected.
*/
- def replace(param: PolyParam, tp: Type)(implicit ctx: Context): OrderingConstraint = {
+ def replace(param: TypeParamRef, tp: Type)(implicit ctx: Context): OrderingConstraint = {
val replacement = tp.dealias.stripTypeVar
if (param == replacement) this
else {
@@ -389,10 +389,10 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
val poly = param.binder
val idx = param.paramNum
- def removeParam(ps: List[PolyParam]) =
+ def removeParam(ps: List[TypeParamRef]) =
ps.filterNot(p => p.binder.eq(poly) && p.paramNum == idx)
- def replaceParam(tp: Type, atPoly: PolyType, atIdx: Int): Type = tp match {
+ def replaceParam(tp: Type, atPoly: TypeLambda, atIdx: Int): Type = tp match {
case bounds @ TypeBounds(lo, hi) =>
def recombine(andor: AndOrType, op: (Type, Boolean) => Type, isUpper: Boolean): Type = {
@@ -404,7 +404,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
}
def normalize(tp: Type, isUpper: Boolean): Type = tp match {
- case p: PolyParam if p.binder == atPoly && p.paramNum == atIdx =>
+ case p: TypeParamRef if p.binder == atPoly && p.paramNum == atIdx =>
if (isUpper) defn.AnyType else defn.NothingType
case tp: AndOrType if isUpper == tp.isAnd => recombine(tp, normalize, isUpper)
case _ => tp
@@ -432,9 +432,9 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
}
}
- def remove(pt: PolyType)(implicit ctx: Context): This = {
+ def remove(pt: TypeLambda)(implicit ctx: Context): This = {
def removeFromOrdering(po: ParamOrdering) = {
- def removeFromBoundss(key: PolyType, bndss: Array[List[PolyParam]]): Array[List[PolyParam]] = {
+ def removeFromBoundss(key: TypeLambda, bndss: Array[List[TypeParamRef]]): Array[List[TypeParamRef]] = {
val bndss1 = bndss.map(_.filterConserve(_.binder ne pt))
if (bndss.corresponds(bndss1)(_ eq _)) bndss else bndss1
}
@@ -443,7 +443,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
newConstraint(boundsMap.remove(pt), removeFromOrdering(lowerMap), removeFromOrdering(upperMap))
}
- def isRemovable(pt: PolyType): Boolean = {
+ def isRemovable(pt: TypeLambda): Boolean = {
val entries = boundsMap(pt)
@tailrec def allRemovable(last: Int): Boolean =
if (last < 0) true
@@ -456,24 +456,24 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
// ---------- Exploration --------------------------------------------------------
- def domainPolys: List[PolyType] = boundsMap.keys
+ def domainLambdas: List[TypeLambda] = boundsMap.keys
- def domainParams: List[PolyParam] =
+ def domainParams: List[TypeParamRef] =
for {
(poly, entries) <- boundsMap.toList
n <- 0 until paramCount(entries)
if entries(n).exists
- } yield PolyParam(poly, n)
+ } yield TypeParamRef(poly, n)
- def forallParams(p: PolyParam => Boolean): Boolean = {
+ def forallParams(p: TypeParamRef => Boolean): Boolean = {
boundsMap.foreachBinding { (poly, entries) =>
for (i <- 0 until paramCount(entries))
- if (isBounds(entries(i)) && !p(PolyParam(poly, i))) return false
+ if (isBounds(entries(i)) && !p(TypeParamRef(poly, i))) return false
}
true
}
- def foreachParam(p: (PolyType, Int) => Unit): Unit =
+ def foreachParam(p: (TypeLambda, Int) => Unit): Unit =
boundsMap.foreachBinding { (poly, entries) =>
0.until(poly.paramNames.length).foreach(p(poly, _))
}
@@ -503,7 +503,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
merged
}
- def mergeParams(ps1: List[PolyParam], ps2: List[PolyParam]) =
+ def mergeParams(ps1: List[TypeParamRef], ps2: List[TypeParamRef]) =
(ps1 /: ps2)((ps1, p2) => if (ps1.contains(p2)) ps1 else p2 :: ps1)
def mergeEntries(e1: Type, e2: Type): Type = e1 match {
@@ -532,13 +532,13 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
}
override def checkClosed()(implicit ctx: Context): Unit = {
- def isFreePolyParam(tp: Type) = tp match {
- case PolyParam(binder: PolyType, _) => !contains(binder)
+ def isFreeTypeParamRef(tp: Type) = tp match {
+ case TypeParamRef(binder: TypeLambda, _) => !contains(binder)
case _ => false
}
def checkClosedType(tp: Type, where: String) =
if (tp != null)
- assert(!tp.existsPart(isFreePolyParam), i"unclosed constraint: $this refers to $tp in $where")
+ assert(!tp.existsPart(isFreeTypeParamRef), i"unclosed constraint: $this refers to $tp in $where")
boundsMap.foreachBinding((_, tps) => tps.foreach(checkClosedType(_, "bounds")))
lowerMap.foreachBinding((_, paramss) => paramss.foreach(_.foreach(checkClosedType(_, "lower"))))
upperMap.foreachBinding((_, paramss) => paramss.foreach(_.foreach(checkClosedType(_, "upper"))))
@@ -567,7 +567,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
def checkNonCyclic()(implicit ctx: Context): Unit =
domainParams.foreach(checkNonCyclic)
- private def checkNonCyclic(param: PolyParam)(implicit ctx: Context): Unit =
+ private def checkNonCyclic(param: TypeParamRef)(implicit ctx: Context): Unit =
assert(!isLess(param, param), i"cyclic constraint involving $param in $this")
// ---------- toText -----------------------------------------------------
@@ -584,7 +584,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
val uninstVarsText = " uninstVars = " ~
Text(uninstVars map (_.toText(printer)), ", ") ~ ";"
val constrainedText =
- " constrained types = " ~ Text(domainPolys map (_.toText(printer)), ", ")
+ " constrained types = " ~ Text(domainLambdas map (_.toText(printer)), ", ")
val boundsText =
" bounds = " ~ {
val assocs =
@@ -614,8 +614,8 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
case _ =>" := " + tp
}
val constrainedText =
- " constrained types = " + domainPolys.mkString("\n")
- val boundsText =
+ " constrained types = " + domainLambdas.mkString("\n")
+ val boundsText = domainLambdas
" bounds = " + {
val assocs =
for (param <- domainParams)
diff --git a/compiler/src/dotty/tools/dotc/core/TypeParamInfo.scala b/compiler/src/dotty/tools/dotc/core/ParamInfo.scala
index 647c895db..46e378fc2 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeParamInfo.scala
+++ b/compiler/src/dotty/tools/dotc/core/ParamInfo.scala
@@ -1,13 +1,15 @@
package dotty.tools.dotc.core
-import Names.TypeName
+import Names.Name
import Contexts.Context
-import Types.{Type, TypeBounds}
+import Types.Type
/** A common super trait of Symbol and LambdaParam.
* Used to capture the attributes of type parameters which can be implemented as either.
*/
-trait TypeParamInfo {
+trait ParamInfo {
+
+ type ThisName <: Name
/** Is this the info of a type parameter? Will return `false` for symbols
* that are not type parameters.
@@ -15,26 +17,30 @@ trait TypeParamInfo {
def isTypeParam(implicit ctx: Context): Boolean
/** The name of the type parameter */
- def paramName(implicit ctx: Context): TypeName
+ def paramName(implicit ctx: Context): ThisName
/** The info of the type parameter */
- def paramBounds(implicit ctx: Context): TypeBounds
+ def paramInfo(implicit ctx: Context): Type
/** The info of the type parameter as seen from a prefix type.
* For type parameter symbols, this is the `memberInfo` as seen from `prefix`.
- * For type lambda parameters, it's the same as `paramBounds` as
+ * For type lambda parameters, it's the same as `paramInfos` as
* `asSeenFrom` has already been applied to the whole type lambda.
*/
- def paramBoundsAsSeenFrom(pre: Type)(implicit ctx: Context): TypeBounds
+ def paramInfoAsSeenFrom(pre: Type)(implicit ctx: Context): Type
/** The parameter bounds, or the completer if the type parameter
* is an as-yet uncompleted symbol.
*/
- def paramBoundsOrCompleter(implicit ctx: Context): Type
+ def paramInfoOrCompleter(implicit ctx: Context): Type
/** The variance of the type parameter */
def paramVariance(implicit ctx: Context): Int
/** A type that refers to the parameter */
def paramRef(implicit ctx: Context): Type
+}
+
+object ParamInfo {
+ type Of[N] = ParamInfo { type ThisName = N }
} \ No newline at end of file
diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala
index bc3f96d91..e7928fd09 100644
--- a/compiler/src/dotty/tools/dotc/core/StdNames.scala
+++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala
@@ -722,9 +722,6 @@ object StdNames {
case _ => termName("_" + j)
}
- def syntheticParamNames(num: Int): List[TermName] =
- (0 until num).map(syntheticParamName)(breakOut)
-
def localDummyName(clazz: Symbol)(implicit ctx: Context): TermName =
LOCALDUMMY_PREFIX ++ clazz.name ++ ">"
@@ -747,9 +744,6 @@ object StdNames {
def syntheticTypeParamName(i: Int): TypeName = "X" + i
- def syntheticTypeParamNames(num: Int): List[TypeName] =
- (0 until num).map(syntheticTypeParamName)(breakOut)
-
final val Conforms = encode("<:<")
final val Uninstantiated: TypeName = "?$"
@@ -850,5 +844,4 @@ object StdNames {
val tpnme = new ScalaTypeNames
val jnme = new JavaTermNames
val jtpnme = new JavaTypeNames
-
}
diff --git a/compiler/src/dotty/tools/dotc/core/Substituters.scala b/compiler/src/dotty/tools/dotc/core/Substituters.scala
index 23683608a..d565ec229 100644
--- a/compiler/src/dotty/tools/dotc/core/Substituters.scala
+++ b/compiler/src/dotty/tools/dotc/core/Substituters.scala
@@ -196,7 +196,7 @@ trait Substituters { this: Context =>
.mapOver(tp)
}
- final def substParam(tp: Type, from: ParamType, to: Type, theMap: SubstParamMap): Type =
+ final def substParam(tp: Type, from: ParamRef, to: Type, theMap: SubstParamMap): Type =
tp match {
case tp: BoundType =>
if (tp == from) to else tp
@@ -216,7 +216,7 @@ trait Substituters { this: Context =>
final def substParams(tp: Type, from: BindingType, to: List[Type], theMap: SubstParamsMap): Type =
tp match {
- case tp: ParamType =>
+ case tp: ParamRef =>
if (tp.binder == from) to(tp.paramNum) else tp
case tp: NamedType =>
if (tp.currentSymbol.isStatic) tp
@@ -269,7 +269,7 @@ trait Substituters { this: Context =>
def apply(tp: Type): Type = substRecThis(tp, from, to, this)
}
- final class SubstParamMap(from: ParamType, to: Type) extends DeepTypeMap {
+ final class SubstParamMap(from: ParamRef, to: Type) extends DeepTypeMap {
def apply(tp: Type) = substParam(tp, from, to, this)
}
diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
index 27782698d..602848a50 100644
--- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -1146,14 +1146,13 @@ object SymDenotations {
case tp: NamedType => hasSkolems(tp.prefix)
case tp: RefinedType => hasSkolems(tp.parent) || hasSkolems(tp.refinedInfo)
case tp: RecType => hasSkolems(tp.parent)
- case tp: PolyType => tp.paramBounds.exists(hasSkolems) || hasSkolems(tp.resType)
- case tp: MethodType => tp.paramTypes.exists(hasSkolems) || hasSkolems(tp.resType)
+ case tp: TypeBounds => hasSkolems(tp.lo) || hasSkolems(tp.hi)
+ case tp: TypeVar => hasSkolems(tp.inst)
case tp: ExprType => hasSkolems(tp.resType)
case tp: HKApply => hasSkolems(tp.tycon) || tp.args.exists(hasSkolems)
+ case tp: LambdaType => tp.paramInfos.exists(hasSkolems) || hasSkolems(tp.resType)
case tp: AndOrType => hasSkolems(tp.tp1) || hasSkolems(tp.tp2)
- case tp: TypeBounds => hasSkolems(tp.lo) || hasSkolems(tp.hi)
case tp: AnnotatedType => hasSkolems(tp.tpe)
- case tp: TypeVar => hasSkolems(tp.inst)
case _ => false
}
diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala
index 33aba4d13..95ff1cb75 100644
--- a/compiler/src/dotty/tools/dotc/core/Symbols.scala
+++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala
@@ -384,7 +384,7 @@ object Symbols {
* @param coord The coordinates of the symbol (a position or an index)
* @param id A unique identifier of the symbol (unique per ContextBase)
*/
- class Symbol private[Symbols] (val coord: Coord, val id: Int) extends DotClass with TypeParamInfo with printing.Showable {
+ class Symbol private[Symbols] (val coord: Coord, val id: Int) extends DotClass with ParamInfo with printing.Showable {
type ThisName <: Name
@@ -513,12 +513,12 @@ object Symbols {
*/
def pos: Position = if (coord.isPosition) coord.toPosition else NoPosition
- // TypeParamInfo methods
+ // ParamInfo types and methods
def isTypeParam(implicit ctx: Context) = denot.is(TypeParam)
- def paramName(implicit ctx: Context) = name.asTypeName
- def paramBounds(implicit ctx: Context) = denot.info.bounds
- def paramBoundsAsSeenFrom(pre: Type)(implicit ctx: Context) = pre.memberInfo(this).bounds
- def paramBoundsOrCompleter(implicit ctx: Context): Type = denot.infoOrCompleter
+ def paramName(implicit ctx: Context) = name.asInstanceOf[ThisName]
+ def paramInfo(implicit ctx: Context) = denot.info
+ def paramInfoAsSeenFrom(pre: Type)(implicit ctx: Context) = pre.memberInfo(this)
+ def paramInfoOrCompleter(implicit ctx: Context): Type = denot.infoOrCompleter
def paramVariance(implicit ctx: Context) = denot.variance
def paramRef(implicit ctx: Context) = denot.typeRef
diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala
index ba3e6a461..23c3f96cc 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -21,6 +21,8 @@ import java.util.NoSuchElementException
object TypeApplications {
+ type TypeParamInfo = ParamInfo.Of[TypeName]
+
/** Assert type is not a TypeBounds instance and return it unchanged */
val noBounds = (tp: Type) => tp match {
case tp: TypeBounds => throw new AssertionError("no TypeBounds allowed")
@@ -73,7 +75,7 @@ object TypeApplications {
}
def unapply(tp: Type)(implicit ctx: Context): Option[TypeRef] = tp match {
- case tp @ PolyType(tparams, AppliedType(fn: TypeRef, args)) if (args == tparams.map(_.toArg)) => Some(fn)
+ case tp @ HKTypeLambda(tparams, AppliedType(fn: TypeRef, args)) if (args == tparams.map(_.toArg)) => Some(fn)
case _ => None
}
}
@@ -119,7 +121,7 @@ object TypeApplications {
*/
def EtaExpandIfHK(tparams: List[TypeParamInfo], args: List[Type])(implicit ctx: Context): List[Type] =
if (tparams.isEmpty) args
- else args.zipWithConserve(tparams)((arg, tparam) => arg.EtaExpandIfHK(tparam.paramBoundsOrCompleter))
+ else args.zipWithConserve(tparams)((arg, tparam) => arg.EtaExpandIfHK(tparam.paramInfoOrCompleter))
/** A type map that tries to reduce (part of) the result type of the type lambda `tycon`
* with the given `args`(some of which are wildcard arguments represented by type bounds).
@@ -160,18 +162,18 @@ object TypeApplications {
* result type. Using this mode, we can guarantee that `appliedTo` will never
* produce a higher-kinded application with a type lambda as type constructor.
*/
- class Reducer(tycon: PolyType, args: List[Type])(implicit ctx: Context) extends TypeMap {
+ class Reducer(tycon: TypeLambda, args: List[Type])(implicit ctx: Context) extends TypeMap {
private var available = (0 until args.length).toSet
var allReplaced = true
- def hasWildcardArg(p: PolyParam) =
+ def hasWildcardArg(p: TypeParamRef) =
p.binder == tycon && args(p.paramNum).isInstanceOf[TypeBounds]
- def canReduceWildcard(p: PolyParam) =
+ def canReduceWildcard(p: TypeParamRef) =
!ctx.mode.is(Mode.AllowLambdaWildcardApply) || available.contains(p.paramNum)
def apply(t: Type) = t match {
- case t @ TypeAlias(p: PolyParam) if hasWildcardArg(p) && canReduceWildcard(p) =>
+ case t @ TypeAlias(p: TypeParamRef) if hasWildcardArg(p) && canReduceWildcard(p) =>
available -= p.paramNum
args(p.paramNum)
- case p: PolyParam if p.binder == tycon =>
+ case p: TypeParamRef if p.binder == tycon =>
args(p.paramNum) match {
case TypeBounds(lo, hi) =>
if (ctx.mode.is(Mode.AllowLambdaWildcardApply)) { allReplaced = false; p }
@@ -213,7 +215,7 @@ class TypeApplications(val self: Type) extends AnyVal {
self match {
case self: ClassInfo =>
self.cls.typeParams
- case self: PolyType =>
+ case self: HKTypeLambda =>
self.typeParams
case self: TypeRef =>
val tsym = self.symbol
@@ -251,7 +253,7 @@ class TypeApplications(val self: Type) extends AnyVal {
def isHK(implicit ctx: Context): Boolean = self.dealias match {
case self: TypeRef => self.info.isHK
case self: RefinedType => false
- case self: PolyType => true
+ case self: HKTypeLambda => true
case self: SingletonType => false
case self: TypeVar =>
// Using `origin` instead of `underlying`, as is done for typeParams,
@@ -270,31 +272,6 @@ class TypeApplications(val self: Type) extends AnyVal {
self
}
- /** Lambda abstract `self` with given type parameters. Examples:
- *
- * type T[X] = U becomes type T = [X] -> U
- * type T[X] >: L <: U becomes type T >: L <: ([X] -> U)
- *
- * TODO: Handle parameterized lower bounds
- */
- def LambdaAbstract(tparams: List[TypeParamInfo])(implicit ctx: Context): Type = {
- def expand(tp: Type) =
- PolyType(
- tparams.map(_.paramName), tparams.map(_.paramVariance))(
- tl => tparams.map(tparam => tl.lifted(tparams, tparam.paramBounds).bounds),
- tl => tl.lifted(tparams, tp))
- if (tparams.isEmpty) self
- else self match {
- case self: TypeAlias =>
- self.derivedTypeAlias(expand(self.alias))
- case self @ TypeBounds(lo, hi) =>
- self.derivedTypeBounds(
- if (lo.isRef(defn.NothingClass)) lo else expand(lo),
- expand(hi))
- case _ => expand(self)
- }
- }
-
/** Convert a type constructor `TC` which has type parameters `T1, ..., Tn`
* in a context where type parameters `U1,...,Un` are expected to
*
@@ -307,7 +284,7 @@ class TypeApplications(val self: Type) extends AnyVal {
*/
def EtaExpand(tparams: List[TypeSymbol])(implicit ctx: Context): Type = {
val tparamsToUse = if (variancesConform(typeParams, tparams)) tparams else typeParamSymbols
- self.appliedTo(tparams map (_.typeRef)).LambdaAbstract(tparamsToUse)
+ HKTypeLambda.fromParams(tparamsToUse, self.appliedTo(tparams map (_.typeRef)))
//.ensuring(res => res.EtaReduce =:= self, s"res = $res, core = ${res.EtaReduce}, self = $self, hc = ${res.hashCode}")
}
@@ -362,11 +339,13 @@ class TypeApplications(val self: Type) extends AnyVal {
if (hkParams.isEmpty) self
else {
def adaptArg(arg: Type): Type = arg match {
- case arg @ PolyType(tparams, body) if
+ case arg @ HKTypeLambda(tparams, body) if
!tparams.corresponds(hkParams)(_.paramVariance == _.paramVariance) &&
tparams.corresponds(hkParams)(varianceConforms) =>
- PolyType(tparams.map(_.paramName), hkParams.map(_.paramVariance))(
- tl => arg.paramBounds.map(_.subst(arg, tl).bounds),
+ HKTypeLambda(
+ (tparams, hkParams).zipped.map((tparam, hkparam) =>
+ tparam.paramName.withVariance(hkparam.paramVariance)))(
+ tl => arg.paramInfos.map(_.subst(arg, tl).bounds),
tl => arg.resultType.subst(arg, tl)
)
case arg @ TypeAlias(alias) =>
@@ -390,7 +369,7 @@ class TypeApplications(val self: Type) extends AnyVal {
*/
final def appliedTo(args: List[Type])(implicit ctx: Context): Type = /*>|>*/ track("appliedTo") /*<|<*/ {
val typParams = self.typeParams
- def matchParams(t: Type, tparams: List[TypeParamInfo], args: List[Type])(implicit ctx: Context): Type = args match {
+ def matchParams(t: Type, tparams: List[ParamInfo], args: List[Type])(implicit ctx: Context): Type = args match {
case arg :: args1 =>
try {
val tparam :: tparams1 = tparams
@@ -407,7 +386,7 @@ class TypeApplications(val self: Type) extends AnyVal {
val dealiased = stripped.safeDealias
if (args.isEmpty || ctx.erasedTypes) self
else dealiased match {
- case dealiased: PolyType =>
+ case dealiased: HKTypeLambda =>
def tryReduce =
if (!args.exists(_.isInstanceOf[TypeBounds])) {
val followAlias = Config.simplifyApplications && {
@@ -426,7 +405,7 @@ class TypeApplications(val self: Type) extends AnyVal {
// In this case we should always dealias since we cannot handle
// higher-kinded applications to wildcard arguments.
dealiased
- .derivedPolyType(resType = tycon.safeDealias.appliedTo(args1))
+ .derivedLambdaType(resType = tycon.safeDealias.appliedTo(args1))
.appliedTo(args)
case _ =>
val reducer = new Reducer(dealiased, args)
@@ -435,6 +414,8 @@ class TypeApplications(val self: Type) extends AnyVal {
else HKApply(dealiased, args)
}
tryReduce
+ case dealiased: PolyType =>
+ dealiased.instantiate(args)
case dealiased: AndOrType =>
dealiased.derivedAndOrType(dealiased.tp1.appliedTo(args), dealiased.tp2.appliedTo(args))
case dealiased: TypeAlias =>
@@ -475,7 +456,7 @@ class TypeApplications(val self: Type) extends AnyVal {
/** Turn this type, which is used as an argument for
* type parameter `tparam`, into a TypeBounds RHS
*/
- final def toBounds(tparam: TypeParamInfo)(implicit ctx: Context): TypeBounds = self match {
+ final def toBounds(tparam: ParamInfo)(implicit ctx: Context): TypeBounds = self match {
case self: TypeBounds => // this can happen for wildcard args
self
case _ =>
diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
index 57dde3288..da6d63387 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -280,7 +280,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
case _ =>
}
thirdTry(tp1, tp2)
- case tp1: PolyParam =>
+ case tp1: TypeParamRef =>
def flagNothingBound = {
if (!frozenConstraint && tp2.isRef(defn.NothingClass) && state.isGlobalCommittable) {
def msg = s"!!! instantiated to Nothing: $tp1, constraint = ${constraint.show}"
@@ -289,13 +289,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
}
true
}
- def comparePolyParam =
+ def compareTypeParamRef =
ctx.mode.is(Mode.TypevarsMissContext) ||
isSubTypeWhenFrozen(bounds(tp1).hi, tp2) || {
if (canConstrain(tp1)) addConstraint(tp1, tp2, fromBelow = false) && flagNothingBound
else thirdTry(tp1, tp2)
}
- comparePolyParam
+ compareTypeParamRef
case tp1: ThisType =>
val cls1 = tp1.cls
tp2 match {
@@ -373,8 +373,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
private def thirdTry(tp1: Type, tp2: Type): Boolean = tp2 match {
case tp2: NamedType =>
thirdTryNamed(tp1, tp2)
- case tp2: PolyParam =>
- def comparePolyParam =
+ case tp2: TypeParamRef =>
+ def compareTypeParamRef =
(ctx.mode is Mode.TypevarsMissContext) || {
val alwaysTrue =
// The following condition is carefully formulated to catch all cases
@@ -391,7 +391,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
else fourthTry(tp1, tp2)
}
}
- comparePolyParam
+ compareTypeParamRef
case tp2: RefinedType =>
def compareRefinedSlow: Boolean = {
val name2 = tp2.refinedName
@@ -428,9 +428,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
compareRec
case tp2 @ HKApply(tycon2, args2) =>
compareHkApply2(tp1, tp2, tycon2, args2)
- case tp2 @ PolyType(tparams2, body2) =>
- def compareHkLambda: Boolean = tp1.stripTypeVar match {
- case tp1 @ PolyType(tparams1, body1) =>
+ case tp2: HKTypeLambda =>
+ def compareTypeLambda: Boolean = tp1.stripTypeVar match {
+ case tp1: HKTypeLambda =>
/* Don't compare bounds of lambdas under language:Scala2, or t2994 will fail
* The issue is that, logically, bounds should compare contravariantly,
* but that would invalidate a pattern exploited in t2994:
@@ -446,16 +446,16 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
*/
def boundsOK =
ctx.scala2Mode ||
- tparams1.corresponds(tparams2)((tparam1, tparam2) =>
- isSubType(tparam2.paramBounds.subst(tp2, tp1), tparam1.paramBounds))
- val saved = comparedPolyTypes
- comparedPolyTypes += tp1
- comparedPolyTypes += tp2
+ tp1.typeParams.corresponds(tp2.typeParams)((tparam1, tparam2) =>
+ isSubType(tparam2.paramInfo.subst(tp2, tp1), tparam1.paramInfo))
+ val saved = comparedTypeLambdas
+ comparedTypeLambdas += tp1
+ comparedTypeLambdas += tp2
try
- variancesConform(tparams1, tparams2) &&
+ variancesConform(tp1.typeParams, tp2.typeParams) &&
boundsOK &&
- isSubType(body1, body2.subst(tp2, tp1))
- finally comparedPolyTypes = saved
+ isSubType(tp1.resType, tp2.resType.subst(tp2, tp1))
+ finally comparedTypeLambdas = saved
case _ =>
if (!tp1.isHK) {
tp2 match {
@@ -466,7 +466,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
}
fourthTry(tp1, tp2)
}
- compareHkLambda
+ compareTypeLambda
case OrType(tp21, tp22) =>
// Rewrite T1 <: (T211 & T212) | T22 to T1 <: (T211 | T22) and T1 <: (T212 | T22)
// and analogously for T1 <: T21 | (T221 & T222)
@@ -484,12 +484,12 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
case _ =>
}
either(isSubType(tp1, tp21), isSubType(tp1, tp22)) || fourthTry(tp1, tp2)
- case tp2: MethodType =>
+ case tp2: MethodOrPoly =>
def compareMethod = tp1 match {
- case tp1: MethodType =>
+ case tp1: MethodOrPoly =>
(tp1.signature consistentParams tp2.signature) &&
- matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) &&
- (tp1.isImplicit == tp2.isImplicit) &&
+ matchingParams(tp1, tp2) &&
+ tp1.isImplicit == tp2.isImplicit &&
isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1))
case _ =>
false
@@ -618,7 +618,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
def isMatchingApply(tp1: Type): Boolean = tp1 match {
case HKApply(tycon1, args1) =>
tycon1.dealias match {
- case tycon1: PolyParam =>
+ case tycon1: TypeParamRef =>
(tycon1 == tycon2 ||
canConstrain(tycon1) && tryInstantiate(tycon1, tycon2)) &&
isSubArgs(args1, args2, tparams)
@@ -646,7 +646,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
* and the resulting type application is a supertype of `tp1`,
* or fallback to fourthTry.
*/
- def canInstantiate(tycon2: PolyParam): Boolean = {
+ def canInstantiate(tycon2: TypeParamRef): Boolean = {
/** Let
*
@@ -669,10 +669,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
val tparams1 = tparams1a.drop(lengthDiff)
variancesConform(tparams1, tparams) && {
if (lengthDiff > 0)
- tycon1b = PolyType(tparams1.map(_.paramName), tparams1.map(_.paramVariance))(
- tl => tparams1.map(tparam => tl.lifted(tparams, tparam.paramBounds).bounds),
+ tycon1b = HKTypeLambda(tparams1.map(_.paramName))(
+ tl => tparams1.map(tparam => tl.integrate(tparams, tparam.paramInfo).bounds),
tl => tycon1a.appliedTo(args1.take(lengthDiff) ++
- tparams1.indices.toList.map(PolyParam(tl, _))))
+ tparams1.indices.toList.map(TypeParamRef(tl, _))))
(ctx.mode.is(Mode.TypevarsMissContext) ||
tryInstantiate(tycon2, tycon1b.ensureHK)) &&
isSubType(tp1, tycon1b.appliedTo(args2))
@@ -725,7 +725,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
fallback(tycon2bounds.lo)
tycon2 match {
- case param2: PolyParam =>
+ case param2: TypeParamRef =>
isMatchingApply(tp1) || {
if (canConstrain(param2)) canInstantiate(param2)
else compareLower(bounds(param2), tyconIsTypeRef = false)
@@ -746,7 +746,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
*/
def compareHkApply1(tp1: HKApply, tycon1: Type, args1: List[Type], tp2: Type): Boolean =
tycon1 match {
- case param1: PolyParam =>
+ case param1: TypeParamRef =>
def canInstantiate = tp2 match {
case AppliedType(tycon2, args2) =>
tryInstantiate(param1, tycon2.ensureHK) && isSubArgs(args1, args2, tycon2.typeParams)
@@ -764,7 +764,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
/** Subtype test for corresponding arguments in `args1`, `args2` according to
* variances in type parameters `tparams`.
*/
- def isSubArgs(args1: List[Type], args2: List[Type], tparams: List[TypeParamInfo]): Boolean =
+ def isSubArgs(args1: List[Type], args2: List[Type], tparams: List[ParamInfo]): Boolean =
if (args1.isEmpty) args2.isEmpty
else args2.nonEmpty && {
val v = tparams.head.paramVariance
@@ -806,7 +806,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
def fix(tp: Type): Type = tp.stripTypeVar match {
case tp: RecType => fix(tp.parent).substRecThis(tp, anchor)
case tp @ RefinedType(parent, rname, rinfo) => tp.derivedRefinedType(fix(parent), rname, rinfo)
- case tp: PolyParam => fixOrElse(bounds(tp).hi, tp)
+ case tp: TypeParamRef => fixOrElse(bounds(tp).hi, tp)
case tp: TypeProxy => fixOrElse(tp.underlying, tp)
case tp: AndOrType => tp.derivedAndOrType(fix(tp.tp1), fix(tp.tp2))
case tp => tp
@@ -967,7 +967,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
/** Defer constraining type variables when compared against prototypes */
def isMatchedByProto(proto: ProtoType, tp: Type) = tp.stripTypeVar match {
- case tp: PolyParam if constraint contains tp => true
+ case tp: TypeParamRef if constraint contains tp => true
case _ => proto.isMatchedBy(tp)
}
@@ -978,7 +978,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
* type variable with (the corresponding type in) `tp2` instead.
*/
private def isCappable(tp: Type): Boolean = tp match {
- case tp: PolyParam => constraint contains tp
+ case tp: TypeParamRef => constraint contains tp
case tp: TypeProxy => isCappable(tp.underlying)
case tp: AndOrType => isCappable(tp.tp1) || isCappable(tp.tp2)
case _ => false
@@ -1021,7 +1021,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
tp2.widen match {
case tp2: MethodType =>
// implicitness is ignored when matching
- matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) &&
+ matchingParams(tp1, tp2) &&
matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), relaxed)
case tp2 =>
relaxed && tp1.paramNames.isEmpty &&
@@ -1031,7 +1031,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
tp2.widen match {
case tp2: PolyType =>
sameLength(tp1.paramNames, tp2.paramNames) &&
- matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), relaxed)
+ matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), relaxed)
case _ =>
false
}
@@ -1047,28 +1047,28 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
}
}
- /** Are `syms1` and `syms2` parameter lists with pairwise equivalent types? */
- def matchingParams(formals1: List[Type], formals2: List[Type], isJava1: Boolean, isJava2: Boolean): Boolean = formals1 match {
- case formal1 :: rest1 =>
- formals2 match {
- case formal2 :: rest2 =>
- (isSameTypeWhenFrozen(formal1, formal2)
- || isJava1 && (formal2 isRef ObjectClass) && (formal1 isRef AnyClass)
- || isJava2 && (formal1 isRef ObjectClass) && (formal2 isRef AnyClass)) &&
- matchingParams(rest1, rest2, isJava1, isJava2)
- case nil =>
- false
- }
- case nil =>
- formals2.isEmpty
- }
-
- /** Do generic types `poly1` and `poly2` have type parameters that
- * have the same bounds (after renaming one set to the other)?
+ /** Do lambda types `lam1` and `lam2` have parameters that have the same types
+ * and the same implicit status? (after renaming one set to the other)
*/
- def matchingTypeParams(poly1: PolyType, poly2: PolyType): Boolean =
- (poly1.paramBounds corresponds poly2.paramBounds)((b1, b2) =>
- isSameType(b1, b2.subst(poly2, poly1)))
+ def matchingParams(lam1: MethodOrPoly, lam2: MethodOrPoly): Boolean = {
+ /** Are `syms1` and `syms2` parameter lists with pairwise equivalent types? */
+ def loop(formals1: List[Type], formals2: List[Type]): Boolean = formals1 match {
+ case formal1 :: rest1 =>
+ formals2 match {
+ case formal2 :: rest2 =>
+ val formal2a = if (lam2.isParamDependent) formal2.subst(lam2, lam1) else formal2
+ (isSameTypeWhenFrozen(formal1, formal2a)
+ || lam1.isJava && (formal2 isRef ObjectClass) && (formal1 isRef AnyClass)
+ || lam2.isJava && (formal1 isRef ObjectClass) && (formal2 isRef AnyClass)) &&
+ loop(rest1, rest2)
+ case nil =>
+ false
+ }
+ case nil =>
+ formals2.isEmpty
+ }
+ loop(lam1.paramInfos, lam2.paramInfos)
+ }
// Type equality =:=
@@ -1216,7 +1216,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
/** Form a normalized conjunction of two types.
* Note: For certain types, `&` is distributed inside the type. This holds for
* all types which are not value types (e.g. TypeBounds, ClassInfo,
- * ExprType, MethodType, PolyType). Also, when forming an `&`,
+ * ExprType, LambdaType). Also, when forming an `&`,
* instantiated TypeVars are dereferenced and annotations are stripped.
* Finally, refined types with the same refined name are
* opportunistically merged.
@@ -1245,7 +1245,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
/** Form a normalized conjunction of two types.
* Note: For certain types, `|` is distributed inside the type. This holds for
* all types which are not value types (e.g. TypeBounds, ClassInfo,
- * ExprType, MethodType, PolyType). Also, when forming an `|`,
+ * ExprType, LambdaType). Also, when forming an `|`,
* instantiated TypeVars are dereferenced and annotations are stripped.
*
* Sometimes, the disjunction of two types cannot be formed because
@@ -1276,20 +1276,20 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
val tparams2 = tp2.typeParams
if (tparams1.isEmpty)
if (tparams2.isEmpty) op(tp1, tp2)
- else original(tp1, tp2.appliedTo(tp2.typeParams.map(_.paramBoundsAsSeenFrom(tp2))))
+ else original(tp1, tp2.appliedTo(tp2.typeParams.map(_.paramInfoAsSeenFrom(tp2))))
else if (tparams2.isEmpty)
- original(tp1.appliedTo(tp1.typeParams.map(_.paramBoundsAsSeenFrom(tp1))), tp2)
+ original(tp1.appliedTo(tp1.typeParams.map(_.paramInfoAsSeenFrom(tp1))), tp2)
else
- PolyType(
- paramNames = tpnme.syntheticTypeParamNames(tparams1.length),
- variances = (tparams1, tparams2).zipped.map((tparam1, tparam2) =>
- (tparam1.paramVariance + tparam2.paramVariance) / 2))(
- paramBoundsExp = tl => (tparams1, tparams2).zipped.map((tparam1, tparam2) =>
- tl.lifted(tparams1, tparam1.paramBoundsAsSeenFrom(tp1)).bounds &
- tl.lifted(tparams2, tparam2.paramBoundsAsSeenFrom(tp2)).bounds),
+ HKTypeLambda(
+ paramNames = (HKTypeLambda.syntheticParamNames(tparams1.length), tparams1, tparams2)
+ .zipped.map((pname, tparam1, tparam2) =>
+ pname.withVariance((tparam1.paramVariance + tparam2.paramVariance) / 2)))(
+ paramInfosExp = tl => (tparams1, tparams2).zipped.map((tparam1, tparam2) =>
+ tl.integrate(tparams1, tparam1.paramInfoAsSeenFrom(tp1)).bounds &
+ tl.integrate(tparams2, tparam2.paramInfoAsSeenFrom(tp2)).bounds),
resultTypeExp = tl =>
- original(tl.lifted(tparams1, tp1).appliedTo(tl.paramRefs),
- tl.lifted(tparams2, tp2).appliedTo(tl.paramRefs)))
+ original(tl.integrate(tparams1, tp1).appliedTo(tl.paramRefs),
+ tl.integrate(tparams2, tp2).appliedTo(tl.paramRefs)))
}
/** Try to distribute `&` inside type, detect and handle conflicts
@@ -1392,8 +1392,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
case tp2: MethodType =>
def asGoodParams(formals1: List[Type], formals2: List[Type]) =
(formals2 corresponds formals1)(isSubTypeWhenFrozen)
- asGoodParams(tp1.paramTypes, tp2.paramTypes) &&
- (!asGoodParams(tp2.paramTypes, tp1.paramTypes) ||
+ asGoodParams(tp1.paramInfos, tp2.paramInfos) &&
+ (!asGoodParams(tp2.paramInfos, tp1.paramInfos) ||
isAsGood(tp1.resultType, tp2.resultType))
case _ =>
false
@@ -1424,7 +1424,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
def showGoal(tp1: Type, tp2: Type)(implicit ctx: Context) = {
println(ex"assertion failure for $tp1 <:< $tp2, frozen = $frozenConstraint")
def explainPoly(tp: Type) = tp match {
- case tp: PolyParam => ctx.echo(s"polyparam ${tp.show} found in ${tp.binder.show}")
+ case tp: TypeParamRef => ctx.echo(s"TypeParamRef ${tp.show} found in ${tp.binder.show}")
case tp: TypeRef if tp.symbol.exists => ctx.echo(s"typeref ${tp.show} found in ${tp.symbol.owner.show}")
case tp: TypeVar => ctx.echo(s"typevar ${tp.show}, origin = ${tp.origin}")
case _ => ctx.echo(s"${tp.show} is a ${tp.getClass}")
@@ -1503,7 +1503,7 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
super.glb(tp1, tp2)
}
- override def addConstraint(param: PolyParam, bound: Type, fromBelow: Boolean): Boolean =
+ override def addConstraint(param: TypeParamRef, bound: Type, fromBelow: Boolean): Boolean =
traceIndented(i"add constraint $param ${if (fromBelow) ">:" else "<:"} $bound $frozenConstraint, constraint = ${ctx.typerState.constraint}") {
super.addConstraint(param, bound, fromBelow)
}
diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
index fe3396fcb..f35752644 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
@@ -28,7 +28,7 @@ import scala.annotation.tailrec
* WildcardType
* ErrorType
*
- * only for isInstanceOf, asInstanceOf: PolyType, PolyParam, TypeBounds
+ * only for isInstanceOf, asInstanceOf: PolyType, TypeParamRef, TypeBounds
*
*/
object TypeErasure {
@@ -55,7 +55,7 @@ object TypeErasure {
case ThisType(tref) =>
isErasedType(tref)
case tp: MethodType =>
- tp.paramTypes.forall(isErasedType) && isErasedType(tp.resultType)
+ tp.paramInfos.forall(isErasedType) && isErasedType(tp.resultType)
case tp @ ClassInfo(pre, _, parents, decls, _) =>
isErasedType(pre) && parents.forall(isErasedType) //&& decls.forall(sym => isErasedType(sym.info)) && isErasedType(tp.selfType)
case NoType | NoPrefix | WildcardType | _: ErrorType | SuperType(_, _) =>
@@ -176,7 +176,7 @@ object TypeErasure {
val erase = erasureFn(isJava, semiEraseVCs, sym.isConstructor, wildcardOK = false)
def eraseParamBounds(tp: PolyType): Type =
- tp.derivedPolyType(
+ tp.derivedLambdaType(
tp.paramNames, tp.paramNames map (Function.const(TypeBounds.upper(defn.ObjectType))), tp.resultType)
if (defn.isPolymorphicAfterErasure(sym)) eraseParamBounds(sym.info.asInstanceOf[PolyType])
@@ -186,7 +186,7 @@ object TypeErasure {
case einfo: MethodType =>
if (sym.isGetter && einfo.resultType.isRef(defn.UnitClass))
MethodType(Nil, defn.BoxedUnitType)
- else if (sym.isAnonymousFunction && einfo.paramTypes.length > MaxImplementedFunctionArity)
+ else if (sym.isAnonymousFunction && einfo.paramInfos.length > MaxImplementedFunctionArity)
MethodType(nme.ALLARGS :: Nil, JavaArrayType(defn.ObjectType) :: Nil, einfo.resultType)
else
einfo
@@ -204,7 +204,7 @@ object TypeErasure {
!tp.symbol.isClass &&
!tp.derivesFrom(defn.ObjectClass) &&
!tp.symbol.is(JavaDefined)
- case tp: PolyParam =>
+ case tp: TypeParamRef =>
!tp.derivesFrom(defn.ObjectClass) &&
!tp.binder.resultType.isInstanceOf[JavaMethodType]
case tp: TypeAlias => isUnboundedGeneric(tp.alias)
@@ -304,7 +304,7 @@ object TypeErasure {
case _: ClassInfo => true
case _ => false
}
- case tp: PolyParam => false
+ case tp: TypeParamRef => false
case tp: TypeProxy => hasStableErasure(tp.superType)
case tp: AndOrType => hasStableErasure(tp.tp1) && hasStableErasure(tp.tp2)
case _ => false
@@ -382,13 +382,15 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
case tp: MethodType =>
def paramErasure(tpToErase: Type) =
erasureFn(tp.isJava, semiEraseVCs, isConstructor, wildcardOK)(tpToErase)
- val formals = tp.paramTypes.mapConserve(paramErasure)
+ val formals = tp.paramInfos.mapConserve(paramErasure)
eraseResult(tp.resultType) match {
case rt: MethodType =>
- tp.derivedMethodType(tp.paramNames ++ rt.paramNames, formals ++ rt.paramTypes, rt.resultType)
+ tp.derivedLambdaType(tp.paramNames ++ rt.paramNames, formals ++ rt.paramInfos, rt.resultType)
case rt =>
- tp.derivedMethodType(tp.paramNames, formals, rt)
+ tp.derivedLambdaType(tp.paramNames, formals, rt)
}
+ case tp: PolyType =>
+ this(tp.resultType)
case tp @ ClassInfo(pre, cls, classParents, decls, _) =>
if (cls is Package) tp
else {
@@ -517,6 +519,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
if (inst.exists) sigName(inst) else tpnme.Uninstantiated
case tp: TypeProxy =>
sigName(tp.underlying)
+ case tp: PolyType =>
+ sigName(tp.resultType)
case _: ErrorType | WildcardType =>
tpnme.WILDCARD
case tp: WildcardType =>
diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala
index 3d2906320..9593bfe93 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala
@@ -157,7 +157,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
tp2
case tp1 => tp1
}
- case tp: PolyParam =>
+ case tp: TypeParamRef =>
typerState.constraint.typeVarOfParam(tp) orElse tp
case _: ThisType | _: BoundType | NoPrefix =>
tp
diff --git a/compiler/src/dotty/tools/dotc/core/TyperState.scala b/compiler/src/dotty/tools/dotc/core/TyperState.scala
index 206438d86..b33b3aa29 100644
--- a/compiler/src/dotty/tools/dotc/core/TyperState.scala
+++ b/compiler/src/dotty/tools/dotc/core/TyperState.scala
@@ -42,7 +42,7 @@ class TyperState(r: Reporter) extends DotClass with Showable {
*/
def instType(tvar: TypeVar)(implicit ctx: Context): Type = constraint.entry(tvar.origin) match {
case _: TypeBounds => NoType
- case tp: PolyParam =>
+ case tp: TypeParamRef =>
var tvar1 = constraint.typeVarOfParam(tp)
if (tvar1.exists) tvar1 else tp
case tp => tp
@@ -155,14 +155,14 @@ extends TyperState(r) {
}
override def gc()(implicit ctx: Context): Unit = {
- val toCollect = new mutable.ListBuffer[PolyType]
+ val toCollect = new mutable.ListBuffer[TypeLambda]
constraint foreachTypeVar { tvar =>
if (!tvar.inst.exists) {
val inst = instType(tvar)
if (inst.exists && (tvar.owningState eq this)) {
tvar.inst = inst
- val poly = tvar.origin.binder
- if (constraint.isRemovable(poly)) toCollect += poly
+ val lam = tvar.origin.binder
+ if (constraint.isRemovable(lam)) toCollect += lam
}
}
}
diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index c80107f93..83fb70aa1 100644
--- a/compiler/src/dotty/tools/dotc/core/Types.scala
+++ b/compiler/src/dotty/tools/dotc/core/Types.scala
@@ -54,10 +54,10 @@ object Types {
* | | +--- ThisType
* | | +--- SuperType
* | | +--- ConstantType
- * | | +--- MethodParam
+ * | | +--- TermParamRef
* | | +----RecThis
* | | +--- SkolemType
- * | +- PolyParam
+ * | +- TypeParamRef
* | +- RefinedOrRecType -+-- RefinedType
* | | -+-- RecType
* | +- HKApply
@@ -65,12 +65,13 @@ object Types {
* | +- ExprType
* | +- AnnotatedType
* | +- TypeVar
- * | +- PolyType
+ * | +- HKTypeLambda
* |
* +- GroundType -+- AndType
* +- OrType
- * +- MethodType -----+- ImplicitMethodType
- * | +- JavaMethodType
+ * +- MethodOrPoly ---+-- PolyType
+ * +-- MethodType ---+- ImplicitMethodType
+ * | +- JavaMethodType
* +- ClassInfo
* |
* +- NoType
@@ -103,7 +104,7 @@ object Types {
final def isValueType: Boolean = this.isInstanceOf[ValueType]
/** Is the is value type or type lambda? */
- final def isValueTypeOrLambda: Boolean = isValueType || this.isInstanceOf[PolyType]
+ final def isValueTypeOrLambda: Boolean = isValueType || this.isInstanceOf[TypeLambda]
/** Does this type denote a stable reference (i.e. singleton type)? */
@tailrec final def isStable(implicit ctx: Context): Boolean = stripTypeVar match {
@@ -215,17 +216,15 @@ object Types {
/** Is this the type of a method that has a repeated parameter type as
* last parameter type?
*/
- def isVarArgsMethod(implicit ctx: Context): Boolean = this match {
- case tp: PolyType => tp.resultType.isVarArgsMethod
- case mt: MethodType => mt.paramTypes.nonEmpty && mt.paramTypes.last.isRepeatedParam
+ def isVarArgsMethod(implicit ctx: Context): Boolean = stripPoly match {
+ case mt: MethodType => mt.paramInfos.nonEmpty && mt.paramInfos.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 {
+ def isNullaryMethod(implicit ctx: Context): Boolean = stripPoly match {
case MethodType(Nil) => true
- case tp: PolyType => tp.resultType.isNullaryMethod
case _ => false
}
@@ -443,10 +442,10 @@ object Types {
case tp: TermRef =>
go (tp.underlying match {
case mt: MethodType
- if mt.paramTypes.isEmpty && (tp.symbol is Stable) => mt.resultType
+ if mt.paramInfos.isEmpty && (tp.symbol is Stable) => mt.resultType
case tp1 => tp1
})
- case tp: PolyParam =>
+ case tp: TypeParamRef =>
goParam(tp)
case tp: RecType =>
goRec(tp)
@@ -541,9 +540,9 @@ object Types {
}
def goApply(tp: HKApply) = tp.tycon match {
- case tl: PolyType =>
+ case tl: HKTypeLambda =>
go(tl.resType).mapInfo(info =>
- tl.derivedLambdaAbstraction(tl.paramNames, tl.paramBounds, info).appliedTo(tp.args))
+ tl.derivedLambdaAbstraction(tl.paramNames, tl.paramInfos, info).appliedTo(tp.args))
case _ =>
go(tp.superType)
}
@@ -563,7 +562,7 @@ object Types {
// loadClassWithPrivateInnerAndSubSelf in ShowClassTests
go(tp.cls.typeRef) orElse d
}
- def goParam(tp: PolyParam) = {
+ def goParam(tp: TypeParamRef) = {
val next = tp.underlying
ctx.typerState.constraint.entry(tp) match {
case bounds: TypeBounds if bounds ne next =>
@@ -814,6 +813,12 @@ object Types {
*/
def stripAnnots(implicit ctx: Context): Type = this
+ /** Strip PolyType prefix */
+ def stripPoly(implicit ctx: Context): Type = this match {
+ case tp: PolyType => tp.resType.stripPoly
+ case _ => this
+ }
+
/** Widen from singleton type to its underlying non-singleton
* base type by applying one or more `underlying` dereferences,
* Also go from => T to T.
@@ -1088,43 +1093,38 @@ object Types {
}
/** The parameter types of a PolyType or MethodType, Empty list for others */
- final def paramTypess(implicit ctx: Context): List[List[Type]] = this match {
- case mt: MethodType => mt.paramTypes :: mt.resultType.paramTypess
- case pt: PolyType => pt.resultType.paramTypess
+ final def paramInfoss(implicit ctx: Context): List[List[Type]] = stripPoly match {
+ case mt: MethodType => mt.paramInfos :: mt.resultType.paramInfoss
case _ => Nil
}
/** The parameter names of a PolyType or MethodType, Empty list for others */
- final def paramNamess(implicit ctx: Context): List[List[TermName]] = this match {
+ final def paramNamess(implicit ctx: Context): List[List[TermName]] = stripPoly match {
case mt: MethodType => mt.paramNames :: mt.resultType.paramNamess
- case pt: PolyType => pt.resultType.paramNamess
case _ => Nil
}
/** The parameter types in the first parameter section of a generic type or MethodType, Empty list for others */
- @tailrec final def firstParamTypes(implicit ctx: Context): List[Type] = this match {
- case mt: MethodType => mt.paramTypes
- case pt: PolyType => pt.resultType.firstParamTypes
+ final def firstParamTypes(implicit ctx: Context): List[Type] = stripPoly match {
+ case mt: MethodType => mt.paramInfos
case _ => Nil
}
/** Is this either not a method at all, or a parameterless method? */
- @tailrec final def isParameterless(implicit ctx: Context): Boolean = this match {
+ final def isParameterless(implicit ctx: Context): Boolean = stripPoly match {
case mt: MethodType => false
- case pt: PolyType => pt.resultType.isParameterless
case _ => true
}
- /** The resultType of a PolyType, MethodType, or ExprType, the type itself for others */
+ /** The resultType of a LambdaType, or ExprType, the type itself for others */
def resultType(implicit ctx: Context): Type = this
/** The final result type of a PolyType, MethodType, or ExprType, after skipping
* all parameter sections, the type itself for all others.
*/
- def finalResultType(implicit ctx: Context): Type = resultType match {
+ def finalResultType(implicit ctx: Context): Type = resultType.stripPoly match {
case mt: MethodType => mt.resultType.finalResultType
- case pt: PolyType => pt.resultType.finalResultType
case _ => resultType
}
@@ -1180,8 +1180,8 @@ object Types {
final def substDealias(from: List[Symbol], to: List[Type])(implicit ctx: Context): Type =
ctx.substDealias(this, from, to, null)
- /** Substitute all types of the form `PolyParam(from, N)` by
- * `PolyParam(to, N)`.
+ /** Substitute all types of the form `TypeParamRef(from, N)` by
+ * `TypeParamRef(to, N)`.
*/
final def subst(from: BindingType, to: BindingType)(implicit ctx: Context): Type =
ctx.subst(this, from, to, null)
@@ -1199,7 +1199,7 @@ object Types {
ctx.substRecThis(this, binder, tp, null)
/** Substitute a bound type by some other type */
- final def substParam(from: ParamType, to: Type)(implicit ctx: Context): Type =
+ final def substParam(from: ParamRef, to: Type)(implicit ctx: Context): Type =
ctx.substParam(this, from, to, null)
/** Substitute bound types by some other types */
@@ -1220,7 +1220,7 @@ object Types {
*/
def toFunctionType(dropLast: Int = 0)(implicit ctx: Context): Type = this match {
case mt: MethodType if !mt.isDependent || ctx.mode.is(Mode.AllowDependentFunctions) =>
- val formals1 = if (dropLast == 0) mt.paramTypes else mt.paramTypes dropRight dropLast
+ val formals1 = if (dropLast == 0) mt.paramInfos else mt.paramInfos dropRight dropLast
defn.FunctionOf(
formals1 mapConserve (_.underlyingIfRepeated(mt.isJava)), mt.resultType, mt.isImplicit && !ctx.erasedTypes)
}
@@ -1360,7 +1360,7 @@ object Types {
}
/** A marker trait for types that bind other types that refer to them.
- * Instances are: PolyType, MethodType, RefinedType.
+ * Instances are: LambdaType, RecType.
*/
trait BindingType extends Type
@@ -2280,7 +2280,7 @@ object Types {
if (tp1 eq tp2) tp1 else apply(tp1, tp2)
}
- // ----- Method types: MethodType/ExprType/PolyType -------------------------------
+ // ----- ExprType and LambdaTypes -----------------------------------
// Note: method types are cached whereas poly types are not. The reason
// is that most poly types are cyclic via poly params,
@@ -2315,20 +2315,126 @@ object Types {
}
}
- trait MethodOrPoly extends MethodicType
+ /** A by-name parameter type of the form `=> T`, or the type of a method with no parameter list. */
+ abstract case class ExprType(resType: Type)
+ extends CachedProxyType with TermType with MethodicType {
+ override def resultType(implicit ctx: Context): Type = resType
+ override def underlying(implicit ctx: Context): Type = resType
+ protected def computeSignature(implicit ctx: Context): Signature = resultSignature
+ def derivedExprType(resType: Type)(implicit ctx: Context) =
+ if (resType eq this.resType) this else ExprType(resType)
+ override def computeHash = doHash(resType)
+ }
- 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._
+ final class CachedExprType(resultType: Type) extends ExprType(resultType)
+
+ object ExprType {
+ def apply(resultType: Type)(implicit ctx: Context) = {
+ assertUnerased()
+ unique(new CachedExprType(resultType))
+ }
+ }
- def isJava = false
+ /** The lambda type square:
+ *
+ * LambdaType | TermLambda | TypeLambda
+ * -------------+-------------------+------------------
+ * HKLambda | HKTermLambda | HKTypeLambda
+ * MethodOrPoly | MethodType | PolyType
+ */
+ trait LambdaType extends BindingType with MethodicType { self =>
+ type ThisName <: Name
+ type PInfo <: Type
+ type This <: LambdaType{type PInfo = self.PInfo}
+
+ def paramNames: List[ThisName]
+ def paramInfos: List[PInfo]
+ def resType: Type
+ def newParamRef(n: Int): ParamRef
+
+ override def resultType(implicit ctx: Context) = resType
+
+ def isJava: Boolean = false
def isImplicit = false
- val paramTypes = paramTypesExp(this)
- private[core] val resType = resultTypeExp(this)
- assert(resType.exists)
+ def isDependent(implicit ctx: Context): Boolean
+ def isParamDependent(implicit ctx: Context): Boolean
+
+ final def isTermLambda = isInstanceOf[TermLambda]
+ final def isTypeLambda = isInstanceOf[TypeLambda]
+ final def isHigherKinded = isInstanceOf[TypeProxy]
+
+ lazy val paramRefs: List[ParamRef] = paramNames.indices.toList.map(newParamRef)
+
+ protected def computeSignature(implicit ctx: Context) = resultSignature
+
+ final def instantiate(argTypes: => List[Type])(implicit ctx: Context): Type =
+ if (isDependent) resultType.substParams(this, argTypes)
+ else resultType
+
+ def companion: LambdaTypeCompanion[ThisName, PInfo, This]
+
+ /** The type `[tparams := paramRefs] tp`, where `tparams` can be
+ * either a list of type parameter symbols or a list of lambda parameters
+ */
+ def integrate(tparams: List[ParamInfo], tp: Type)(implicit ctx: Context): Type =
+ tparams match {
+ case LambdaParam(lam, _) :: _ => tp.subst(lam, this)
+ case tparams: List[Symbol @unchecked] => tp.subst(tparams, paramRefs)
+ }
+
+ final def derivedLambdaType(paramNames: List[ThisName] = this.paramNames,
+ paramInfos: List[PInfo] = this.paramInfos,
+ resType: Type = this.resType)(implicit ctx: Context) =
+ if ((paramNames eq this.paramNames) && (paramInfos eq this.paramInfos) && (resType eq this.resType)) this
+ else newLikeThis(paramNames, paramInfos, resType)
+
+ final def newLikeThis(paramNames: List[ThisName], paramInfos: List[PInfo], resType: Type)(implicit ctx: Context): This =
+ companion(paramNames)(
+ x => paramInfos.mapConserve(_.subst(this, x).asInstanceOf[PInfo]),
+ x => resType.subst(this, x))
+
+ protected def prefixString: String
+ final override def toString = s"$prefixString($paramNames, $paramInfos, $resType)"
+ }
+
+ abstract class HKLambda extends CachedProxyType with LambdaType {
+ final override def underlying(implicit ctx: Context) = resType
+
+ final override def computeHash = doHash(paramNames, resType, paramInfos)
+
+ // Defined here instead of in LambdaType for efficiency
+ final override def equals(that: Any) = that match {
+ case that: HKLambda =>
+ this.paramNames == that.paramNames &&
+ this.paramInfos == that.paramInfos &&
+ this.resType == that.resType &&
+ (this.companion eq that.companion)
+ case _ =>
+ false
+ }
+ }
+
+ abstract class MethodOrPoly extends CachedGroundType with LambdaType with TermType {
+ final override def computeHash = doHash(paramNames, resType, paramInfos)
+
+ // Defined here instead of in LambdaType for efficiency
+ final override def equals(that: Any) = that match {
+ case that: MethodOrPoly =>
+ this.paramNames == that.paramNames &&
+ this.paramInfos == that.paramInfos &&
+ this.resType == that.resType &&
+ (this.companion eq that.companion)
+ case _ =>
+ false
+ }
+ }
+
+ trait TermLambda extends LambdaType { thisLambdaType =>
+ import DepStatus._
+ type ThisName = TermName
+ type PInfo = Type
+ type This <: TermLambda
override def resultType(implicit ctx: Context): Type =
if (dependencyStatus == FalseDeps) { // dealias all false dependencies
@@ -2347,8 +2453,8 @@ object Types {
}
else resType
- var myDependencyStatus: DependencyStatus = Unknown
- var myParamDependencyStatus: DependencyStatus = Unknown
+ private var myDependencyStatus: DependencyStatus = Unknown
+ private var myParamDependencyStatus: DependencyStatus = Unknown
private def depStatus(initial: DependencyStatus, tp: Type)(implicit ctx: Context): DependencyStatus = {
def combine(x: DependencyStatus, y: DependencyStatus) = {
@@ -2361,7 +2467,7 @@ object Types {
if (status == TrueDeps) status
else
tp match {
- case MethodParam(`thisMethodType`, _) => TrueDeps
+ case TermParamRef(`thisLambdaType`, _) => TrueDeps
case tp: TypeRef =>
val status1 = foldOver(status, tp)
tp.info match { // follow type alias to avoid dependency
@@ -2401,8 +2507,8 @@ object Types {
if (myParamDependencyStatus != Unknown) myParamDependencyStatus
else {
val result =
- if (paramTypes.isEmpty) NoDeps
- else (NoDeps /: paramTypes.tail)(depStatus(_, _))
+ if (paramInfos.isEmpty) NoDeps
+ else (NoDeps /: paramInfos.tail)(depStatus(_, _))
if ((result & Provisional) == 0) myParamDependencyStatus = result
(result & StatusMask).toByte
}
@@ -2418,75 +2524,90 @@ object Types {
*/
def isParamDependent(implicit ctx: Context): Boolean = paramDependencyStatus == TrueDeps
- protected def computeSignature(implicit ctx: Context): Signature =
- resultSignature.prepend(paramTypes, isJava)
+ def newParamRef(n: Int) = TermParamRef(this, n)
+ }
- def derivedMethodType(paramNames: List[TermName] = this.paramNames,
- paramTypes: List[Type] = this.paramTypes,
- 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)(paramTypesFn, resTypeFn)
- else if (isImplicit) ImplicitMethodType(paramNames)(paramTypesFn, resTypeFn)
- else MethodType(paramNames)(paramTypesFn, resTypeFn)
- }
+ abstract case class MethodType(paramNames: List[TermName])(
+ paramInfosExp: MethodType => List[Type],
+ resultTypeExp: MethodType => Type)
+ extends MethodOrPoly with TermLambda with NarrowCached { thisMethodType =>
+ import MethodType._
- def instantiate(argTypes: => List[Type])(implicit ctx: Context): Type =
- if (isDependent) resultType.substParams(this, argTypes)
- else resultType
+ type This = MethodType
- override def equals(that: Any) = that match {
- case that: MethodType =>
- this.paramNames == that.paramNames &&
- this.paramTypes == that.paramTypes &&
- this.resType == that.resType
- case _ =>
- false
- }
+ val paramInfos = paramInfosExp(this)
+ val resType = resultTypeExp(this)
+ assert(resType.exists)
- override def computeHash = doHash(paramNames, resType, paramTypes)
+ override def computeSignature(implicit ctx: Context): Signature =
+ resultSignature.prepend(paramInfos, isJava)
protected def prefixString = "MethodType"
- override def toString = s"$prefixString($paramNames, $paramTypes, $resType)"
}
- 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 CachedMethodType(paramNames: List[TermName])(paramInfosExp: MethodType => List[Type], resultTypeExp: MethodType => Type)
+ extends MethodType(paramNames)(paramInfosExp, resultTypeExp) {
+ def companion = MethodType
}
- final class JavaMethodType(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)
- extends MethodType(paramNames)(paramTypesExp, resultTypeExp) {
+ final class JavaMethodType(paramNames: List[TermName])(paramInfosExp: MethodType => List[Type], resultTypeExp: MethodType => Type)
+ extends MethodType(paramNames)(paramInfosExp, resultTypeExp) {
+ def companion = JavaMethodType
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])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)
- extends MethodType(paramNames)(paramTypesExp, resultTypeExp) {
+ final class ImplicitMethodType(paramNames: List[TermName])(paramInfosExp: MethodType => List[Type], resultTypeExp: MethodType => Type)
+ extends MethodType(paramNames)(paramInfosExp, resultTypeExp) {
+ def companion = ImplicitMethodType
override def isImplicit = true
- override def equals(that: Any) = super.equals(that) && that.isInstanceOf[ImplicitMethodType]
- override def computeHash = addDelta(super.computeHash, 2)
override protected def prefixString = "ImplicitMethodType"
}
- abstract class MethodTypeCompanion {
- 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)
- def apply(paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType =
- 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)
+ abstract class LambdaTypeCompanion[N <: Name, PInfo <: Type, LT <: LambdaType] {
+ def syntheticParamName(n: Int): N
+
+ @sharable private val memoizedNames = new mutable.HashMap[Int, List[N]]
+ def syntheticParamNames(n: Int): List[N] = synchronized {
+ memoizedNames.getOrElseUpdate(n, (0 until n).map(syntheticParamName).toList)
+ }
+
+ def apply(paramNames: List[N])(paramInfosExp: LT => List[PInfo], resultTypeExp: LT => Type)(implicit ctx: Context): LT
+ def apply(paramNames: List[N], paramInfos: List[PInfo], resultType: Type)(implicit ctx: Context): LT =
+ apply(paramNames)(_ => paramInfos, _ => resultType)
+ def apply(paramInfos: List[PInfo])(resultTypeExp: LT => Type)(implicit ctx: Context): LT =
+ apply(syntheticParamNames(paramInfos.length))(_ => paramInfos, resultTypeExp)
+ def apply(paramInfos: List[PInfo], resultType: Type)(implicit ctx: Context): LT =
+ apply(syntheticParamNames(paramInfos.length), paramInfos, resultType)
+
+ protected def paramName(param: ParamInfo.Of[N])(implicit ctx: Context): N =
+ param.paramName
+
+ def fromParams[PI <: ParamInfo.Of[N]](params: List[PI], resultType: Type)(implicit ctx: Context): Type =
+ if (params.isEmpty) resultType
+ else apply(params.map(paramName))(
+ tl => params.map(param => tl.integrate(params, param.paramInfo).asInstanceOf[PInfo]),
+ tl => tl.integrate(params, resultType))
+ }
+
+ abstract class TermLambdaCompanion[LT <: TermLambda]
+ extends LambdaTypeCompanion[TermName, Type, LT] {
+ def syntheticParamName(n: Int) = nme.syntheticParamName(n)
+ }
+
+ abstract class TypeLambdaCompanion[LT <: TypeLambda]
+ extends LambdaTypeCompanion[TypeName, TypeBounds, LT] {
+ def syntheticParamName(n: Int) = tpnme.syntheticTypeParamName(n)
+ }
+
+ abstract class MethodTypeCompanion extends TermLambdaCompanion[MethodType] {
/** Produce method type from parameter symbols, with special mappings for repeated
- * and inline parameters.
+ * and inline parameters:
+ * - replace @repeated annotations on Seq or Array types by <repeated> types
+ * - add @inlineParam to inline call-by-value parameters
*/
def fromSymbols(params: List[Symbol], resultType: Type)(implicit ctx: Context) = {
- /** Replace @repeated annotations on Seq or Array types by <repeated> types */
def translateRepeated(tp: Type): Type = tp match {
case tp @ ExprType(tp1) => tp.derivedExprType(translateRepeated(tp1))
case AnnotatedType(tp, annot) if annot matches defn.RepeatedAnnot =>
@@ -2496,27 +2617,25 @@ object Types {
case tp =>
tp
}
- /** Add @inlineParam to inline call-by-value parameters */
def translateInline(tp: Type): Type = tp match {
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 = {
+ def paramInfo(param: Symbol) = {
val paramType = translateRepeated(param.info)
if (param.is(Inline)) translateInline(paramType) else paramType
}
+
apply(params.map(_.name.asTermName))(
- mt => params.map(param => integrate(paramInfo(param), mt)),
- mt => integrate(resultType, mt))
+ tl => params.map(p => tl.integrate(params, paramInfo(p))),
+ tl => tl.integrate(params, resultType))
}
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)
+ for ((paramInfo, idx) <- mt.paramInfos.zipWithIndex)
+ paramInfo.foreachPart {
+ case TermParamRef(`mt`, j) => assert(j < idx, mt)
case _ =>
}
mt
@@ -2524,114 +2643,97 @@ object Types {
}
object MethodType extends MethodTypeCompanion {
- 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
- private final val NoDeps: DependencyStatus = 1 // no dependent parameters found
- private final val FalseDeps: DependencyStatus = 2 // all dependent parameters are prefixes of non-depended alias types
- private final val TrueDeps: DependencyStatus = 3 // some truly dependent parameters exist
- private final val StatusMask: DependencyStatus = 3 // the bits indicating actual dependency status
- private final val Provisional: DependencyStatus = 4 // set if dependency status can still change due to type variable instantiations
+ def apply(paramNames: List[TermName])(paramInfosExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType =
+ checkValid(unique(new CachedMethodType(paramNames)(paramInfosExp, resultTypeExp)))
}
object JavaMethodType extends MethodTypeCompanion {
- def apply(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType =
- unique(new JavaMethodType(paramNames)(paramTypesExp, resultTypeExp))
+ def apply(paramNames: List[TermName])(paramInfosExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType =
+ unique(new JavaMethodType(paramNames)(paramInfosExp, resultTypeExp))
}
object ImplicitMethodType extends MethodTypeCompanion {
- def apply(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType =
- checkValid(unique(new ImplicitMethodType(paramNames)(paramTypesExp, resultTypeExp)))
+ def apply(paramNames: List[TermName])(paramInfosExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType =
+ checkValid(unique(new ImplicitMethodType(paramNames)(paramInfosExp, 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. */
- abstract case class ExprType(resType: Type)
- extends CachedProxyType with TermType with MethodicType {
- override def resultType(implicit ctx: Context): Type = resType
- override def underlying(implicit ctx: Context): Type = resType
- protected def computeSignature(implicit ctx: Context): Signature = resultSignature
- def derivedExprType(resType: Type)(implicit ctx: Context) =
- if (resType eq this.resType) this else ExprType(resType)
- override def computeHash = doHash(resType)
+ Some((mt.paramNames, mt.paramInfos, mt.resultType))
}
- final class CachedExprType(resultType: Type) extends ExprType(resultType)
-
- object ExprType {
- def apply(resultType: Type)(implicit ctx: Context) = {
- assertUnerased()
- unique(new CachedExprType(resultType))
- }
- }
-
- /** A type lambda of the form `[v_0 X_0, ..., v_n X_n] => T` */
- class PolyType(val paramNames: List[TypeName], val variances: List[Int])(
- paramBoundsExp: PolyType => List[TypeBounds], resultTypeExp: PolyType => Type)
- extends CachedProxyType with BindingType with MethodOrPoly {
-
- /** The bounds of the type parameters */
- val paramBounds: List[TypeBounds] = paramBoundsExp(this)
-
- /** The result type of a PolyType / body of a type lambda */
- val resType: Type = resultTypeExp(this)
-
- assert(resType.isInstanceOf[TermType], this)
- assert(paramNames.nonEmpty)
-
- protected def computeSignature(implicit ctx: Context) = resultSignature
+ trait TypeLambda extends LambdaType {
+ type ThisName = TypeName
+ type PInfo = TypeBounds
+ type This <: TypeLambda
- def isPolymorphicMethodType: Boolean = resType match {
- case _: MethodType => true
- case _ => false
- }
+ def isDependent(implicit ctx: Context): Boolean = true
+ def isParamDependent(implicit ctx: Context): Boolean = true
- /** PolyParam references to all type parameters of this type */
- lazy val paramRefs: List[PolyParam] = paramNames.indices.toList.map(PolyParam(this, _))
+ def newParamRef(n: Int) = TypeParamRef(this, n)
lazy val typeParams: List[LambdaParam] =
paramNames.indices.toList.map(new LambdaParam(this, _))
- override def resultType(implicit ctx: Context) = resType
- override def underlying(implicit ctx: Context) = resType
-
- /** Instantiate result type by substituting parameters with given arguments */
- final def instantiate(argTypes: List[Type])(implicit ctx: Context): Type =
- resultType.substParams(this, argTypes)
-
/** Instantiate parameter bounds by substituting parameters with given arguments */
- final def instantiateBounds(argTypes: List[Type])(implicit ctx: Context): List[TypeBounds] =
- paramBounds.mapConserve(_.substParams(this, argTypes).bounds)
-
- def newLikeThis(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): PolyType =
- PolyType.apply(paramNames, variances)(
- x => paramBounds mapConserve (_.subst(this, x).bounds),
- x => resType.subst(this, x))
-
- def derivedPolyType(paramNames: List[TypeName] = this.paramNames,
- paramBounds: List[TypeBounds] = this.paramBounds,
- resType: Type = this.resType)(implicit ctx: Context) =
- if ((paramNames eq this.paramNames) && (paramBounds eq this.paramBounds) && (resType eq this.resType)) this
- else newLikeThis(paramNames, paramBounds, resType)
+ final def instantiateBounds(argTypes: List[Type])(implicit ctx: Context): List[Type] =
+ paramInfos.mapConserve(_.substParams(this, argTypes))
- def derivedLambdaAbstraction(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): Type =
+ def derivedLambdaAbstraction(paramNames: List[TypeName], paramInfos: List[TypeBounds], resType: Type)(implicit ctx: Context): Type =
resType match {
case resType @ TypeAlias(alias) =>
- resType.derivedTypeAlias(newLikeThis(paramNames, paramBounds, alias))
+ resType.derivedTypeAlias(newLikeThis(paramNames, paramInfos, alias))
case resType @ TypeBounds(lo, hi) =>
resType.derivedTypeBounds(
- if (lo.isRef(defn.NothingClass)) lo else newLikeThis(paramNames, paramBounds, lo),
- newLikeThis(paramNames, paramBounds, hi))
+ if (lo.isRef(defn.NothingClass)) lo else newLikeThis(paramNames, paramInfos, lo),
+ newLikeThis(paramNames, paramInfos, hi))
case _ =>
- derivedPolyType(paramNames, paramBounds, resType)
+ derivedLambdaType(paramNames, paramInfos, resType)
}
+ }
+
+ /** A type lambda of the form `[X_0 B_0, ..., X_n B_n] => T`
+ * Variances are encoded in parameter names. A name starting with `+`
+ * designates a covariant parameter, a name starting with `-` designates
+ * a contravariant parameter, and every other name designates a non-variant parameter.
+ *
+ * @param paramNames The names `X_0`, ..., `X_n`
+ * @param paramInfosExp A function that, given the polytype itself, returns the
+ * parameter bounds `B_1`, ..., `B_n`
+ * @param resultTypeExp A function that, given the polytype itself, returns the
+ * result type `T`.
+ */
+ class HKTypeLambda(val paramNames: List[TypeName])(
+ paramInfosExp: HKTypeLambda => List[TypeBounds], resultTypeExp: HKTypeLambda => Type)
+ extends HKLambda with TypeLambda {
+ type This = HKTypeLambda
+ def companion = HKTypeLambda
+
+ val paramInfos: List[TypeBounds] = paramInfosExp(this)
+ val resType: Type = resultTypeExp(this)
+
+ assert(resType.isInstanceOf[TermType], this)
+ assert(paramNames.nonEmpty)
+
+ protected def prefixString = "HKTypeLambda"
+ }
+
+ /** The type of a polymorphic method. It has the same form as HKTypeLambda,
+ * except it applies to terms and parameters do not have variances.
+ */
+ class PolyType(val paramNames: List[TypeName])(
+ paramInfosExp: PolyType => List[TypeBounds], resultTypeExp: PolyType => Type)
+ extends MethodOrPoly with TypeLambda {
+
+ type This = PolyType
+ def companion = PolyType
+
+ val paramInfos: List[TypeBounds] = paramInfosExp(this)
+ val resType: Type = resultTypeExp(this)
+
+ assert(resType.isInstanceOf[TermType], this)
+ assert(paramNames.nonEmpty)
/** Merge nested polytypes into one polytype. nested polytypes are normally not supported
* but can arise as temporary data structures.
@@ -2640,67 +2742,95 @@ object Types {
case that: PolyType =>
val shift = new TypeMap {
def apply(t: Type) = t match {
- case PolyParam(`that`, n) => PolyParam(that, n + paramNames.length)
+ case TypeParamRef(`that`, n) => TypeParamRef(that, n + paramNames.length)
case t => mapOver(t)
}
}
- PolyType(paramNames ++ that.paramNames, variances ++ that.variances)(
- x => this.paramBounds.mapConserve(_.subst(this, x).bounds) ++
- that.paramBounds.mapConserve(shift(_).subst(that, x).bounds),
+ PolyType(paramNames ++ that.paramNames)(
+ x => this.paramInfos.mapConserve(_.subst(this, x).bounds) ++
+ that.paramInfos.mapConserve(shift(_).subst(that, x).bounds),
x => shift(that.resultType).subst(that, x).subst(this, x))
case _ => this
}
- /** The type `[tparams := paramRefs] tp`, where `tparams` can be
- * either a list of type parameter symbols or a list of lambda parameters
- */
- def lifted(tparams: List[TypeParamInfo], tp: Type)(implicit ctx: Context): Type =
- tparams match {
- case LambdaParam(poly, _) :: _ => tp.subst(poly, this)
- case tparams: List[Symbol @unchecked] => tp.subst(tparams, paramRefs)
- }
+ protected def prefixString = "PolyType"
+ }
- override def equals(other: Any) = other match {
- case other: PolyType =>
- other.paramNames == this.paramNames &&
- other.paramBounds == this.paramBounds &&
- other.resType == this.resType &&
- other.variances == this.variances
- case _ => false
+ object HKTypeLambda extends TypeLambdaCompanion[HKTypeLambda] {
+ def apply(paramNames: List[TypeName])(
+ paramInfosExp: HKTypeLambda => List[TypeBounds],
+ resultTypeExp: HKTypeLambda => Type)(implicit ctx: Context): HKTypeLambda = {
+ unique(new HKTypeLambda(paramNames)(paramInfosExp, resultTypeExp))
}
- override def toString = s"PolyType($variances, $paramNames, $paramBounds, $resType)"
+ def unapply(tl: HKTypeLambda): Some[(List[LambdaParam], Type)] =
+ Some((tl.typeParams, tl.resType))
+
+ def any(n: Int)(implicit ctx: Context) =
+ apply(syntheticParamNames(n))(
+ pt => List.fill(n)(TypeBounds.empty), pt => defn.AnyType)
- override def computeHash = doHash(variances ::: paramNames, resType, paramBounds)
+ override def paramName(param: ParamInfo.Of[TypeName])(implicit ctx: Context): TypeName =
+ param.paramName.withVariance(param.paramVariance)
+
+ /** Distributes Lambda inside type bounds. Examples:
+ *
+ * type T[X] = U becomes type T = [X] -> U
+ * type T[X] <: U becomes type T >: Nothign <: ([X] -> U)
+ * type T[X] >: L <: U becomes type T >: ([X] -> L) <: ([X] -> U)
+ */
+ override def fromParams[PI <: ParamInfo.Of[TypeName]](params: List[PI], resultType: Type)(implicit ctx: Context): Type = {
+ def expand(tp: Type) = super.fromParams(params, tp)
+ resultType match {
+ case rt: TypeAlias =>
+ rt.derivedTypeAlias(expand(rt.alias))
+ case rt @ TypeBounds(lo, hi) =>
+ rt.derivedTypeBounds(
+ if (lo.isRef(defn.NothingClass)) lo else expand(lo), expand(hi))
+ case rt =>
+ expand(rt)
+ }
+ }
}
- object PolyType {
- def apply(paramNames: List[TypeName], variances: List[Int])(
- paramBoundsExp: PolyType => List[TypeBounds],
+ object PolyType extends TypeLambdaCompanion[PolyType] {
+ def apply(paramNames: List[TypeName])(
+ paramInfosExp: PolyType => List[TypeBounds],
resultTypeExp: PolyType => Type)(implicit ctx: Context): PolyType = {
- unique(new PolyType(paramNames, variances)(paramBoundsExp, resultTypeExp))
+ unique(new PolyType(paramNames)(paramInfosExp, resultTypeExp))
}
def unapply(tl: PolyType): Some[(List[LambdaParam], Type)] =
Some((tl.typeParams, tl.resType))
def any(n: Int)(implicit ctx: Context) =
- apply(tpnme.syntheticTypeParamNames(n), List.fill(n)(0))(
+ apply(syntheticParamNames(n))(
pt => List.fill(n)(TypeBounds.empty), pt => defn.AnyType)
}
+ private object DepStatus {
+ type DependencyStatus = Byte
+ final val Unknown: DependencyStatus = 0 // not yet computed
+ final val NoDeps: DependencyStatus = 1 // no dependent parameters found
+ final val FalseDeps: DependencyStatus = 2 // all dependent parameters are prefixes of non-depended alias types
+ final val TrueDeps: DependencyStatus = 3 // some truly dependent parameters exist
+ final val StatusMask: DependencyStatus = 3 // the bits indicating actual dependency status
+ final val Provisional: DependencyStatus = 4 // set if dependency status can still change due to type variable instantiations
+ }
+
// ----- HK types: LambdaParam, HKApply ---------------------
/** The parameter of a type lambda */
- case class LambdaParam(tl: PolyType, n: Int) extends TypeParamInfo {
- def isTypeParam(implicit ctx: Context) = true
- def paramName(implicit ctx: Context): TypeName = tl.paramNames(n)
- def paramBounds(implicit ctx: Context): TypeBounds = tl.paramBounds(n)
- def paramBoundsAsSeenFrom(pre: Type)(implicit ctx: Context): TypeBounds = paramBounds
- def paramBoundsOrCompleter(implicit ctx: Context): Type = paramBounds
- def paramVariance(implicit ctx: Context): Int = tl.variances(n)
- def toArg: Type = PolyParam(tl, n)
- def paramRef(implicit ctx: Context): Type = PolyParam(tl, n)
+ case class LambdaParam(tl: TypeLambda, n: Int) extends ParamInfo {
+ type ThisName = TypeName
+ def isTypeParam(implicit ctx: Context) = tl.paramNames.head.isTypeName
+ def paramName(implicit ctx: Context) = tl.paramNames(n)
+ def paramInfo(implicit ctx: Context) = tl.paramInfos(n)
+ def paramInfoAsSeenFrom(pre: Type)(implicit ctx: Context) = paramInfo
+ def paramInfoOrCompleter(implicit ctx: Context): Type = paramInfo
+ def paramVariance(implicit ctx: Context): Int = tl.paramNames(n).variance
+ def toArg: Type = TypeParamRef(tl, n)
+ def paramRef(implicit ctx: Context): Type = TypeParamRef(tl, n)
}
/** A higher kinded type application `C[T_1, ..., T_n]` */
@@ -2715,7 +2845,7 @@ object Types {
override def superType(implicit ctx: Context): Type = {
if (ctx.period != validSuper) {
cachedSuper = tycon match {
- case tp: PolyType => defn.AnyType
+ case tp: HKTypeLambda => defn.AnyType
case tp: TypeVar if !tp.inst.exists =>
// supertype not stable, since underlying might change
return tp.underlying.applyIfParameterized(args)
@@ -2739,9 +2869,9 @@ object Types {
NoType
}
- def typeParams(implicit ctx: Context): List[TypeParamInfo] = {
+ def typeParams(implicit ctx: Context): List[ParamInfo] = {
val tparams = tycon.typeParams
- if (tparams.isEmpty) PolyType.any(args.length).typeParams else tparams
+ if (tparams.isEmpty) HKTypeLambda.any(args.length).typeParams else tparams
}
def derivedAppliedType(tycon: Type, args: List[Type])(implicit ctx: Context): Type =
@@ -2753,8 +2883,8 @@ object Types {
protected def checkInst(implicit ctx: Context): this.type = {
def check(tycon: Type): Unit = tycon.stripTypeVar match {
case tycon: TypeRef if !tycon.symbol.isClass =>
- case _: PolyParam | _: ErrorType | _: WildcardType =>
- case _: PolyType =>
+ case _: TypeParamRef | _: ErrorType | _: WildcardType =>
+ case _: TypeLambda =>
assert(args.exists(_.isInstanceOf[TypeBounds]), s"unreduced type apply: $this")
case tycon: AnnotatedType =>
check(tycon.underlying)
@@ -2773,92 +2903,61 @@ object Types {
unique(new CachedHKApply(tycon, args)).checkInst
}
- // ----- Bound types: MethodParam, PolyParam --------------------------
+ // ----- BoundTypes: ParamRef, RecThis ----------------------------------------
abstract class BoundType extends CachedProxyType with ValueType {
type BT <: Type
- def binder: BT
- // Dotty deviation: copyBoundType was copy, but
- // dotty generates copy methods always automatically, and therefore
- // does not accept same-named method definitions in subclasses.
- // Scala2x, on the other hand, requires them (not sure why!)
+ val binder: BT
def copyBoundType(bt: BT): Type
}
- abstract class ParamType extends BoundType {
+ abstract class ParamRef extends BoundType {
+ type BT <: LambdaType
def paramNum: Int
- def paramName: Name
- }
-
- abstract case class MethodParam(binder: MethodType, paramNum: Int) extends ParamType with SingletonType {
- type BT = MethodType
-
- def paramName = binder.paramNames(paramNum)
+ def paramName: binder.ThisName = binder.paramNames(paramNum)
- override def underlying(implicit ctx: Context): Type = binder.paramTypes(paramNum)
- def copyBoundType(bt: BT) = new MethodParamImpl(bt, paramNum)
+ override def underlying(implicit ctx: Context): Type = {
+ val infos = binder.paramInfos
+ if (infos == null) NoType // this can happen if the referenced generic type is not initialized yet
+ else infos(paramNum)
+ }
- // need to customize hashCode and equals to prevent infinite recursion for dep meth types.
- override def computeHash = addDelta(binder.identityHash, paramNum)
+ override def computeHash = doHash(paramNum, binder.identityHash)
override def equals(that: Any) = that match {
- case that: MethodParam =>
+ case that: ParamRef =>
(this.binder eq that.binder) && this.paramNum == that.paramNum
case _ =>
false
}
- override def toString = s"MethodParam($paramName)"
+ override def toString =
+ try s"ParamRef($paramName)"
+ catch {
+ case ex: IndexOutOfBoundsException => s"ParamRef(<bad index: $paramNum>)"
+ }
}
- class MethodParamImpl(binder: MethodType, paramNum: Int) extends MethodParam(binder, paramNum)
-
- object MethodParam {
- def apply(binder: MethodType, paramNum: Int)(implicit ctx: Context): MethodParam = {
- assertUnerased()
- new MethodParamImpl(binder, paramNum)
- }
+ case class TermParamRef(binder: TermLambda, paramNum: Int) extends ParamRef {
+ type BT = TermLambda
+ def copyBoundType(bt: BT) = TermParamRef(bt, paramNum)
}
- /** TODO Some docs would be nice here! */
- case class PolyParam(binder: PolyType, paramNum: Int) extends ParamType {
- type BT = PolyType
- def copyBoundType(bt: BT) = PolyParam(bt, paramNum)
+ case class TypeParamRef(binder: TypeLambda, paramNum: Int) extends ParamRef {
+ type BT = TypeLambda
+ def copyBoundType(bt: BT) = TypeParamRef(bt, paramNum)
/** Looking only at the structure of `bound`, is one of the following true?
* - fromBelow and param <:< bound
* - !fromBelow and param >:> bound
*/
def occursIn(bound: Type, fromBelow: Boolean)(implicit ctx: Context): Boolean = bound.stripTypeVar match {
- case bound: PolyParam => bound == this
+ case bound: ParamRef => bound == this
case bound: AndOrType =>
def occ1 = occursIn(bound.tp1, fromBelow)
def occ2 = occursIn(bound.tp2, fromBelow)
if (fromBelow == bound.isAnd) occ1 && occ2 else occ1 || occ2
case _ => false
}
-
- def paramName = binder.paramNames(paramNum)
-
- override def underlying(implicit ctx: Context): Type = {
- val bounds = binder.paramBounds
- if (bounds == null) NoType // this can happen if the referenced generic type is not initialized yet
- else bounds(paramNum)
- }
- // no customized hashCode/equals needed because cycle is broken in PolyType
- override def toString =
- try s"PolyParam($paramName)"
- catch {
- case ex: IndexOutOfBoundsException => s"PolyParam(<bad index: $paramNum>)"
- }
-
- override def computeHash = doHash(paramNum, binder.identityHash)
-
- override def equals(that: Any) = that match {
- case that: PolyParam =>
- (this.binder eq that.binder) && this.paramNum == that.paramNum
- case _ =>
- false
- }
}
/** a self-reference to an enclosing recursive type. */
@@ -2929,7 +3028,7 @@ object Types {
* `owningTree` and `owner` are used to determine whether a type-variable can be instantiated
* at some given point. See `Inferencing#interpolateUndetVars`.
*/
- final class TypeVar(val origin: PolyParam, creatorState: TyperState, val bindingTree: untpd.Tree, val owner: Symbol) extends CachedProxyType with ValueType {
+ final class TypeVar(val origin: TypeParamRef, creatorState: TyperState, val bindingTree: untpd.Tree, val owner: Symbol) extends CachedProxyType with ValueType {
/** The permanent instance type of the variable, or NoType is none is given yet */
private[core] var inst: Type = NoType
@@ -3341,9 +3440,8 @@ object Types {
object SAMType {
def zeroParamClass(tp: Type)(implicit ctx: Context): Type = tp match {
case tp: ClassInfo =>
- def zeroParams(tp: Type): Boolean = tp match {
- case pt: PolyType => zeroParams(pt.resultType)
- case mt: MethodType => mt.paramTypes.isEmpty && !mt.resultType.isInstanceOf[MethodType]
+ def zeroParams(tp: Type): Boolean = tp.stripPoly match {
+ case mt: MethodType => mt.paramInfos.isEmpty && !mt.resultType.isInstanceOf[MethodType]
case et: ExprType => true
case _ => false
}
@@ -3426,12 +3524,11 @@ object Types {
tp.derivedClassInfo(pre)
protected def derivedJavaArrayType(tp: JavaArrayType, elemtp: Type): Type =
tp.derivedJavaArrayType(elemtp)
- protected def derivedMethodType(tp: MethodType, formals: List[Type], restpe: Type): Type =
- tp.derivedMethodType(tp.paramNames, formals, restpe)
protected def derivedExprType(tp: ExprType, restpe: Type): Type =
tp.derivedExprType(restpe)
- protected def derivedPolyType(tp: PolyType, pbounds: List[TypeBounds], restpe: Type): Type =
- tp.derivedPolyType(tp.paramNames, pbounds, restpe)
+ // note: currying needed because Scala2 does not support param-dependencies
+ protected def derivedLambdaType(tp: LambdaType)(formals: List[tp.PInfo], restpe: Type): Type =
+ tp.derivedLambdaType(tp.paramNames, formals, restpe)
/** Map this function over given type */
def mapOver(tp: Type): Type = {
@@ -3461,29 +3558,34 @@ object Types {
variance = -variance
derivedTypeBounds(tp, lo1, this(tp.hi))
- case tp: MethodType =>
- def mapOverMethod = {
- variance = -variance
- val ptypes1 = tp.paramTypes mapConserve this
- variance = -variance
- derivedMethodType(tp, ptypes1, this(tp.resultType))
+ case tp: RecType =>
+ derivedRecType(tp, this(tp.parent))
+
+ case tp: TypeVar =>
+ val inst = tp.instanceOpt
+ if (inst.exists) apply(inst) else tp
+
+ case tp: HKApply =>
+ def mapArg(arg: Type, tparam: ParamInfo): Type = {
+ val saved = variance
+ variance *= tparam.paramVariance
+ try this(arg)
+ finally variance = saved
}
- mapOverMethod
+ derivedAppliedType(tp, this(tp.tycon),
+ tp.args.zipWithConserve(tp.typeParams)(mapArg))
case tp: ExprType =>
derivedExprType(tp, this(tp.resultType))
- case tp: PolyType =>
- def mapOverPoly = {
+ case tp: LambdaType =>
+ def mapOverLambda = {
variance = -variance
- val bounds1 = tp.paramBounds.mapConserve(this).asInstanceOf[List[TypeBounds]]
+ val ptypes1 = tp.paramInfos.mapConserve(this).asInstanceOf[List[tp.PInfo]]
variance = -variance
- derivedPolyType(tp, bounds1, this(tp.resultType))
+ derivedLambdaType(tp)(ptypes1, this(tp.resultType))
}
- mapOverPoly
-
- case tp: RecType =>
- derivedRecType(tp, this(tp.parent))
+ mapOverLambda
case tp @ SuperType(thistp, supertp) =>
derivedSuperType(tp, this(thistp), this(supertp))
@@ -3494,21 +3596,7 @@ object Types {
case tp: ClassInfo =>
mapClassInfo(tp)
- case tp: TypeVar =>
- val inst = tp.instanceOpt
- if (inst.exists) apply(inst) else tp
-
- case tp: HKApply =>
- def mapArg(arg: Type, tparam: TypeParamInfo): Type = {
- val saved = variance
- variance *= tparam.paramVariance
- try this(arg)
- finally variance = saved
- }
- derivedAppliedType(tp, this(tp.tycon),
- tp.args.zipWithConserve(tp.typeParams)(mapArg))
-
- case tp: AndOrType =>
+ case tp: AndOrType =>
derivedAndOrType(tp, this(tp.tp1), this(tp.tp2))
case tp: SkolemType =>
@@ -3689,23 +3777,14 @@ object Types {
this(y, hi)
}
- case tp: MethodType =>
- variance = -variance
- val y = foldOver(x, tp.paramTypes)
- variance = -variance
- this(y, tp.resultType)
+ case tp: RecType =>
+ this(x, tp.parent)
case ExprType(restpe) =>
this(x, restpe)
- case tp: PolyType =>
- variance = -variance
- val y = foldOver(x, tp.paramBounds)
- variance = -variance
- this(y, tp.resultType)
-
- case tp: RecType =>
- this(x, tp.parent)
+ case tp: TypeVar =>
+ this(x, tp.underlying)
case SuperType(thistp, supertp) =>
this(this(x, thistp), supertp)
@@ -3714,7 +3793,7 @@ object Types {
this(x, prefix)
case tp @ HKApply(tycon, args) =>
- @tailrec def foldArgs(x: T, tparams: List[TypeParamInfo], args: List[Type]): T =
+ @tailrec def foldArgs(x: T, tparams: List[ParamInfo], args: List[Type]): T =
if (args.isEmpty) {
assert(tparams.isEmpty)
x
@@ -3730,6 +3809,12 @@ object Types {
}
foldArgs(this(x, tycon), tp.typeParams, args)
+ case tp: LambdaType =>
+ variance = -variance
+ val y = foldOver(x, tp.paramInfos)
+ variance = -variance
+ this(y, tp.resultType)
+
case tp: AndOrType =>
this(this(x, tp.tp1), tp.tp2)
@@ -3739,9 +3824,6 @@ object Types {
case AnnotatedType(underlying, annot) =>
this(applyToAnnot(x, annot), underlying)
- case tp: TypeVar =>
- this(x, tp.underlying)
-
case tp: WildcardType =>
this(x, tp.optBounds)
@@ -3804,9 +3886,7 @@ object Types {
apply(x, tp.tref)
case tp: ConstantType =>
apply(x, tp.underlying)
- case tp: MethodParam =>
- apply(x, tp.underlying)
- case tp: PolyParam =>
+ case tp: ParamRef =>
apply(x, tp.underlying)
case _ =>
foldOver(x, tp)
diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
index e0b233ce8..da875c906 100644
--- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
+++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
@@ -199,7 +199,7 @@ class ClassfileParser(
def stripOuterParamFromConstructor() = innerClasses.get(currentClassName) match {
case Some(entry) if !isStatic(entry.jflags) =>
val mt @ MethodTpe(paramNames, paramTypes, resultType) = denot.info
- denot.info = mt.derivedMethodType(paramNames.tail, paramTypes.tail, resultType)
+ denot.info = mt.derivedLambdaType(paramNames.tail, paramTypes.tail, resultType)
case _ =>
}
@@ -209,7 +209,7 @@ class ClassfileParser(
def normalizeConstructorInfo() = {
val mt @ MethodType(paramNames) = denot.info
val rt = classRoot.typeRef appliedTo (classRoot.typeParams map (_.typeRef))
- denot.info = mt.derivedMethodType(paramNames, mt.paramTypes, rt)
+ denot.info = mt.derivedLambdaType(paramNames, mt.paramInfos, rt)
addConstructorTypeParams(denot)
}
@@ -975,7 +975,7 @@ class ClassfileParser(
if (name == nme.CONSTRUCTOR)
tpe match {
case tp: MethodType =>
- tp.derivedMethodType(tp.paramNames, tp.paramTypes, ownerTpe)
+ tp.derivedLambdaType(tp.paramNames, tp.paramInfos, ownerTpe)
}
p = (name, tpe)
values(index) = p
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
index cb1b56c3c..8b2255e94 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
@@ -151,8 +151,9 @@ Standard-Section: "ASTs" TopLevelStat*
BIND Length boundName_NameRef bounds_Type
// for type-variables defined in a type pattern
BYNAMEtype underlying_Type
- POLYtype Length result_Type NamesTypes // variance encoded in front of name: +/-/=
+ POLYtype Length result_Type NamesTypes
METHODtype Length result_Type NamesTypes // needed for refinements
+ TYPELAMBDAtype Length result_Type NamesTypes // variance encoded in front of name: +/-/(nothing)
PARAMtype Length binder_ASTref paramNum_Nat // needed for refinements
SHARED type_ASTRef
NamesTypes = NameType*
@@ -345,9 +346,10 @@ object TastyFormat {
final val ORtpt = 169
final val METHODtype = 170
final val POLYtype = 171
- final val POLYtpt = 172
- final val PARAMtype = 173
- final val ANNOTATION = 174
+ final val TYPELAMBDAtype = 172
+ final val LAMBDAtpt = 173
+ final val PARAMtype = 174
+ final val ANNOTATION = 175
final val firstSimpleTreeTag = UNITconst
final val firstNatTreeTag = SHARED
@@ -397,7 +399,7 @@ object TastyFormat {
| SINGLETONtpt
| REFINEDtpt
| APPLIEDtpt
- | POLYtpt
+ | LAMBDAtpt
| TYPEBOUNDStpt
| ANNOTATEDtpt
| ANDtpt
@@ -528,8 +530,9 @@ object TastyFormat {
case BYNAMEtype => "BYNAMEtype"
case BYNAMEtpt => "BYNAMEtpt"
case POLYtype => "POLYtype"
- case POLYtpt => "POLYtpt"
case METHODtype => "METHODtype"
+ case TYPELAMBDAtype => "TYPELAMBDAtype"
+ case LAMBDAtpt => "LAMBDAtpt"
case PARAMtype => "PARAMtype"
case ANNOTATION => "ANNOTATION"
case PRIVATEqualified => "PRIVATEqualified"
@@ -543,11 +546,7 @@ object TastyFormat {
case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM | NAMEDARG | RETURN | BIND |
SELFDEF | REFINEDtype => 1
case RENAMED | PARAMtype => 2
- case POLYtype | METHODtype => -1
+ case POLYtype | METHODtype | TYPELAMBDAtype => -1
case _ => 0
}
-
- /** Map between variances and name prefixes */
- val varianceToPrefix = Map(-1 -> '-', 0 -> '=', 1 -> '+')
- val prefixToVariance = Map('-' -> -1, '=' -> 0, '+' -> 1)
}
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala
index fb37c9e7d..ce3722ff1 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala
@@ -77,7 +77,7 @@ class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) {
printName(); printTree(); printTrees()
case RETURN =>
printNat(); printTrees()
- case METHODtype | POLYtype =>
+ case METHODtype | POLYtype | TYPELAMBDAtype =>
printTree()
until(end) { printName(); printTree() }
case PARAMtype =>
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
index 80270aa25..902d01c21 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
@@ -253,23 +253,21 @@ class TreePickler(pickler: TastyPickler) {
case tpe: ExprType =>
writeByte(BYNAMEtype)
pickleType(tpe.underlying)
- case tpe: PolyType =>
- writeByte(POLYtype)
- val paramNames = tpe.typeParams.map(tparam =>
- varianceToPrefix(tparam.paramVariance) +: tparam.paramName)
- pickleMethodic(tpe.resultType, paramNames, tpe.paramBounds)
+ case tpe: HKTypeLambda =>
+ pickleMethodic(TYPELAMBDAtype, tpe)
+ case tpe: PolyType if richTypes =>
+ pickleMethodic(POLYtype, tpe)
case tpe: MethodType if richTypes =>
- writeByte(METHODtype)
- pickleMethodic(tpe.resultType, tpe.paramNames, tpe.paramTypes)
- case tpe: PolyParam =>
- if (!pickleParamType(tpe))
+ pickleMethodic(METHODtype, tpe)
+ case tpe: TypeParamRef =>
+ if (!pickleParamRef(tpe))
// TODO figure out why this case arises in e.g. pickling AbstractFileReader.
ctx.typerState.constraint.entry(tpe) match {
case TypeBounds(lo, hi) if lo eq hi => pickleNewType(lo, richTypes)
case _ => assert(false, s"orphan poly parameter: $tpe")
}
- case tpe: MethodParam =>
- assert(pickleParamType(tpe), s"orphan method parameter: $tpe")
+ case tpe: TermParamRef =>
+ assert(pickleParamRef(tpe), s"orphan method parameter: $tpe")
case tpe: LazyRef =>
pickleType(tpe.ref)
}} catch {
@@ -283,15 +281,17 @@ class TreePickler(pickler: TastyPickler) {
pickleName(qualifiedName(pkg))
}
- def pickleMethodic(result: Type, names: List[Name], types: List[Type])(implicit ctx: Context) =
+ def pickleMethodic(tag: Int, tpe: LambdaType)(implicit ctx: Context) = {
+ writeByte(tag)
withLength {
- pickleType(result, richTypes = true)
- (names, types).zipped.foreach { (name, tpe) =>
+ pickleType(tpe.resultType, richTypes = true)
+ (tpe.paramNames, tpe.paramInfos).zipped.foreach { (name, tpe) =>
pickleName(name); pickleType(tpe)
}
}
+ }
- def pickleParamType(tpe: ParamType)(implicit ctx: Context): Boolean = {
+ def pickleParamRef(tpe: ParamRef)(implicit ctx: Context): Boolean = {
val binder = pickledTypes.get(tpe.binder)
val pickled = binder != null
if (pickled) {
@@ -555,8 +555,8 @@ class TreePickler(pickler: TastyPickler) {
case Annotated(tree, annot) =>
writeByte(ANNOTATEDtpt)
withLength { pickleTree(tree); pickleTree(annot.tree) }
- case PolyTypeTree(tparams, body) =>
- writeByte(POLYtpt)
+ case LambdaTypeTree(tparams, body) =>
+ writeByte(LAMBDAtpt)
withLength { pickleParams(tparams); pickleTree(body) }
case TypeBoundsTree(lo, hi) =>
writeByte(TYPEBOUNDStpt)
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
index 88b6eef7a..4db995e10 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
@@ -38,7 +38,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
/** A map from addresses of type entries to the types they define.
* Currently only populated for types that might be recursively referenced
- * from within themselves (i.e. RefinedTypes, PolyTypes, MethodTypes).
+ * from within themselves (i.e. RecTypes, LambdaTypes).
*/
private val typeAtAddr = new mutable.HashMap[Addr, Type]
@@ -227,11 +227,17 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
def readLengthType(): Type = {
val end = readEnd()
- def readNamesSkipParams: (List[Name], TreeReader) = {
+ def readMethodic[N <: Name, PInfo <: Type, LT <: LambdaType]
+ (companion: LambdaTypeCompanion[N, PInfo, LT], nameMap: Name => N): LT = {
val nameReader = fork
nameReader.skipTree() // skip result
val paramReader = nameReader.fork
- (nameReader.readParamNames(end), paramReader)
+ val paramNames = nameReader.readParamNames(end).map(nameMap)
+ val result = companion(paramNames)(
+ pt => registeringType(pt, paramReader.readParamTypes[PInfo](end)),
+ pt => readType())
+ goto(end)
+ result
}
val result =
@@ -268,25 +274,14 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
registerSym(start, sym)
TypeRef.withFixedSym(NoPrefix, sym.name, sym)
case POLYtype =>
- val (rawNames, paramReader) = readNamesSkipParams
- val (variances, paramNames) = rawNames
- .map(name => (prefixToVariance(name.head), name.tail.toTypeName)).unzip
- val result = PolyType(paramNames, variances)(
- pt => registeringType(pt, paramReader.readParamTypes[TypeBounds](end)),
- pt => readType())
- goto(end)
- result
+ readMethodic(PolyType, _.toTypeName)
case METHODtype =>
- val (names, paramReader) = readNamesSkipParams
- val result = MethodType(names.map(_.toTermName))(
- mt => registeringType(mt, paramReader.readParamTypes[Type](end)),
- mt => readType())
- goto(end)
- result
+ readMethodic(MethodType, _.toTermName)
+ case TYPELAMBDAtype =>
+ readMethodic(HKTypeLambda, _.toTypeName)
case PARAMtype =>
readTypeRef() match {
- case binder: PolyType => PolyParam(binder, readNat())
- case binder: MethodType => MethodParam(binder, readNat())
+ case binder: LambdaType => binder.newParamRef(readNat())
}
case CLASSconst =>
ConstantType(Constant(readType()))
@@ -412,7 +407,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
}
def isAbstractType(ttag: Int)(implicit ctx: Context): Boolean = nextUnsharedTag match {
- case POLYtpt =>
+ case LAMBDAtpt =>
val rdr = fork
rdr.reader.readByte() // tag
rdr.reader.readNat() // length
@@ -1035,11 +1030,11 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
OrTypeTree(readTpt(), readTpt())
case ANNOTATEDtpt =>
Annotated(readTpt(), readTerm())
- case POLYtpt =>
+ case LAMBDAtpt =>
val localCtx = localNonClassCtx
val tparams = readParams[TypeDef](TYPEPARAM)(localCtx)
val body = readTpt()(localCtx)
- PolyTypeTree(tparams, body)
+ LambdaTypeTree(tparams, body)
case TYPEBOUNDStpt =>
TypeBoundsTree(readTpt(), readTpt())
case _ =>
diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
index 688a2d007..cf99bb022 100644
--- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
+++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
@@ -42,13 +42,15 @@ object Scala2Unpickler {
/** Convert temp poly type to poly type and leave other types alone. */
def translateTempPoly(tp: Type)(implicit ctx: Context): Type = tp match {
- case TempPolyType(tparams, restpe) => restpe.LambdaAbstract(tparams)
+ case TempPolyType(tparams, restpe) =>
+ (if (tparams.head.owner.isTerm) PolyType else HKTypeLambda)
+ .fromParams(tparams, restpe)
case tp => tp
}
def addConstructorTypeParams(denot: SymDenotation)(implicit ctx: Context) = {
assert(denot.isConstructor)
- denot.info = denot.info.LambdaAbstract(denot.owner.typeParams)
+ denot.info = PolyType.fromParams(denot.owner.typeParams, denot.info)
}
/** Convert array parameters denoting a repeated parameter of a Java method
@@ -56,7 +58,7 @@ object Scala2Unpickler {
*/
def arrayToRepeated(tp: Type)(implicit ctx: Context): Type = tp match {
case tp: MethodType =>
- val lastArg = tp.paramTypes.last
+ val lastArg = tp.paramInfos.last
assert(lastArg isRef defn.ArrayClass)
val elemtp0 :: Nil = lastArg.baseArgInfos(defn.ArrayClass)
val elemtp = elemtp0 match {
@@ -65,12 +67,12 @@ object Scala2Unpickler {
case _ =>
elemtp0
}
- tp.derivedMethodType(
+ tp.derivedLambdaType(
tp.paramNames,
- tp.paramTypes.init :+ defn.RepeatedParamType.appliedTo(elemtp),
+ tp.paramInfos.init :+ defn.RepeatedParamType.appliedTo(elemtp),
tp.resultType)
case tp: PolyType =>
- tp.derivedPolyType(tp.paramNames, tp.paramBounds, arrayToRepeated(tp.resultType))
+ tp.derivedLambdaType(tp.paramNames, tp.paramInfos, arrayToRepeated(tp.resultType))
}
def ensureConstructor(cls: ClassSymbol, scope: Scope)(implicit ctx: Context) =
@@ -745,7 +747,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
TempClassInfoType(until(end, readTypeRef), symScope(clazz), clazz)
case METHODtpe | IMPLICITMETHODtpe =>
val restpe = readTypeRef()
- val params = until(end, readSymbolRef)
+ val params = until(end, readSymbolRef).asInstanceOf[List[TermSymbol]]
def isImplicit =
tag == IMPLICITMETHODtpe ||
params.nonEmpty && (params.head is Implicit)