@@ -1001,44 +1001,53 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
1001
1001
}
1002
1002
1003
1003
/** Subtype test for corresponding arguments in `args1`, `args2` according to
1004
- * variances in type parameters `tparams`.
1004
+ * variances in type parameters `tparams2`.
1005
+ * @param tp1 The applied type containing `args1`
1006
+ * @param tparams2 The type parameters of the type constructor applied to `args2`
1005
1007
*/
1006
- def isSubArgs (args1 : List [Type ], args2 : List [Type ], tp1 : Type , tparams : List [ParamInfo ]): Boolean =
1007
- if (args1.isEmpty) args2.isEmpty
1008
- else args2.nonEmpty && {
1009
- val tparam = tparams.head
1010
- val v = tparam.paramVariance
1011
-
1012
- def compareCaptured (arg1 : Type , arg2 : Type ): Boolean = arg1 match {
1013
- case arg1 : TypeBounds =>
1014
- val captured = TypeRef (tp1, tparam.asInstanceOf [TypeSymbol ])
1015
- isSubArg(captured, arg2)
1016
- case _ =>
1017
- false
1018
- }
1008
+ def isSubArgs (args1 : List [Type ], args2 : List [Type ], tp1 : Type , tparams2 : List [ParamInfo ]): Boolean = {
1019
1009
1020
- def isSubArg (arg1 : Type , arg2 : Type ): Boolean = arg2 match {
1021
- case arg2 : TypeBounds =>
1022
- arg2.contains(arg1) || compareCaptured(arg1, arg2)
1023
- case _ =>
1024
- arg1 match {
1025
- case arg1 : TypeBounds =>
1026
- compareCaptured(arg1, arg2)
1027
- case _ =>
1028
- (v > 0 || isSubType(arg2, arg1)) &&
1029
- (v < 0 || isSubType(arg1, arg2))
1030
- }
1031
- }
1010
+ def paramBounds (tparam : Symbol ): TypeBounds =
1011
+ tparam.info.substApprox(tparams2.asInstanceOf [List [Symbol ]], args2).bounds
1032
1012
1033
- val arg1 = args1.head
1034
- val arg2 = args2.head
1035
- isSubArg(arg1, arg2) || {
1036
- // last effort: try to adapt variances of higher-kinded types if this is sound.
1037
- // TODO: Move this to eta-expansion?
1038
- val adapted2 = arg2.adaptHkVariances(tparam.paramInfo)
1039
- adapted2.ne(arg2) && isSubArg(arg1, adapted2)
1040
- }
1041
- } && isSubArgs(args1.tail, args2.tail, tp1, tparams.tail)
1013
+ def recur (args1 : List [Type ], args2 : List [Type ], tparams2 : List [ParamInfo ]): Boolean =
1014
+ if (args1.isEmpty) args2.isEmpty
1015
+ else args2.nonEmpty && {
1016
+ val tparam = tparams2.head
1017
+ val v = tparam.paramVariance
1018
+
1019
+ def isSubArg (arg1 : Type , arg2 : Type ): Boolean = arg2 match {
1020
+ case arg2 : TypeBounds =>
1021
+ val arg1norm = arg1 match {
1022
+ case arg1 : TypeBounds =>
1023
+ tparam match {
1024
+ case tparam : Symbol => arg1 & paramBounds(tparam)
1025
+ case _ => arg1 // This case can only arise when a hk-type is illegally instantiated with a wildcard
1026
+ }
1027
+ case _ => arg1
1028
+ }
1029
+ arg2.contains(arg1norm)
1030
+ case _ =>
1031
+ arg1 match {
1032
+ case arg1 : TypeBounds => false
1033
+ case _ =>
1034
+ (v > 0 || isSubType(arg2, arg1)) &&
1035
+ (v < 0 || isSubType(arg1, arg2))
1036
+ }
1037
+ }
1038
+
1039
+ val arg1 = args1.head
1040
+ val arg2 = args2.head
1041
+ isSubArg(arg1, arg2) || {
1042
+ // last effort: try to adapt variances of higher-kinded types if this is sound.
1043
+ // TODO: Move this to eta-expansion?
1044
+ val adapted2 = arg2.adaptHkVariances(tparam.paramInfo)
1045
+ adapted2.ne(arg2) && isSubArg(arg1, adapted2)
1046
+ }
1047
+ } && recur(args1.tail, args2.tail, tparams2.tail)
1048
+
1049
+ recur(args1, args2, tparams2)
1050
+ }
1042
1051
1043
1052
/** Test whether `tp1` has a base type of the form `B[T1, ..., Tn]` where
1044
1053
* - `B` derives from one of the class symbols of `tp2`,
0 commit comments