diff options
author | Martin Odersky <odersky@gmail.com> | 2015-12-18 18:50:18 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2015-12-18 18:50:40 +0100 |
commit | d362455add3fcfb99d87c1e8290d9f6e1bf23654 (patch) | |
tree | 279b5cf47618b27783b3507297db52a3c863c7bb /src/dotty/tools/dotc/core/TypeApplications.scala | |
parent | 570cf0f84b0daa78a6234ead4b5b3c5b58b5db79 (diff) | |
download | dotty-d362455add3fcfb99d87c1e8290d9f6e1bf23654.tar.gz dotty-d362455add3fcfb99d87c1e8290d9f6e1bf23654.tar.bz2 dotty-d362455add3fcfb99d87c1e8290d9f6e1bf23654.zip |
Fix higher-kinded unions and intersections
Since And/Or type themselves are parameterless, their
the union and intersection of hgiher-kinded types has to be treated
specially: The types have to be pulled under a common lambda.
Diffstat (limited to 'src/dotty/tools/dotc/core/TypeApplications.scala')
-rw-r--r-- | src/dotty/tools/dotc/core/TypeApplications.scala | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index fbab4ee39..9a12d2635 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -173,8 +173,45 @@ object TypeApplications { if (tparams.isEmpty) args else args.zipWithConserve(tparams)((arg, tparam) => arg.etaExpandIfHK(tparam.infoOrCompleter)) + /** The references `<rt>.this.$hk0, ..., <rt>.this.$hk<n-1>`. */ def argRefs(rt: RefinedType, n: Int)(implicit ctx: Context) = List.range(0, n).map(i => RefinedThis(rt).select(tpnme.hkArg(i))) + + /** Merge `tp1` and `tp2` under a common lambda, combining them with `op`. + * @param tparams1 The type parameters of `tp1` + * @param tparams2 The type parameters of `tp2` + * Produces the type lambda + * + * [v1 X1 B1, ..., vn Xn Bn] -> op(tp1[X1, ..., Xn], tp2[X1, ..., Xn]) + * + * where + * + * - variances `vi` are the variances of corresponding type parameters for `tp1` + * or `tp2`, or are 0 of the latter disagree. + * - bounds `Bi` are the intersection of the corresponding type parameter bounds + * of `tp1` and `tp2`. + */ + def hkCombine(tp1: Type, tp2: Type, + tparams1: List[TypeSymbol], tparams2: List[TypeSymbol], op: (Type, Type) => Type) + (implicit ctx: Context): Type = { + val variances = (tparams1, tparams2).zipped.map { (tparam1, tparam2) => + val v1 = tparam1.variance + val v2 = tparam2.variance + if (v1 == v2) v1 else 0 + } + val bounds: List[RefinedType => TypeBounds] = + (tparams1, tparams2).zipped.map { (tparam1, tparam2) => + val b1: RefinedType => TypeBounds = + tp1.memberInfo(tparam1).bounds.internalizeFrom(tparams1) + val b2: RefinedType => TypeBounds = + tp2.memberInfo(tparam2).bounds.internalizeFrom(tparams2) + (rt: RefinedType) => b1(rt) & b2(rt) + } + val app1: RefinedType => Type = rt => tp1.appliedTo(argRefs(rt, tparams1.length)) + val app2: RefinedType => Type = rt => tp2.appliedTo(argRefs(rt, tparams2.length)) + val body = (rt: RefinedType) => op(app1(rt), app2(rt)) + TypeLambda(variances, bounds, body) + } } import TypeApplications._ @@ -273,6 +310,14 @@ class TypeApplications(val self: Type) extends AnyVal { false } + /** Replace references to type parameters with references to hk arguments `this.$hk_i` + * Care is needed not to cause cyclic reference errors, hence `SafeSubstMap`. + */ + private[TypeApplications] def internalizeFrom[T <: Type](tparams: List[Symbol])(implicit ctx: Context): RefinedType => T = + (rt: RefinedType) => + new ctx.SafeSubstMap(tparams , argRefs(rt, tparams.length)) + .apply(self).asInstanceOf[T] + /** Lambda abstract `self` with given type parameters. Examples: * * type T[X] = U becomes type T = [X] -> U |