aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/annotation/internal/ContravariantBetween.scala3
-rw-r--r--src/dotty/annotation/internal/CovariantBetween.scala3
-rw-r--r--src/dotty/annotation/internal/InvariantBetween.scala3
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala81
-rw-r--r--src/dotty/tools/dotc/core/TypeComparers.scala19
-rw-r--r--src/dotty/tools/dotc/core/Types.scala75
-rw-r--r--src/dotty/tools/dotc/core/pickling/UnPickler.scala45
7 files changed, 69 insertions, 160 deletions
diff --git a/src/dotty/annotation/internal/ContravariantBetween.scala b/src/dotty/annotation/internal/ContravariantBetween.scala
deleted file mode 100644
index 7eb068b89..000000000
--- a/src/dotty/annotation/internal/ContravariantBetween.scala
+++ /dev/null
@@ -1,3 +0,0 @@
-package dotty.annotation.internal
-
-trait ContravariantBetween[-Lo, +Hi] \ No newline at end of file
diff --git a/src/dotty/annotation/internal/CovariantBetween.scala b/src/dotty/annotation/internal/CovariantBetween.scala
deleted file mode 100644
index d65a5f1b9..000000000
--- a/src/dotty/annotation/internal/CovariantBetween.scala
+++ /dev/null
@@ -1,3 +0,0 @@
-package dotty.annotation.internal
-
-trait CovariantBetween[-Lo, +Hi] \ No newline at end of file
diff --git a/src/dotty/annotation/internal/InvariantBetween.scala b/src/dotty/annotation/internal/InvariantBetween.scala
deleted file mode 100644
index bf572b66c..000000000
--- a/src/dotty/annotation/internal/InvariantBetween.scala
+++ /dev/null
@@ -1,3 +0,0 @@
-package dotty.annotation.internal
-
-trait InvariantBetween[-Lo, +Hi] \ No newline at end of file
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index ae8b7887f..9d7f84449 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -289,39 +289,10 @@ class Definitions(implicit ctx: Context) {
// ----- Higher kinds machinery ------------------------------------------
private var _hkTraits: Set[Symbol] = Set()
- private var _hkTrait: Map[Int, ClassSymbol] = Map()
- /** The set of all `HigherKinded_n` traits that are referred to in thos compilation run. */
+ /** The set of HigherKindedXYZ traits encountered so far */
def hkTraits: Set[Symbol] = _hkTraits
- /** A trait `HigherKinded_n[B1, ..., Bn]` that represents
- * the bounds of a higher-kinded type.
- */
- def hkTrait(n: Int): ClassSymbol = {
- val completer = new LazyType {
- def complete(denot: SymDenotation): Unit = {
- val cls = denot.asClass.classSymbol
- val paramDecls = newScope
- for (i <- 0 until n)
- newSyntheticTypeParam(cls, paramDecls, "B"+i).setFlag(Covariant)
- denot.info = ClassInfo(ScalaPackageClass.thisType, cls, List(ObjectClass.typeConstructor), paramDecls)
- }
- }
- _hkTrait get n match {
- case Some(cls) =>
- cls
- case None =>
- val cls = ctx.newClassSymbol(
- ScalaPackageClass,
- tpnme.higherKindedTraitName(n),
- Trait | Interface | Synthetic,
- completer).entered
- _hkTraits += cls
- _hkTrait = _hkTrait.updated(n, cls)
- cls
- }
- }
-
private var hkTraitOfArity = mutable.Map[List[Int], ClassSymbol]()
/** The HigherKinded trait corresponding to symbols `boundSyms` (which are assumed
@@ -337,45 +308,47 @@ class Definitions(implicit ctx: Context) {
* - v_i are the variances of the bound symbols (i.e. +, -, or empty).
* - _$hk$i are hgiher-kinded parameter names, which are special treated in type application.
*/
- def hkTrait(boundSyms: List[Symbol]) = {
+ def hkTrait(variances: List[Int]) = {
+
+ def varianceSuffix(v: Int) = v match {
+ case -1 => "N"
+ case 0 => "I"
+ case 1 => "P"
+ }
+
+ def varianceFlags(v: Int)= v match {
+ case -1 => Contravariant
+ case 0 => Covariant
+ case 1 => EmptyFlags
+ }
val completer = new LazyType {
def complete(denot: SymDenotation): Unit = {
val cls = denot.asClass.classSymbol
val paramDecls = newScope
- for ((bsym, i) <- boundSyms.zipWithIndex)
- newTypeParam(cls, tpnme.higherKindedParamName(i), bsym.flags & VarianceFlags, paramDecls)
+ for ((v, i) <- variances.zipWithIndex)
+ newTypeParam(cls, tpnme.higherKindedParamName(i), varianceFlags(v), paramDecls)
denot.info = ClassInfo(ScalaPackageClass.thisType, cls, List(ObjectClass.typeConstructor), paramDecls)
}
}
- def varianceSuffix(v: Int) = v match {
- case -1 => "N"
- case 0 => "I"
- case 1 => "P"
- }
-
- val variances = boundSyms map (_.variance)
val traitName =
- tpnme.higherKindedTraitName(boundSyms.length) ++ (variances map varianceSuffix).mkString
-
- def createTrait = ctx.newClassSymbol(
- ScalaPackageClass,
- traitName,
- Trait | Interface | Synthetic,
- completer).entered
+ tpnme.higherKindedTraitName(variances.length) ++ (variances map varianceSuffix).mkString
+
+ def createTrait = {
+ val cls = ctx.newClassSymbol(
+ ScalaPackageClass,
+ traitName,
+ Trait | Interface | Synthetic,
+ completer).entered
+ _hkTraits += cls
+ cls
+ }
hkTraitOfArity.getOrElseUpdate(variances, createTrait)
}
- /** The bounds trait corresponding to the given variance */
- def hkBoundsClass(variance: Int) = variance match {
- case 0 => InvariantBetweenClass
- case 1 => CovariantBetweenClass
- case -1 => ContravariantBetweenClass
- }
-
// ----- Value class machinery ------------------------------------------
lazy val ScalaValueClasses: collection.Set[Symbol] = Set(
diff --git a/src/dotty/tools/dotc/core/TypeComparers.scala b/src/dotty/tools/dotc/core/TypeComparers.scala
index 7dd874325..e59954fca 100644
--- a/src/dotty/tools/dotc/core/TypeComparers.scala
+++ b/src/dotty/tools/dotc/core/TypeComparers.scala
@@ -201,21 +201,22 @@ object TypeComparers {
}
*/
/** Is `tp1` a subtype of a type `tp2` of the form
- * `scala.HigerKindedN[xBetween_1[Lo_1, Hi_1], ..., xBetween_n[Lo_n, Hi_n]]`?
- * This is the case if `tp1` has `n` type parameters and
- * for all `0 <= i < n`, the i'th type parameter's bounds are contained in
- * `Lo_i..Hi_i` and its variance corresponds to the xBetween_i class.
+ * `scala.HigerKindedXYZ { ... }?
+ * This is the case if `tp1` and `tp2` have the same number
+ * of type parameters, the bounds of tp1's paremeters
+ * are contained in the corresponding bounds of tp2's parameters
+ * and the variances of correesponding parameters agree.
*/
def isSubTypeHK(tp1: Type, tp2: Type): Boolean = {
val tparams = tp1.typeParams
val hkArgs = tp2.typeArgs
(hkArgs.length == tparams.length) && {
val base = ctx.newSkolemSingleton(tp1)
- (hkArgs, tparams).zipped.forall { (hkArg, tparam) =>
- val lo2 :: hi2 :: Nil = hkArg.typeArgs
- val TypeBounds(lo1, hi1) = base.memberInfo(tparam)
- isSubType(lo2, lo1) && isSubType(hi1, hi2) &&
- defn.hkBoundsClass(tparam.variance) == hkArg.typeSymbol
+ (tparams, hkArgs).zipped.forall { (tparam, hkArg) =>
+ base.memberInfo(tparam) <:< hkArg.bounds // TODO: base.memberInfo needed?
+ } &&
+ (tparams, tp2.typeSymbol.typeParams).zipped.forall { (tparam, tparam2) =>
+ tparam.variance == tparam2.variance
}
}
}
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 0acf084c5..71a7e555c 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -227,6 +227,9 @@ object Types {
/** The type parameters of this type are:
* For a ClassInfo type, the type parameters of its class.
* For a typeref referring to a class, the type parameters of the class.
+ * For a typeref referring to an alias type, the type parameters of the aliased type.
+ * For a typeref referring to an abstract type with a HigherKindedXYZ bound, the
+ * type parameters of the HigherKinded class.
* For a refinement type, the type parameters of its parent, unless there's a
* refinement with the same name. Inherited by all other type proxies.
* Empty list for all other types.
@@ -238,7 +241,12 @@ object Types {
val tsym = tp.typeSymbol
if (tsym.isClass) tsym.typeParams
else if (tsym.isAliasType) tp.underlying.typeParams
- else Nil
+ else tp.info.bounds.hi match {
+ case AndType(hkBound, other) if defn.hkTraits contains hkBound.typeSymbol =>
+ hkBound.typeSymbol.typeParams
+ case _ =>
+ Nil
+ }
case tp: RefinedType =>
tp.parent.typeParams filterNot (_.name == tp.refinedName)
case tp: TypeProxy =>
@@ -630,59 +638,21 @@ object Types {
case nil => tp
}
- def hkApp(tp: Type): Type = tp match {
- case AndType(l, r) =>
- hkApp(l) orElse hkApp(r)
- case tp: RefinedType if defn.hkTraits contains tp.typeSymbol =>
- tp
- case tp: TypeProxy =>
- hkApp(tp.underlying)
- }
-
- def hkRefinement(tp: TypeRef): Type = {
- val hkArgs =
- if (tp.symbol.isCompleting)
- // This can happen if a higher-kinded type appears applied to arguments in its own bounds.
- // TODO: Catch this case and mark as "proceed at own risk" later.
- args map (_ => defn.InvariantBetweenClass.typeConstructor)
- else {
- if (tp.info == NoType) {
- println(s"typeless type ref: $tp")
- debugTrace = true
- tp.prefix.member(tp.name)
- }
-
- hkApp(tp.info).typeArgs
- }
- ((tp: Type) /: hkArgs.zipWithIndex.zip(args)) {
- case (parent, ((hkArg, idx), arg)) =>
- val vsym = hkArg.typeSymbol
- val rhs =
- if (vsym == defn.InvariantBetweenClass)
- TypeAlias(arg)
- else if (vsym == defn.CovariantBetweenClass)
- TypeBounds.upper(arg)
- else {
- assert(vsym == defn.ContravariantBetweenClass)
- TypeBounds.lower(arg)
- }
- RefinedType(parent, tpnme.higherKindedParamName(idx), rhs)
+ def safeTypeParams(tsym: Symbol) =
+ if (tsym.isClass || !typeSymbol.isCompleting) typeParams
+ else {
+ ctx.warning("encountered F-bounded higher-kinded type parameters; assuming they are invariant")
+ defn.hkTrait(args map Function.const(0)).typeParams
}
- }
- // begin applied type
if (args.isEmpty) this
else this match {
case tp: PolyType =>
tp.instantiate(args)
case tp: TypeRef =>
val tsym = tp.symbol
- if (tsym.isClass)
- recur(tp, tp.typeParams, args)
- else if (tsym.isAliasType)
- tp.underlying.appliedTo(args)
- else
- hkRefinement(tp)
+ if (tsym.isAliasType) tp.underlying.appliedTo(args)
+ else recur(tp, safeTypeParams(tsym), args)
case tp: TypeProxy =>
tp.underlying.appliedTo(args)
case AndType(l, r) =>
@@ -1236,14 +1206,17 @@ object Types {
override def underlying(implicit ctx: Context) = parent
- def derivedRefinedType(parent: Type, refinedName: Name, refinedInfo: Type)(implicit ctx: Context): RefinedType =
+ def derivedRefinedType(parent: Type, refinedName: Name, refinedInfo: Type)(implicit ctx: Context): RefinedType = {
+ def originalName = parent.typeParams.apply(refinedName.hkParamIndex).name
if ((parent eq this.parent) && (refinedName eq this.refinedName) && (refinedInfo eq this.refinedInfo))
this
- else if (refinedName.isHkParamName && typeParams.length > refinedName.hkParamIndex)
- derivedRefinedType(
- parent, parent.typeParams.apply(refinedName.hkParamIndex).name, refinedInfo)
+ else if (refinedName.isHkParamName &&
+ refinedName.hkParamIndex < typeParams.length &&
+ originalName != refinedName)
+ derivedRefinedType(parent, originalName, refinedInfo)
else
RefinedType(parent, refinedName, rt => refinedInfo.substThis(this, RefinedThis(rt)))
+ }
override def equals(that: Any) = that match {
case that: RefinedType =>
@@ -1641,7 +1614,7 @@ object Types {
* @see Definitions.hkTrait
*/
def higherKinded(boundSyms: List[Symbol])(implicit ctx: Context) = {
- val parent = defn.hkTrait(boundSyms).typeConstructor
+ val parent = defn.hkTrait(boundSyms map (_.variance)).typeConstructor
val hkParamNames = boundSyms.indices.toList map tpnme.higherKindedParamName
def substBoundSyms(tp: Type)(rt: RefinedType): Type =
tp.subst(boundSyms, hkParamNames map (TypeRef(RefinedThis(rt), _)))
diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
index f96115f95..f35c24fd7 100644
--- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala
+++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
@@ -34,47 +34,18 @@ object UnPickler {
case class TempClassInfoType(parentTypes: List[Type], decls: Scope, clazz: Symbol) extends UncachedGroundType
/** Convert temp poly type to some native Dotty idiom.
- * @param forSym The symbol that gets the converted type as info.
- * If `forSym` is not an abstract type, this simply returns an equivalent `PolyType`.
- * If `forSym` is an abstract type, it converts a
+ * @param denot The denotation that gets the converted type as info.
+ * If `denot` is not an abstract type, this simply returns an equivalent `PolyType`.
+ * If `denot` is an abstract type, it converts a
*
* TempPolyType(List(v_1 T_1, ..., v_n T_n), lo .. hi)
*
- * to
- *
- * lo .. HigherKinded_n[v_1Between[lo_1, hi_1],..., v_nBetween[lo_n, hi_n]] & hi
- *
- * where lo_i, hi_i are the lower/upper bounds of the type parameters T_i.
- * This works only as long as none of the type parameters T_i appears in any
- * of the bounds or the result type. Such occurrences of type parameters are
- * replaced by Any, and a warning is issued in this case.
- */
- def depoly(tp: Type, forSym: SymDenotation)(implicit ctx: Context): Type = tp match {
+ * to a higher-kinded type appoximation (@see TypeBounds.higherKinded)
+ */
+ def depoly(tp: Type, denot: SymDenotation)(implicit ctx: Context): Type = tp match {
case TempPolyType(tparams, restpe) =>
- if (forSym.isAbstractType) {
- val typeArgs = for (tparam <- tparams) yield {
- val TypeBounds(lo, hi) = tparam.info
- defn.hkBoundsClass(tparam.variance).typeConstructor
- .appliedTo(List(lo, hi))
- }
- val elimTparams: Type => Type = _.subst(tparams, tparams map (_ => defn.AnyType))
- val correctedArgs = typeArgs.mapConserve(elimTparams)
- val correctedRes = elimTparams(restpe)
- val hkBound = defn.hkTrait(tparams.length).typeConstructor
- .appliedTo(correctedArgs)
- val result = correctedRes match {
- case TypeBounds(lo, hi) =>
- val hi1 = if (hi == defn.AnyType) hkBound else AndType(hkBound, hi)
- TypeBounds(lo, hi1) //note: using & instead would be too eager
- }
- if ((typeArgs ne correctedArgs) || (restpe ne correctedRes))
- ctx.warning(s"""failure to import F-bounded higher-kinded type
- |original type definition: ${forSym.show}${tp.show}
- |definition used instead : ${forSym.show}${result.show}
- |proceed at own risk.""".stripMargin)
- result
- } else
- PolyType.fromSymbols(tparams, restpe)
+ if (denot.isAbstractType) restpe.bounds.higherKinded(tparams)
+ else PolyType.fromSymbols(tparams, restpe)
case tp => tp
}