diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index ab125e793582..4bca0f196079 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -477,7 +477,7 @@ self => /* --------------- PLACEHOLDERS ------------------------------------------- */ - /** The implicit parameters introduced by `_` in the current expression. + /** The parameters introduced by `_` "placeholder syntax" in the current expression. * Parameters appear in reverse order. */ var placeholderParams: List[ValDef] = Nil @@ -529,8 +529,8 @@ self => @tailrec final def isWildcard(t: Tree): Boolean = t match { - case Ident(name1) => !placeholderParams.isEmpty && name1 == placeholderParams.head.name - case Typed(t1, _) => isWildcard(t1) + case Ident(name1) => !placeholderParams.isEmpty && name1 == placeholderParams.head.name + case Typed(t1, _) => isWildcard(t1) case Annotated(t1, _) => isWildcard(t1) case _ => false } @@ -784,7 +784,7 @@ self => /** Convert tree to formal parameter. */ def convertToParam(tree: Tree): ValDef = atPos(tree.pos) { def removeAsPlaceholder(name: Name): Unit = { - placeholderParams = placeholderParams filter (_.name != name) + placeholderParams = placeholderParams.filter(_.name != name) } def errorParam = makeParam(nme.ERROR, errorTypeTree setPos o2p(tree.pos.end)) def propagateNoWarnAttachment(from: Tree, to: ValDef): to.type = @@ -1711,7 +1711,7 @@ self => case IMPLICIT => implicitClosure(in.skipToken(), location) case _ => - def parseOther = { + def parseOther: Tree = { var t = postfixExpr() if (in.token == EQUALS) { t match { @@ -1738,13 +1738,13 @@ self => } else { t = atPos(t.pos.start, colonPos) { val tpt = typeOrInfixType(location) + // for placeholder syntax `(_: Int) + 1`; function literal `(_: Int) => 42` uses `t` below if (isWildcard(t)) (placeholderParams: @unchecked) match { case (vd @ ValDef(mods, name, _, _)) :: rest => placeholderParams = treeCopy.ValDef(vd, mods, name, tpt.duplicate, EmptyTree) :: rest } - // this does not correspond to syntax, but is necessary to - // accept closures. We might restrict closures to be between {...} only. + // this does not correspond to syntax, but is necessary to accept closures. See below & convertToParam. Typed(t, tpt) } } @@ -1755,10 +1755,9 @@ self => // "(this: Int) =>" is parsed as an erroneous function literal but emits special guidance on // what's probably intended. def lhsIsTypedParamList() = t match { - case Parens(List(Typed(This(_), _))) => { + case Parens(List(Typed(This(_), _))) => reporter.error(t.pos, "self-type annotation may not be in parentheses") false - } case Parens(xs) => xs.forall(isTypedParam) case _ => false } @@ -1779,15 +1778,15 @@ self => * Expr ::= implicit Id `=>` Expr * }}} */ - def implicitClosure(start: Offset, location: Location): Tree = { val param0 = convertToParam { atPos(in.offset) { - Ident(ident()) match { - case expr if in.token == COLON => - in.nextToken() ; Typed(expr, typeOrInfixType(location)) - case expr => expr + val p = if (in.token == USCORE) freshPlaceholder() else Ident(ident()) + if (in.token == COLON) { + in.nextToken() + Typed(p, typeOrInfixType(location)) } + else p } } val param = copyValDef(param0)(mods = param0.mods | Flags.IMPLICIT) @@ -3507,7 +3506,7 @@ self => else if (isDefIntro || isLocalModifier || isAnnotation) { if (in.token == IMPLICIT) { val start = in.skipToken() - if (isIdent) stats += implicitClosure(start, InBlock) + if (isIdent || in.token == USCORE) stats += implicitClosure(start, InBlock) else stats ++= localDef(Flags.IMPLICIT) } else { stats ++= localDef(0) diff --git a/test/files/pos/t3672.scala b/test/files/pos/t3672.scala index d861fd69297f..25cecd2263e2 100644 --- a/test/files/pos/t3672.scala +++ b/test/files/pos/t3672.scala @@ -6,17 +6,17 @@ object Test { foo { x: Int => x + 1 } foo { implicit x: Int => x + 1 } foo { _ => 42 } - //foo { implicit _ => implicitly[Int] + 1 } + foo { implicit _ => implicitly[Int] + 1 } // scala 2 deficit foo { _: Int => 42 } - //foo { implicit _: Int => implicitly[Int] + 1 } + foo { implicit _: Int => implicitly[Int] + 1 } // scala 2 deficit foo(x => x + 1) foo(implicit x => x + 1) foo((x: Int) => x + 1) - //foo(implicit (x: Int) => x + 1) + //foo(implicit (x: Int) => x + 1) // scala 3 foo(_ => 42) - //foo(implicit _ => implicitly[Int] + 1) + foo(implicit _ => implicitly[Int] + 1) // scala 2 deficit foo((_: Int) => 42) - //foo(implicit (_: Int) => implicitly[Int] + 1) + //foo(implicit (_: Int) => implicitly[Int] + 1) // scala 3 } }