@@ -176,11 +176,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
176
176
&& ! tp1.isInstanceOf [WithFixedSym ]
177
177
&& ! tp2.isInstanceOf [WithFixedSym ]
178
178
) ||
179
- compareHK (tp1, tp2, inOrder = true ) ||
180
- compareHK (tp2, tp1, inOrder = false ) ||
179
+ compareHkApply (tp1, tp2, inOrder = true ) ||
180
+ compareHkApply (tp2, tp1, inOrder = false ) ||
181
181
thirdTryNamed(tp1, tp2)
182
182
case _ =>
183
- compareHK (tp2, tp1, inOrder = false ) ||
183
+ compareHkApply (tp2, tp1, inOrder = false ) ||
184
184
secondTry(tp1, tp2)
185
185
}
186
186
}
@@ -257,7 +257,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
257
257
if (tp1.prefix.isStable) return false
258
258
case _ =>
259
259
}
260
- compareHK (tp1, tp2, inOrder = true ) ||
260
+ compareHkApply (tp1, tp2, inOrder = true ) ||
261
261
thirdTry(tp1, tp2)
262
262
case tp1 : PolyParam =>
263
263
def flagNothingBound = {
@@ -352,8 +352,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
352
352
isSubType(tp1, tp2.parent) &&
353
353
(name2 == nme.WILDCARD || hasMatchingMember(name2, tp1, tp2))
354
354
}
355
- def etaExpandedSubType (tp1 : Type ) =
356
- isSubType(tp1.typeConstructor.EtaExpand (tp2.typeParams), tp2)
357
355
def compareRefined : Boolean = {
358
356
val tp1w = tp1.widen
359
357
val skipped2 = skipMatching(tp1w, tp2)
@@ -367,7 +365,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
367
365
case _ =>
368
366
compareRefinedSlow ||
369
367
fourthTry(tp1, tp2) ||
370
- needsEtaLift(tp1, tp2) && testLifted( tp1, tp2, tp2.typeParams, etaExpandedSubType )
368
+ compareHkLambda(tp2, tp1, inOrder = false )
371
369
}
372
370
else // fast path, in particular for refinements resulting from parameterization.
373
371
isSubType(tp1, skipped2) &&
@@ -487,10 +485,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
487
485
}
488
486
isNewSubType(tp1.underlying.widenExpr, tp2) || comparePaths
489
487
case tp1 : RefinedType =>
490
- isNewSubType(tp1.parent, tp2) ||
491
- needsEtaLift(tp2, tp1) &&
492
- tp2.typeParams.length == tp1.typeParams.length &&
493
- isSubType(tp1, tp2.EtaExpand (tp1.typeParams))
488
+ isNewSubType(tp1.parent, tp2) || compareHkLambda(tp1, tp2, inOrder = true )
494
489
case AndType (tp11, tp12) =>
495
490
// Rewrite (T111 | T112) & T12 <: T2 to (T111 & T12) <: T2 and (T112 | T12) <: T2
496
491
// and analogously for T11 & (T121 | T122) & T12 <: T2
@@ -521,14 +516,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
521
516
false
522
517
}
523
518
524
- /** Does `tp` need to be eta lifted to be comparable to `target`?
525
- * This is the case if:
526
- * - target is a type lambda, and
527
- * - `tp` is eta-expandable (i.e. is a non-lambda class ref)
528
- */
529
- private def needsEtaLift (tp : Type , target : RefinedType ): Boolean =
530
- target.refinedName == tpnme.hkApply && tp.isEtaExpandable
531
-
532
519
/** Test whether `tp1` has a base type of the form `B[T1, ..., Tn]` where
533
520
* - `B` derives from one of the class symbols of `tp2`,
534
521
* - the type parameters of `B` match one-by-one the variances of `tparams`,
@@ -570,7 +557,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
570
557
*
571
558
* (4) If `inOrder`, test `projection <: other` else test `other <: projection`.
572
559
*/
573
- def compareHK (projection : NamedType , other : Type , inOrder : Boolean ): Boolean = {
560
+ def compareHkApply (projection : NamedType , other : Type , inOrder : Boolean ): Boolean = {
574
561
def tryInfer (tp : Type ): Boolean = ctx.traceIndented(i " compareHK( $projection, $other, inOrder = $inOrder, constr = $tp) " , subtyping) {
575
562
tp match {
576
563
case tp : TypeVar => tryInfer(tp.underlying)
@@ -605,6 +592,18 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
605
592
tryInfer(projection.prefix.typeConstructor.dealias)
606
593
}
607
594
595
+ /** Compare type lambda with non-lambda type. */
596
+ def compareHkLambda (rt : RefinedType , other : Type , inOrder : Boolean ) = rt match {
597
+ case TypeLambda (vs, args, body) =>
598
+ other.isInstanceOf [TypeRef ] &&
599
+ args.length == other.typeParams.length && {
600
+ val applied = other.appliedTo(argRefs(rt, args.length))
601
+ if (inOrder) isSubType(body, applied) else isSubType(applied, body)
602
+ }
603
+ case _ =>
604
+ false
605
+ }
606
+
608
607
/** Returns true iff either `tp11 <:< tp21` or `tp12 <:< tp22`, trying at the same time
609
608
* to keep the constraint as wide as possible. Specifically, if
610
609
*
@@ -1003,12 +1002,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
1003
1002
val t2 = distributeAnd(tp2, tp1)
1004
1003
if (t2.exists) t2
1005
1004
else if (erased) erasedGlb(tp1, tp2, isJava = false )
1006
- else {
1007
- // if (isHKRef(tp1)) tp2
1008
- // else if (isHKRef(tp2)) tp1
1009
- // else
1010
- AndType (tp1, tp2)
1011
- }
1005
+ else liftIfHK(tp1, tp2, AndType (_, _))
1012
1006
}
1013
1007
}
1014
1008
@@ -1032,14 +1026,23 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
1032
1026
val t2 = distributeOr(tp2, tp1)
1033
1027
if (t2.exists) t2
1034
1028
else if (erased) erasedLub(tp1, tp2)
1035
- else
1036
- // if (isHKRef(tp1)) tp1
1037
- // else if (isHKRef(tp2)) tp2
1038
- // else
1039
- OrType (tp1, tp2)
1029
+ else liftIfHK(tp1, tp2, OrType (_, _))
1040
1030
}
1041
1031
}
1042
1032
1033
+ /** `op(tp1, tp2)` unless `tp1` and `tp2` are type-constructors.
1034
+ * In the latter case, combine `tp1` and `tp2` under a type lambda like this:
1035
+ *
1036
+ * [X1, ..., Xn] -> op(tp1[X1, ..., Xn], tp2[X1, ..., Xn])
1037
+ */
1038
+ private def liftIfHK (tp1 : Type , tp2 : Type , op : (Type , Type ) => Type ) = {
1039
+ val tparams1 = tp1.typeParams
1040
+ val tparams2 = tp2.typeParams
1041
+ if (tparams1.isEmpty || tparams2.isEmpty) op(tp1, tp2)
1042
+ else if (tparams1.length != tparams2.length) mergeConflict(tp1, tp2)
1043
+ else hkCombine(tp1, tp2, tparams1, tparams2, op)
1044
+ }
1045
+
1043
1046
/** Try to distribute `&` inside type, detect and handle conflicts */
1044
1047
private def distributeAnd (tp1 : Type , tp2 : Type ): Type = tp1 match {
1045
1048
// opportunistically merge same-named refinements
@@ -1318,12 +1321,12 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
1318
1321
1319
1322
override def copyIn (ctx : Context ) = new ExplainingTypeComparer (ctx)
1320
1323
1321
- override def compareHK (projection : NamedType , other : Type , inOrder : Boolean ) =
1324
+ override def compareHkApply (projection : NamedType , other : Type , inOrder : Boolean ) =
1322
1325
if (projection.name == tpnme.hkApply)
1323
1326
traceIndented(i " compareHK $projection, $other, $inOrder" ) {
1324
- super .compareHK (projection, other, inOrder)
1327
+ super .compareHkApply (projection, other, inOrder)
1325
1328
}
1326
- else super .compareHK (projection, other, inOrder)
1329
+ else super .compareHkApply (projection, other, inOrder)
1327
1330
1328
1331
override def toString = " Subtype trace:" + { try b.toString finally b.clear() }
1329
1332
}
0 commit comments