aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/TypeComparer.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-06-29 09:50:27 +0200
committerMartin Odersky <odersky@gmail.com>2016-07-11 13:35:06 +0200
commit6bd7ba9ea4484ee2065dd16077cba6c26b2050d9 (patch)
tree7b13e292f072fed02e0ba9a8a431eef92f71cf57 /src/dotty/tools/dotc/core/TypeComparer.scala
parenta23c1a476296a25566d7aa08de676a1217b243cb (diff)
downloaddotty-6bd7ba9ea4484ee2065dd16077cba6c26b2050d9.tar.gz
dotty-6bd7ba9ea4484ee2065dd16077cba6c26b2050d9.tar.bz2
dotty-6bd7ba9ea4484ee2065dd16077cba6c26b2050d9.zip
Remove refinement encoding of hk types
Remove the code that implemented the encoding of hk types using refinements. Drop the notion that RefinedTypes can be type parameters. This is no longer true under the new representation. Also, refactoring MemberBinding -> TypeParamInfo
Diffstat (limited to 'src/dotty/tools/dotc/core/TypeComparer.scala')
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala175
1 files changed, 15 insertions, 160 deletions
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 38b45b2b0..55a964ee9 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -364,16 +364,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
// This twist is needed to make collection/generic/ParFactory.scala compile
fourthTry(tp1, tp2) || compareRefinedSlow
case _ =>
- if (tp2.isTypeParam) {
- compareHkLambdaOLD(tp1, tp2) ||
- fourthTry(tp1, tp2)
- }
- else {
- compareHkApplyOLD(tp2, tp1, inOrder = false) ||
- compareRefinedSlow ||
- fourthTry(tp1, tp2) ||
- compareAliasedRefined(tp2, tp1, inOrder = false)
- }
+ compareRefinedSlow ||
+ fourthTry(tp1, tp2) ||
+ compareAliasedRefined(tp2, tp1, inOrder = false) // @@@ still needed?
}
else // fast path, in particular for refinements resulting from parameterization.
isSubRefinements(tp1w.asInstanceOf[RefinedType], tp2, skipped2) &&
@@ -399,7 +392,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
// so the bounds checking should look like this:
//
// tparams1.corresponds(tparams2)((tparam1, tparam2) =>
- // isSubType(tparam2.memberBounds.subst(tp2, tp1), tparam1.memberBounds))
+ // isSubType(tparam2.paramBounds.subst(tp2, tp1), tparam1.paramBounds))
//
// But that would invalidate a pattern such as
// `[X0 <: Number] -> Number <:< [X0] -> Any`
@@ -531,7 +524,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
}
isNewSubType(tp1.underlying.widenExpr, tp2) || comparePaths
case tp1: RefinedType =>
- compareHkApplyOLD(tp1, tp2, inOrder = true) ||
isNewSubType(tp1.parent, tp2) ||
compareAliasedRefined(tp1, tp2, inOrder = true)
case tp1: RecType =>
@@ -693,10 +685,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
/** Subtype test for corresponding arguments in `args1`, `args2` according to
* variances in type parameters `tparams`.
*/
- def isSubArgs(args1: List[Type], args2: List[Type], tparams: List[MemberBinding]): Boolean =
+ def isSubArgs(args1: List[Type], args2: List[Type], tparams: List[TypeParamInfo]): Boolean =
if (args1.isEmpty) args2.isEmpty
else args2.nonEmpty && {
- val v = tparams.head.memberVariance
+ val v = tparams.head.paramVariance
(v > 0 || isSubType(args2.head, args1.head)) &&
(v < 0 || isSubType(args1.head, args2.head))
}
@@ -706,7 +698,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
* - the type parameters of `B` match one-by-one the variances of `tparams`,
* - `B` satisfies predicate `p`.
*/
- private def testLifted(tp1: Type, tp2: Type, tparams: List[MemberBinding], p: Type => Boolean): Boolean = {
+ private def testLifted(tp1: Type, tp2: Type, tparams: List[TypeParamInfo], p: Type => Boolean): Boolean = {
val classBounds = tp2.classSymbols
def recur(bcs: List[ClassSymbol]): Boolean = bcs match {
case bc :: bcs1 =>
@@ -722,109 +714,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
recur(tp1.baseClasses)
}
- /** Handle subtype tests
- *
- * app <:< other if inOrder = true
- * other <:< app if inOrder = false
- *
- * where `app` is an hk application but `other` is not.
- *
- * As a first step, if `app` appears on the right, try to normalize it using
- * `normalizeHkApply`, if that gives a different type proceed with a regular subtype
- * test using that type instead of `app`.
- *
- * Otherwise, if `app` has constrainable poly param as type constructor,
- * perform the following steps:
- *
- * (1) If not `inOrder` then perform the next steps until they all succeed
- * for each base type of other which
- * - derives from a class bound of `app`,
- * - has the same number of type parameters as `app`
- * - has type parameter variances which conform to those of `app`.
- * If `inOrder` then perform the same steps on the original `other` type.
- *
- * (2) Try to eta expand the constructor of `other`.
- *
- * (3a) In mode `TypevarsMissConetxt` replace the projection's hk constructor parameter
- * by the eta expansion of step (2) reapplied to the projection's arguments.
- * (3b) In normal mode, try to unify the projection's hk constructor parameter with
- * the eta expansion of step(2)
- *
- * (4) If `inOrder`, test `app <: other` else test `other <: app`.
- */
- def compareHkApplyOLD(app: RefinedType, other: Type, inOrder: Boolean): Boolean = {
- def tryInfer(tp: Type): Boolean = ctx.traceIndented(i"compareHK($app, $other, inOrder = $inOrder, constr = $tp)", subtyping) {
- tp match {
- case tp: TypeVar => tryInfer(tp.underlying)
- case param: PolyParam if canConstrain(param) =>
-
- def unifyWith(liftedOther: Type): Boolean = {
- subtyping.println(i"unify with $liftedOther")
- liftedOther.typeConstructor.widen match {
- case tycon: TypeRef if tycon.isEtaExpandableOLD && tycon.typeParams.nonEmpty =>
- val (ok, app1) =
- if (ctx.mode.is(Mode.TypevarsMissContext))
- (true, EtaExpansion(tycon).appliedTo(app.argInfos))
- else
- (tryInstantiate(param, EtaExpansion(tycon)), app)
- ok &&
- (if (inOrder) isSubType(app1, other) else isSubType(other, app1))
- case _ =>
- false
- }
- }
- val hkTypeParams = param.typeParams
- subtyping.println(i"classBounds = ${app.classSymbols}")
- subtyping.println(i"base classes = ${other.baseClasses}")
- subtyping.println(i"type params = $hkTypeParams, ${app.classSymbol}")
- if (inOrder) unifyWith(other)
- else testLifted(other, app, hkTypeParams, unifyWith)
- case _ =>
- // why only handle the case where one of the sides is a typevar or poly param?
- // If the LHS is a hk application, then the normal logic already handles
- // all other cases. Indeed, say you have
- //
- // type C[T] <: List[T]
- //
- // where C is an abstract type. Then to verify `C[Int] <: List[Int]`,
- // use compareRefinedslow to get `C <: List` and verify that
- //
- // C#List$T = C$$hk0 = Int
- //
- // If the RHS is a hk application, we can also go through
- // the normal logic because lower bounds are not parameterized.
- // If were to re-introduce parameterized lower bounds of hk types
- // we'd have to add some logic to handle them here.
- false
- }
- }
- app.isHKApplyOLD && !other.isHKApplyOLD && {
- val reduced = if (inOrder) app else app.normalizeHkApplyOLD
- if (reduced ne app)
- if (inOrder) isSubType(reduced, other) else isSubType(other, reduced)
- else tryInfer(app.typeConstructor.dealias)
- }
- }
-
- /** Compare type lambda with non-lambda type. */
- def compareHkLambdaOLD(tp1: Type, tp2: RefinedType): Boolean = tp1.stripTypeVar match {
- case TypeLambdaOLD(args1, body1) =>
- //println(i"comparing $tp1 <:< $tp2")
- tp2 match {
- case TypeLambdaOLD(args2, body2) =>
- args1.corresponds(args2)((arg1, arg2) =>
- varianceConforms(BindingKind.toVariance(arg1.bindingKind),
- BindingKind.toVariance(arg2.bindingKind))) &&
- // don't compare bounds; it would go in the wrong sense anyway.
- isSubType(body1, body2)
- case _ => false
- }
- case RefinedType(parent1, _, _) =>
- compareHkLambdaOLD(parent1, tp2)
- case _ =>
- false
- }
-
/** Say we are comparing a refined type `P{type M = U}` or `P{type M >: L <: U}`.
* If P#M refers to a BaseTypeArg aliased to some other typeref P#N,
* do the same comparison with `P{type N = U}` or `P{type N >: L <: U}`, respectively.
@@ -1324,45 +1213,25 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
private def liftIfHK(tp1: Type, tp2: Type, op: (Type, Type) => Type, original: (Type, Type) => Type) = {
val tparams1 = tp1.typeParams
val tparams2 = tp2.typeParams
- if (!Config.newHK && tparams1.isEmpty || tparams2.isEmpty) op(tp1, tp2)
- else if (Config.newHK && tparams1.isEmpty)
+ if (tparams1.isEmpty)
if (tparams2.isEmpty) op(tp1, tp2)
- else original(tp1, tp2.appliedTo(tp2.typeParams.map(_.memberBoundsAsSeenFrom(tp2))))
- else if (Config.newHK && tparams2.isEmpty)
- original(tp1.appliedTo(tp1.typeParams.map(_.memberBoundsAsSeenFrom(tp1))), tp2)
- else if (!Config.newHK && (tparams1.isEmpty || tparams2.isEmpty)) op(tp1, tp2)
- else if (!Config.newHK && tparams1.length != tparams2.length) mergeConflict(tp1, tp2)
- else if (Config.newHK) {
+ else original(tp1, tp2.appliedTo(tp2.typeParams.map(_.paramBoundsAsSeenFrom(tp2))))
+ else if (tparams2.isEmpty)
+ original(tp1.appliedTo(tp1.typeParams.map(_.paramBoundsAsSeenFrom(tp1))), tp2)
+ else {
val numArgs = tparams1.length
def argRefs(tl: GenericType) = List.range(0, numArgs).map(PolyParam(tl, _))
TypeLambda(
paramNames = tpnme.syntheticLambdaParamNames(numArgs),
variances = (tparams1, tparams2).zipped.map((tparam1, tparam2) =>
- (tparam1.memberVariance + tparam2.memberVariance) / 2))(
+ (tparam1.paramVariance + tparam2.paramVariance) / 2))(
paramBoundsExp = tl => (tparams1, tparams2).zipped.map((tparam1, tparam2) =>
- tl.lifted(tparams1, tparam1.memberBoundsAsSeenFrom(tp1)).bounds &
- tl.lifted(tparams2, tparam2.memberBoundsAsSeenFrom(tp2)).bounds),
+ tl.lifted(tparams1, tparam1.paramBoundsAsSeenFrom(tp1)).bounds &
+ tl.lifted(tparams2, tparam2.paramBoundsAsSeenFrom(tp2)).bounds),
resultTypeExp = tl =>
original(tl.lifted(tparams1, tp1).appliedTo(argRefs(tl)),
tl.lifted(tparams2, tp2).appliedTo(argRefs(tl))))
}
- else {
- val bindings: List[RecType => TypeBounds] =
- (tparams1, tparams2).zipped.map { (tparam1, tparam2) =>
- val b1: RecType => TypeBounds =
- tparam1.memberBoundsAsSeenFrom(tp1).recursifyOLD(tparams1)
- val b2: RecType => TypeBounds =
- tparam2.memberBoundsAsSeenFrom(tp2).recursifyOLD(tparams2)
- (rt: RecType) => (b1(rt) & b2(rt))
- .withBindingKind(
- BindingKind.fromVariance(
- (tparam1.memberVariance + tparam2.memberVariance) / 2))
- }
- val app1: RecType => Type = rt => tp1.appliedTo(argRefsOLD(rt, tparams1.length))
- val app2: RecType => Type = rt => tp2.appliedTo(argRefsOLD(rt, tparams2.length))
- val body: RecType => Type = rt => op(app1(rt), app2(rt))
- TypeLambdaOLD(bindings, body)
- }
}
/** Try to distribute `&` inside type, detect and handle conflicts
@@ -1652,19 +1521,5 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
}
}
- override def compareHkApplyOLD(app: RefinedType, other: Type, inOrder: Boolean) =
- if (app.isHKApplyOLD)
- traceIndented(i"compareHkApply $app, $other, $inOrder, ${app.normalizeHkApplyOLD}") {
- super.compareHkApplyOLD(app, other, inOrder)
- }
- else super.compareHkApplyOLD(app, other, inOrder)
-
- override def compareHkLambdaOLD(tp1: Type, tp2: RefinedType): Boolean =
- if (tp2.isTypeParam)
- traceIndented(i"compareHkLambda $tp1, $tp2") {
- super.compareHkLambdaOLD(tp1, tp2)
- }
- else super.compareHkLambdaOLD(tp1, tp2)
-
override def toString = "Subtype trace:" + { try b.toString finally b.clear() }
}