Skip to content

Commit

Permalink
Better error message for polytypes wrapping capturing types
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
odersky committed Oct 24, 2024
1 parent ebbd685 commit e6b7e3d
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 20 deletions.
38 changes: 18 additions & 20 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions tests/neg-custom-args/captures/polyCaptures.check
Original file line number Diff line number Diff line change
@@ -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
7 changes: 7 additions & 0 deletions tests/neg-custom-args/captures/polyCaptures.scala
Original file line number Diff line number Diff line change
@@ -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


0 comments on commit e6b7e3d

Please sign in to comment.