aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/TypeApplications.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-12-06 15:36:34 +0100
committerMartin Odersky <odersky@gmail.com>2015-12-06 16:17:44 +0100
commit7f6decfe9b30396fb788a16639eb9e4700f532b0 (patch)
tree6731fdbed48739a19f1e5ffdfc979f31a421b896 /src/dotty/tools/dotc/core/TypeApplications.scala
parentb8c6e73eb970894c12eb11f3b99123f502d52ae7 (diff)
downloaddotty-7f6decfe9b30396fb788a16639eb9e4700f532b0.tar.gz
dotty-7f6decfe9b30396fb788a16639eb9e4700f532b0.tar.bz2
dotty-7f6decfe9b30396fb788a16639eb9e4700f532b0.zip
Code and documentation cleanups
Diffstat (limited to 'src/dotty/tools/dotc/core/TypeApplications.scala')
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala407
1 files changed, 107 insertions, 300 deletions
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index ab15b3e1a..684e83633 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -107,12 +107,6 @@ object TypeApplications {
tp match {
case TypeLambda(_, argBounds, AppliedType(fn: TypeRef, args))
if argsAreForwarders(args, tp.typeParams.length) => Some(fn)
- //case TypeLambda(_, argBounds, AppliedType(fn: TypeRef, args)) =>
- // println(i"eta expansion failed because args $args are not forwarders for ${tp.toString}")
- // None
- //case TypeLambda(_, argBounds, _) =>
- // println(i"eta expansion failed because body is not applied type")
- // None
case _ => None
}
}
@@ -210,9 +204,14 @@ class TypeApplications(val self: Type) extends AnyVal {
Nil
else tsym.info.typeParams
case self: RefinedType =>
- val hkParams = self.hkTypeParams
- if (hkParams.nonEmpty) hkParams
- else self.parent.typeParams.filterNot(_.name == self.refinedName)
+ // inlined and optimized version of
+ // val sym = self.LambdaTrait
+ // if (sym.exists) return sym.typeParams
+ if (self.refinedName == tpnme.hkApply) {
+ val sym = self.parent.classSymbol
+ if (sym.isLambdaTrait) return sym.typeParams
+ }
+ self.parent.typeParams.filterNot(_.name == self.refinedName)
case self: SingletonType =>
Nil
case self: TypeProxy =>
@@ -222,16 +221,6 @@ class TypeApplications(val self: Type) extends AnyVal {
}
}
- /** The higherkinded type parameters in case this is a type lambda
- *
- * [X1, ..., Xn] -> T
- *
- * These are the parameters of the underlying lambda class.
- * Returns `Nil` for all other types.
- */
- final def hkTypeParams(implicit ctx: Context): List[TypeSymbol] =
- self.LambdaTrait.typeParams
-
/** The Lambda trait underlying a type lambda */
def LambdaTrait(implicit ctx: Context): Symbol = self.stripTypeVar match {
case RefinedType(parent, tpnme.hkApply) =>
@@ -241,25 +230,56 @@ class TypeApplications(val self: Type) extends AnyVal {
case _ => NoSymbol
}
- /** A type ref is eta expandable if it refers to a non-lambda class.
- * In that case we can look for parameterized base types fo the type
- * to eta expand them.
- */
- def isEtaExpandable(implicit ctx: Context) = self match {
- case self: TypeRef => self.symbol.isClass && !self.name.isLambdaTraitName
+ /** Is receiver type higher-kinded (i.e. of kind != "*")? */
+ def isHK(implicit ctx: Context): Boolean = self.dealias match {
+ case self: TypeRef => self.info.isHK
+ case RefinedType(_, name) => name == tpnme.hkApply
+ case TypeBounds(_, hi) => hi.isHK
+ case _ => false
+ }
+
+ /** is receiver of the form T#$Apply? */
+ def isHKApply: Boolean = self match {
+ case TypeRef(_, name) => name == tpnme.hkApply
case _ => false
}
+ /** True if it can be determined without forcing that the class symbol
+ * of this application exists and is not a lambda trait.
+ * Equivalent to
+ *
+ * self.classSymbol.exists && !self.classSymbol.isLambdaTrait
+ *
+ * but without forcing anything.
+ */
+ def classNotLambda(implicit ctx: Context): Boolean = self.stripTypeVar match {
+ case self: RefinedType =>
+ self.parent.classNotLambda
+ case self: TypeRef =>
+ self.denot.exists && {
+ val sym = self.symbol
+ if (sym.isClass) !sym.isLambdaTrait
+ else sym.isCompleted && self.info.isAlias && self.info.bounds.hi.classNotLambda
+ }
+ case _ =>
+ false
+ }
+
/** 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)
*/
def LambdaAbstract(tparams: List[Symbol])(implicit ctx: Context): Type = {
+
+ /** Replace references to type parameters with references to hk arguments `this.$hk_i`
+ * Care is needed not to cause cycles, hence `SafeSubstMap`.
+ */
def internalize[T <: Type](tp: T) =
(rt: RefinedType) =>
new ctx.SafeSubstMap(tparams, argRefs(rt, tparams.length))
.apply(tp).asInstanceOf[T]
+
def expand(tp: Type) = {
TypeLambda(
tparams.map(_.variance),
@@ -274,15 +294,41 @@ class TypeApplications(val self: Type) extends AnyVal {
case _ => expand(self)
}
}
-/*
- def betaReduce(implicit ctx: Context): Type = self.stripTypeVar match {
- case TypeRef(prefix, tpnme.hkApply) =>
- prefix.betaReduce
- case self @ RefinedType(parent, tpnme.hkArg) if parent.isTypeLambda =>
- HKApplication(parent, self.refinedInfo.dropAlias)
+
+ /** A type ref is eta expandable if it refers to a non-lambda class.
+ * In that case we can look for parameterized base types of the type
+ * to eta expand them.
+ */
+ def isEtaExpandable(implicit ctx: Context) = self match {
+ case self: TypeRef => self.symbol.isClass && !self.name.isLambdaTraitName
+ case _ => false
+ }
+
+ /** Convert a type constructor `TC` which has type parameters `T1, ..., Tn`
+ * in a context where type parameters `U1,...,Un` are expected to
+ *
+ * LambdaXYZ { Apply = TC[hk$0, ..., hk$n] }
+ *
+ * Here, XYZ corresponds to the variances of
+ * - `U1,...,Un` if the variances of `T1,...,Tn` are pairwise compatible with `U1,...,Un`,
+ * - `T1,...,Tn` otherwise.
+ * v1 is compatible with v2, if v1 = v2 or v2 is non-variant.
+ */
+ def EtaExpand(tparams: List[TypeSymbol])(implicit ctx: Context): Type = {
+ val tparamsToUse = if (variancesConform(typeParams, tparams)) tparams else typeParams
+ self.appliedTo(tparams map (_.typeRef)).LambdaAbstract(tparamsToUse)
+ //.ensuring(res => res.EtaReduce =:= self, s"res = $res, core = ${res.EtaReduce}, self = $self, hc = ${res.hashCode}")
+ }
+
+ /** Eta expand the prefix in front of any refinements. */
+ def EtaExpandCore(implicit ctx: Context): Type = self.stripTypeVar match {
+ case self: RefinedType =>
+ self.derivedRefinedType(self.parent.EtaExpandCore, self.refinedName, self.refinedInfo)
+ case _ =>
+ self.EtaExpand(self.typeParams)
}
-*/
- /** Adapt argument A to type parameter P in the case P is higher-kinded.
+
+ /** Adapt argument A to type parameter P in the case P is higher-kinded.
* This means:
* (1) Make sure that A is a type lambda, if necessary by eta-expanding it.
* (2) Make sure the variances of the type lambda
@@ -331,77 +377,21 @@ class TypeApplications(val self: Type) extends AnyVal {
}
}
- /*
- /** If type `self` is equal, aliased-to, or upperbounded-by a type of the form
- * `LambdaXYZ { ... }`, the class symbol of that type, otherwise NoSymbol.
- * symbol of that type, otherwise NoSymbol.
- * @param forcing if set, might force completion. If not, never forces
- * but returns NoSymbol when it would have to otherwise.
- */
- def LambdaClass(forcing: Boolean)(implicit ctx: Context): Symbol = track("LambdaClass") { self.stripTypeVar match {
- case self: TypeRef =>
- val sym = self.symbol
- if (sym.isLambdaTrait) sym
- else if (sym.isClass || sym.isCompleting && !forcing) NoSymbol
- else self.info.LambdaClass(forcing)
- case self: TypeProxy =>
- self.underlying.LambdaClass(forcing)
- case _ =>
- NoSymbol
- }}
-
- /** Is type `self` equal, aliased-to, or upperbounded-by a type of the form
- * `LambdaXYZ { ... }`?
- */
- def isLambda(implicit ctx: Context): Boolean =
- LambdaClass(forcing = true).exists
-
- /** Same is `isLambda`, except that symbol denotations are not forced
- * Symbols in completion count as not lambdas.
- */
- def isSafeLambda(implicit ctx: Context): Boolean =
- LambdaClass(forcing = false).exists
-
- /** Is type `self` a Lambda with all hk$i fields fully instantiated? */
- def isInstantiatedLambda(implicit ctx: Context): Boolean =
- isSafeLambda && typeParams.isEmpty
-*/
- /** Is receiver type higher-kinded (i.e. of kind != "*")? */
- def isHK(implicit ctx: Context): Boolean = self.dealias match {
- case self: TypeRef => self.info.isHK
- case RefinedType(_, name) => name == tpnme.hkApply
- case TypeBounds(_, hi) => hi.isHK
- case _ => false
- }
-
- /** is receiver of the form T#$apply? */
- def isHKApply: Boolean = self match {
- case TypeRef(_, name) => name == tpnme.hkApply
- case _ => false
- }
-
- /** True if it can be determined without forcing that the class symbol
- * of this application exists and is not a lambda trait.
- * Equivalent to
+ /** Encode
*
- * self.classSymbol.exists && !self.classSymbol.isLambdaTrait
+ * T[U1, ..., Un]
*
- * but without forcing anything.
+ * where
+ * @param self = `T`
+ * @param args = `U1,...,Un`
+ * performing the following simplifications
+ *
+ * 1. If `T` is an eta expansion `[X1,..,Xn] -> C[X1,...,Xn]` of class `C` compute
+ * `C[U1, ..., Un]` instead.
+ * 2. If `T` is some other type lambda `[X1,...,Xn] -> S` none of the arguments
+ * `U1,...,Un` is a wildcard, compute `[X1:=U1, ..., Xn:=Un]S` instead.
+ * 3. If `T` is a polytype, instantiate it to `U1,...,Un`.
*/
- def classNotLambda(implicit ctx: Context): Boolean = self.stripTypeVar match {
- case self: RefinedType =>
- self.parent.classNotLambda
- case self: TypeRef =>
- self.denot.exists && {
- val sym = self.symbol
- if (sym.isClass) !sym.isLambdaTrait
- else sym.isCompleted && self.info.isAlias && self.info.bounds.hi.classNotLambda
- }
- case _ =>
- false
- }
-
- /** Encode the type resulting from applying this type to given arguments */
final def appliedTo(args: List[Type])(implicit ctx: Context): Type = /*>|>*/ track("appliedTo") /*<|<*/ {
def substHkArgs = new TypeMap {
def apply(tp: Type): Type = tp match {
@@ -424,7 +414,12 @@ class TypeApplications(val self: Type) extends AnyVal {
}
}
- def appliedTo(args: List[Type], typParams: List[TypeSymbol])(implicit ctx: Context): Type = {
+ /** Encode application `T[U1, ..., Un]` without simplifications, where
+ * @param self = `T`
+ * @param args = `U1, ..., Un`
+ * @param tparams are assumed to be the type parameters of `T`.
+ */
+ final def appliedTo(args: List[Type], typParams: List[TypeSymbol])(implicit ctx: Context): Type = {
def matchParams(t: Type, tparams: List[TypeSymbol], args: List[Type])(implicit ctx: Context): Type = args match {
case arg :: args1 =>
try {
@@ -447,10 +442,14 @@ class TypeApplications(val self: Type) extends AnyVal {
}
}
-
final def appliedTo(arg: Type)(implicit ctx: Context): Type = appliedTo(arg :: Nil)
final def appliedTo(arg1: Type, arg2: Type)(implicit ctx: Context): Type = appliedTo(arg1 :: arg2 :: Nil)
+ /** A cycle-safe version of `appliedTo` where computing type parameters do not force
+ * the typeconstructor. Instead, if the type constructor is completing, we make
+ * up hk type parameters matching the arguments. This is needed when unpickling
+ * Scala2 files such as `scala.collection.generic.Mapfactory`.
+ */
final def safeAppliedTo(args: List[Type])(implicit ctx: Context) = {
val safeTypeParams = self match {
case self: TypeRef if !self.symbol.isClass && self.symbol.isCompleting =>
@@ -462,18 +461,6 @@ class TypeApplications(val self: Type) extends AnyVal {
}
appliedTo(args, safeTypeParams)
}
-/*
- /** Simplify a fully instantiated type of the form `LambdaX{... type Apply = T } # Apply` to `T`.
- */
- def simplifyApply(implicit ctx: Context): Type = self match {
- case self @ TypeRef(prefix, tpnme.hkApply) if prefix.isInstantiatedLambda =>
- prefix.member(tpnme.hkApply).info match {
- case TypeAlias(alias) => alias
- case _ => self
- }
- case _ => self
- }
-*/
/** Turn this type, which is used as an argument for
* type parameter `tparam`, into a TypeBounds RHS
@@ -488,7 +475,7 @@ class TypeApplications(val self: Type) extends AnyVal {
else TypeAlias(self, v)
}
- /** The type arguments of this type's base type instance wrt.`base`.
+ /** The type arguments of this type's base type instance wrt. `base`.
* Existential types in arguments are returned as TypeBounds instances.
*/
final def baseArgInfos(base: Symbol)(implicit ctx: Context): List[Type] =
@@ -616,6 +603,7 @@ class TypeApplications(val self: Type) extends AnyVal {
case _ => NoType
}
+ /** If this is a type alias, its underlying type, otherwise the type itself */
def dropAlias(implicit ctx: Context): Type = self match {
case TypeAlias(alias) => alias
case _ => self
@@ -628,6 +616,9 @@ class TypeApplications(val self: Type) extends AnyVal {
case _ => firstBaseArgInfo(defn.SeqClass)
}
+ /** Does this type contain RefinedThis type with `target` as its underling
+ * refinement type?
+ */
def containsRefinedThis(target: Type)(implicit ctx: Context): Boolean = {
def recur(tp: Type): Boolean = tp.stripTypeVar match {
case RefinedThis(tp) =>
@@ -651,188 +642,4 @@ class TypeApplications(val self: Type) extends AnyVal {
}
recur(self)
}
-/*
- /** The typed lambda abstraction of this type `T` relative to `boundSyms`.
- * This is:
- *
- * LambdaXYZ{ bounds }{ type Apply = toHK(T) }
- *
- * where
- * - XYZ reflects the variances of the bound symbols,
- * - `bounds` consists of type declarations `type hk$i >: toHK(L) <: toHK(U),
- * one for each type parameter in `T` with non-trivial bounds L,U.
- * - `toHK` is a substitution that replaces every bound symbol sym_i by
- * `this.hk$i`.
- *
- * TypeBounds are lambda abstracting by lambda abstracting their upper bound.
- *
- * @param cycleParanoid If `true` don't force denotation of a TypeRef unless
- * its name matches one of `boundSyms`. Needed to avoid cycles
- * involving F-boundes hk-types when reading Scala2 collection classes
- * with new hk-scheme.
- */
- def LambdaAbstract(boundSyms: List[Symbol], cycleParanoid: Boolean = false)(implicit ctx: Context): Type = {
- def expand(tp: Type): Type = {
- val lambda = defn.LambdaTrait(boundSyms.map(_.variance))
- def toHK(tp: Type) = (rt: RefinedType) => {
- val argRefs = boundSyms.indices.toList.map(i =>
- RefinedThis(rt).select(tpnme.hkArg(i)))
- val substituted =
- if (cycleParanoid) new ctx.SafeSubstMap(boundSyms, argRefs).apply(tp)
- else tp.subst(boundSyms, argRefs)
- substituted.bounds.withVariance(1)
- }
- val boundNames = new mutable.ListBuffer[Name]
- val boundss = new mutable.ListBuffer[TypeBounds]
- for (sym <- boundSyms) {
- val bounds = sym.info.bounds
- if (!(TypeBounds.empty frozen_<:< bounds)) {
- boundNames += sym.name
- boundss += bounds
- }
- }
- val lambdaWithBounds =
- RefinedType.make(lambda.typeRef, boundNames.toList, boundss.toList.map(toHK))
- RefinedType(lambdaWithBounds, tpnme.hkApply, toHK(tp))
- }
- self match {
- case self @ TypeBounds(lo, hi) =>
- self.derivedTypeBounds(lo, expand(TypeBounds.upper(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
- *
- * LambdaXYZ { Apply = TC[hk$0, ..., hk$n] }
- *
- * Here, XYZ corresponds to the variances of
- * - `U1,...,Un` if the variances of `T1,...,Tn` are pairwise compatible with `U1,...,Un`,
- * - `T1,...,Tn` otherwise.
- * v1 is compatible with v2, if v1 = v2 or v2 is non-variant.
- */
- def EtaExpand(tparams: List[TypeSymbol])(implicit ctx: Context): Type = {
- val tparamsToUse = if (variancesConform(typeParams, tparams)) tparams else typeParams
- self.appliedTo(tparams map (_.typeRef)).LambdaAbstract(tparamsToUse)
- //.ensuring(res => res.EtaReduce =:= self, s"res = $res, core = ${res.EtaReduce}, self = $self, hc = ${res.hashCode}")
- }
-/*
- /** Eta expand if `bound` is a higher-kinded type */
- def EtaExpandIfHK(bound: Type)(implicit ctx: Context): Type =
- if (bound.isHK && !isHK && self.typeSymbol.isClass && typeParams.nonEmpty) EtaExpand(bound.typeParams)
- else self
-*/
- /** Eta expand the prefix in front of any refinements. */
- def EtaExpandCore(implicit ctx: Context): Type = self.stripTypeVar match {
- case self: RefinedType =>
- self.derivedRefinedType(self.parent.EtaExpandCore, self.refinedName, self.refinedInfo)
- case _ =>
- self.EtaExpand(self.typeParams)
- }
-/*
- /** If `self` is a (potentially partially instantiated) eta expansion of type T, return T,
- * otherwise NoType. More precisely if `self` is of the form
- *
- * T { type $apply = U[T1, ..., Tn] }
- *
- * where
- *
- * - hk$0, ..., hk${m-1} are the type parameters of T
- * - a sublist of the arguments Ti_k (k = 0,...,m_1) are of the form T{...}.this.hk$i_k
- *
- * rewrite `self` to
- *
- * U[T'1,...T'j]
- *
- * where
- *
- * T'j = _ >: Lj <: Uj if j is in the i_k list defined above
- * where Lj and Uj are the bounds of hk$j mapped using `fromHK`.
- * = fromHK(Tj) otherwise.
- *
- * `fromHK` is the function that replaces every occurrence of `<self>.this.hk$i` by the
- * corresponding parameter reference in `U[T'1,...T'j]`
- */
- def EtaReduce(implicit ctx: Context): Type = {
- def etaCore(tp: Type, tparams: List[Symbol]): Type = tparams match {
- case Nil => tp
- case tparam :: otherParams =>
- tp match {
- case tp: RefinedType =>
- tp.refinedInfo match {
- case TypeAlias(TypeRef(RefinedThis(rt), rname))
- if (rname == tparam.name) && (rt eq self) =>
- // we have a binding T = Lambda$XYZ{...}.this.hk$i where hk$i names the current `tparam`.
- val pcore = etaCore(tp.parent, otherParams)
- val hkBounds = self.member(rname).info.bounds
- if (TypeBounds.empty frozen_<:< hkBounds) pcore
- else tp.derivedRefinedType(pcore, tp.refinedName, hkBounds)
- case _ =>
- val pcore = etaCore(tp.parent, tparams)
- if (pcore.exists) tp.derivedRefinedType(pcore, tp.refinedName, tp.refinedInfo)
- else NoType
- }
- case _ =>
- NoType
- }
- }
- // Map references `Lambda$XYZ{...}.this.hk$i to corresponding parameter references of the reduced core.
- def fromHK(reduced: Type) = reduced match {
- case reduced: RefinedType =>
- new TypeMap {
- def apply(tp: Type): Type = tp match {
- case TypeRef(RefinedThis(binder), name) if binder eq self =>
- assert(name.isHkArgName)
- RefinedThis(reduced).select(reduced.typeParams.apply(name.hkArgIndex))
- case _ =>
- mapOver(tp)
- }
- }.apply(reduced)
- case _ =>
- reduced
- }
-
- self match {
- case self @ RefinedType(parent, tpnme.hkApply) =>
- val lc = parent.LambdaClass(forcing = false)
- self.refinedInfo match {
- case TypeAlias(alias) if lc.exists =>
- fromHK(etaCore(alias, lc.typeParams.reverse))
- case _ => NoType
- }
- case _ => NoType
- }
- }
-
- /** Test whether this type has a base type of the form `B[T1, ..., Tn]` where
- * the type parameters of `B` match one-by-one the variances of `tparams`,
- * and where the lambda abstracted type
- *
- * LambdaXYZ { type Apply = B[hk$0, ..., hk${n-1}] }
- * { type hk$0 = T1; ...; type hk${n-1} = Tn }
- *
- * satisfies predicate `p`. Try base types in the order of their occurrence in `baseClasses`.
- * A type parameter matches a variance V if it has V as its variance or if V == 0.
- * @param classBounds A hint to bound the search. Only types that derive from one of the
- * classes in classBounds are considered.
- */
- def testLifted(tparams: List[Symbol], p: Type => Boolean, classBounds: List[ClassSymbol] = Nil)(implicit ctx: Context): Boolean = {
- def recur(bcs: List[ClassSymbol]): Boolean = bcs match {
- case bc :: bcs1 =>
- val baseRef = self.baseTypeRef(bc)
- def variancesMatch(param1: Symbol, param2: Symbol) =
- param2.variance == param2.variance || param2.variance == 0
- (classBounds.exists(bc.derivesFrom) &&
- baseRef.typeParams.corresponds(tparams)(variancesMatch) &&
- p(baseRef.appliedTo(self.baseArgInfos(bc)))
- ||
- recur(bcs1))
- case nil =>
- false
- }
- classBounds.nonEmpty && recur(self.baseClasses)
- }
- */
}