diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index db87d2f45faa..9db4aea7c024 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1365,26 +1365,12 @@ class Typer extends Namer case _ => false } - val result = pt match { + pt match { case MatchTypeInDisguise(mt) if isMatchTypeShaped(mt) => typedDependentMatchFinish(tree, sel1, selType, tree.cases, mt) case _ => typedMatchFinish(tree, sel1, selType, tree.cases, pt) } - - result match { - case Match(sel, CaseDef(pat, _, _) :: _) => - tree.selector.removeAttachment(desugar.CheckIrrefutable) match { - case Some(checkMode) => - val isPatDef = checkMode == desugar.MatchCheck.IrrefutablePatDef - if (!checkIrrefutable(pat, sel.tpe, isPatDef) && sourceVersion == `3.1-migration`) - if (isPatDef) patch(Span(pat.span.end), ": @unchecked") - else patch(Span(pat.span.start), "case ") - case _ => - } - case _ => - } - result } /** Special typing of Match tree when the expected type is a MatchType, diff --git a/docs/docs/reference/changed-features/pattern-bindings.md b/docs/docs/reference/changed-features/pattern-bindings.md index 65c170717b47..632964d644aa 100644 --- a/docs/docs/reference/changed-features/pattern-bindings.md +++ b/docs/docs/reference/changed-features/pattern-bindings.md @@ -3,47 +3,17 @@ layout: doc-page title: "Pattern Bindings" --- -In Scala 2, pattern bindings in `val` definitions and `for` expressions are -loosely typed. Potentially failing matches are still accepted at compile-time, -but may influence the program's runtime behavior. -From Scala 3.1 on, type checking rules will be tightened so that errors are reported at compile-time instead. +In Scala 3 pattern definitions can carry ascriptions such as `: @unchecked`, and `for` expressions can prefix `case` when filter. -## Bindings in Pattern Definitions - -```scala -val xs: List[Any] = List(1, 2, 3) -val (x: String) :: _ = xs // error: pattern's type String is more specialized - // than the right hand side expression's type Any -``` -This code gives a compile-time error in Scala 3.1 (and also in Scala 3.0 under the `-source 3.1` setting) whereas it will fail at runtime with a `ClassCastException` in Scala 2. In Scala 3.1, a pattern binding is only allowed if the pattern is _irrefutable_, that is, if the right-hand side's type conforms to the pattern's type. For instance, the following is OK: -```scala - val pair = (1, true) - val (x, y) = pair -``` -Sometimes one wants to decompose data anyway, even though the pattern is refutable. For instance, if at some point one knows that a list `elems` is non-empty one might -want to decompose it like this: -```scala -val first :: rest = elems // error -``` -This works in Scala 2. In fact it is a typical use case for Scala 2's rules. But in Scala 3.1 it will give a type error. One can avoid the error by marking the pattern with an `@unchecked` annotation: -```scala -val first :: rest : @unchecked = elems // OK -``` -This will make the compiler accept the pattern binding. It might give an error at runtime instead, if the underlying assumption that `elems` can never be empty is wrong. +## Pattern Definitions Ascriptions +Pattern definitions can have ascriptions at the end of them. +`val first :: rest : @unchecked = elems` ## Pattern Bindings in `for` Expressions -Analogous changes apply to patterns in `for` expressions. For instance: - -```scala -val elems: List[Any] = List((1, 2), "hello", (3, 4)) -for ((x, y) <- elems) yield (y, x) // error: pattern's type (Any, Any) is more specialized - // than the right hand side expression's type Any -``` -This code gives a compile-time error in Scala 3.1 whereas in Scala 2 the list `elems` -is filtered to retain only the elements of tuple type that match the pattern `(x, y)`. The filtering functionality can be obtained in Scala 3 by prefixing the pattern with `case`: ```scala + val elems: List[Any] = List((1, 2), "hello", (3, 4)) for (case (x, y) <- elems) yield (y, x) // returns List((2, 1), (4, 3)) ``` @@ -55,7 +25,3 @@ PatDef ::= ids [‘:’ Type] ‘=’ Expr | Pattern2 [‘:’ Type | Ascription] ‘=’ Expr Generator ::= [‘case’] Pattern1 ‘<-’ Expr ``` - -## Migration - -The new syntax is supported in Dotty and Scala 3.0. However, to enable smooth cross compilation between Scala 2 and Scala 3, the changed behavior and additional type checks are only enabled under the `-source 3.1` setting. They will be enabled by default in version 3.1 of the language. diff --git a/tests/neg-strict/filtering-fors.scala b/tests/neg-strict/filtering-fors.scala deleted file mode 100644 index 784e354c53ff..000000000000 --- a/tests/neg-strict/filtering-fors.scala +++ /dev/null @@ -1,32 +0,0 @@ -object Test { - - val xs: List[Any] = ??? - - for (x <- xs) do () // OK - for (x: Any <- xs) do () // OK - - for (x: String <- xs) do () // error - for ((x: String) <- xs) do () // error - for (y@ (x: String) <- xs) do () // error - for ((x, y) <- xs) do () // error - - for ((x: String) <- xs if x.isEmpty) do () // error - for ((x: String) <- xs; y = x) do () // error - for ((x: String) <- xs; (y, z) <- xs) do () // error // error - for (case (x: String) <- xs; (y, z) <- xs) do () // error - for ((x: String) <- xs; case (y, z) <- xs) do () // error - - val pairs: List[Any] = List((1, 2), "hello", (3, 4)) - for ((x, y) <- pairs) yield (y, x) // error - - for (case x: String <- xs) do () // OK - for (case (x: String) <- xs) do () // OK - for (case y@ (x: String) <- xs) do () // OK - for (case (x, y) <- xs) do () // OK - - for (case (x: String) <- xs if x.isEmpty) do () // OK - for (case (x: String) <- xs; y = x) do () // OK - for (case (x: String) <- xs; case (y, z) <- xs) do () // OK - - for (case (x, y) <- pairs) yield (y, x) // OK -} \ No newline at end of file diff --git a/tests/neg-strict/unchecked-patterns.scala b/tests/neg-strict/unchecked-patterns.scala deleted file mode 100644 index 8cf797e88029..000000000000 --- a/tests/neg-strict/unchecked-patterns.scala +++ /dev/null @@ -1,25 +0,0 @@ -object Test { - - val (y1: Some[Int] @unchecked) = Some(1): Option[Int] // OK - val y2: Some[Int] @unchecked = Some(1): Option[Int] // error - - val x :: xs = List(1, 2, 3) // error - val (1, c) = (1, 2) // error - val 1 *: cs = 1 *: Tuple() // error - - val (_: Int | _: Any) = ??? : Any // error - - val 1 = 2 // error - - object Positive { def unapply(i: Int): Option[Int] = Some(i).filter(_ > 0) } - object Always1 { def unapply(i: Int): Some[Int] = Some(i) } - object Pair { def unapply(t: (Int, Int)): t.type = t } - object Triple { def unapply(t: (Int, Int, Int)): (Int, Int, Int) = t } - - val Positive(p) = 5 // error - val Some(s1) = Option(1) // error - val Some(s2) = Some(1) // OK - val Always1(p1) = 5 // OK - val Pair(t1, t2) = (5, 5) // OK - val Triple(u1, u2, u3) = (5, 5, 5) // OK -} \ No newline at end of file