Skip to content

Commit ded42af

Browse files
committed
Refine kind checking
Fix problems in previous iteration.
1 parent 41a716b commit ded42af

File tree

6 files changed

+24
-13
lines changed

6 files changed

+24
-13
lines changed

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,25 @@ object Checking {
100100
checkValidIfHKApply(ctx.addMode(Mode.AllowLambdaWildcardApply))
101101
}
102102

103-
def checkKind(arg: Tree, paramBounds: TypeBounds)(implicit ctx: Context): Tree =
103+
/** Check that `arg` has a *-type, unless `paramBounds` is higher-kinded.
104+
* More detailed kind checking is done as part of checkBounds in PostTyper.
105+
* The purpose of checkStarKind is to do a rough test earlier in Typer,
106+
* in order to prevent scenarios that lead to self application of
107+
* types. Self application needs to be avoided since it can lead to stackoverflows.
108+
* A test case is neg/i2771.scala.
109+
*/
110+
def checkStarKind(arg: Tree, paramBounds: TypeBounds)(implicit ctx: Context): Tree =
104111
if (arg.tpe.isHK && !paramBounds.isHK)
105112
errorTree(arg, em"${arg.tpe} takes type parameters")
106113
else
107114
arg
108115

109-
def checkKinds(args: List[Tree], paramBoundss: List[TypeBounds])(implicit ctx: Context): List[Tree] =
110-
args.zipWithConserve(paramBoundss)(checkKind)
116+
def checkStarKinds(args: List[Tree], paramBoundss: List[TypeBounds])(implicit ctx: Context): List[Tree] = {
117+
val args1 = args.zipWithConserve(paramBoundss)(checkStarKind)
118+
args1 ++ args.drop(paramBoundss.length)
119+
// add any arguments that do not correspond to a parameter back,
120+
// so the wrong number of parameters is reported afterwards.
121+
}
111122

112123
/** Check that `tp` refers to a nonAbstract class
113124
* and that the instance conforms to the self type of the created class.

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -838,9 +838,9 @@ class Namer { typer: Typer =>
838838
* only if parent type contains uninstantiated type parameters.
839839
*/
840840
def parentType(parent: untpd.Tree)(implicit ctx: Context): Type =
841-
if (parent.isType) {
841+
if (parent.isType)
842842
typedAheadType(parent, AnyTypeConstructorProto).tpe
843-
} else {
843+
else {
844844
val (core, targs) = stripApply(parent) match {
845845
case TypeApply(core, targs) => (core, targs)
846846
case core => (core, Nil)

compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import NameOps._
1414
import collection.mutable
1515
import reporting.diagnostic.Message
1616
import reporting.diagnostic.messages._
17-
import Checking.{checkKind, checkKinds, checkNoPrivateLeaks}
17+
import Checking.{checkStarKind, checkStarKinds, checkNoPrivateLeaks}
1818

1919
trait TypeAssigner {
2020
import tpd._
@@ -358,7 +358,7 @@ trait TypeAssigner {
358358
else if (!paramNames.contains(name))
359359
ctx.error(s"undefined parameter name, required: ${paramNames.mkString(" or ")}", arg.pos)
360360
else
361-
namedArgMap(name) = checkKind(arg, paramBoundsByName(name.asTypeName)).tpe
361+
namedArgMap(name) = checkStarKind(arg, paramBoundsByName(name.asTypeName)).tpe
362362

363363
// Holds indexes of non-named typed arguments in paramNames
364364
val gapBuf = new mutable.ListBuffer[Int]
@@ -391,7 +391,7 @@ trait TypeAssigner {
391391
}
392392
}
393393
else {
394-
val argTypes = checkKinds(args, pt.paramInfos).tpes
394+
val argTypes = checkStarKinds(args, pt.paramInfos).tpes
395395
if (sameLength(argTypes, paramNames) || ctx.phase.prev.relaxedTyping) pt.instantiate(argTypes)
396396
else wrongNumberOfTypeArgs(fn.tpe, pt.typeParams, args, tree.pos)
397397
}

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1140,7 +1140,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
11401140
}
11411141
args.zipWithConserve(tparams)(typedArg(_, _)).asInstanceOf[List[Tree]]
11421142
}
1143-
val args2 = checkKinds(args1, tparams.map(_.paramInfo.bounds))
1143+
val args2 = checkStarKinds(args1, tparams.map(_.paramInfo.bounds))
11441144
// check that arguments conform to bounds is done in phase PostTyper
11451145
assignType(cpy.AppliedTypeTree(tree)(tpt1, args2), tpt1, args2)
11461146
}

tests/neg/i1652.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
object Test {
2-
val v: Array[Array[Array]] = Array() // error // error
2+
val v: Array[Array[Array]] = Array() // error: Array takes type parameters
33
def f[T](w: Array[Array[T]]) = { for (r <- w) () }
4-
f(v) // error
4+
f(v)
55
}

tests/neg/i2771.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ trait D { type M >: B }
66
object Test {
77
def test(x: C with D): Unit = {
88
def f(y: x.M)(z: y.L[y.L]) = z // error: y.L takes type parameters
9-
f(new B { type L[F[_]] = F[F] })(1) // error: F takes type parameters
9+
f(new B { type L[F[_]] = F[F] })(1)
1010
}
1111

1212
def foo[X[_] <: Any]() = ()
13-
foo[Int]() // should be an error
13+
foo[Int]() // an error would be raised later, during PostTyper.
1414

1515
def bar[X, Y]() = ()
1616
bar[List, Int]() // error: List takes type parameters

0 commit comments

Comments
 (0)