Skip to content

Commit 3a66d73

Browse files
authored
Merge pull request #2645 from dotty-staging/fix-#2642
Fix #2642: Disallow nullary implicit function types
2 parents 8b814cf + 9ea9bf5 commit 3a66d73

File tree

4 files changed

+31
-12
lines changed

4 files changed

+31
-12
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,10 @@ class Definitions {
740740
lazy val TupleType = mkArityArray("scala.Tuple", MaxTupleArity, 2)
741741

742742
def FunctionClass(n: Int, isImplicit: Boolean = false)(implicit ctx: Context) =
743-
if (isImplicit) ctx.requiredClass("scala.ImplicitFunction" + n.toString)
743+
if (isImplicit) {
744+
require(n > 0)
745+
ctx.requiredClass("scala.ImplicitFunction" + n.toString)
746+
}
744747
else if (n <= MaxImplementedFunctionArity) FunctionClassPerRun()(ctx)(n)
745748
else ctx.requiredClass("scala.Function" + n.toString)
746749

@@ -773,12 +776,12 @@ class Definitions {
773776

774777
/** Is a function class.
775778
* - FunctionN for N >= 0
776-
* - ImplicitFunctionN for N >= 0
779+
* - ImplicitFunctionN for N > 0
777780
*/
778781
def isFunctionClass(cls: Symbol) = scalaClassName(cls).isFunction
779782

780783
/** Is an implicit function class.
781-
* - ImplicitFunctionN for N >= 0
784+
* - ImplicitFunctionN for N > 0
782785
*/
783786
def isImplicitFunctionClass(cls: Symbol) = scalaClassName(cls).isImplicitFunction
784787

@@ -790,7 +793,7 @@ class Definitions {
790793

791794
/** Is a synthetic function class
792795
* - FunctionN for N > 22
793-
* - ImplicitFunctionN for N >= 0
796+
* - ImplicitFunctionN for N > 0
794797
*/
795798
def isSyntheticFunctionClass(cls: Symbol) = scalaClassName(cls).isSyntheticFunction
796799

compiler/src/dotty/tools/dotc/core/NameOps.scala

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -156,33 +156,36 @@ object NameOps {
156156

157157
/** Is a synthetic function name
158158
* - N for FunctionN
159-
* - N for ImplicitFunctionN
159+
* - N for ImplicitFunctionN (N >= 1)
160160
* - (-1) otherwise
161161
*/
162162
def functionArity: Int =
163-
functionArityFor(str.Function) max functionArityFor(str.ImplicitFunction)
163+
functionArityFor(str.Function) max {
164+
val n = functionArityFor(str.ImplicitFunction)
165+
if (n == 0) -1 else n
166+
}
164167

165168
/** Is a function name
166169
* - FunctionN for N >= 0
167-
* - ImplicitFunctionN for N >= 0
170+
* - ImplicitFunctionN for N >= 1
168171
* - false otherwise
169172
*/
170173
def isFunction: Boolean = functionArity >= 0
171174

172175
/** Is a implicit function name
173-
* - ImplicitFunctionN for N >= 0
176+
* - ImplicitFunctionN for N >= 1
174177
* - false otherwise
175178
*/
176-
def isImplicitFunction: Boolean = functionArityFor(str.ImplicitFunction) >= 0
179+
def isImplicitFunction: Boolean = functionArityFor(str.ImplicitFunction) >= 1
177180

178181
/** Is a synthetic function name
179182
* - FunctionN for N > 22
180-
* - ImplicitFunctionN for N >= 0
183+
* - ImplicitFunctionN for N >= 1
181184
* - false otherwise
182185
*/
183186
def isSyntheticFunction: Boolean = {
184187
functionArityFor(str.Function) > MaxImplementedFunctionArity ||
185-
functionArityFor(str.ImplicitFunction) >= 0
188+
functionArityFor(str.ImplicitFunction) >= 1
186189
}
187190

188191
/** Parsed function arity for function with some specific prefix */

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,16 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
687687
def typedFunction(tree: untpd.Function, pt: Type)(implicit ctx: Context) = track("typedFunction") {
688688
val untpd.Function(args, body) = tree
689689
if (ctx.mode is Mode.Type) {
690-
val funCls = defn.FunctionClass(args.length, tree.isInstanceOf[untpd.ImplicitFunction])
690+
val isImplicit = tree match {
691+
case _: untpd.ImplicitFunction =>
692+
if (args.length == 0) {
693+
ctx.error(i"implicit function type needs non-empty parameter list", tree.pos)
694+
false
695+
}
696+
else true
697+
case _ => false
698+
}
699+
val funCls = defn.FunctionClass(args.length, isImplicit)
691700
typed(cpy.AppliedTypeTree(tree)(
692701
untpd.TypeTree(funCls.typeRef), args :+ body), pt)
693702
}

tests/neg/i2642.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
object Foo {
2+
type X = implicit () => Int // error: implicit function needs parameters
3+
def ff: X = () // error: found: Unit, expected: X
4+
}

0 commit comments

Comments
 (0)