aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core
diff options
context:
space:
mode:
authorGuillaume Martres <smarter@ubuntu.com>2016-10-13 01:49:08 +0200
committerGitHub <noreply@github.com>2016-10-13 01:49:08 +0200
commit1c62d0557417612fb90108fd6a3728d7c510f968 (patch)
treef354c07cba6a589474d4a9a6a528ec21e32702b9 /src/dotty/tools/dotc/core
parentf738201973f6965b861fe4b0b580c2dfed61f158 (diff)
parent9e74d72d3638f70285aff88c53bab6cc57223d16 (diff)
downloaddotty-1c62d0557417612fb90108fd6a3728d7c510f968.tar.gz
dotty-1c62d0557417612fb90108fd6a3728d7c510f968.tar.bz2
dotty-1c62d0557417612fb90108fd6a3728d7c510f968.zip
Merge pull request #1560 from dotty-staging/change-one-polytype
Harmonize PolyType and TypeLambda
Diffstat (limited to 'src/dotty/tools/dotc/core')
-rw-r--r--src/dotty/tools/dotc/core/Constraint.scala10
-rw-r--r--src/dotty/tools/dotc/core/ConstraintHandling.scala10
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala6
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala285
-rw-r--r--src/dotty/tools/dotc/core/OrderingConstraint.scala46
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala7
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala20
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala114
-rw-r--r--src/dotty/tools/dotc/core/TypeErasure.scala20
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala1
-rw-r--r--src/dotty/tools/dotc/core/TyperState.scala2
-rw-r--r--src/dotty/tools/dotc/core/Types.scala232
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreePickler.scala5
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala4
14 files changed, 364 insertions, 398 deletions
diff --git a/src/dotty/tools/dotc/core/Constraint.scala b/src/dotty/tools/dotc/core/Constraint.scala
index 91e70b7b5..c99b748b7 100644
--- a/src/dotty/tools/dotc/core/Constraint.scala
+++ b/src/dotty/tools/dotc/core/Constraint.scala
@@ -23,7 +23,7 @@ abstract class Constraint extends Showable {
type This <: Constraint
/** Does the constraint's domain contain the type parameters of `pt`? */
- def contains(pt: GenericType): Boolean
+ def contains(pt: PolyType): Boolean
/** Does the constraint's domain contain the type parameter `param`? */
def contains(param: PolyParam): Boolean
@@ -79,7 +79,7 @@ abstract class Constraint extends Showable {
* satisfiability but will solved to give instances of
* type variables.
*/
- def add(poly: GenericType, tvars: List[TypeVar])(implicit ctx: Context): This
+ def add(poly: PolyType, 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`.
@@ -121,13 +121,13 @@ abstract class Constraint extends Showable {
* all type parameters of the entry are associated with type variables
* which have their `inst` fields set.
*/
- def isRemovable(pt: GenericType): Boolean
+ def isRemovable(pt: PolyType): Boolean
/** A new constraint with all entries coming from `pt` removed. */
- def remove(pt: GenericType)(implicit ctx: Context): This
+ def remove(pt: PolyType)(implicit ctx: Context): This
/** The polytypes constrained by this constraint */
- def domainPolys: List[GenericType]
+ def domainPolys: List[PolyType]
/** The polytype parameters constrained by this constraint */
def domainParams: List[PolyParam]
diff --git a/src/dotty/tools/dotc/core/ConstraintHandling.scala b/src/dotty/tools/dotc/core/ConstraintHandling.scala
index 84f531385..3835d553c 100644
--- a/src/dotty/tools/dotc/core/ConstraintHandling.scala
+++ b/src/dotty/tools/dotc/core/ConstraintHandling.scala
@@ -44,10 +44,10 @@ trait ConstraintHandling {
try op finally alwaysFluid = saved
}
- /** We are currently comparing lambdas. Used as a flag for
+ /** We are currently comparing polytypes. Used as a flag for
* optimization: when `false`, no need to do an expensive `pruneLambdaParams`
*/
- protected var comparingLambdas = false
+ protected var comparedPolyTypes: Set[PolyType] = Set.empty
private def addOneBound(param: PolyParam, bound: Type, isUpper: Boolean): Boolean =
!constraint.contains(param) || {
@@ -316,12 +316,12 @@ trait ConstraintHandling {
* missing.
*/
def pruneLambdaParams(tp: Type) =
- if (comparingLambdas && param.binder.isInstanceOf[PolyType]) {
+ if (comparedPolyTypes.nonEmpty) {
val approx = new ApproximatingTypeMap {
def apply(t: Type): Type = t match {
- case t @ PolyParam(tl: TypeLambda, n) =>
+ case t @ PolyParam(pt: PolyType, n) if comparedPolyTypes contains pt =>
val effectiveVariance = if (fromBelow) -variance else variance
- val bounds = tl.paramBounds(n)
+ val bounds = pt.paramBounds(n)
if (effectiveVariance > 0) bounds.lo
else if (effectiveVariance < 0) bounds.hi
else NoType
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index b1c2bc535..50746c61d 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -92,17 +92,17 @@ class Definitions {
}
private def newPolyMethod(cls: ClassSymbol, name: TermName, typeParamCount: Int,
- resultTypeFn: GenericType => Type, flags: FlagSet = EmptyFlags) = {
+ resultTypeFn: PolyType => Type, flags: FlagSet = EmptyFlags) = {
val tparamNames = tpnme.syntheticTypeParamNames(typeParamCount)
val tparamBounds = tparamNames map (_ => TypeBounds.empty)
val ptype = PolyType(tparamNames)(_ => tparamBounds, resultTypeFn)
newMethod(cls, name, ptype, flags)
}
- private def newT1ParameterlessMethod(cls: ClassSymbol, name: TermName, resultTypeFn: GenericType => Type, flags: FlagSet) =
+ private def newT1ParameterlessMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) =
newPolyMethod(cls, name, 1, resultTypeFn, flags)
- private def newT1EmptyParamsMethod(cls: ClassSymbol, name: TermName, resultTypeFn: GenericType => Type, flags: FlagSet) =
+ private def newT1EmptyParamsMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) =
newPolyMethod(cls, name, 1, pt => MethodType(Nil, resultTypeFn(pt)), flags)
private def mkArityArray(name: String, arity: Int, countFrom: Int): Array[TypeRef] = {
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index 0f95fc591..7866d6697 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -6,6 +6,7 @@ import SymDenotations.{ SymDenotation, ClassDenotation, NoDenotation, NotDefined
import Contexts.{Context, ContextBase}
import Names.{Name, PreName}
import Names.TypeName
+import StdNames._
import Symbols.NoSymbol
import Symbols._
import Types._
@@ -247,6 +248,25 @@ object Denotations {
else asSingleDenotation
}
+ /** Handle merge conflict by throwing a `MergeError` exception */
+ private def mergeConflict(tp1: Type, tp2: Type)(implicit ctx: Context): Type = {
+ def showType(tp: Type) = tp match {
+ case ClassInfo(_, cls, _, _, _) => cls.showLocated
+ case bounds: TypeBounds => i"type bounds $bounds"
+ case _ => tp.show
+ }
+ if (true) throw new MergeError(s"cannot merge ${showType(tp1)} with ${showType(tp2)}", tp1, tp2)
+ 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,
+ * 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
+
/** Form a denotation by conjoining with denotation `that`.
*
* NoDenotations are dropped. MultiDenotations are handled by merging
@@ -277,6 +297,50 @@ object Denotations {
*/
def & (that: Denotation, pre: Type, safeIntersection: Boolean = false)(implicit ctx: Context): Denotation = {
+ /** Normally, `tp1 & tp2`. Special cases for matching methods and classes, with
+ * the possibility of raising a merge error.
+ */
+ def infoMeet(tp1: Type, tp2: Type): Type = {
+ if (tp1 eq tp2) tp1
+ else tp1 match {
+ case tp1: TypeBounds =>
+ tp2 match {
+ case tp2: TypeBounds => if (safeIntersection) tp1 safe_& tp2 else tp1 & tp2
+ case tp2: ClassInfo if tp1 contains tp2 => tp2
+ case _ => mergeConflict(tp1, tp2)
+ }
+ case tp1: ClassInfo =>
+ tp2 match {
+ case tp2: ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix & tp2.prefix)
+ case tp2: TypeBounds if tp2 contains tp1 => tp1
+ case _ => mergeConflict(tp1, tp2)
+ }
+ case tp1 @ MethodType(names1, formals1) if isTerm =>
+ tp2 match {
+ case tp2 @ MethodType(names2, formals2) if ctx.typeComparer.matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) &&
+ tp1.isImplicit == tp2.isImplicit =>
+ tp1.derivedMethodType(
+ mergeNames(names1, names2, nme.syntheticParamName),
+ formals1,
+ 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
+ }
+ }
+
/** Try to merge denot1 and denot2 without adding a new signature. */
def mergeDenot(denot1: Denotation, denot2: SingleDenotation): Denotation = denot1 match {
case denot1 @ MultiDenotation(denot11, denot12) =>
@@ -289,96 +353,95 @@ object Denotations {
}
case denot1: SingleDenotation =>
if (denot1 eq denot2) denot1
- else if (denot1.matches(denot2)) {
- val info1 = denot1.info
- val info2 = denot2.info
- val sym1 = denot1.symbol
- val sym2 = denot2.symbol
-
- val sym2Accessible = sym2.isAccessibleFrom(pre)
-
- /** Does `sym1` come before `sym2` in the linearization of `pre`? */
- def precedes(sym1: Symbol, sym2: Symbol) = {
- def precedesIn(bcs: List[ClassSymbol]): Boolean = bcs match {
- case bc :: bcs1 => (sym1 eq bc) || !(sym2 eq bc) && precedesIn(bcs1)
- case Nil => true
- }
- (sym1 ne sym2) &&
- (sym1.derivesFrom(sym2) ||
- !sym2.derivesFrom(sym1) && precedesIn(pre.baseClasses))
- }
+ else if (denot1.matches(denot2)) mergeSingleDenot(denot1, denot2)
+ else NoDenotation
+ }
- /** Similar to SymDenotation#accessBoundary, but without the special cases. */
- def accessBoundary(sym: Symbol) =
- if (sym.is(Private)) sym.owner
- else sym.privateWithin.orElse(
- if (sym.is(Protected)) sym.owner.enclosingPackageClass
- else defn.RootClass
- )
-
- /** Establish a partial order "preference" order between symbols.
- * Give preference to `sym1` over `sym2` if one of the following
- * conditions holds, in decreasing order of weight:
- * 1. sym1 is concrete and sym2 is abstract
- * 2. The owner of sym1 comes before the owner of sym2 in the linearization
- * of the type of the prefix `pre`.
- * 3. The access boundary of sym2 is properly contained in the access
- * boundary of sym1. For protected access, we count the enclosing
- * package as access boundary.
- * 4. sym1 a method but sym2 is not.
- * The aim of these criteria is to give some disambiguation on access which
- * - does not depend on textual order or other arbitrary choices
- * - minimizes raising of doubleDef errors
- */
- def preferSym(sym1: Symbol, sym2: Symbol) =
- sym1.eq(sym2) ||
- sym1.isAsConcrete(sym2) &&
- (!sym2.isAsConcrete(sym1) ||
- precedes(sym1.owner, sym2.owner) ||
- accessBoundary(sym2).isProperlyContainedIn(accessBoundary(sym1)) ||
- sym1.is(Method) && !sym2.is(Method)) ||
- sym1.info.isErroneous
-
- /** Sym preference provided types also override */
- def prefer(sym1: Symbol, sym2: Symbol, info1: Type, info2: Type) =
- preferSym(sym1, sym2) && info1.overrides(info2)
-
- def handleDoubleDef =
- if (preferSym(sym1, sym2)) denot1
- else if (preferSym(sym2, sym1)) denot2
- else doubleDefError(denot1, denot2, pre)
-
- if (sym2Accessible && prefer(sym2, sym1, info2, info1)) denot2
- else {
- val sym1Accessible = sym1.isAccessibleFrom(pre)
- if (sym1Accessible && prefer(sym1, sym2, info1, info2)) denot1
- else if (sym1Accessible && sym2.exists && !sym2Accessible) denot1
- else if (sym2Accessible && sym1.exists && !sym1Accessible) denot2
- else if (isDoubleDef(sym1, sym2)) handleDoubleDef
- else {
- val sym =
- if (!sym1.exists) sym2
- else if (!sym2.exists) sym1
- else if (preferSym(sym2, sym1)) sym2
- else sym1
- val jointInfo =
- try
- if (safeIntersection)
- info1 safe_& info2
- else
- info1 & info2
- catch {
- case ex: MergeError =>
- if (pre.widen.classSymbol.is(Scala2x) || ctx.scala2Mode)
- info1 // follow Scala2 linearization -
- // compare with way merge is performed in SymDenotation#computeMembersNamed
- else
- throw new MergeError(s"${ex.getMessage} as members of type ${pre.show}", ex.tp1, ex.tp2)
- }
- new JointRefDenotation(sym, jointInfo, denot1.validFor & denot2.validFor)
+ /** Try to merge single-denotations. */
+ def mergeSingleDenot(denot1: SingleDenotation, denot2: SingleDenotation): SingleDenotation = {
+ val info1 = denot1.info
+ val info2 = denot2.info
+ val sym1 = denot1.symbol
+ val sym2 = denot2.symbol
+
+ val sym2Accessible = sym2.isAccessibleFrom(pre)
+
+ /** Does `sym1` come before `sym2` in the linearization of `pre`? */
+ def precedes(sym1: Symbol, sym2: Symbol) = {
+ def precedesIn(bcs: List[ClassSymbol]): Boolean = bcs match {
+ case bc :: bcs1 => (sym1 eq bc) || !(sym2 eq bc) && precedesIn(bcs1)
+ case Nil => true
+ }
+ (sym1 ne sym2) &&
+ (sym1.derivesFrom(sym2) ||
+ !sym2.derivesFrom(sym1) && precedesIn(pre.baseClasses))
+ }
+
+ /** Similar to SymDenotation#accessBoundary, but without the special cases. */
+ def accessBoundary(sym: Symbol) =
+ if (sym.is(Private)) sym.owner
+ else sym.privateWithin.orElse(
+ if (sym.is(Protected)) sym.owner.enclosingPackageClass
+ else defn.RootClass)
+
+ /** Establish a partial order "preference" order between symbols.
+ * Give preference to `sym1` over `sym2` if one of the following
+ * conditions holds, in decreasing order of weight:
+ * 1. sym1 is concrete and sym2 is abstract
+ * 2. The owner of sym1 comes before the owner of sym2 in the linearization
+ * of the type of the prefix `pre`.
+ * 3. The access boundary of sym2 is properly contained in the access
+ * boundary of sym1. For protected access, we count the enclosing
+ * package as access boundary.
+ * 4. sym1 a method but sym2 is not.
+ * The aim of these criteria is to give some disambiguation on access which
+ * - does not depend on textual order or other arbitrary choices
+ * - minimizes raising of doubleDef errors
+ */
+ def preferSym(sym1: Symbol, sym2: Symbol) =
+ sym1.eq(sym2) ||
+ sym1.isAsConcrete(sym2) &&
+ (!sym2.isAsConcrete(sym1) ||
+ precedes(sym1.owner, sym2.owner) ||
+ accessBoundary(sym2).isProperlyContainedIn(accessBoundary(sym1)) ||
+ sym1.is(Method) && !sym2.is(Method)) ||
+ sym1.info.isErroneous
+
+ /** Sym preference provided types also override */
+ def prefer(sym1: Symbol, sym2: Symbol, info1: Type, info2: Type) =
+ preferSym(sym1, sym2) && info1.overrides(info2)
+
+ def handleDoubleDef =
+ if (preferSym(sym1, sym2)) denot1
+ else if (preferSym(sym2, sym1)) denot2
+ else doubleDefError(denot1, denot2, pre)
+
+ if (sym2Accessible && prefer(sym2, sym1, info2, info1)) denot2
+ else {
+ val sym1Accessible = sym1.isAccessibleFrom(pre)
+ if (sym1Accessible && prefer(sym1, sym2, info1, info2)) denot1
+ else if (sym1Accessible && sym2.exists && !sym2Accessible) denot1
+ else if (sym2Accessible && sym1.exists && !sym1Accessible) denot2
+ else if (isDoubleDef(sym1, sym2)) handleDoubleDef
+ else {
+ val sym =
+ if (!sym1.exists) sym2
+ else if (!sym2.exists) sym1
+ else if (preferSym(sym2, sym1)) sym2
+ else sym1
+ val jointInfo =
+ try infoMeet(info1, info2)
+ catch {
+ case ex: MergeError =>
+ if (pre.widen.classSymbol.is(Scala2x) || ctx.scala2Mode)
+ info1 // follow Scala2 linearization -
+ // compare with way merge is performed in SymDenotation#computeMembersNamed
+ else
+ throw new MergeError(s"${ex.getMessage} as members of type ${pre.show}", ex.tp1, ex.tp2)
}
- }
- } else NoDenotation
+ new JointRefDenotation(sym, jointInfo, denot1.validFor & denot2.validFor)
+ }
+ }
}
if (this eq that) this
@@ -399,6 +462,46 @@ object Denotations {
*/
def | (that: Denotation, pre: Type)(implicit ctx: Context): Denotation = {
+ /** Normally, `tp1 | tp2`. Special cases for matching methods and classes, with
+ * the possibility of raising a merge error.
+ */
+ def infoJoin(tp1: Type, tp2: Type): Type = tp1 match {
+ case tp1: TypeBounds =>
+ tp2 match {
+ case tp2: TypeBounds => tp1 | tp2
+ case tp2: ClassInfo if tp1 contains tp2 => tp1
+ case _ => mergeConflict(tp1, tp2)
+ }
+ case tp1: ClassInfo =>
+ tp2 match {
+ case tp2: ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix | tp2.prefix)
+ case tp2: TypeBounds if tp2 contains tp1 => tp2
+ case _ => mergeConflict(tp1, tp2)
+ }
+ case tp1 @ MethodType(names1, formals1) =>
+ tp2 match {
+ case tp2 @ MethodType(names2, formals2)
+ if ctx.typeComparer.matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) &&
+ tp1.isImplicit == tp2.isImplicit =>
+ tp1.derivedMethodType(
+ mergeNames(names1, names2, nme.syntheticParamName),
+ formals1, tp1.resultType | tp2.resultType.subst(tp2, tp1))
+ case _ =>
+ mergeConflict(tp1, tp2)
+ }
+ case tp1: PolyType =>
+ 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 _ =>
+ mergeConflict(tp1, tp2)
+ }
+ case _ =>
+ tp1 | tp2
+ }
+
def unionDenot(denot1: SingleDenotation, denot2: SingleDenotation): Denotation =
if (denot1.matches(denot2)) {
val sym1 = denot1.symbol
@@ -428,7 +531,8 @@ object Denotations {
}
lubSym(sym1.allOverriddenSymbols, NoSymbol)
}
- new JointRefDenotation(jointSym, info1 | info2, denot1.validFor & denot2.validFor)
+ new JointRefDenotation(
+ jointSym, infoJoin(info1, info2), denot1.validFor & denot2.validFor)
}
}
else NoDenotation
@@ -1134,5 +1238,4 @@ object Denotations {
util.Stats.record("not defined here")
override def getMessage() = msg
}
-}
-
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/core/OrderingConstraint.scala b/src/dotty/tools/dotc/core/OrderingConstraint.scala
index 68c7655ef..72c7a8e51 100644
--- a/src/dotty/tools/dotc/core/OrderingConstraint.scala
+++ b/src/dotty/tools/dotc/core/OrderingConstraint.scala
@@ -14,7 +14,7 @@ import annotation.tailrec
object OrderingConstraint {
- type ArrayValuedMap[T] = SimpleMap[GenericType, Array[T]]
+ type ArrayValuedMap[T] = SimpleMap[PolyType, Array[T]]
/** The type of `OrderingConstraint#boundsMap` */
type ParamBounds = ArrayValuedMap[Type]
@@ -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: GenericType): Array[T]
- def updateEntries(c: OrderingConstraint, poly: GenericType, entries: Array[T])(implicit ctx: Context): OrderingConstraint
+ def entries(c: OrderingConstraint, poly: PolyType): Array[T]
+ def updateEntries(c: OrderingConstraint, poly: PolyType, entries: Array[T])(implicit ctx: Context): OrderingConstraint
def initial: T
- def apply(c: OrderingConstraint, poly: GenericType, idx: Int) = {
+ def apply(c: OrderingConstraint, poly: PolyType, 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: GenericType, idx: Int, entry: T)(implicit ctx: Context): OrderingConstraint = {
+ poly: PolyType, idx: Int, entry: T)(implicit ctx: Context): OrderingConstraint = {
var es = entries(current, poly)
if (es != null && (es(idx) eq entry)) current
else {
@@ -72,7 +72,7 @@ object OrderingConstraint {
update(prev, current, param.binder, param.paramNum, entry)
def map(prev: OrderingConstraint, current: OrderingConstraint,
- poly: GenericType, idx: Int, f: T => T)(implicit ctx: Context): OrderingConstraint =
+ poly: PolyType, 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,
@@ -81,25 +81,25 @@ object OrderingConstraint {
}
val boundsLens = new ConstraintLens[Type] {
- def entries(c: OrderingConstraint, poly: GenericType): Array[Type] =
+ def entries(c: OrderingConstraint, poly: PolyType): Array[Type] =
c.boundsMap(poly)
- def updateEntries(c: OrderingConstraint, poly: GenericType, entries: Array[Type])(implicit ctx: Context): OrderingConstraint =
+ def updateEntries(c: OrderingConstraint, poly: PolyType, 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: GenericType): Array[List[PolyParam]] =
+ def entries(c: OrderingConstraint, poly: PolyType): Array[List[PolyParam]] =
c.lowerMap(poly)
- def updateEntries(c: OrderingConstraint, poly: GenericType, entries: Array[List[PolyParam]])(implicit ctx: Context): OrderingConstraint =
+ def updateEntries(c: OrderingConstraint, poly: PolyType, entries: Array[List[PolyParam]])(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: GenericType): Array[List[PolyParam]] =
+ def entries(c: OrderingConstraint, poly: PolyType): Array[List[PolyParam]] =
c.upperMap(poly)
- def updateEntries(c: OrderingConstraint, poly: GenericType, entries: Array[List[PolyParam]])(implicit ctx: Context): OrderingConstraint =
+ def updateEntries(c: OrderingConstraint, poly: PolyType, entries: Array[List[PolyParam]])(implicit ctx: Context): OrderingConstraint =
newConstraint(c.boundsMap, c.lowerMap, c.upperMap.updated(poly, entries))
def initial = Nil
}
@@ -149,7 +149,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
// ----------- Contains tests --------------------------------------------------
- def contains(pt: GenericType): Boolean = boundsMap(pt) != null
+ def contains(pt: PolyType): Boolean = boundsMap(pt) != null
def contains(param: PolyParam): Boolean = {
val entries = boundsMap(param.binder)
@@ -280,7 +280,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
stripParams(tp, paramBuf, isUpper)
.orElse(if (isUpper) defn.AnyType else defn.NothingType)
- def add(poly: GenericType, tvars: List[TypeVar])(implicit ctx: Context): This = {
+ def add(poly: PolyType, tvars: List[TypeVar])(implicit ctx: Context): This = {
assert(!contains(poly))
val nparams = poly.paramNames.length
val entries1 = new Array[Type](nparams * 2)
@@ -293,7 +293,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
* Update all bounds to be normalized and update ordering to account for
* dependent parameters.
*/
- private def init(poly: GenericType)(implicit ctx: Context): This = {
+ private def init(poly: PolyType)(implicit ctx: Context): This = {
var current = this
val loBuf, hiBuf = new mutable.ListBuffer[PolyParam]
var i = 0
@@ -393,14 +393,14 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
val replacement = tp.dealias.stripTypeVar
if (param == replacement) this
else {
- assert(replacement.isValueType)
+ assert(replacement.isValueTypeOrLambda)
val poly = param.binder
val idx = param.paramNum
def removeParam(ps: List[PolyParam]) =
ps.filterNot(p => p.binder.eq(poly) && p.paramNum == idx)
- def replaceParam(tp: Type, atPoly: GenericType, atIdx: Int): Type = tp match {
+ def replaceParam(tp: Type, atPoly: PolyType, atIdx: Int): Type = tp match {
case bounds @ TypeBounds(lo, hi) =>
def recombine(andor: AndOrType, op: (Type, Boolean) => Type, isUpper: Boolean): Type = {
@@ -440,9 +440,9 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
}
}
- def remove(pt: GenericType)(implicit ctx: Context): This = {
+ def remove(pt: PolyType)(implicit ctx: Context): This = {
def removeFromOrdering(po: ParamOrdering) = {
- def removeFromBoundss(key: GenericType, bndss: Array[List[PolyParam]]): Array[List[PolyParam]] = {
+ def removeFromBoundss(key: PolyType, bndss: Array[List[PolyParam]]): Array[List[PolyParam]] = {
val bndss1 = bndss.map(_.filterConserve(_.binder ne pt))
if (bndss.corresponds(bndss1)(_ eq _)) bndss else bndss1
}
@@ -451,7 +451,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
newConstraint(boundsMap.remove(pt), removeFromOrdering(lowerMap), removeFromOrdering(upperMap))
}
- def isRemovable(pt: GenericType): Boolean = {
+ def isRemovable(pt: PolyType): Boolean = {
val entries = boundsMap(pt)
@tailrec def allRemovable(last: Int): Boolean =
if (last < 0) true
@@ -464,7 +464,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
// ---------- Exploration --------------------------------------------------------
- def domainPolys: List[GenericType] = boundsMap.keys
+ def domainPolys: List[PolyType] = boundsMap.keys
def domainParams: List[PolyParam] =
for {
@@ -481,7 +481,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
true
}
- def foreachParam(p: (GenericType, Int) => Unit): Unit =
+ def foreachParam(p: (PolyType, Int) => Unit): Unit =
boundsMap.foreachBinding { (poly, entries) =>
0.until(poly.paramNames.length).foreach(p(poly, _))
}
@@ -541,7 +541,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
override def checkClosed()(implicit ctx: Context): Unit = {
def isFreePolyParam(tp: Type) = tp match {
- case PolyParam(binder: GenericType, _) => !contains(binder)
+ case PolyParam(binder: PolyType, _) => !contains(binder)
case _ => false
}
def checkClosedType(tp: Type, where: String) =
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 5a5eacd18..a98d6732a 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -41,7 +41,7 @@ trait SymDenotations { this: Context =>
}
def stillValid(denot: SymDenotation): Boolean =
- if (denot.is(ValidForever) || denot.isRefinementClass) true
+ if (denot.is(ValidForever) || denot.isRefinementClass || denot.isImport) true
else {
val initial = denot.initial
val firstPhaseId = initial.validFor.firstPhaseId.max(ctx.typerPhase.id)
@@ -590,6 +590,9 @@ object SymDenotations {
originalName.isSetterName &&
(!isCompleted || info.firstParamTypes.nonEmpty) // to avoid being fooled by var x_= : Unit = ...
+ /** is this a symbol representing an import? */
+ final def isImport = name == nme.IMPORT
+
/** is this the constructor of a class? */
final def isClassConstructor = name == nme.CONSTRUCTOR
@@ -1147,7 +1150,7 @@ 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: GenericType => tp.paramBounds.exists(hasSkolems) || hasSkolems(tp.resType)
+ case tp: PolyType => tp.paramBounds.exists(hasSkolems) || hasSkolems(tp.resType)
case tp: MethodType => tp.paramTypes.exists(hasSkolems) || hasSkolems(tp.resType)
case tp: ExprType => hasSkolems(tp.resType)
case tp: HKApply => hasSkolems(tp.tycon) || tp.args.exists(hasSkolems)
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index f32a591a6..8aaf77032 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -72,7 +72,7 @@ object TypeApplications {
}
def unapply(tp: Type)(implicit ctx: Context): Option[TypeRef] = tp match {
- case tp @ TypeLambda(tparams, AppliedType(fn: TypeRef, args)) if (args == tparams.map(_.toArg)) => Some(fn)
+ case tp @ PolyType(tparams, AppliedType(fn: TypeRef, args)) if (args == tparams.map(_.toArg)) => Some(fn)
case _ => None
}
}
@@ -159,7 +159,7 @@ 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: TypeLambda, args: List[Type])(implicit ctx: Context) extends TypeMap {
+ class Reducer(tycon: PolyType, args: List[Type])(implicit ctx: Context) extends TypeMap {
private var available = (0 until args.length).toSet
var allReplaced = true
def hasWildcardArg(p: PolyParam) =
@@ -212,7 +212,7 @@ class TypeApplications(val self: Type) extends AnyVal {
self match {
case self: ClassInfo =>
self.cls.typeParams
- case self: TypeLambda =>
+ case self: PolyType =>
self.typeParams
case self: TypeRef =>
val tsym = self.symbol
@@ -311,7 +311,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: TypeLambda => true
+ case self: PolyType => true
case self: SingletonType => false
case self: TypeVar =>
// Using `origin` instead of `underlying`, as is done for typeParams,
@@ -339,7 +339,7 @@ class TypeApplications(val self: Type) extends AnyVal {
*/
def LambdaAbstract(tparams: List[TypeParamInfo])(implicit ctx: Context): Type = {
def expand(tp: Type) =
- TypeLambda(
+ PolyType(
tpnme.syntheticLambdaParamNames(tparams.length), tparams.map(_.paramVariance))(
tl => tparams.map(tparam => tl.lifted(tparams, tparam.paramBounds).bounds),
tl => tl.lifted(tparams, tp))
@@ -421,10 +421,10 @@ class TypeApplications(val self: Type) extends AnyVal {
if (hkParams.isEmpty) self
else {
def adaptArg(arg: Type): Type = arg match {
- case arg @ TypeLambda(tparams, body) if
+ case arg @ PolyType(tparams, body) if
!tparams.corresponds(hkParams)(_.paramVariance == _.paramVariance) &&
tparams.corresponds(hkParams)(varianceConforms) =>
- TypeLambda(tparams.map(_.paramName), hkParams.map(_.paramVariance))(
+ PolyType(tparams.map(_.paramName), hkParams.map(_.paramVariance))(
tl => arg.paramBounds.map(_.subst(arg, tl).bounds),
tl => arg.resultType.subst(arg, tl)
)
@@ -466,7 +466,7 @@ class TypeApplications(val self: Type) extends AnyVal {
val dealiased = stripped.safeDealias
if (args.isEmpty || ctx.erasedTypes) self
else dealiased match {
- case dealiased: TypeLambda =>
+ case dealiased: PolyType =>
def tryReduce =
if (!args.exists(_.isInstanceOf[TypeBounds])) {
val followAlias = Config.simplifyApplications && {
@@ -485,7 +485,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
- .derivedTypeLambda(resType = tycon.safeDealias.appliedTo(args1))
+ .derivedPolyType(resType = tycon.safeDealias.appliedTo(args1))
.appliedTo(args)
case _ =>
val reducer = new Reducer(dealiased, args)
@@ -494,8 +494,6 @@ 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 =>
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 52b248abb..b495f00d0 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -412,9 +412,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
compareRec
case tp2 @ HKApply(tycon2, args2) =>
compareHkApply2(tp1, tp2, tycon2, args2)
- case tp2 @ TypeLambda(tparams2, body2) =>
+ case tp2 @ PolyType(tparams2, body2) =>
def compareHkLambda: Boolean = tp1.stripTypeVar match {
- case tp1 @ TypeLambda(tparams1, body1) =>
+ case tp1 @ PolyType(tparams1, body1) =>
/* 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:
@@ -432,13 +432,14 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
ctx.scala2Mode ||
tparams1.corresponds(tparams2)((tparam1, tparam2) =>
isSubType(tparam2.paramBounds.subst(tp2, tp1), tparam1.paramBounds))
- val saved = comparingLambdas
- comparingLambdas = true
+ val saved = comparedPolyTypes
+ comparedPolyTypes += tp1
+ comparedPolyTypes += tp2
try
variancesConform(tparams1, tparams2) &&
boundsOK &&
isSubType(body1, body2.subst(tp2, tp1))
- finally comparingLambdas = saved
+ finally comparedPolyTypes = saved
case _ =>
if (!tp1.isHK) {
tp2 match {
@@ -478,16 +479,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
false
}
compareMethod
- case tp2: PolyType =>
- def comparePoly = tp1 match {
- case tp1: PolyType =>
- (tp1.signature consistentParams tp2.signature) &&
- matchingTypeParams(tp1, tp2) &&
- isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1))
- case _ =>
- false
- }
- comparePoly
case tp2 @ ExprType(restpe2) =>
def compareExpr = tp1 match {
// We allow ()T to be a subtype of => T.
@@ -543,7 +534,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
case OrType(tp1, tp2) => isNullable(tp1) || isNullable(tp2)
case _ => false
}
- (tp1.symbol eq NothingClass) && tp2.isInstanceOf[ValueType] ||
+ (tp1.symbol eq NothingClass) && tp2.isValueTypeOrLambda ||
(tp1.symbol eq NullClass) && isNullable(tp2)
}
case tp1: SingletonType =>
@@ -660,7 +651,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
val tparams1 = tparams1a.drop(lengthDiff)
variancesConform(tparams1, tparams) && {
if (lengthDiff > 0)
- tycon1b = TypeLambda(tparams1.map(_.paramName), tparams1.map(_.paramVariance))(
+ tycon1b = PolyType(tparams1.map(_.paramName), tparams1.map(_.paramVariance))(
tl => tparams1.map(tparam => tl.lifted(tparams, tparam.paramBounds).bounds),
tl => tycon1a.appliedTo(args1.take(lengthDiff) ++
tparams1.indices.toList.map(PolyParam(tl, _))))
@@ -1032,7 +1023,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
}
/** Are `syms1` and `syms2` parameter lists with pairwise equivalent types? */
- private def matchingParams(formals1: List[Type], formals2: List[Type], isJava1: Boolean, isJava2: Boolean): Boolean = formals1 match {
+ def matchingParams(formals1: List[Type], formals2: List[Type], isJava1: Boolean, isJava2: Boolean): Boolean = formals1 match {
case formal1 :: rest1 =>
formals2 match {
case formal2 :: rest2 =>
@@ -1050,7 +1041,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
/** Do generic types `poly1` and `poly2` have type parameters that
* have the same bounds (after renaming one set to the other)?
*/
- private def matchingTypeParams(poly1: GenericType, poly2: GenericType): Boolean =
+ def matchingTypeParams(poly1: PolyType, poly2: PolyType): Boolean =
(poly1.paramBounds corresponds poly2.paramBounds)((b1, b2) =>
isSameType(b1, b2.subst(poly2, poly1)))
@@ -1274,7 +1265,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
else if (tparams2.isEmpty)
original(tp1.appliedTo(tp1.typeParams.map(_.paramBoundsAsSeenFrom(tp1))), tp2)
else
- TypeLambda(
+ PolyType(
paramNames = tpnme.syntheticLambdaParamNames(tparams1.length),
variances = (tparams1, tparams2).zipped.map((tparam1, tparam2) =>
(tparam1.paramVariance + tparam2.paramVariance) / 2))(
@@ -1318,38 +1309,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
}
case tp1: RecType =>
tp1.rebind(distributeAnd(tp1.parent, tp2))
- case tp1: TypeBounds =>
- tp2 match {
- case tp2: TypeBounds => tp1 & tp2
- case tp2: ClassInfo if tp1 contains tp2 => tp2
- case _ => mergeConflict(tp1, tp2)
- }
- case tp1: ClassInfo =>
- tp2 match {
- case tp2: ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix & tp2.prefix)
- case tp2: TypeBounds if tp2 contains tp1 => tp1
- case _ => mergeConflict(tp1, tp2)
- }
- case tp1 @ MethodType(names1, formals1) =>
- tp2 match {
- case tp2 @ MethodType(names2, formals2)
- if matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) &&
- tp1.isImplicit == tp2.isImplicit =>
- tp1.derivedMethodType(
- mergeNames(names1, names2, nme.syntheticParamName),
- formals1, tp1.resultType & tp2.resultType.subst(tp2, tp1))
- case _ =>
- mergeConflict(tp1, tp2)
- }
- case tp1: PolyType =>
- tp2 match {
- case tp2: PolyType if matchingTypeParams(tp1, tp2) =>
- tp1.derivedPolyType(
- mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName),
- tp1.paramBounds, tp1.resultType & tp2.resultType.subst(tp2, tp1))
- case _ =>
- mergeConflict(tp1, tp2)
- }
case ExprType(rt1) =>
tp2 match {
case ExprType(rt2) =>
@@ -1374,38 +1333,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
* The rhs is a proper supertype of the lhs.
*/
private def distributeOr(tp1: Type, tp2: Type): Type = tp1 match {
- case tp1: TypeBounds =>
- tp2 match {
- case tp2: TypeBounds => tp1 | tp2
- case tp2: ClassInfo if tp1 contains tp2 => tp1
- case _ => mergeConflict(tp1, tp2)
- }
- case tp1: ClassInfo =>
- tp2 match {
- case tp2: ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix | tp2.prefix)
- case tp2: TypeBounds if tp2 contains tp1 => tp2
- case _ => mergeConflict(tp1, tp2)
- }
- case tp1 @ MethodType(names1, formals1) =>
- tp2 match {
- case tp2 @ MethodType(names2, formals2)
- if matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) &&
- tp1.isImplicit == tp2.isImplicit =>
- tp1.derivedMethodType(
- mergeNames(names1, names2, nme.syntheticParamName),
- formals1, tp1.resultType | tp2.resultType.subst(tp2, tp1))
- case _ =>
- mergeConflict(tp1, tp2)
- }
- case tp1: GenericType =>
- tp2 match {
- case tp2: GenericType if matchingTypeParams(tp1, tp2) =>
- tp1.derivedGenericType(
- mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName),
- tp1.paramBounds, tp1.resultType | tp2.resultType.subst(tp2, tp1))
- case _ =>
- mergeConflict(tp1, tp2)
- }
case ExprType(rt1) =>
ExprType(rt1 | tp2.widenExpr)
case tp1: TypeVar if tp1.isInstantiated =>
@@ -1416,25 +1343,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
NoType
}
- /** Handle merge conflict by throwing a `MergeError` exception */
- private def mergeConflict(tp1: Type, tp2: Type): Type = {
- def showType(tp: Type) = tp match {
- case ClassInfo(_, cls, _, _, _) => cls.showLocated
- case bounds: TypeBounds => i"type bounds $bounds"
- case _ => tp.show
- }
- if (true) throw new MergeError(s"cannot merge ${showType(tp1)} with ${showType(tp2)}", tp1, tp2)
- 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,
- * otherwise generate new synthetic names.
- */
- private 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
-
/** Show type, handling type types better than the default */
private def showType(tp: Type)(implicit ctx: Context) = tp match {
case ClassInfo(_, cls, _, _, _) => cls.showLocated
diff --git a/src/dotty/tools/dotc/core/TypeErasure.scala b/src/dotty/tools/dotc/core/TypeErasure.scala
index 1a7342a12..fd5fcb921 100644
--- a/src/dotty/tools/dotc/core/TypeErasure.scala
+++ b/src/dotty/tools/dotc/core/TypeErasure.scala
@@ -356,8 +356,6 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
SuperType(this(thistpe), this(supertpe))
case ExprType(rt) =>
defn.FunctionClass(0).typeRef
- case tp: TypeProxy =>
- this(tp.underlying)
case AndType(tp1, tp2) =>
erasedGlb(this(tp1), this(tp2), isJava)
case OrType(tp1, tp2) =>
@@ -372,11 +370,6 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
case rt =>
tp.derivedMethodType(tp.paramNames, formals, rt)
}
- case tp: PolyType =>
- this(tp.resultType) match {
- case rt: MethodType => rt
- case rt => MethodType(Nil, Nil, rt)
- }
case tp @ ClassInfo(pre, cls, classParents, decls, _) =>
if (cls is Package) tp
else {
@@ -398,6 +391,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
tp
case tp: WildcardType if wildcardOK =>
tp
+ case tp: TypeProxy =>
+ this(tp.underlying)
}
private def eraseArray(tp: RefinedType)(implicit ctx: Context) = {
@@ -409,9 +404,9 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
else JavaArrayType(arrayErasure(elemtp))
}
- /** The erasure of a symbol's info. This is different from `apply` in the way `ExprType`s are
- * treated. `eraseInfo` maps them them to nullary method types, whereas `apply` maps them
- * to `Function0`.
+ /** The erasure of a symbol's info. This is different from `apply` in the way `ExprType`s and
+ * `PolyType`s are treated. `eraseInfo` maps them them to method types, whereas `apply` maps them
+ * to the underlying type.
*/
def eraseInfo(tp: Type, sym: Symbol)(implicit ctx: Context) = tp match {
case ExprType(rt) =>
@@ -421,6 +416,11 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
// forwarders to mixin methods.
// See doc comment for ElimByName for speculation how we could improve this.
else MethodType(Nil, Nil, eraseResult(rt))
+ case tp: PolyType =>
+ this(tp.resultType) match {
+ case rt: MethodType => rt
+ case rt => MethodType(Nil, Nil, rt)
+ }
case tp => this(tp)
}
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index d480a792b..92e5f9d57 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -136,7 +136,6 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
finally seen = saved
}
case _ =>
- if (tp.isInstanceOf[MethodicType]) assert(variance != 0, tp)
mapOver(tp)
}
}
diff --git a/src/dotty/tools/dotc/core/TyperState.scala b/src/dotty/tools/dotc/core/TyperState.scala
index 7e332b412..5c476c1cb 100644
--- a/src/dotty/tools/dotc/core/TyperState.scala
+++ b/src/dotty/tools/dotc/core/TyperState.scala
@@ -152,7 +152,7 @@ extends TyperState(r) {
}
override def gc()(implicit ctx: Context): Unit = {
- val toCollect = new mutable.ListBuffer[GenericType]
+ val toCollect = new mutable.ListBuffer[PolyType]
constraint foreachTypeVar { tvar =>
if (!tvar.inst.exists) {
val inst = instType(tvar)
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 0f81f8c38..d242843e5 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -61,14 +61,13 @@ object Types {
* | +- ExprType
* | +- AnnotatedType
* | +- TypeVar
+ * | +- PolyType
* |
* +- GroundType -+- AndType
* +- OrType
* +- MethodType -----+- ImplicitMethodType
* | +- JavaMethodType
* +- ClassInfo
- * +- GenericType ----+- PolyType
- * | +- TypeLambda
* |
* +- NoType
* +- NoPrefix
@@ -96,6 +95,9 @@ object Types {
/** Is this type a value type? */
final def isValueType: Boolean = this.isInstanceOf[ValueType]
+ /** Is the is value type or type lambda? */
+ final def isValueTypeOrLambda: Boolean = isValueType || this.isInstanceOf[PolyType]
+
/** Does this type denote a stable reference (i.e. singleton type)? */
final def isStable(implicit ctx: Context): Boolean = stripTypeVar match {
case tp: TermRef => tp.termSymbol.isStable && tp.prefix.isStable
@@ -519,7 +521,7 @@ object Types {
}
def goApply(tp: HKApply) = tp.tycon match {
- case tl: TypeLambda =>
+ case tl: PolyType =>
go(tl.resType).mapInfo(info =>
tl.derivedLambdaAbstraction(tl.paramNames, tl.paramBounds, info).appliedTo(tp.args))
case _ =>
@@ -1084,7 +1086,7 @@ object Types {
/** The parameter types in the first parameter section of a generic type or MethodType, Empty list for others */
final def firstParamTypes(implicit ctx: Context): List[Type] = this match {
case mt: MethodType => mt.paramTypes
- case pt: GenericType => pt.resultType.firstParamTypes
+ case pt: PolyType => pt.resultType.firstParamTypes
case _ => Nil
}
@@ -2197,7 +2199,7 @@ object Types {
object AndType {
def apply(tp1: Type, tp2: Type)(implicit ctx: Context) = {
- assert(tp1.isInstanceOf[ValueType] && tp2.isInstanceOf[ValueType], i"$tp1 & $tp2 / " + s"$tp1 & $tp2")
+ assert(tp1.isValueType && tp2.isValueType, i"$tp1 & $tp2 / " + s"$tp1 & $tp2")
unchecked(tp1, tp2)
}
def unchecked(tp1: Type, tp2: Type)(implicit ctx: Context) = {
@@ -2260,7 +2262,7 @@ object Types {
// and therefore two different poly types would never be equal.
/** A trait that mixes in functionality for signature caching */
- trait MethodicType extends Type {
+ trait MethodicType extends TermType {
private[this] var mySignature: Signature = _
private[this] var mySignatureRunId: Int = NoRunId
@@ -2500,82 +2502,67 @@ object Types {
}
}
- /** A common supertrait of PolyType and TypeLambda */
- trait GenericType extends BindingType with TermType {
-
- /** The names of the type parameters */
- val paramNames: List[TypeName]
+ /** 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]
+ val paramBounds: List[TypeBounds] = paramBoundsExp(this)
/** The result type of a PolyType / body of a type lambda */
- val resType: Type
+ val resType: Type = resultTypeExp(this)
- /** If this is a type lambda, the variances of its parameters, otherwise Nil.*/
- def variances: List[Int]
+ assert(resType.isInstanceOf[TermType], this)
+ assert(paramNames.nonEmpty)
- override def resultType(implicit ctx: Context) = resType
+ protected def computeSignature(implicit ctx: Context) = resultSignature
+
+ def isPolymorphicMethodType: Boolean = resType match {
+ case _: MethodType => true
+ case _ => false
+ }
+
+ /** PolyParam references to all type parameters of this type */
+ lazy val paramRefs: List[PolyParam] = paramNames.indices.toList.map(PolyParam(this, _))
+
+ lazy val typeParams: List[LambdaParam] =
+ paramNames.indices.toList.map(new LambdaParam(this, _))
- /** Unconditionally create a new generic type like this one with given elements */
- def duplicate(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): GenericType
+ 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 */
- def instantiateBounds(argTypes: List[Type])(implicit ctx: Context): List[TypeBounds] =
+ final def instantiateBounds(argTypes: List[Type])(implicit ctx: Context): List[TypeBounds] =
paramBounds.mapConserve(_.substParams(this, argTypes).bounds)
- def derivedGenericType(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context) =
- if ((paramNames eq this.paramNames) && (paramBounds eq this.paramBounds) && (resType eq this.resType)) this
- else duplicate(paramNames, paramBounds, resType)
+ 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))
- /** PolyParam references to all type parameters of this type */
- lazy val paramRefs: List[PolyParam] = paramNames.indices.toList.map(PolyParam(this, _))
+ 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)
- /** 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)
+ def derivedLambdaAbstraction(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): Type =
+ resType match {
+ case resType @ TypeAlias(alias) =>
+ resType.derivedTypeAlias(newLikeThis(paramNames, paramBounds, alias))
+ case resType @ TypeBounds(lo, hi) =>
+ resType.derivedTypeBounds(
+ if (lo.isRef(defn.NothingClass)) lo else newLikeThis(paramNames, paramBounds, lo),
+ newLikeThis(paramNames, paramBounds, hi))
+ case _ =>
+ derivedPolyType(paramNames, paramBounds, resType)
}
- override def equals(other: Any) = other match {
- case other: GenericType =>
- other.paramNames == this.paramNames &&
- other.paramBounds == this.paramBounds &&
- other.resType == this.resType &&
- other.variances == this.variances
- case _ => false
- }
- }
-
- /** A type for polymorphic methods */
- class PolyType(val paramNames: List[TypeName])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)
- extends CachedGroundType with GenericType with MethodOrPoly {
- val paramBounds: List[TypeBounds] = paramBoundsExp(this)
- val resType: Type = resultTypeExp(this)
- def variances = Nil
-
- protected def computeSignature(implicit ctx: Context) = resultSignature
-
- def isPolymorphicMethodType: Boolean = resType match {
- case _: MethodType => true
- case _ => false
- }
-
- def derivedPolyType(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): PolyType =
- derivedGenericType(paramNames, paramBounds, resType).asInstanceOf[PolyType]
-
- def duplicate(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): PolyType =
- PolyType(paramNames)(
- x => paramBounds mapConserve (_.subst(this, x).bounds),
- x => resType.subst(this, x))
-
/** Merge nested polytypes into one polytype. nested polytypes are normally not supported
* but can arise as temporary data structures.
*/
@@ -2594,66 +2581,55 @@ object Types {
case _ => this
}
- override def toString = s"PolyType($paramNames, $paramBounds, $resType)"
+ /** 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)
+ }
+
+ 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
+ }
+
+ override def toString = s"PolyType($variances, $paramNames, $paramBounds, $resType)"
- override def computeHash = doHash(paramNames, resType, paramBounds)
+ override def computeHash = doHash(variances ::: paramNames, resType, paramBounds)
}
object PolyType {
- def apply(paramNames: List[TypeName])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)(implicit ctx: Context): PolyType = {
- unique(new PolyType(paramNames)(paramBoundsExp, resultTypeExp))
+ def apply(paramNames: List[TypeName], variances: List[Int] = Nil)(
+ paramBoundsExp: PolyType => List[TypeBounds],
+ resultTypeExp: PolyType => Type)(implicit ctx: Context): PolyType = {
+ val vs = if (variances.isEmpty) paramNames.map(alwaysZero) else variances
+ unique(new PolyType(paramNames, vs)(paramBoundsExp, resultTypeExp))
}
- def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context) =
+ def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context): Type =
if (tparams.isEmpty) resultType
- else apply(tparams map (_.name.asTypeName))(
+ else apply(tparams map (_.name.asTypeName), tparams.map(_.variance))(
pt => tparams.map(tparam => pt.lifted(tparams, tparam.info).bounds),
pt => pt.lifted(tparams, resultType))
- }
-
- // ----- HK types: TypeLambda, LambdaParam, HKApply ---------------------
-
- /** A type lambda of the form `[v_0 X_0, ..., v_n X_n] => T` */
- class TypeLambda(val paramNames: List[TypeName], val variances: List[Int])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)
- extends CachedProxyType with GenericType with ValueType {
- val paramBounds = paramBoundsExp(this)
- val resType = resultTypeExp(this)
-
- assert(resType.isInstanceOf[TermType], this)
- assert(paramNames.nonEmpty)
-
- override def underlying(implicit ctx: Context) = resType
-
- lazy val typeParams: List[LambdaParam] =
- paramNames.indices.toList.map(new LambdaParam(this, _))
- def derivedLambdaAbstraction(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): Type =
- resType match {
- case resType @ TypeAlias(alias) =>
- resType.derivedTypeAlias(duplicate(paramNames, paramBounds, alias))
- case resType @ TypeBounds(lo, hi) =>
- resType.derivedTypeBounds(
- if (lo.isRef(defn.NothingClass)) lo else duplicate(paramNames, paramBounds, lo),
- duplicate(paramNames, paramBounds, hi))
- case _ =>
- derivedTypeLambda(paramNames, paramBounds, resType)
- }
-
- def derivedTypeLambda(paramNames: List[TypeName] = paramNames, paramBounds: List[TypeBounds] = paramBounds, resType: Type)(implicit ctx: Context): TypeLambda =
- derivedGenericType(paramNames, paramBounds, resType).asInstanceOf[TypeLambda]
-
- def duplicate(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): TypeLambda =
- TypeLambda(paramNames, variances)(
- x => paramBounds mapConserve (_.subst(this, x).bounds),
- x => resType.subst(this, x))
-
- override def toString = s"TypeLambda($variances, $paramNames, $paramBounds, $resType)"
+ def unapply(tl: PolyType): Some[(List[LambdaParam], Type)] =
+ Some((tl.typeParams, tl.resType))
- override def computeHash = doHash(variances ::: paramNames, resType, paramBounds)
+ def any(n: Int)(implicit ctx: Context) =
+ apply(tpnme.syntheticLambdaParamNames(n), List.fill(n)(0))(
+ pt => List.fill(n)(TypeBounds.empty), pt => defn.AnyType)
}
+ // ----- HK types: LambdaParam, HKApply ---------------------
+
/** The parameter of a type lambda */
- case class LambdaParam(tl: TypeLambda, n: Int) extends TypeParamInfo {
+ 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)
@@ -2664,24 +2640,6 @@ object Types {
def paramRef(implicit ctx: Context): Type = PolyParam(tl, n)
}
- object TypeLambda {
- def apply(paramNames: List[TypeName], variances: List[Int])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)(implicit ctx: Context): TypeLambda = {
- unique(new TypeLambda(paramNames, variances)(paramBoundsExp, resultTypeExp))
- }
-
- def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context) =
- if (tparams.isEmpty) resultType
- else apply(tparams map (_.name.asTypeName), tparams.map(_.variance))(
- pt => tparams.map(tparam => pt.lifted(tparams, tparam.info).bounds),
- pt => pt.lifted(tparams, resultType))
- def unapply(tl: TypeLambda): Some[(List[LambdaParam], Type)] =
- Some((tl.typeParams, tl.resType))
-
- def any(n: Int)(implicit ctx: Context) =
- apply(tpnme.syntheticLambdaParamNames(n), List.fill(n)(0))(
- pt => List.fill(n)(TypeBounds.empty), pt => defn.AnyType)
- }
-
/** A higher kinded type application `C[T_1, ..., T_n]` */
abstract case class HKApply(tycon: Type, args: List[Type])
extends CachedProxyType with ValueType {
@@ -2694,7 +2652,7 @@ object Types {
override def superType(implicit ctx: Context): Type = {
if (ctx.period != validSuper) {
cachedSuper = tycon match {
- case tp: TypeLambda => defn.AnyType
+ case tp: PolyType => defn.AnyType
case tp: TypeVar if !tp.inst.exists =>
// supertype not stable, since underlying might change
return tp.underlying.applyIfParameterized(args)
@@ -2720,7 +2678,7 @@ object Types {
def typeParams(implicit ctx: Context): List[TypeParamInfo] = {
val tparams = tycon.typeParams
- if (tparams.isEmpty) TypeLambda.any(args.length).typeParams else tparams
+ if (tparams.isEmpty) PolyType.any(args.length).typeParams else tparams
}
def derivedAppliedType(tycon: Type, args: List[Type])(implicit ctx: Context): Type =
@@ -2733,7 +2691,7 @@ object Types {
def check(tycon: Type): Unit = tycon.stripTypeVar match {
case tycon: TypeRef if !tycon.symbol.isClass =>
case _: PolyParam | ErrorType | _: WildcardType =>
- case _: TypeLambda =>
+ case _: PolyType =>
assert(args.exists(_.isInstanceOf[TypeBounds]), s"unreduced type apply: $this")
case tycon: AnnotatedType =>
check(tycon.underlying)
@@ -2799,8 +2757,8 @@ object Types {
}
/** TODO Some docs would be nice here! */
- case class PolyParam(binder: GenericType, paramNum: Int) extends ParamType {
- type BT = GenericType
+ case class PolyParam(binder: PolyType, paramNum: Int) extends ParamType {
+ type BT = PolyType
def copyBoundType(bt: BT) = PolyParam(bt, paramNum)
/** Looking only at the structure of `bound`, is one of the following true?
@@ -3406,8 +3364,8 @@ object Types {
tp.derivedMethodType(tp.paramNames, formals, restpe)
protected def derivedExprType(tp: ExprType, restpe: Type): Type =
tp.derivedExprType(restpe)
- protected def derivedGenericType(tp: GenericType, pbounds: List[TypeBounds], restpe: Type): Type =
- tp.derivedGenericType(tp.paramNames, pbounds, restpe)
+ protected def derivedPolyType(tp: PolyType, pbounds: List[TypeBounds], restpe: Type): Type =
+ tp.derivedPolyType(tp.paramNames, pbounds, restpe)
/** Map this function over given type */
def mapOver(tp: Type): Type = {
@@ -3449,12 +3407,12 @@ object Types {
case tp: ExprType =>
derivedExprType(tp, this(tp.resultType))
- case tp: GenericType =>
+ case tp: PolyType =>
def mapOverPoly = {
variance = -variance
val bounds1 = tp.paramBounds.mapConserve(this).asInstanceOf[List[TypeBounds]]
variance = -variance
- derivedGenericType(tp, bounds1, this(tp.resultType))
+ derivedPolyType(tp, bounds1, this(tp.resultType))
}
mapOverPoly
@@ -3667,7 +3625,7 @@ object Types {
case ExprType(restpe) =>
this(x, restpe)
- case tp: GenericType =>
+ case tp: PolyType =>
variance = -variance
val y = foldOver(x, tp.paramBounds)
variance = -variance
diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
index b6f52c0ec..8889e8a5c 100644
--- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
@@ -251,7 +251,7 @@ class TreePickler(pickler: TastyPickler) {
case tpe: ExprType =>
writeByte(BYNAMEtype)
pickleType(tpe.underlying)
- case tpe: TypeLambda =>
+ case tpe: PolyType =>
writeByte(LAMBDAtype)
val paramNames = tpe.typeParams.map(tparam =>
varianceToPrefix(tparam.paramVariance) +: tparam.paramName)
@@ -259,9 +259,6 @@ class TreePickler(pickler: TastyPickler) {
case tpe: MethodType if richTypes =>
writeByte(METHODtype)
pickleMethodic(tpe.resultType, tpe.paramNames, tpe.paramTypes)
- case tpe: PolyType if richTypes =>
- writeByte(POLYtype)
- pickleMethodic(tpe.resultType, tpe.paramNames, tpe.paramBounds)
case tpe: PolyParam =>
if (!pickleParamType(tpe))
// TODO figure out why this case arises in e.g. pickling AbstractFileReader.
diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
index 09f2c0d1f..f67159808 100644
--- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
@@ -270,7 +270,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
val (rawNames, paramReader) = readNamesSkipParams
val (variances, paramNames) = rawNames
.map(name => (prefixToVariance(name.head), name.tail.toTypeName)).unzip
- val result = TypeLambda(paramNames, variances)(
+ val result = PolyType(paramNames, variances)(
pt => registeringType(pt, paramReader.readParamTypes[TypeBounds](end)),
pt => readType())
goto(end)
@@ -290,7 +290,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
result
case PARAMtype =>
readTypeRef() match {
- case binder: GenericType => PolyParam(binder, readNat())
+ case binder: PolyType => PolyParam(binder, readNat())
case binder: MethodType => MethodParam(binder, readNat())
}
case CLASSconst =>