@@ -100,30 +100,38 @@ object Checking {
100100 checkValidIfHKApply(ctx.addMode(Mode .AllowLambdaWildcardApply ))
101101 }
102102
103- /** Check that the rank of the kind of `arg` does not exceed the rank of the
104- * kind of `paramBounds`. E.g. if `paramBounds` has *-kind , `arg` must have
105- * *-kind as well, and analogously for higher kinds.
106- * More detailed kind checking is done as part of checkBounds in PostTyper.
107- * The purpose of checkKindRank is to do a rough test earlier in Typer,
103+ /** Check that kind of `arg` has the same outline as the kind of paramBounds.
104+ * E.g. if `paramBounds` has kind * -> * , `arg` must have that kind as well,
105+ * and analogously for all other kinds. This kind checking does not take into account
106+ * variances or bounds. The more detailed kind checking is done as part of checkBounds in PostTyper.
107+ * The purpose of preCheckKind is to do a rough test earlier in Typer,
108108 * in order to prevent scenarios that lead to self application of
109- * types. Self application needs to be avoided since it can lead to stackoverflows .
110- * A test case is neg/i2771.scala.
109+ * types. Self application needs to be avoided since it can lead to stack overflows .
110+ * Test cases are neg/i2771.scala and neg/i2771b .scala.
111111 */
112- def checkKindRank (arg : Tree , paramBounds : TypeBounds )(implicit ctx : Context ): Tree = {
112+ def preCheckKind (arg : Tree , paramBounds : TypeBounds )(implicit ctx : Context ): Tree = {
113113 def result (tp : Type ): Type = tp match {
114114 case tp : HKTypeLambda => tp.resultType
115115 case tp : TypeProxy => result(tp.superType)
116116 case _ => defn.AnyType
117117 }
118- def kindOK (argType : Type , boundType : Type ): Boolean =
119- ! argType.isHK ||
120- boundType.isHK && kindOK(result(argType), result(boundType))
118+ def kindOK (argType : Type , boundType : Type ): Boolean = {
119+ // println(i"check kind rank2$arg $argType $boundType") // DEBUG
120+ val argResult = argType.hkResult
121+ val boundResult = argType.hkResult
122+ if (argResult.exists)
123+ boundResult.exists &&
124+ kindOK(boundResult, argResult) &&
125+ argType.typeParams.corresponds(boundType.typeParams)((ap, bp) =>
126+ kindOK(ap.paramInfo, bp.paramInfo))
127+ else ! boundResult.exists
128+ }
121129 if (kindOK(arg.tpe, paramBounds.hi)) arg
122- else errorTree(arg, em " ${arg.tpe} takes type parameters " )
130+ else errorTree(arg, em " ${arg.tpe} has wrong kind " )
123131 }
124132
125- def checkKindRanks (args : List [Tree ], paramBoundss : List [TypeBounds ])(implicit ctx : Context ): List [Tree ] = {
126- val args1 = args.zipWithConserve(paramBoundss)(checkKindRank )
133+ def preCheckKinds (args : List [Tree ], paramBoundss : List [TypeBounds ])(implicit ctx : Context ): List [Tree ] = {
134+ val args1 = args.zipWithConserve(paramBoundss)(preCheckKind )
127135 args1 ++ args.drop(paramBoundss.length)
128136 // add any arguments that do not correspond to a parameter back,
129137 // so the wrong number of parameters is reported afterwards.
0 commit comments