Skip to content

Commit d3d1a3f

Browse files
committed
Reject poly functions with erased parameters
1 parent 8fde4f0 commit d3d1a3f

File tree

3 files changed

+65
-16
lines changed

3 files changed

+65
-16
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,13 +1434,30 @@ object Parsers {
14341434
*/
14351435
def toplevelTyp(): Tree = rejectWildcardType(typ())
14361436

1437-
private def isFunction(tree: Tree): Boolean = tree match {
1438-
case Parens(tree1) => isFunction(tree1)
1439-
case Block(Nil, tree1) => isFunction(tree1)
1440-
case _: Function => true
1441-
case _ => false
1437+
private def getFunction(tree: Tree): Option[Function] = tree match {
1438+
case Parens(tree1) => getFunction(tree1)
1439+
case Block(Nil, tree1) => getFunction(tree1)
1440+
case t: Function => Some(t)
1441+
case _ => None
14421442
}
14431443

1444+
private def checkFunctionNotErased(f: Function, context: String) =
1445+
def fail(span: Span) =
1446+
syntaxError(em"Implementation restriction: erased parameters are not supported in $context", span)
1447+
// erased parameter in type
1448+
val hasErasedParam = f match
1449+
case f: FunctionWithMods => f.hasErasedParams
1450+
case _ => false
1451+
if hasErasedParam then
1452+
fail(f.span)
1453+
// erased parameter in term
1454+
val hasErasedMods = f.args.collectFirst {
1455+
case v: ValDef if v.mods.is(Flags.Erased) => v
1456+
}
1457+
hasErasedMods match
1458+
case Some(param) => fail(param.span)
1459+
case _ =>
1460+
14441461
/** CaptureRef ::= ident | `this`
14451462
*/
14461463
def captureRef(): Tree =
@@ -1580,11 +1597,13 @@ object Parsers {
15801597
val arrowOffset = in.skipToken()
15811598
val body = toplevelTyp()
15821599
atSpan(start, arrowOffset) {
1583-
if (isFunction(body))
1584-
PolyFunction(tparams, body)
1585-
else {
1586-
syntaxError(em"Implementation restriction: polymorphic function types must have a value parameter", arrowOffset)
1587-
Ident(nme.ERROR.toTypeName)
1600+
getFunction(body) match {
1601+
case Some(f) =>
1602+
checkFunctionNotErased(f, "poly function")
1603+
PolyFunction(tparams, body)
1604+
case None =>
1605+
syntaxError(em"Implementation restriction: polymorphic function types must have a value parameter", arrowOffset)
1606+
Ident(nme.ERROR.toTypeName)
15881607
}
15891608
}
15901609
}
@@ -2113,12 +2132,13 @@ object Parsers {
21132132
val arrowOffset = accept(ARROW)
21142133
val body = expr(location)
21152134
atSpan(start, arrowOffset) {
2116-
if (isFunction(body))
2117-
PolyFunction(tparams, body)
2118-
else {
2119-
syntaxError(em"Implementation restriction: polymorphic function literals must have a value parameter", arrowOffset)
2120-
errorTermTree(arrowOffset)
2121-
}
2135+
getFunction(body) match
2136+
case Some(f) =>
2137+
checkFunctionNotErased(f, "poly function")
2138+
PolyFunction(tparams, f)
2139+
case None =>
2140+
syntaxError(em"Implementation restriction: polymorphic function literals must have a value parameter", arrowOffset)
2141+
errorTermTree(arrowOffset)
21222142
}
21232143
case _ =>
21242144
val saved = placeholderParams

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2614,6 +2614,19 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
26142614
// check value class constraints
26152615
checkDerivedValueClass(cls, body1)
26162616

2617+
// check PolyFunction constraints (no erased functions!)
2618+
if parents1.exists(_.tpe.classSymbol eq defn.PolyFunctionClass) then
2619+
body1.foreach {
2620+
case ddef: DefDef =>
2621+
ddef.paramss.foreach { params =>
2622+
val erasedParam = params.collectFirst { case vdef: ValDef if vdef.symbol.is(Erased) => vdef }
2623+
erasedParam.foreach { p =>
2624+
report.error(em"Implementation restriction: erased classes are not allowed in a poly function definition", p.srcPos)
2625+
}
2626+
}
2627+
case _ =>
2628+
}
2629+
26172630
val effectiveOwner = cls.owner.skipWeakOwner
26182631
if !cls.isRefinementClass
26192632
&& !cls.isAllOf(PrivateLocal)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
object Test:
2+
// Poly functions with erased parameters are disallowed as an implementation restriction
3+
4+
type T1 = [X] => (erased x: X, y: Int) => Int // error
5+
type T2 = [X] => (x: X, erased y: Int) => X // error
6+
7+
val t1 = [X] => (erased x: X, y: Int) => y // error
8+
val t2 = [X] => (x: X, erased y: Int) => x // error
9+
10+
// Erased classes should be detected too
11+
erased class A
12+
13+
type T3 = [X] => (x: A, y: X) => X // error
14+
15+
val t3 = [X] => (x: A, y: X) => y // error
16+

0 commit comments

Comments
 (0)