Skip to content

Commit 3c6c5a7

Browse files
committed
Revise polymorphic function syntax
* Use => as the arrow rather than -> * Term-parameterless polymorphic functions are now reported as unsupported due to an implementation restriction * Added run/neg tests
1 parent 860c96b commit 3c6c5a7

File tree

4 files changed

+39
-14
lines changed

4 files changed

+39
-14
lines changed

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

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -924,9 +924,18 @@ object Parsers {
924924
val tparams = typeParamClause(ParamOwner.TypeParam)
925925
if (in.token == TLARROW)
926926
atSpan(start, in.skipToken())(LambdaTypeTree(tparams, toplevelTyp()))
927-
else if (isIdent && in.name.toString == "->")
928-
atSpan(start, in.skipToken())(PolyFunction(tparams, toplevelTyp()))
929-
else { accept(TLARROW); typ() }
927+
else if (in.token == ARROW) {
928+
val arrowOffset = in.skipToken()
929+
val body = toplevelTyp()
930+
atSpan(start, arrowOffset) {
931+
body match {
932+
case _: Function => PolyFunction(tparams, body)
933+
case _ =>
934+
syntaxError("Implementation restriction: polymorphic function types must have a value parameter", arrowOffset)
935+
Ident(nme.ERROR.toTypeName)
936+
}
937+
}
938+
} else { accept(TLARROW); typ() }
930939
}
931940
else infixType()
932941

@@ -1328,8 +1337,16 @@ object Parsers {
13281337
case LBRACKET =>
13291338
val start = in.offset
13301339
val tparams = typeParamClause(ParamOwner.TypeParam)
1331-
assert(isIdent && in.name.toString == "->", "Expected `->`")
1332-
atSpan(start, in.skipToken())(PolyFunction(tparams, expr()))
1340+
val arrowOffset = accept(ARROW)
1341+
val body = expr()
1342+
atSpan(start, arrowOffset) {
1343+
body match {
1344+
case _: Function => PolyFunction(tparams, body)
1345+
case _ =>
1346+
syntaxError("Implementation restriction: polymorphic function literals must have a value parameter", arrowOffset)
1347+
errorTermTree
1348+
}
1349+
}
13331350
case _ =>
13341351
if (isIdent(nme.inline) && !in.inModifierPosition() && in.lookaheadIn(canStartExpressionTokens)) {
13351352
val start = in.skipToken()

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
561561
case PolyFunction(targs, body) =>
562562
val targsText = "[" ~ Text(targs.map((arg: Tree) => toText(arg)), ", ") ~ "]"
563563
changePrec(GlobalPrec) {
564-
targsText ~ " -> " ~ toText(body)
564+
targsText ~ " => " ~ toText(body)
565565
}
566566
case InfixOp(l, op, r) =>
567567
val opPrec = parsing.precedence(op.name)

tests/neg/polymorphic-functions.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object Test {
2+
val pv0: [T] => List[T] = ??? // error
3+
val pv1: Any = [T] => Nil // error
4+
val pv2: [T] => List[T] = [T] => Nil // error // error
5+
}

tests/run/polymorphic-functions.scala

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
object Test {
2-
def test1(f: [T <: AnyVal] -> List[T] => List[(T, T)]) = {
3-
f(List(1, 2, 3))
4-
}
1+
object Test extends App {
2+
// Types
3+
type F0 = [T] => List[T] => Option[T]
4+
type F1 = [F[_], G[_], T] => (F[T], F[T] => G[T]) => G[T]
55

6-
def main(args: Array[String]): Unit = {
7-
val fun = [T <: AnyVal] -> (x: List[T]) => x.map(e => (e, e))
6+
// Terms
7+
val t0 = [T] => (ts: List[T]) => ts.headOption
8+
val t0a: F0 = t0
9+
assert(t0(List(1, 2, 3)) == Some(1))
810

9-
assert(test1(fun) == List((1, 1), (2, 2), (3, 3)))
10-
}
11+
val t1 = [F[_], G[_], T] => (ft: F[T], f: F[T] => G[T]) => f(ft)
12+
val t1a: F1 = t1
13+
assert(t1(List(1, 2, 3), (ts: List[Int]) => ts.headOption) == Some(1))
1114
}

0 commit comments

Comments
 (0)