@@ -390,40 +390,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
390390 isSubType(fixRecs(tp1stable, tp1stable.widenExpr), tp2.parent.substRecThis(tp2, tp1stable))
391391 }
392392 case tp2 @ HKApply (tycon2, args2) =>
393- def compareHkApply (tycon2 : Type ): Boolean = tycon2 match {
394- case tycon2 : TypeVar => compareHkApply(tycon2.underlying)
395- case param2 : PolyParam if canConstrain(param2) =>
396- val tparams2 = tycon2.typeParams
397-
398- def tyconOK (tycon1a : Type ) =
399- variancesConform(tycon1a.typeParams, tparams2) && {
400- if (ctx.mode.is(Mode .TypevarsMissContext )) isSubType(tp1, tycon1a.appliedTo(args2))
401- else tryInstantiate(param2, tycon1a) && isSubType(tp1, tp2)
402- }
403-
404- tp1 match {
405- case tp1 @ HKApply (tycon1, _) =>
406- tyconOK(tycon1) || isSubType(tp1.upperBound, tp2)
407- case _ if tp1.widenDealias.typeSymbol.isClass =>
408- val classBounds = tp2.classSymbols
409- def liftToBase (bcs : List [ClassSymbol ]): Boolean = bcs match {
410- case bc :: bcs1 =>
411- classBounds.exists(bc.derivesFrom) && tyconOK(tp1.baseTypeRef(bc)) ||
412- liftToBase(bcs1)
413- case _ =>
414- false
415- }
416- liftToBase(tp1.baseClasses)
417- case tp1 : TypeProxy =>
418- isSubType(tp1.underlying, tp2)
419- case _ =>
420- false
421- }
422- case _ =>
423- // TODO handle lower bounds of hk params here
424- false
425- }
426- compareHkApply(tycon2) || fourthTry(tp1, tp2)
393+ compareHkApply2(tp1, tp2, tycon2, args2)
427394 case tp2 @ TypeLambda (tparams2, body2) =>
428395 def compareHkLambda = tp1.stripTypeVar match {
429396 case tp1 @ TypeLambda (tparams1, body1) =>
@@ -452,7 +419,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
452419 return isSubType(tp1, OrType (tp21, tp221)) && isSubType(tp1, OrType (tp21, tp222))
453420 case _ =>
454421 }
455- eitherIsSubType( tp1, tp21, tp1, tp22) || fourthTry(tp1, tp2)
422+ either(isSubType( tp1, tp21), isSubType( tp1, tp22) ) || fourthTry(tp1, tp2)
456423 case tp2 @ MethodType (_, formals2) =>
457424 def compareMethod = tp1 match {
458425 case tp1 @ MethodType (_, formals1) =>
@@ -555,14 +522,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
555522 case tp1 : RecType =>
556523 isNewSubType(tp1.parent, tp2)
557524 case HKApply (tycon1, args1) =>
558- tp2 match {
559- case AppliedType (tycon2, args2) =>
560- assert(! tycon2.isHK) // this should have been handled by thirdTry
561- isSubType(tycon1, EtaExpansion (tycon2)) &&
562- isSubArgs(args1, args2, tycon2.typeParams)
563- case _ =>
564- false
565- }
525+ compareHkApply1(tp1, tycon1, args1, tp2)
566526 case EtaExpansion (tycon1) =>
567527 isSubType(tycon1, tp2)
568528 case AndType (tp11, tp12) =>
@@ -581,7 +541,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
581541 return isSubType(AndType (tp11, tp121), tp2) && isSubType(AndType (tp11, tp122), tp2)
582542 case _ =>
583543 }
584- eitherIsSubType( tp11, tp2, tp12, tp2)
544+ either(isSubType( tp11, tp2), isSubType( tp12, tp2) )
585545 case JavaArrayType (elem1) =>
586546 def compareJavaArray = tp2 match {
587547 case JavaArrayType (elem2) => isSubType(elem1, elem2)
@@ -595,6 +555,128 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
595555 false
596556 }
597557
558+ /** Subtype test for the hk application `tp2 = tycon2[args2]`.
559+ */
560+ def compareHkApply2 (tp1 : Type , tp2 : Type , tycon2 : Type , args2 : List [Type ]): Boolean = {
561+ val tparams = tycon2.typeParams
562+
563+ def isMatchingApply (tp1 : Type ): Boolean = tp1 match {
564+ case HKApply (tycon1, args1) =>
565+ tycon1 match {
566+ case tycon1 : PolyParam =>
567+ (tycon1 == tycon2 ||
568+ canConstrain(tycon1) && tryInstantiate(tycon1, tycon2)) &&
569+ isSubArgs(args1, args2, tparams)
570+ case tycon1 : TypeRef =>
571+ tycon2 match {
572+ case tycon2 : TypeRef if tycon1.symbol == tycon2.symbol =>
573+ isSubType(tycon1.prefix, tycon2.prefix) &&
574+ isSubArgs(args1, args2, tparams)
575+ case _ =>
576+ false
577+ }
578+ case tycon1 : TypeVar =>
579+ isMatchingApply(tycon1.underlying)
580+ case tycon1 : AnnotatedType =>
581+ isMatchingApply(tycon1.underlying)
582+ case _ =>
583+ false
584+ }
585+ case _ =>
586+ false
587+ }
588+
589+ /** `param2` can be instantiated to the type constructor of the LHS
590+ * or to the type constructor of one of the LHS base class instances
591+ * and the resulting type application is a supertype of `tp1`,
592+ * or fallback to fourthTry.
593+ */
594+ def canInstantiate (param2 : PolyParam ): Boolean = {
595+
596+ /** `param2` can be instantiated to `tycon1a`.
597+ * and the resulting type application is a supertype of `tp1`.
598+ */
599+ def tyconOK (tycon1a : Type ) =
600+ variancesConform(tycon1a.typeParams, tparams) && {
601+ (ctx.mode.is(Mode .TypevarsMissContext ) ||
602+ tryInstantiate(param2, tycon1a.ensureHK)) &&
603+ isSubType(tp1, tycon1a.appliedTo(args2))
604+ }
605+
606+ tp1.widen match {
607+ case tp1w @ HKApply (tycon1, _) =>
608+ tyconOK(tycon1)
609+ case tp1w =>
610+ tp1w.typeSymbol.isClass && {
611+ val classBounds = tycon2.classSymbols
612+ def liftToBase (bcs : List [ClassSymbol ]): Boolean = bcs match {
613+ case bc :: bcs1 =>
614+ classBounds.exists(bc.derivesFrom) && tyconOK(tp1w.baseTypeRef(bc)) ||
615+ liftToBase(bcs1)
616+ case _ =>
617+ false
618+ }
619+ liftToBase(tp1w.baseClasses)
620+ } ||
621+ fourthTry(tp1, tp2)
622+ }
623+ }
624+
625+ /** Let `tycon2bounds` be the bounds of the RHS type constructor `tycon2`.
626+ * Let `app2 = tp2` where the type constructor of `tp2` is replaced by
627+ * `tycon2bounds.lo`.
628+ * If both bounds are the same, continue with `tp1 <:< app2`.
629+ * otherwise continue with either
630+ *
631+ * tp1 <:< tp2 using fourthTry (this might instantiate params in tp1)
632+ * tp1 <:< app2 using isSubType (this might instantiate params in tp2)
633+ */
634+ def compareLower (tycon2bounds : TypeBounds ): Boolean = {
635+ val app2 = tycon2bounds.lo.applyIfParameterized(args2)
636+ if (tycon2bounds.lo eq tycon2bounds.hi) isSubType(tp1, app2)
637+ else either(fourthTry(tp1, tp2), isSubType(tp1, app2))
638+ }
639+
640+ tycon2 match {
641+ case param2 : PolyParam =>
642+ isMatchingApply(tp1) || {
643+ if (canConstrain(param2)) canInstantiate(param2)
644+ else compareLower(bounds(param2))
645+ }
646+ case tycon2 : TypeRef =>
647+ isMatchingApply(tp1) ||
648+ compareLower(tycon2.info.bounds)
649+ case tycon2 : TypeVar =>
650+ isSubType(tp1, tycon2.underlying.appliedTo(args2))
651+ case tycon2 : AnnotatedType =>
652+ compareHkApply2(tp1, tp2, tycon2.underlying, args2)
653+ case _ =>
654+ false
655+ }
656+ }
657+
658+ /** Subtype test for the hk application `tp1 = tycon1[args1]`.
659+ */
660+ def compareHkApply1 (tp1 : Type , tycon1 : Type , args1 : List [Type ], tp2 : Type ): Boolean =
661+ tycon1 match {
662+ case param1 : PolyParam =>
663+ def canInstantiate = tp2 match {
664+ case AppliedType (tycon2, args2) =>
665+ tryInstantiate(param1, tycon2.ensureHK) && isSubArgs(args1, args2, tycon2.typeParams)
666+ case _ =>
667+ false
668+ }
669+ canConstrain(param1) && canInstantiate ||
670+ isSubType(bounds(param1).hi.applyIfParameterized(args1), tp2)
671+ case tycon1 : TypeProxy =>
672+ isSubType(tycon1.underlying.applyIfParameterized(args1), tp2)
673+ case _ =>
674+ false
675+ }
676+
677+ /** Subtype test for corresponding arguments in `args1`, `args2` according to
678+ * variances in type parameters `tparams`.
679+ */
598680 def isSubArgs (args1 : List [Type ], args2 : List [Type ], tparams : List [MemberBinding ]): Boolean =
599681 if (args1.isEmpty) args2.isEmpty
600682 else args2.nonEmpty && {
@@ -678,7 +760,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
678760 val hkTypeParams = param.typeParams
679761 subtyping.println(i " classBounds = ${app.classSymbols}" )
680762 subtyping.println(i " base classes = ${other.baseClasses}" )
681- subtyping.println(i " type params = $hkTypeParams" )
763+ subtyping.println(i " type params = $hkTypeParams, ${app.classSymbol} " )
682764 if (inOrder) unifyWith(other)
683765 else testLifted(other, app, hkTypeParams, unifyWith)
684766 case _ =>
@@ -775,8 +857,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
775857 /** The symbol referred to in the refinement of `rt` */
776858 private def refinedSymbol (rt : RefinedType ) = rt.parent.member(rt.refinedName).symbol
777859
778- /** Returns true iff either `tp11 <:< tp21` or `tp12 <:< tp22`, trying at the same time
779- * to keep the constraint as wide as possible. Specifically, if
860+ /** Returns true iff the result of evaluating either `op1` or `op2` is true,
861+ * trying at the same time to keep the constraint as wide as possible.
862+ * E.g, if
780863 *
781864 * tp11 <:< tp12 = true with post-constraint c1
782865 * tp12 <:< tp22 = true with post-constraint c2
@@ -803,15 +886,15 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
803886 * Here, each precondition leads to a different constraint, and neither of
804887 * the two post-constraints subsumes the other.
805888 */
806- private def eitherIsSubType ( tp11 : Type , tp21 : Type , tp12 : Type , tp22 : Type ) = {
889+ private def either ( op1 : => Boolean , op2 : => Boolean ) : Boolean = {
807890 val preConstraint = constraint
808- isSubType(tp11, tp21) && {
891+ op1 && {
809892 val leftConstraint = constraint
810893 constraint = preConstraint
811- if (! (isSubType(tp12, tp22) && subsumes(leftConstraint, constraint, preConstraint)))
894+ if (! (op2 && subsumes(leftConstraint, constraint, preConstraint)))
812895 constraint = leftConstraint
813896 true
814- } || isSubType(tp12, tp22)
897+ } || op2
815898 }
816899
817900 /** Like tp1 <:< tp2, but returns false immediately if we know that
@@ -1533,12 +1616,23 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
15331616 }
15341617
15351618 override def addConstraint (param : PolyParam , bound : Type , fromBelow : Boolean ): Boolean =
1536- traceIndented(s " add constraint $param ${if (fromBelow) " >:" else " <:" } $bound $frozenConstraint" ) {
1619+ traceIndented(i " add constraint $param ${if (fromBelow) " >:" else " <:" } $bound $frozenConstraint" ) {
15371620 super .addConstraint(param, bound, fromBelow)
15381621 }
15391622
15401623 override def copyIn (ctx : Context ) = new ExplainingTypeComparer (ctx)
15411624
1625+ override def compareHkApply2 (tp1 : Type , tp2 : Type , tycon2 : Type , args2 : List [Type ]): Boolean = {
1626+ def addendum = tycon2 match {
1627+ case param2 : PolyParam =>
1628+ i " : it's a polyparam with entry ${ctx.typerState.constraint.entry(param2)}"
1629+ case _ =>
1630+ }
1631+ traceIndented(i " compareHkApply $tp1, $tp2, $addendum" ) {
1632+ super .compareHkApply2(tp1, tp2, tycon2, args2)
1633+ }
1634+ }
1635+
15421636 override def compareHkApplyOLD (app : RefinedType , other : Type , inOrder : Boolean ) =
15431637 if (app.isHKApplyOLD)
15441638 traceIndented(i " compareHkApply $app, $other, $inOrder, ${app.normalizeHkApplyOLD}" ) {
0 commit comments