Skip to content

Fix #2642: Disallow nullary implicit function types #2645

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,10 @@ class Definitions {
lazy val TupleType = mkArityArray("scala.Tuple", MaxTupleArity, 2)

def FunctionClass(n: Int, isImplicit: Boolean = false)(implicit ctx: Context) =
if (isImplicit) ctx.requiredClass("scala.ImplicitFunction" + n.toString)
if (isImplicit) {
require(n > 0)
ctx.requiredClass("scala.ImplicitFunction" + n.toString)
}
else if (n <= MaxImplementedFunctionArity) FunctionClassPerRun()(ctx)(n)
else ctx.requiredClass("scala.Function" + n.toString)

Expand Down Expand Up @@ -773,12 +776,12 @@ class Definitions {

/** Is a function class.
* - FunctionN for N >= 0
* - ImplicitFunctionN for N >= 0
* - ImplicitFunctionN for N > 0
*/
def isFunctionClass(cls: Symbol) = scalaClassName(cls).isFunction

/** Is an implicit function class.
* - ImplicitFunctionN for N >= 0
* - ImplicitFunctionN for N > 0
*/
def isImplicitFunctionClass(cls: Symbol) = scalaClassName(cls).isImplicitFunction

Expand All @@ -790,7 +793,7 @@ class Definitions {

/** Is a synthetic function class
* - FunctionN for N > 22
* - ImplicitFunctionN for N >= 0
* - ImplicitFunctionN for N > 0
*/
def isSyntheticFunctionClass(cls: Symbol) = scalaClassName(cls).isSyntheticFunction

Expand Down
17 changes: 10 additions & 7 deletions compiler/src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -156,33 +156,36 @@ object NameOps {

/** Is a synthetic function name
* - N for FunctionN
* - N for ImplicitFunctionN
* - N for ImplicitFunctionN (N >= 1)
* - (-1) otherwise
*/
def functionArity: Int =
functionArityFor(str.Function) max functionArityFor(str.ImplicitFunction)
functionArityFor(str.Function) max {
val n = functionArityFor(str.ImplicitFunction)
if (n == 0) -1 else n
}

/** Is a function name
* - FunctionN for N >= 0
* - ImplicitFunctionN for N >= 0
* - ImplicitFunctionN for N >= 1
* - false otherwise
*/
def isFunction: Boolean = functionArity >= 0

/** Is a implicit function name
* - ImplicitFunctionN for N >= 0
* - ImplicitFunctionN for N >= 1
* - false otherwise
*/
def isImplicitFunction: Boolean = functionArityFor(str.ImplicitFunction) >= 0
def isImplicitFunction: Boolean = functionArityFor(str.ImplicitFunction) >= 1

/** Is a synthetic function name
* - FunctionN for N > 22
* - ImplicitFunctionN for N >= 0
* - ImplicitFunctionN for N >= 1
* - false otherwise
*/
def isSyntheticFunction: Boolean = {
functionArityFor(str.Function) > MaxImplementedFunctionArity ||
functionArityFor(str.ImplicitFunction) >= 0
functionArityFor(str.ImplicitFunction) >= 1
}

/** Parsed function arity for function with some specific prefix */
Expand Down
11 changes: 10 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,16 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def typedFunction(tree: untpd.Function, pt: Type)(implicit ctx: Context) = track("typedFunction") {
val untpd.Function(args, body) = tree
if (ctx.mode is Mode.Type) {
val funCls = defn.FunctionClass(args.length, tree.isInstanceOf[untpd.ImplicitFunction])
val isImplicit = tree match {
case _: untpd.ImplicitFunction =>
if (args.length == 0) {
ctx.error(i"implicit function type needs non-empty parameter list", tree.pos)
false
}
else true
case _ => false
}
val funCls = defn.FunctionClass(args.length, isImplicit)
typed(cpy.AppliedTypeTree(tree)(
untpd.TypeTree(funCls.typeRef), args :+ body), pt)
}
Expand Down
4 changes: 4 additions & 0 deletions tests/neg/i2642.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
object Foo {
type X = implicit () => Int // error: implicit function needs parameters
def ff: X = () // error: found: Unit, expected: X
}