From e6b7e3d06faf4b833fd03fe73b5610362b8f4b8c Mon Sep 17 00:00:00 2001 From: odersky Date: Thu, 24 Oct 2024 23:47:16 +0200 Subject: [PATCH] Better error message for polytypes wrapping capturing types A type like [X] -> A ->{c} B is currently not allowed since it expands to a PolyType wrapping a CapturingType and we have an implementation restriction that requires PolyTypes to wrap only FunctionTypes. It would be great if we could lift that implementation restriction. Until we do so, we should have a better error message, which is commit implements. --- .../dotty/tools/dotc/parsing/Parsers.scala | 38 +++++++++---------- .../captures/polyCaptures.check | 8 ++++ .../captures/polyCaptures.scala | 7 ++++ 3 files changed, 33 insertions(+), 20 deletions(-) create mode 100644 tests/neg-custom-args/captures/polyCaptures.check create mode 100644 tests/neg-custom-args/captures/polyCaptures.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index d933e55a9823..293b5590fec6 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -518,6 +518,22 @@ object Parsers { tree } + def makePolyFunction(tparams: List[Tree], body: Tree, + kind: String, errorTree: => Tree, + start: Offset, arrowOffset: Offset): Tree = + atSpan(start, arrowOffset): + getFunction(body) match + case None => + syntaxError(em"Implementation restriction: polymorphic function ${kind}s must have a value parameter", arrowOffset) + errorTree + case Some(Function(_, _: CapturesAndResult)) => + // A function tree like this will be desugared + // into a capturing type in the typer. + syntaxError(em"Implementation restriction: polymorphic function types cannot wrap function types that have capture sets", arrowOffset) + errorTree + case Some(f) => + PolyFunction(tparams, body) + /* --------------- PLACEHOLDERS ------------------------------------------- */ /** The implicit parameters introduced by `_` in the current expression. @@ -1539,11 +1555,6 @@ object Parsers { private def getFunction(tree: Tree): Option[Function] = tree match { case Parens(tree1) => getFunction(tree1) case Block(Nil, tree1) => getFunction(tree1) - case Function(_, _: CapturesAndResult) => - // A function tree like this will be desugared - // into a capturing type in the typer, - // so None is returned. - None case t: Function => Some(t) case _ => None } @@ -1757,13 +1768,7 @@ object Parsers { else if in.token == ARROW || isPureArrow(nme.PUREARROW) then val arrowOffset = in.skipToken() val body = toplevelTyp(nestedIntoOK(in.token)) - atSpan(start, arrowOffset): - getFunction(body) match - case Some(f) => - PolyFunction(tparams, body) - case None => - syntaxError(em"Implementation restriction: polymorphic function types must have a value parameter", arrowOffset) - Ident(nme.ERROR.toTypeName) + makePolyFunction(tparams, body, "type", Ident(nme.ERROR.toTypeName), start, arrowOffset) else accept(TLARROW) typ() @@ -2360,14 +2365,7 @@ object Parsers { val tparams = typeParamClause(ParamOwner.Type) val arrowOffset = accept(ARROW) val body = expr(location) - atSpan(start, arrowOffset) { - getFunction(body) match - case Some(f) => - PolyFunction(tparams, f) - case None => - syntaxError(em"Implementation restriction: polymorphic function literals must have a value parameter", arrowOffset) - errorTermTree(arrowOffset) - } + makePolyFunction(tparams, body, "literal", errorTermTree(arrowOffset), start, arrowOffset) case _ => val saved = placeholderParams placeholderParams = Nil diff --git a/tests/neg-custom-args/captures/polyCaptures.check b/tests/neg-custom-args/captures/polyCaptures.check new file mode 100644 index 000000000000..8173828b7bc8 --- /dev/null +++ b/tests/neg-custom-args/captures/polyCaptures.check @@ -0,0 +1,8 @@ +-- Error: tests/neg-custom-args/captures/polyCaptures.scala:4:22 ------------------------------------------------------- +4 |val runOpsCheck: [C^] -> (ops: List[() ->{C^} Unit]) ->{C^} Unit = runOps // error + | ^ + | Implementation restriction: polymorphic function types cannot wrap function types that have capture sets +-- Error: tests/neg-custom-args/captures/polyCaptures.scala:5:23 ------------------------------------------------------- +5 |val runOpsCheck2: [C^] => (ops: List[() ->{C^} Unit]) ->{C^} Unit = runOps // error + | ^ + | Implementation restriction: polymorphic function types cannot wrap function types that have capture sets diff --git a/tests/neg-custom-args/captures/polyCaptures.scala b/tests/neg-custom-args/captures/polyCaptures.scala new file mode 100644 index 000000000000..776af95e5dcf --- /dev/null +++ b/tests/neg-custom-args/captures/polyCaptures.scala @@ -0,0 +1,7 @@ +class Box[X](val elem: X) + +val runOps = [C^] => (b: Box[() ->{C^} Unit]) => b.elem() +val runOpsCheck: [C^] -> (ops: List[() ->{C^} Unit]) ->{C^} Unit = runOps // error +val runOpsCheck2: [C^] => (ops: List[() ->{C^} Unit]) ->{C^} Unit = runOps // error + +