aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/TypeComparer.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-06-29 20:00:59 +0200
committerMartin Odersky <odersky@gmail.com>2016-07-11 13:35:02 +0200
commit60d81f81ddfc85719fd303e8d15d3891adbf4dfd (patch)
tree17e830e9e73157451c1a46ba2d716ca0d1037f97 /src/dotty/tools/dotc/core/TypeComparer.scala
parentd1f809f14cad2c14c312767d71361c7f2e7d8244 (diff)
downloaddotty-60d81f81ddfc85719fd303e8d15d3891adbf4dfd.tar.gz
dotty-60d81f81ddfc85719fd303e8d15d3891adbf4dfd.tar.bz2
dotty-60d81f81ddfc85719fd303e8d15d3891adbf4dfd.zip
Start new, direct HK scheme
- Re-introduce newHK option. Label some things that will be removed with OLD.
Diffstat (limited to 'src/dotty/tools/dotc/core/TypeComparer.scala')
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala128
1 files changed, 104 insertions, 24 deletions
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index cf3086323..566865eb4 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -365,11 +365,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
fourthTry(tp1, tp2) || compareRefinedSlow
case _ =>
if (tp2.isTypeParam) {
- compareHkLambda(tp1, tp2) ||
+ compareHkLambdaOLD(tp1, tp2) ||
fourthTry(tp1, tp2)
}
else {
- compareHkApply(tp2, tp1, inOrder = false) ||
+ compareHkApplyOLD(tp2, tp1, inOrder = false) ||
compareRefinedSlow ||
fourthTry(tp1, tp2) ||
compareAliasedRefined(tp2, tp1, inOrder = false)
@@ -389,6 +389,53 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
val tp1stable = ensureStableSingleton(tp1)
isSubType(fixRecs(tp1stable, tp1stable.widenExpr), tp2.parent.substRecThis(tp2, tp1stable))
}
+ case tp2 @ HKApply(tycon2, args2) =>
+ def compareHkApply(tycon2: Type): Boolean = tycon2 match {
+ case tycon2: TypeVar => compareHkApply(tycon2.underlying)
+ case param2: PolyParam if canConstrain(param2) =>
+ val tparams2 = tycon2.typeParams
+
+ def tyconOK(tycon1a: Type) =
+ variancesConform(tycon1a.typeParams, tparams2) && {
+ if (ctx.mode.is(Mode.TypevarsMissContext)) isSubType(tp1, tycon1a.appliedTo(args2))
+ else tryInstantiate(param2, tycon1a) && isSubType(tp1, tp2)
+ }
+
+ tp1 match {
+ case tp1 @ HKApply(tycon1, _) =>
+ tyconOK(tycon1) || isSubType(tp1.upperBound, tp2)
+ case _ if tp1.widenDealias.typeSymbol.isClass =>
+ val classBounds = tp2.classSymbols
+ def liftToBase(bcs: List[ClassSymbol]): Boolean = bcs match {
+ case bc :: bcs1 =>
+ classBounds.exists(bc.derivesFrom) && tyconOK(tp1.baseTypeRef(bc)) ||
+ liftToBase(bcs1)
+ case _ =>
+ false
+ }
+ liftToBase(tp1.baseClasses)
+ case tp1: TypeProxy =>
+ isSubType(tp1.underlying, tp2)
+ case _ =>
+ false
+ }
+ case _ =>
+ // TODO handle lower bounds of hk params here
+ false
+ }
+ compareHkApply(tycon2) || fourthTry(tp1, tp2)
+ case tp2 @ TypeLambda(tparams2, body2) =>
+ def compareHkLambda = tp1.stripTypeVar match {
+ case tp1 @ TypeLambda(tparams1, body1) =>
+ val boundsConform =
+ tparams1.corresponds(tparams2)((tparam1, tparam2) =>
+ isSubType(tparam2.memberBounds.subst(tp2, tp1), tparam1.memberBounds))
+ val bodiesConform = isSubType(body1, body2.subst(tp2, tp1))
+ variancesConform(tparams1, tparams2) && boundsConform && bodiesConform
+ case _ =>
+ fourthTry(tp1, tp2)
+ }
+ compareHkLambda
case OrType(tp21, tp22) =>
// Rewrite T1 <: (T211 & T212) | T22 to T1 <: (T211 | T22) and T1 <: (T212 | T22)
// and analogously for T1 <: T21 | (T221 & T222)
@@ -502,11 +549,22 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
}
isNewSubType(tp1.underlying.widenExpr, tp2) || comparePaths
case tp1: RefinedType =>
- compareHkApply(tp1, tp2, inOrder = true) ||
+ compareHkApplyOLD(tp1, tp2, inOrder = true) ||
isNewSubType(tp1.parent, tp2) ||
compareAliasedRefined(tp1, tp2, inOrder = true)
case tp1: RecType =>
isNewSubType(tp1.parent, tp2)
+ case HKApply(tycon1, args1) =>
+ tp2 match {
+ case AppliedType(tycon2, args2) =>
+ assert(!tycon2.isHK) // this should have been handled by thirdTry
+ isSubType(tycon1, EtaExpansion(tycon2)) &&
+ isSubArgs(args1, args2, tycon2.typeParams)
+ case _ =>
+ false
+ }
+ case EtaExpansion(tycon1) =>
+ isSubType(tycon1, tp2)
case AndType(tp11, tp12) =>
// Rewrite (T111 | T112) & T12 <: T2 to (T111 & T12) <: T2 and (T112 | T12) <: T2
// and analogously for T11 & (T121 | T122) & T12 <: T2
@@ -537,6 +595,14 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
false
}
+ def isSubArgs(args1: List[Type], args2: List[Type], tparams: List[MemberBinding]): Boolean =
+ if (args1.isEmpty) args2.isEmpty
+ else args2.nonEmpty && {
+ val v = tparams.head.memberVariance
+ (v > 0 || isSubType(args2.head, args1.head)) &&
+ (v < 0 || isSubType(args1.head, args2.head))
+ }
+
/** Test whether `tp1` has a base type of the form `B[T1, ..., Tn]` where
* - `B` derives from one of the class symbols of `tp2`,
* - the type parameters of `B` match one-by-one the variances of `tparams`,
@@ -588,7 +654,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
*
* (4) If `inOrder`, test `app <: other` else test `other <: app`.
*/
- def compareHkApply(app: RefinedType, other: Type, inOrder: Boolean): Boolean = {
+ 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)
@@ -597,7 +663,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
def unifyWith(liftedOther: Type): Boolean = {
subtyping.println(i"unify with $liftedOther")
liftedOther.typeConstructor.widen match {
- case tycon: TypeRef if tycon.isEtaExpandable && tycon.typeParams.nonEmpty =>
+ case tycon: TypeRef if tycon.isEtaExpandableOLD && tycon.typeParams.nonEmpty =>
val (ok, app1) =
if (ctx.mode.is(Mode.TypevarsMissContext))
(true, EtaExpansion(tycon).appliedTo(app.argInfos))
@@ -634,8 +700,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
false
}
}
- app.isHKApply && !other.isHKApply && {
- val reduced = if (inOrder) app else app.normalizeHkApply
+ 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)
@@ -643,11 +709,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
}
/** Compare type lambda with non-lambda type. */
- def compareHkLambda(tp1: Type, tp2: RefinedType): Boolean = tp1.stripTypeVar match {
- case TypeLambda(args1, body1) =>
+ def compareHkLambdaOLD(tp1: Type, tp2: RefinedType): Boolean = tp1.stripTypeVar match {
+ case TypeLambdaOLD(args1, body1) =>
//println(i"comparing $tp1 <:< $tp2")
tp2 match {
- case TypeLambda(args2, body2) =>
+ case TypeLambdaOLD(args2, body2) =>
args1.corresponds(args2)((arg1, arg2) =>
varianceConforms(BindingKind.toVariance(arg1.bindingKind),
BindingKind.toVariance(arg2.bindingKind))) &&
@@ -656,7 +722,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
case _ => false
}
case RefinedType(parent1, _, _) =>
- compareHkLambda(parent1, tp2)
+ compareHkLambdaOLD(parent1, tp2)
case _ =>
false
}
@@ -1161,22 +1227,36 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
val tparams2 = tp2.typeParams
if (tparams1.isEmpty || tparams2.isEmpty) op(tp1, tp2)
else if (tparams1.length != tparams2.length) mergeConflict(tp1, tp2)
+ else if (Config.newHK) {
+ val numArgs = tparams1.length
+ def argRefs(tl: PolyType) = List.range(0, numArgs).map(PolyParam(tl, _))
+ TypeLambda(
+ paramNames = tpnme.syntheticLambdaParamNames(numArgs),
+ variances = (tparams1, tparams2).zipped.map((tparam1, tparam2) =>
+ (tparam1.memberVariance + tparam2.memberVariance) / 2))(
+ paramBoundsExp = tl => (tparams1, tparams2).zipped.map((tparam1, tparam2) =>
+ tl.lifted(tparams1, tparam1.memberBoundsAsSeenFrom(tp1)).bounds &
+ tl.lifted(tparams2, tparam2.memberBoundsAsSeenFrom(tp2)).bounds),
+ resultTypeExp = tl =>
+ op(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).recursify(tparams1)
+ tparam1.memberBoundsAsSeenFrom(tp1).recursifyOLD(tparams1)
val b2: RecType => TypeBounds =
- tparam2.memberBoundsAsSeenFrom(tp2).recursify(tparams2)
+ 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(argRefs(rt, tparams1.length))
- val app2: RecType => Type = rt => tp2.appliedTo(argRefs(rt, tparams2.length))
+ 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))
- TypeLambda(bindings, body)
+ TypeLambdaOLD(bindings, body)
}
}
@@ -1459,19 +1539,19 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
override def copyIn(ctx: Context) = new ExplainingTypeComparer(ctx)
- override def compareHkApply(app: RefinedType, other: Type, inOrder: Boolean) =
- if (app.isHKApply)
- traceIndented(i"compareHkApply $app, $other, $inOrder, ${app.normalizeHkApply}") {
- super.compareHkApply(app, other, inOrder)
+ 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.compareHkApply(app, other, inOrder)
+ else super.compareHkApplyOLD(app, other, inOrder)
- override def compareHkLambda(tp1: Type, tp2: RefinedType): Boolean =
+ override def compareHkLambdaOLD(tp1: Type, tp2: RefinedType): Boolean =
if (tp2.isTypeParam)
traceIndented(i"compareHkLambda $tp1, $tp2") {
- super.compareHkLambda(tp1, tp2)
+ super.compareHkLambdaOLD(tp1, tp2)
}
- else super.compareHkLambda(tp1, tp2)
+ else super.compareHkLambdaOLD(tp1, tp2)
override def toString = "Subtype trace:" + { try b.toString finally b.clear() }
}