From fd2c24c3159cefa583889a176f31d1e2325fe7e6 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 3 Dec 2016 12:53:10 +0100 Subject: Add syntax for implicit functions --- compiler/src/dotty/tools/dotc/ast/untpd.scala | 4 +++ .../src/dotty/tools/dotc/parsing/Parsers.scala | 16 ++++++++---- compiler/src/dotty/tools/dotc/typer/Typer.scala | 8 ++++-- docs/syntax-summary.txt | 4 +-- tests/pos/implicitFuns.scala | 30 ++++++++++++++++++++++ 5 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 tests/pos/implicitFuns.scala diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index 6c5210287..25b69b1f5 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -53,6 +53,10 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { override def isTerm = body.isTerm override def isType = body.isType } + + /** An implicit function type */ + class ImplicitFunction(args: List[Tree], body: Tree) extends Function(args, body) + /** A function created from a wildcard expression * @param placeHolderParams a list of definitions of synthetic parameters * @param body the function body where wildcards are replaced by diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 704f399ca..dabd8d2b0 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -681,7 +681,7 @@ object Parsers { } } - /** Type ::= FunArgTypes `=>' Type + /** Type ::= [`implicit'] FunArgTypes `=>' Type * | HkTypeParamClause `->' Type * | InfixType * FunArgTypes ::= InfixType @@ -689,20 +689,26 @@ object Parsers { */ def typ(): Tree = { val start = in.offset + val isImplicit = in.token == IMPLICIT + if (isImplicit) in.nextToken() + def functionRest(params: List[Tree]): Tree = + atPos(start, accept(ARROW)) { + val t = typ() + if (isImplicit) new ImplicitFunction(params, t) else Function(params, t) + } val t = if (in.token == LPAREN) { in.nextToken() if (in.token == RPAREN) { in.nextToken() - atPos(start, accept(ARROW)) { Function(Nil, typ()) } + functionRest(Nil) } else { openParens.change(LPAREN, 1) val ts = commaSeparated(funArgType) openParens.change(LPAREN, -1) accept(RPAREN) - if (in.token == ARROW) - atPos(start, in.skipToken()) { Function(ts, typ()) } + if (isImplicit || in.token == ARROW) functionRest(ts) else { for (t <- ts) if (t.isInstanceOf[ByNameTypeTree]) @@ -722,7 +728,7 @@ object Parsers { else infixType() in.token match { - case ARROW => atPos(start, in.skipToken()) { Function(List(t), typ()) } + case ARROW => functionRest(t :: Nil) case FORSOME => syntaxError("existential types no longer supported; use a wildcard type or dependent type instead"); t case _ => t } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index eec3859f9..c8deda4bc 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -660,9 +660,13 @@ 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) + if (ctx.mode is Mode.Type) { + val funCls = + if (tree.isInstanceOf[untpd.ImplicitFunction]) defn.ImplicitFunctionClass(args.length) + else defn.FunctionClass(args.length) typed(cpy.AppliedTypeTree(tree)( - untpd.TypeTree(defn.FunctionClass(args.length).typeRef), args :+ body), pt) + untpd.TypeTree(funCls.typeRef), args :+ body), pt) + } else { val params = args.asInstanceOf[List[untpd.ValDef]] diff --git a/docs/syntax-summary.txt b/docs/syntax-summary.txt index 04e149de6..fe0ebc89c 100644 --- a/docs/syntax-summary.txt +++ b/docs/syntax-summary.txt @@ -95,8 +95,8 @@ grammar. | [id '.'] `super' [ClassQualifier] `.' id ClassQualifier ::= `[' id `]' - Type ::= FunArgTypes `=>' Type Function(ts, t) - | HkTypeParamClause `=>' Type TypeLambda(ps, t) + Type ::= [`implicit'] FunArgTypes `=>' Type Function(ts, t) + | HkTypeParamClause `=>' Type TypeLambda(ps, t) | InfixType FunArgTypes ::= InfixType | `(' [ FunArgType {`,' FunArgType } ] `)' diff --git a/tests/pos/implicitFuns.scala b/tests/pos/implicitFuns.scala new file mode 100644 index 000000000..e62682546 --- /dev/null +++ b/tests/pos/implicitFuns.scala @@ -0,0 +1,30 @@ +object Test { + + val x: ImplicitFunction1[String, Boolean] = ??? + + val y: String => Boolean = x + + val b = x("hello") + + val b1: Boolean = b + +} +object Test2 { + + val x: implicit String => Boolean = ??? + + val xx: implicit (String, Int) => Int = ??? + + val y: String => Boolean = x + + val yy: (String, Int) => Any = xx + + val b = x("hello") + + val b1: Boolean = b + + val c = xx("hh", 22) + + val c1: Int = c + +} -- cgit v1.2.3