From 4e33ebcc08b9f19ad4fb078172a103069897c00d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 10 Oct 2017 16:58:12 +0200 Subject: [PATCH 1/2] Fix #3246: Refine handling of postfix _ for non-functions --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 12 +++++++----- tests/pos-scala2/i3246.scala | 7 +++++++ 2 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 tests/pos-scala2/i3246.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 095ccd29bdfe..ae7b8b0e5d4d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1548,17 +1548,19 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedAsFunction(tree: untpd.PostfixOp, pt: Type)(implicit ctx: Context): Tree = { val untpd.PostfixOp(qual, Ident(nme.WILDCARD)) = tree val pt1 = if (defn.isFunctionType(pt)) pt else AnyFunctionProto - var res = typed(qual, pt1) - if (pt1.eq(AnyFunctionProto) && !defn.isFunctionClass(res.tpe.classSymbol)) { - ctx.errorOrMigrationWarning(i"not a function: ${res.tpe}; cannot be followed by `_'", tree.pos) + val nestedCtx = ctx.fresh.setNewTyperState() + var res = typed(qual, pt1)(nestedCtx) + if (!defn.isFunctionClass(res.tpe.classSymbol)) { + ctx.errorOrMigrationWarning(i"not a function: $qual; cannot be followed by `_'", tree.pos) if (ctx.scala2Mode) { // Under -rewrite, patch `x _` to `(() => x)` patch(Position(tree.pos.start), "(() => ") patch(Position(qual.pos.end, tree.pos.end), ")") - res = typed(untpd.Function(Nil, untpd.TypedSplice(res))) + return typed(untpd.Function(Nil, res)) } } - else if (ctx.settings.strict.value) { + nestedCtx.typerState.commit() + if (ctx.settings.strict.value) { lazy val (prefix, suffix) = res match { case Block(mdef @ DefDef(_, _, vparams :: Nil, _, _) :: Nil, _: Closure) => val arity = vparams.length diff --git a/tests/pos-scala2/i3246.scala b/tests/pos-scala2/i3246.scala new file mode 100644 index 000000000000..1a263bcea58b --- /dev/null +++ b/tests/pos-scala2/i3246.scala @@ -0,0 +1,7 @@ +class Test { + def foo(x: => Int) = bar(x _) + def bar(x: () => Int) = ??? + def baz = 1 + def bam: () => Int = baz _ + def ban: () => Int = 1 _ +} From a7efd5720405705ab533a98ad5d5344dc5f103cc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 24 Oct 2017 16:48:55 +0200 Subject: [PATCH 2/2] Fix crash reported by reviewer --- .../src/dotty/tools/dotc/typer/Typer.scala | 20 ++++++++++--------- tests/neg/i3246.scala | 4 ++++ 2 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 tests/neg/i3246.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ae7b8b0e5d4d..076e49027281 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1549,15 +1549,17 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val untpd.PostfixOp(qual, Ident(nme.WILDCARD)) = tree val pt1 = if (defn.isFunctionType(pt)) pt else AnyFunctionProto val nestedCtx = ctx.fresh.setNewTyperState() - var res = typed(qual, pt1)(nestedCtx) - if (!defn.isFunctionClass(res.tpe.classSymbol)) { - ctx.errorOrMigrationWarning(i"not a function: $qual; cannot be followed by `_'", tree.pos) - if (ctx.scala2Mode) { - // Under -rewrite, patch `x _` to `(() => x)` - patch(Position(tree.pos.start), "(() => ") - patch(Position(qual.pos.end, tree.pos.end), ")") - return typed(untpd.Function(Nil, res)) - } + val res = typed(qual, pt1)(nestedCtx) + res match { + case res @ closure(_, _, _) => + case _ => + ctx.errorOrMigrationWarning(i"not a function: $qual; cannot be followed by `_'", tree.pos) + if (ctx.scala2Mode) { + // Under -rewrite, patch `x _` to `(() => x)` + patch(Position(tree.pos.start), "(() => ") + patch(Position(qual.pos.end, tree.pos.end), ")") + return typed(untpd.Function(Nil, qual), pt) + } } nestedCtx.typerState.commit() if (ctx.settings.strict.value) { diff --git a/tests/neg/i3246.scala b/tests/neg/i3246.scala new file mode 100644 index 000000000000..e98db368695b --- /dev/null +++ b/tests/neg/i3246.scala @@ -0,0 +1,4 @@ +class Test { + def foo(x: Int) = 1 + val bar: () => Int = foo _ +}