Skip to content

Commit d34b677

Browse files
committed
Drop requirement that implicit/erased functions must be non-empty
It's the kind of trivial requirement we should not do. In the case of implicit function types, it turns out that it even blocks something that would be useful! Also, rename NonEmptyFunction to FunctionWithMods.
1 parent def8b69 commit d34b677

File tree

6 files changed

+9
-88
lines changed

6 files changed

+9
-88
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -869,7 +869,7 @@ object desugar {
869869

870870
def makeImplicitFunction(formals: List[Type], body: Tree)(implicit ctx: Context): Tree = {
871871
val params = makeImplicitParameters(formals.map(TypeTree))
872-
new NonEmptyFunction(params, body, Modifiers(Implicit))
872+
new FunctionWithMods(params, body, Modifiers(Implicit))
873873
}
874874

875875
/** Add annotation to tree:

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,15 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
5656
override def isType = body.isType
5757
}
5858

59-
/** A function type that should have non empty args */
60-
class NonEmptyFunction(args: List[Tree], body: Tree, val mods: Modifiers) extends Function(args, body)
59+
/** A function type with `implicit` or `erased` modifiers */
60+
class FunctionWithMods(args: List[Tree], body: Tree, val mods: Modifiers) extends Function(args, body)
6161

6262
/** A function created from a wildcard expression
6363
* @param placeholderParams a list of definitions of synthetic parameters.
6464
* @param body the function body where wildcards are replaced by
6565
* references to synthetic parameters.
66+
* This is equivalent to Function, except that forms a special case for the overlapping
67+
* positions tests.
6668
*/
6769
class WildcardFunction(placeholderParams: List[ValDef], body: Tree) extends Function(placeholderParams, body)
6870

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@ object Parsers {
732732
def functionRest(params: List[Tree]): Tree =
733733
atPos(start, accept(ARROW)) {
734734
val t = typ()
735-
if (imods.is(Implicit) || imods.is(Erased)) new NonEmptyFunction(params, t, imods)
735+
if (imods.is(Implicit) || imods.is(Erased)) new FunctionWithMods(params, t, imods)
736736
else Function(params, t)
737737
}
738738
def funArgTypesRest(first: Tree, following: () => Tree) = {
@@ -800,7 +800,7 @@ object Parsers {
800800
case ARROW => functionRest(t :: Nil)
801801
case FORSOME => syntaxError(ExistentialTypesNoLongerSupported()); t
802802
case _ =>
803-
if (imods.is(Implicit) && !t.isInstanceOf[NonEmptyFunction])
803+
if (imods.is(Implicit) && !t.isInstanceOf[FunctionWithMods])
804804
syntaxError("Types with implicit keyword can only be function types", Position(start, start + nme.IMPLICITkw.asSimpleName.length))
805805
t
806806
}

compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1722,26 +1722,6 @@ object messages {
17221722
}
17231723
}
17241724

1725-
case class FunctionTypeNeedsNonEmptyParameterList(isImplicit: Boolean, isErased: Boolean)(implicit ctx: Context)
1726-
extends Message(FunctionTypeNeedsNonEmptyParameterListID) {
1727-
assert(isImplicit || isErased)
1728-
val kind = "Syntax"
1729-
val mods = ((isErased, "erased") :: (isImplicit, "implicit") :: Nil).collect { case (true, mod) => mod }.mkString(" ")
1730-
val msg = mods + " function type needs non-empty parameter list"
1731-
val explanation = {
1732-
val code1 = s"type Transactional[T] = $mods Transaction => T"
1733-
val code2 = "val cl: implicit A => B"
1734-
hl"""It is not allowed to leave $mods function parameter list empty.
1735-
|Possible ways to define $mods function type:
1736-
|
1737-
|$code1
1738-
|
1739-
|or
1740-
|
1741-
|$code2""".stripMargin
1742-
}
1743-
}
1744-
17451725
case class WrongNumberOfParameters(expected: Int)(implicit ctx: Context)
17461726
extends Message(WrongNumberOfParametersID) {
17471727
val kind = "Syntax"

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

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -761,13 +761,8 @@ class Typer extends Namer
761761
def typedFunctionType(tree: untpd.Function, pt: Type)(implicit ctx: Context) = {
762762
val untpd.Function(args, body) = tree
763763
val (isImplicit, isErased) = tree match {
764-
case tree: untpd.NonEmptyFunction =>
765-
if (args.nonEmpty) (tree.mods.is(Implicit), tree.mods.is(Erased))
766-
else {
767-
ctx.error(FunctionTypeNeedsNonEmptyParameterList(tree.mods.is(Implicit), tree.mods.is(Erased)), tree.pos)
768-
(false, false)
769-
}
770-
case _ => (false, false)
764+
case tree: untpd.FunctionWithMods => (tree.mods.is(Implicit), tree.mods.is(Erased))
765+
case _ => (false, false)
771766
}
772767
val funCls = defn.FunctionClass(args.length, isImplicit, isErased)
773768

compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -873,20 +873,6 @@ class ErrorMessagesTests extends ErrorMessagesTest {
873873
assertEquals(err, WildcardOnTypeArgumentNotAllowedOnNew())
874874
}
875875

876-
@Test def implicitFunctionTypeNeedsNonEmptyParameterList =
877-
checkMessagesAfter(RefChecks.name) {
878-
"""abstract class Foo {
879-
| type Contextual[T] = implicit () => T
880-
| val x: implicit () => Int
881-
|}""".stripMargin
882-
}
883-
.expect { (ictx, messages) =>
884-
implicit val ctx: Context = ictx
885-
886-
assertMessageCount(2, messages)
887-
messages.foreach(assertEquals(_, FunctionTypeNeedsNonEmptyParameterList(isImplicit = true, isErased = false)))
888-
}
889-
890876
@Test def wrongNumberOfParameters =
891877
checkMessagesAfter(RefChecks.name) {
892878
"""object NumberOfParams {
@@ -1310,48 +1296,6 @@ class ErrorMessagesTests extends ErrorMessagesTest {
13101296
assertEquals(symbol.name.mangledString, "a")
13111297
}
13121298

1313-
@Test def i4127a =
1314-
checkMessagesAfter(FrontEnd.name) {
1315-
"""
1316-
|class Foo {
1317-
| val x: implicit () => Int = () => 1
1318-
|}
1319-
""".stripMargin
1320-
}.expect { (ictx, messages) =>
1321-
implicit val ctx: Context = ictx
1322-
assertMessageCount(1, messages)
1323-
val (msg @ FunctionTypeNeedsNonEmptyParameterList(_, _)) :: Nil = messages
1324-
assertEquals(msg.mods, "implicit")
1325-
}
1326-
1327-
@Test def i4127b =
1328-
checkMessagesAfter(FrontEnd.name) {
1329-
"""
1330-
|class Foo {
1331-
| val x: erased () => Int = () => 1
1332-
|}
1333-
""".stripMargin
1334-
}.expect { (ictx, messages) =>
1335-
implicit val ctx: Context = ictx
1336-
assertMessageCount(1, messages)
1337-
val (msg @ FunctionTypeNeedsNonEmptyParameterList(_, _)) :: Nil = messages
1338-
assertEquals(msg.mods, "erased")
1339-
}
1340-
1341-
@Test def i4127c =
1342-
checkMessagesAfter(FrontEnd.name) {
1343-
"""
1344-
|class Foo {
1345-
| val x: erased implicit () => Int = () => 1
1346-
|}
1347-
""".stripMargin
1348-
}.expect { (ictx, messages) =>
1349-
implicit val ctx: Context = ictx
1350-
assertMessageCount(1, messages)
1351-
val (msg @ FunctionTypeNeedsNonEmptyParameterList(_, _)) :: Nil = messages
1352-
assertEquals(msg.mods, "erased implicit")
1353-
}
1354-
13551299
@Test def renameImportTwice =
13561300
checkMessagesAfter(PostTyper.name) {
13571301
"""

0 commit comments

Comments
 (0)