Skip to content

Fix #9829: Allow as in place of @ for pattern bindings #9837

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
Sep 24, 2020
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
8 changes: 6 additions & 2 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2631,7 +2631,10 @@ object Parsers {
/** Pattern2 ::= [id `@'] InfixPattern
*/
val pattern2: () => Tree = () => infixPattern() match {
case p @ Ident(name) if in.token == AT =>
case p @ Ident(name) if in.token == AT || in.isIdent(nme.as) =>
if in.token == AT && sourceVersion.isAtLeast(`3.1`) then
deprecationWarning(s"`@` bindings have been deprecated; use `as` instead", in.offset)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to update the syntax.md file with the syntax change.

val offset = in.skipToken()

// compatibility for Scala2 `x @ _*` syntax
Expand Down Expand Up @@ -2659,7 +2662,8 @@ object Parsers {
/** InfixPattern ::= SimplePattern {id [nl] SimplePattern}
*/
def infixPattern(): Tree =
infixOps(simplePattern(), in.canStartExprTokens, simplePattern, isOperator = in.name != nme.raw.BAR)
infixOps(simplePattern(), in.canStartExprTokens, simplePattern,
isOperator = in.name != nme.raw.BAR && in.name != nme.as)

/** SimplePattern ::= PatVar
* | Literal
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/internals/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ TypeCaseClause ::= ‘case’ InfixType ‘=>’ Type [nl]
Pattern ::= Pattern1 { ‘|’ Pattern1 } Alternative(pats)
Pattern1 ::= Pattern2 [‘:’ RefinedType] Bind(name, Typed(Ident(wildcard), tpe))
| ‘given’ PatVar ‘:’ RefinedType
Pattern2 ::= [id ‘@’] InfixPattern Bind(name, pat)
Pattern2 ::= [id ‘as’] InfixPattern Bind(name, pat)
InfixPattern ::= SimplePattern { id [nl] SimplePattern } InfixOp(pat, op, pat)
SimplePattern ::= PatVar Ident(wildcard)
| Literal Bind(name, Ident(wildcard))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ object StringContextMacro {
val sourceFile = strCtxExpr.unseal.pos.sourceFile

val (partsExpr, parts) = strCtxExpr match {
case Expr.StringContext(p1 @ Consts(p2)) => (p1.toList, p2.toList)
case Expr.StringContext(p1 as Consts(p2)) => (p1.toList, p2.toList)
case _ => report.throwError("Expected statically known String Context", strCtxExpr)
}

Expand Down
4 changes: 2 additions & 2 deletions library/src-bootstrapped/scala/internal/quoted/Matcher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ object Matcher {

/* Term hole */
// Match a scala.internal.Quoted.patternHole typed as a repeated argument and return the scrutinee tree
case (scrutinee @ Typed(s, tpt1), Typed(TypeApply(patternHole, tpt :: Nil), tpt2))
case (scrutinee as Typed(s, tpt1), Typed(TypeApply(patternHole, tpt :: Nil), tpt2))
if patternHole.symbol == qctx.tasty.Definitions_InternalQuotedMatcher_patternHole &&
s.tpe <:< tpt.tpe &&
tpt2.tpe.derivesFrom(defn.RepeatedParamClass) =>
Expand All @@ -259,7 +259,7 @@ object Matcher {

/* Higher order term hole */
// Matches an open term and wraps it into a lambda that provides the free variables
case (scrutinee, pattern @ Apply(TypeApply(Ident("higherOrderHole"), List(Inferred())), Repeated(args, _) :: Nil))
case (scrutinee, pattern as Apply(TypeApply(Ident("higherOrderHole"), List(Inferred())), Repeated(args, _) :: Nil))
if pattern.symbol == qctx.tasty.Definitions_InternalQuotedMatcher_higherOrderHole =>

def bodyFn(lambdaArgs: List[Tree]): Tree = {
Expand Down
2 changes: 1 addition & 1 deletion library/src-bootstrapped/scala/quoted/util/ExprMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ trait ExprMap {
tree
case Super(qual, mix) =>
tree
case tree @ Apply(fun, args) =>
case tree as Apply(fun, args) =>
val MethodType(_, tpes, _) = fun.tpe.widen
Apply.copy(tree)(transformTerm(fun, Type.of[Any]), transformTerms(args, tpes))
case TypeApply(fun, args) =>
Expand Down
4 changes: 2 additions & 2 deletions tests/init/crash/fors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ object Test extends App {
var n = 0
for (_ <- xs) n += 1; println(n)
for ((x, y) <- xs zip ys) print(x + " "); println()
for (p @ (x, y) <- xs zip ys) print(p._1 + " "); println()
for (p as (x, y) <- xs zip ys) print(p._1 + " "); println()

// iterators
for (x <- it) print(x + " "); println()
Expand All @@ -53,7 +53,7 @@ object Test extends App {
var n = 0
for (_ <- xs) n += 1; println(n)
for ((x, y) <- xs zip ys) print(x + " "); println()
for (p @ (x, y) <- xs zip ys) print(p._1 + " "); println()
for (p as (x, y) <- xs zip ys) print(p._1 + " "); println()

// iterators
for (x <- it) print(x + " "); println()
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/Iter3.scala
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ object Iter2 {
flatten(map(f(_).buildIterator))

override def ++[B >: A](that: IterableOnce[B]): ArrayIterator[B] = {
val thatIterator @ ArrayIterator(elems2, len2) = fromIterator(that.iterator)
val thatIterator as ArrayIterator(elems2, len2) = fromIterator(that.iterator)
if (len == 0) thatIterator
else if (len2 == 0) this.asInstanceOf[ArrayIterator[B]]
else {
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/ensureReported.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
object AnonymousF {
val f = {
case l @ List(1) => // error: missing parameter type
case l as List(1) => // error: missing parameter type
Some(l)
}
}
2 changes: 1 addition & 1 deletion tests/neg/i1716.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
object Fail {
def f(m: Option[Int]): Unit = {
m match {
case x @ Some[_] => // error: unbound wildcard type
case x as Some[_] => // error: unbound wildcard type
case _ =>
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/i3200.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
object Test {
case object Bob { override def equals(other: Any) = true }
def main(args: Array[String]): Unit = {
val m : Bob.type = (5: Any) match { case x @ Bob => x } // error
val m : Bob.type = (5: Any) match { case x as Bob => x } // error
}
}
8 changes: 4 additions & 4 deletions tests/neg/i3200b.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
object Test {
def main(args: Array[String]): Unit = {
val a: Nil.type = (Vector(): Any) match { case n @ Nil => n } // error
val b: Nil.type = (Vector(): Any) match { case n @ (m @ Nil) => n } // error
val c: Int = (1.0: Any) match { case n @ 1 => n } // error
val d: Int = (1.0: Any) match { case n @ (m @ 1) => n } // error
val a: Nil.type = (Vector(): Any) match { case n as Nil => n } // error
val b: Nil.type = (Vector(): Any) match { case n as (m as Nil) => n } // error
val c: Int = (1.0: Any) match { case n as 1 => n } // error
val d: Int = (1.0: Any) match { case n as (m as 1) => n } // error
}
}
2 changes: 1 addition & 1 deletion tests/neg/i3332.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ object Test {
case _ => println("nope")
}
def test(x: Any) = x match {
case _: String | _ @ A() => 1
case _: String | _ as A() => 1
}
}
4 changes: 2 additions & 2 deletions tests/neg/i3812b.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ object Test {
Some(x) match { case Some(Z2.v) => () } // ok

Some(x) match { case Some(4) | Some(Z1.v) => () } // error
Some(x) match { case a @ Some(Z1.v) => () } // error
Some(x) match { case a as Some(Z1.v) => () } // error

Some(x) match { case Some(4) | Some(Z2.v) => () } // ok
Some(x) match { case a @ Some(Z2.v) => () } // ok
Some(x) match { case a as Some(Z2.v) => () } // ok
}
}
2 changes: 1 addition & 1 deletion tests/neg/i8407.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
object Test:
val xs = List(1, 2, 3, 4, 5)
xs match {
case List(1, 2, xs1 @ xs2: _*) => println(xs2) // error // error
case List(1, 2, xs1 as xs2: _*) => println(xs2) // error // error
case _ => ()
}
2 changes: 1 addition & 1 deletion tests/neg/i8715.scala
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
@main
def Test = List(42) match { case List(xs @ (ys: _*)) => xs } // error
def Test = List(42) match { case List(xs as (ys: _*)) => xs } // error
2 changes: 1 addition & 1 deletion tests/neg/i9310.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//AE-d101cfe6d25117a51897609e673f6c8e74d31e6e
val foo @ this = 0
val foo as this = 0
class Foo {
foo { } // error
}
2 changes: 1 addition & 1 deletion tests/neg/multi-patterns.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
object Test {
val (a :: as), bs = List(1, 2, 3) // error
val B @ List(), C: List[Int] = List() // error
val B as List(), C: List[Int] = List() // error
}
2 changes: 1 addition & 1 deletion tests/neg/patternUnsoundness.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ object patternUnsoundness extends App {
val y: C[Object] = x

y match {
case d @ D(x) => d.s = new Integer(1) // error
case d as D(x) => d.s = new Integer(1) // error
}

val z: String = x.s // used to throw ClassCast exception
Expand Down
2 changes: 1 addition & 1 deletion tests/pos/Iter2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ object Iter2 {
flatten(map(f(_).buildIterator))

override def ++[B >: A](that: IterableOnce[B]): ArrayIterator[B] = {
val thatIterator @ ArrayIterator(elems2, len2) = fromIterator(that.iterator)
val thatIterator as ArrayIterator(elems2, len2) = fromIterator(that.iterator)
if (len == 0) thatIterator
else if (len2 == 0) this
else {
Expand Down
2 changes: 1 addition & 1 deletion tests/pos/i1540.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ object Casey1 { def unapply(a: Casey1) = a }

object Test {
def main(args: Array[String]): Unit = {
val c @ Casey1(x) = new Casey1(0)
val c as Casey1(x) = new Casey1(0)
assert(x == c.get)
}
}
2 changes: 1 addition & 1 deletion tests/pos/i1540b.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ object Casey1 { def unapply[T](a: Casey1[T]) = a }

object Test {
def main(args: Array[String]): Unit = {
val c @ Casey1(x) = new Casey1(0)
val c as Casey1(x) = new Casey1(0)
assert(x == c.get)
}
}
2 changes: 1 addition & 1 deletion tests/pos/i3412.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
class Test {
val A @ List() = List()
val A as List() = List()
}
2 changes: 1 addition & 1 deletion tests/pos/i4177.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class Test {
val a: PartialFunction[Int, String] = { case Foo(x) => x }
val b: PartialFunction[Int, String] = { case x => x.toString }

val e: PartialFunction[String, String] = { case x @ "abc" => x }
val e: PartialFunction[String, String] = { case x as "abc" => x }
val f: PartialFunction[String, String] = x => x match { case "abc" => x }
val g: PartialFunction[String, String] = x => x match { case "abc" if x.isEmpty => x }

Expand Down
2 changes: 1 addition & 1 deletion tests/pos/i4564.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ object ClashNoSig { // ok
def unapply(x: ClashNoSig) = x

ClashNoSig(2) match {
case c @ ClashNoSig(y) => c.copy(y + c._1)
case c as ClashNoSig(y) => c.copy(y + c._1)
}
}
case class ClashNoSig private (x: Int) {
Expand Down
2 changes: 1 addition & 1 deletion tests/pos/i5402.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ object Main {
case 1 => 1
case 0 | 0 => 0
case 2 | 2 | 2 | 3 | 2 | 3 => 0
case 4 | (_ @ 4) => 0
case 4 | (_ as 4) => 0
case _ => -1
}

Expand Down
4 changes: 2 additions & 2 deletions tests/pos/simpleExtractors-2.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
class Foo {
def bar(x: Any): Unit = x match {
case Some(Some(i: Int)) => println(i)
case Some(s @ Some(i)) => println(s)
case s @ Some(r @ Some(i)) => println(s)
case Some(s as Some(i)) => println(s)
case s as Some(r as Some(i)) => println(s)
}
}
2 changes: 1 addition & 1 deletion tests/pos/t10533.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
object Foo {
val b @ Bar(_) = Bar(1)(2)(3)
val b as Bar(_) = Bar(1)(2)(3)
}

case class Bar(a: Int)(b: Int)(c: Int)
2 changes: 1 addition & 1 deletion tests/pos/t3136.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ object NullaryMethodType {
object Test {
def TEST(tp: Type): String =
tp match {
case PolyType(ps1, PolyType(ps2, res @ PolyType(a, b))) => "1" + tp // couldn't find a simpler version that still crashes
case PolyType(ps1, PolyType(ps2, res as PolyType(a, b))) => "1" + tp // couldn't find a simpler version that still crashes
case NullaryMethodType(meh) => "2" + meh
}
}
2 changes: 1 addition & 1 deletion tests/pos/t6675.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ object LeftOrRight {

object Test {
(Left((0, 0)): Either[(Int, Int), (Int, Int)]) match {
case LeftOrRight(pair @ (a, b)) => a // false -Xlint warning: "extractor pattern binds a single value to a Product2 of type (Int, Int)"
case LeftOrRight(pair as (a, b)) => a // false -Xlint warning: "extractor pattern binds a single value to a Product2 of type (Int, Int)"
}

(Left((0, 0)): Either[(Int, Int), (Int, Int)]) match {
Expand Down
2 changes: 1 addition & 1 deletion tests/pos/trailingCommas/trailingCommas.scala
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ trait SimplePattern {

// test '@' syntax in patterns
Some(1) match {
case Some(x @ 1,
case Some(x as 1,
) => x
}

Expand Down
2 changes: 1 addition & 1 deletion tests/pos/virtpatmat_alts_subst.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
case class Foo(s: String) {
def appliedType(tycon: Any) =
tycon match {
case Foo(sym @ ("NothingClass" | "AnyClass")) => println(sym)
case Foo(sym as ("NothingClass" | "AnyClass")) => println(sym)
}
}
2 changes: 1 addition & 1 deletion tests/run/3179.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
object Test {
def main(args: Array[String]): Unit = {
("": Any) match {
case a @ Test => 1
case a as Test => 1
case _ => 2
}
}
Expand Down
6 changes: 3 additions & 3 deletions tests/run/enums-serialization-compat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,19 @@ extension (ref: AnyRef) def aliases(compare: AnyRef) = assert(ref eq compare, co
val read = use(ByteArrayInputStream(buf.toByteArray))
val in = use(ObjectInputStream(read))

val Seq(Red @ _, Green @ _, Blue @ _, Indigo @ _) = (1 to 4).map(_ => in.readObject)
val Seq(Red as _, Green as _, Blue as _, Indigo as _) = (1 to 4).map(_ => in.readObject)
Red aliases JColor.Red
Green aliases SColor.Green
Blue aliases SColorTagged.Blue
Indigo aliases SColorTagged.Indigo

val Seq(A @ _, C @ _, G @ _, T @ _) = (1 to 4).map(_ => in.readObject)
val Seq(A as _, C as _, G as _, T as _) = (1 to 4).map(_ => in.readObject)
A aliases Nucleobase.A
C aliases Nucleobase.C
G aliases Nucleobase.G
T aliases Nucleobase.T

val Seq(IntTag @ _, UnitTag @ _) = (1 to 2).map(_ => in.readObject)
val Seq(IntTag as _, UnitTag as _) = (1 to 2).map(_ => in.readObject)
IntTag aliases MyClassTag.IntTag
UnitTag aliases MyClassTag.UnitTag

Expand Down
4 changes: 2 additions & 2 deletions tests/run/fors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ object Test extends App {
var n = 0
for (_ <- xs) n += 1; println(n)
for ((x, y) <- xs zip ys) print(x + " "); println()
for (p @ (x, y) <- xs zip ys) print(p._1 + " "); println()
for (p as (x, y) <- xs zip ys) print(p._1 + " "); println()

// iterators
for (x <- it) print(x + " "); println()
Expand All @@ -53,7 +53,7 @@ object Test extends App {
var n = 0
for (_ <- xs) n += 1; println(n)
for ((x, y) <- xs zip ys) print(x + " "); println()
for (p @ (x, y) <- xs zip ys) print(p._1 + " "); println()
for (p as (x, y) <- xs zip ys) print(p._1 + " "); println()

// iterators
for (x <- it) print(x + " "); println()
Expand Down
8 changes: 4 additions & 4 deletions tests/run/fully-abstract-interface.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ object Test {
const1 match {
case AppliedOp(_, _, _) =>
println("test1 fail")
case c @ Constant(n) =>
case c as Constant(n) =>
println("test1 OK")
println(s"$n = ${c.eval}")
}
Expand All @@ -41,9 +41,9 @@ object Test {
println(applied.eval)

applied match {
case c @ Constant(n) =>
case c as Constant(n) =>
println("test3 fail")
case a @ AppliedOp(op, x, y) =>
case a as AppliedOp(op, x, y) =>
println("test3 OK")
println(s"AppliedOp($op, $x, $y) = ${a.eval}")
}
Expand Down Expand Up @@ -304,7 +304,7 @@ object ListImplementation extends Arithmetic {
def opClassTag: ClassTag[Op] = new ClassTag[Constant] {
def runtimeClass: Class[_] = classOf[List[_]]
override def unapply(x: Any): Option[List[Any]] = x match {
case op @ (("+" | "*") :: Nil) =>
case op as (("+" | "*") :: Nil) =>
// Test that it is:
// type Op <: List[Any] // List(id: "+" | "*")
Some(op)
Expand Down
2 changes: 1 addition & 1 deletion tests/run/fully-abstract-nat-1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ object Test {
}

def divOpt(a: Nat, b: Nat): Option[(Nat, Nat)] = b match {
case s @ Succ(_) =>
case s as Succ(_) =>
// s is of type Nat though we know it is a Succ
Some(safeDiv(a, s.asInstanceOf[Succ]))
case _ => None
Expand Down
2 changes: 1 addition & 1 deletion tests/run/fully-abstract-nat-2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ object Test {
}

def divOpt(a: Nat, b: Nat): Option[(Nat, Nat)] = b match {
case s @ Succ(_) => Some(safeDiv(a, s))
case s as Succ(_) => Some(safeDiv(a, s))
case _ => None
}

Expand Down
Loading