aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-06-26 16:57:38 +0200
committerMartin Odersky <odersky@gmail.com>2016-07-11 13:35:04 +0200
commit8805dd4f821e06a688fcf492b61033fe0992e752 (patch)
tree47da644d5eba1c2c536183ef1e396d2333af59c6 /src/dotty/tools/dotc
parentde5d8fe696cdf7acfa80991ceae322aedb1dfd20 (diff)
downloaddotty-8805dd4f821e06a688fcf492b61033fe0992e752.tar.gz
dotty-8805dd4f821e06a688fcf492b61033fe0992e752.tar.bz2
dotty-8805dd4f821e06a688fcf492b61033fe0992e752.zip
When comparing types revert eta-expansion as needed
The problem is that some existential types read from Java (and Scala as well? not sure) appear as naked typerefs. They consequently get expanded via eta expansion to type lambdas. This commit compensates for this by collapsing an eta expansion if this can make a subtype tests succeed or a union or intersection be legal. Also, take hk types into account for liftToClasses Needs to special-treat TypeLambda and HKApply since otherwise we risk creating malformed And-types.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/core/ConstraintHandling.scala11
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala48
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala8
3 files changed, 53 insertions, 14 deletions
diff --git a/src/dotty/tools/dotc/core/ConstraintHandling.scala b/src/dotty/tools/dotc/core/ConstraintHandling.scala
index 66767d58a..44b6abe12 100644
--- a/src/dotty/tools/dotc/core/ConstraintHandling.scala
+++ b/src/dotty/tools/dotc/core/ConstraintHandling.scala
@@ -6,6 +6,7 @@ import Types._, Contexts._, Symbols._
import Decorators._
import config.Config
import config.Printers._
+import TypeApplications.EtaExpansion
import collection.mutable
/** Methods for adding constraints and solving them.
@@ -239,8 +240,6 @@ trait ConstraintHandling {
def addParamBound(bound: PolyParam) =
if (fromBelow) addLess(bound, param) else addLess(param, bound)
- assert(param.isHK == bound.isHK, s"$param / $bound / $fromBelow")
-
/** Drop all constrained parameters that occur at the toplevel in `bound` and
* handle them by `addLess` calls.
* The preconditions make sure that such parameters occur only
@@ -297,7 +296,13 @@ trait ConstraintHandling {
case bound: PolyParam if constraint contains bound =>
addParamBound(bound)
case _ =>
- val pbound = prune(bound)
+ var pbound = prune(bound)
+ if (pbound.isHK && !param.isHK) {
+ param match {
+ case EtaExpansion(tycon) if tycon.symbol.isClass => pbound = tycon
+ case _ =>
+ }
+ }
pbound.exists && (
if (fromBelow) addLowerBound(param, pbound) else addUpperBound(param, pbound))
}
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 12e9e638a..e6cd0a0df 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -392,12 +392,12 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
case tp2 @ HKApply(tycon2, args2) =>
compareHkApply2(tp1, tp2, tycon2, args2)
case tp2 @ TypeLambda(tparams2, body2) =>
- def compareHkLambda = tp1.stripTypeVar match {
+ def compareHkLambda: Boolean = tp1.stripTypeVar match {
case tp1 @ TypeLambda(tparams1, body1) =>
// Don't compare bounds of lambdas, or t2994 will fail
// The issue is that, logically, bounds should compare contravariantly,
// so the bounds checking should look like this:
- //
+ //
// tparams1.corresponds(tparams2)((tparam1, tparam2) =>
// isSubType(tparam2.memberBounds.subst(tp2, tp1), tparam1.memberBounds))
//
@@ -408,6 +408,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
// bounds of * types are checked.
variancesConform(tparams1, tparams2) && isSubType(body1, body2.subst(tp2, tp1))
case _ =>
+ if (!tp1.isHK) {
+ tp2 match {
+ case EtaExpansion(tycon2) if tycon2.symbol.isClass =>
+ return isSubType(tp1, tycon2)
+ case _ =>
+ }
+ }
fourthTry(tp1, tp2)
}
compareHkLambda
@@ -1269,7 +1276,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
val t2 = distributeAnd(tp2, tp1)
if (t2.exists) t2
else if (erased) erasedGlb(tp1, tp2, isJava = false)
- else liftIfHK(tp1, tp2, AndType(_, _))
+ else liftIfHK(tp1, tp2, AndType(_, _), _ & _)
}
}
@@ -1293,7 +1300,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
val t2 = distributeOr(tp2, tp1)
if (t2.exists) t2
else if (erased) erasedLub(tp1, tp2)
- else liftIfHK(tp1, tp2, OrType(_, _))
+ else liftIfHK(tp1, tp2, OrType(_, _), _ | _)
}
}
@@ -1314,11 +1321,24 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
* allowing both interpretations. A possible remedy is to be somehow stricter
* in where we allow which interpretation.
*/
- private def liftIfHK(tp1: Type, tp2: Type, op: (Type, Type) => Type) = {
+ private def liftIfHK(tp1: Type, tp2: Type, op: (Type, Type) => Type, original: (Type, Type) => Type) = {
val tparams1 = tp1.typeParams
val tparams2 = tp2.typeParams
- if (tparams1.isEmpty || tparams2.isEmpty) op(tp1, tp2)
- else if (tparams1.length != tparams2.length) mergeConflict(tp1, tp2)
+ if (!Config.newHK && tparams1.isEmpty || tparams2.isEmpty) op(tp1, tp2)
+ else if (Config.newHK && tparams1.isEmpty)
+ if (tparams2.isEmpty) op(tp1, tp2)
+ else tp2 match {
+ case EtaExpansion(tycon2) if tycon2.symbol.isClass => original(tp1, tycon2) // TODO: Roll isClass into EtaExpansion?
+ case _ => mergeConflict(tp1, tp2)
+ }
+ else if (Config.newHK && tparams2.isEmpty) {
+ tp1 match {
+ case EtaExpansion(tycon1) if tycon1.symbol.isClass => original(tycon1, tp2)
+ case _ => mergeConflict(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) {
val numArgs = tparams1.length
def argRefs(tl: GenericType) = List.range(0, numArgs).map(PolyParam(tl, _))
@@ -1330,7 +1350,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
tl.lifted(tparams1, tparam1.memberBoundsAsSeenFrom(tp1)).bounds &
tl.lifted(tparams2, tparam2.memberBoundsAsSeenFrom(tp2)).bounds),
resultTypeExp = tl =>
- op(tl.lifted(tparams1, tp1).appliedTo(argRefs(tl)),
+ original(tl.lifted(tparams1, tp1).appliedTo(argRefs(tl)),
tl.lifted(tparams2, tp2).appliedTo(argRefs(tl))))
}
else {
@@ -1389,12 +1409,18 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
mergeNames(names1, names2, nme.syntheticParamName),
formals1, tp1.resultType & tp2.resultType.subst(tp2, tp1))
case _ =>
+ tp2 match {
+ case tp2 @ MethodType(names2, formals2) =>
+ println(
+ TypeComparer.explained(implicit ctx => isSameType(formals1.head, formals2.head)))
+ case _ =>
+ }
mergeConflict(tp1, tp2)
}
- case tp1: GenericType =>
+ case tp1: PolyType =>
tp2 match {
- case tp2: GenericType if matchingTypeParams(tp1, tp2) =>
- tp1.derivedGenericType(
+ case tp2: PolyType if matchingTypeParams(tp1, tp2) =>
+ tp1.derivedPolyType(
mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName),
tp1.paramBounds, tp1.resultType & tp2.resultType.subst(tp2, tp1))
case _ =>
diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala
index a5246cf6b..d3f9fd777 100644
--- a/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/src/dotty/tools/dotc/typer/Implicits.scala
@@ -292,6 +292,14 @@ trait ImplicitRunInfo { self: RunInfo =>
(lead /: tp.classSymbols)(joinClass)
case tp: TypeVar =>
apply(tp.underlying)
+ case tp: HKApply =>
+ def applyArg(arg: Type) = arg match {
+ case TypeBounds(lo, hi) => AndType.make(lo, hi)
+ case _ => arg
+ }
+ (apply(tp.tycon) /: tp.args)((tc, arg) => AndType.make(tc, applyArg(arg)))
+ case tp: TypeLambda =>
+ apply(tp.resType)
case _ =>
mapOver(tp)
}