Skip to content

Commit cba5c9a

Browse files
authored
Just warn on type ascription on a pattern (#17454)
Raise a warning instead of an error for a type ascription on a pattern other than a variable or a number literal. This partially reverts the changes from #16150. This change is motivated by not breaking source compatibility for a number of projects in the Open Community Build.
2 parents 75b0126 + 07c395b commit cba5c9a

File tree

12 files changed

+105
-14
lines changed

12 files changed

+105
-14
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

+12-1
Original file line numberDiff line numberDiff line change
@@ -2860,7 +2860,18 @@ object Parsers {
28602860
*/
28612861
def pattern1(location: Location = Location.InPattern): Tree =
28622862
val p = pattern2()
2863-
if (isVarPattern(p) || p.isInstanceOf[Number]) && in.isColon then
2863+
if in.isColon then
2864+
val isVariableOrNumber = isVarPattern(p) || p.isInstanceOf[Number]
2865+
if !isVariableOrNumber then
2866+
report.gradualErrorOrMigrationWarning(
2867+
em"""Type ascriptions after patterns other than:
2868+
| * variable pattern, e.g. `case x: String =>`
2869+
| * number literal pattern, e.g. `case 10.5: Double =>`
2870+
|are no longer supported. Remove the type ascription or move it to a separate variable pattern.""",
2871+
in.sourcePos(),
2872+
warnFrom = `3.3`,
2873+
errorFrom = future
2874+
)
28642875
in.nextToken()
28652876
ascription(p, location)
28662877
else p

compiler/test/dotty/tools/dotc/CompilationTests.scala

+1
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ class CompilationTests {
185185
compileFile("tests/neg-custom-args/i13026.scala", defaultOptions.and("-print-lines")),
186186
compileFile("tests/neg-custom-args/i13838.scala", defaultOptions.and("-Ximplicit-search-limit", "1000")),
187187
compileFile("tests/neg-custom-args/jdk-9-app.scala", defaultOptions.and("-release:8")),
188+
compileFile("tests/neg-custom-args/i10994.scala", defaultOptions.and("-source", "future")),
188189
).checkExpectedErrors()
189190
}
190191

docs/_docs/internals/syntax.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,8 @@ TypeCaseClause ::= ‘case’ (InfixType | ‘_’) ‘=>’ Type [semi]
315315
316316
Pattern ::= Pattern1 { ‘|’ Pattern1 } Alternative(pats)
317317
Pattern1 ::= PatVar ‘:’ RefinedType Bind(name, Typed(Ident(wildcard), tpe))
318-
| [‘-’] integerLiteral ‘:’ RefinedType Typed(pat, tpe)
319-
| [‘-’] floatingPointLiteral ‘:’ RefinedType Typed(pat, tpe)
318+
| [‘-’] integerLiteral ‘:’ RefinedType Typed(pat, tpe)
319+
| [‘-’] floatingPointLiteral ‘:’ RefinedType Typed(pat, tpe)
320320
| Pattern2
321321
Pattern2 ::= [id ‘@’] InfixPattern [‘*’] Bind(name, pat)
322322
InfixPattern ::= SimplePattern { id [nl] SimplePattern } InfixOp(pat, op, pat)

docs/_docs/reference/syntax.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,8 @@ TypeCaseClause ::= ‘case’ (InfixType | ‘_’) ‘=>’ Type [semi]
313313
314314
Pattern ::= Pattern1 { ‘|’ Pattern1 }
315315
Pattern1 ::= PatVar ‘:’ RefinedType
316-
| [‘-’] integerLiteral ‘:’ RefinedType
317-
| [‘-’] floatingPointLiteral ‘:’ RefinedType
316+
| [‘-’] integerLiteral ‘:’ RefinedType
317+
| [‘-’] floatingPointLiteral ‘:’ RefinedType
318318
| Pattern2
319319
Pattern2 ::= [id ‘@’] InfixPattern [‘*’]
320320
InfixPattern ::= SimplePattern { id [nl] SimplePattern }

tests/neg/i15893.scala renamed to tests/neg-custom-args/fatal-warnings/i15893.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ transparent inline def transparentInlineMod2(inline n: NatT): NatT = inline n m
2222
case Succ(Zero()) => Succ(Zero())
2323
case Succ(Succ(predPredN)) => transparentInlineMod2(predPredN)
2424

25-
def dependentlyTypedMod2[N <: NatT](n: N): Mod2[N] = n match // exhaustivity warning; unexpected
25+
def dependentlyTypedMod2[N <: NatT](n: N): Mod2[N] = n match
2626
case Zero(): Zero => Zero() // error
2727
case Succ(Zero()): Succ[Zero] => Succ(Zero()) // error
2828
case Succ(Succ(predPredN)): Succ[Succ[_]] => dependentlyTypedMod2(predPredN) // error
@@ -57,5 +57,5 @@ inline def transparentInlineFoo(inline n: NatT): NatT = inline transparentInline
5757
println(transparentInlineMod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected
5858
println(transparentInlineFoo(Succ(Succ(Succ(Zero()))))) // prints Zero(), as expected
5959
println(dependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // runtime error; unexpected
60-
// println(inlineDependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // doesn't compile; unexpected
61-
// println(transparentInlineDependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // doesn't compile; unexpected
60+
println(inlineDependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected
61+
println(transparentInlineDependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected

tests/neg-custom-args/i10994.check

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- Error: tests/neg-custom-args/i10994.scala:2:19 ----------------------------------------------------------------------
2+
2 | case (b: Boolean): Boolean => () // error
3+
| ^
4+
| Type ascriptions after patterns other than:
5+
| * variable pattern, e.g. `case x: String =>`
6+
| * number literal pattern, e.g. `case 10.5: Double =>`
7+
| are no longer supported. Remove the type ascription or move it to a separate variable pattern.

tests/neg-custom-args/i10994.scala

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def foo = true match
2+
case (b: Boolean): Boolean => () // error

tests/neg/t5702-neg-bad-and-wild.check

+10-3
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
| pattern expected
1111
|
1212
| longer explanation available when compiling with `-explain`
13-
-- [E040] Syntax Error: tests/neg/t5702-neg-bad-and-wild.scala:13:22 ---------------------------------------------------
13+
-- [E040] Syntax Error: tests/neg/t5702-neg-bad-and-wild.scala:13:23 ---------------------------------------------------
1414
13 | case List(1, _*3:) => // error // error
15-
| ^
16-
| ')' expected, but ':' found
15+
| ^
16+
| an identifier expected, but ')' found
1717
-- [E032] Syntax Error: tests/neg/t5702-neg-bad-and-wild.scala:15:18 ---------------------------------------------------
1818
15 | case List(x*, 1) => // error: pattern expected
1919
| ^
@@ -56,6 +56,13 @@
5656
| Recursive value $1$ needs type
5757
|
5858
| longer explanation available when compiling with `-explain`
59+
-- Warning: tests/neg/t5702-neg-bad-and-wild.scala:13:22 ---------------------------------------------------------------
60+
13 | case List(1, _*3:) => // error // error
61+
| ^
62+
| Type ascriptions after patterns other than:
63+
| * variable pattern, e.g. `case x: String =>`
64+
| * number literal pattern, e.g. `case 10.5: Double =>`
65+
| are no longer supported. Remove the type ascription or move it to a separate variable pattern.
5966
-- Warning: tests/neg/t5702-neg-bad-and-wild.scala:22:20 ---------------------------------------------------------------
6067
22 | val K(x @ _*) = k
6168
| ^

tests/pending/run/i15893.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ transparent inline def transparentInlineMod2(inline n: NatT): NatT = inline n m
2424
case Succ(Zero()) => Succ(Zero())
2525
case Succ(Succ(predPredN)) => transparentInlineMod2(predPredN)
2626
*/
27-
def dependentlyTypedMod2[N <: NatT](n: N): Mod2[N] = n match // exhaustivity warning; unexpected
27+
def dependentlyTypedMod2[N <: NatT](n: N): Mod2[N] = n match
2828
case Zero(): Zero => Zero()
2929
case Succ(Zero()): Succ[Zero] => Succ(Zero())
3030
case Succ(Succ(predPredN)): Succ[Succ[_]] => dependentlyTypedMod2(predPredN)
@@ -61,5 +61,5 @@ inline def transparentInlineFoo(inline n: NatT): NatT = inline transparentInline
6161
println(transparentInlineFoo(Succ(Succ(Succ(Zero()))))) // prints Zero(), as expected
6262
*/
6363
println(dependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // runtime error; unexpected
64-
// println(inlineDependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // doesn't compile; unexpected
65-
// println(transparentInlineDependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // doesn't compile; unexpected
64+
// println(inlineDependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected
65+
// println(transparentInlineDependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected

tests/pos/i10994.scala

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def foo = true match
2+
case (b: Boolean): Boolean => () // warning

tests/pos/i15893.scala

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
sealed trait NatT
2+
case class Zero() extends NatT
3+
case class Succ[+N <: NatT](n: N) extends NatT
4+
5+
type Mod2[N <: NatT] <: NatT = N match
6+
case Zero => Zero
7+
case Succ[Zero] => Succ[Zero]
8+
case Succ[Succ[predPredN]] => Mod2[predPredN]
9+
10+
def mod2(n: NatT): NatT = n match
11+
case Zero() => Zero()
12+
case Succ(Zero()) => Succ(Zero())
13+
case Succ(Succ(predPredN)) => mod2(predPredN)
14+
15+
inline def inlineMod2(inline n: NatT): NatT = inline n match
16+
case Zero() => Zero()
17+
case Succ(Zero()) => Succ(Zero())
18+
case Succ(Succ(predPredN)) => inlineMod2(predPredN)
19+
20+
transparent inline def transparentInlineMod2(inline n: NatT): NatT = inline n match
21+
case Zero() => Zero()
22+
case Succ(Zero()) => Succ(Zero())
23+
case Succ(Succ(predPredN)) => transparentInlineMod2(predPredN)
24+
25+
def dependentlyTypedMod2[N <: NatT](n: N): Mod2[N] = n match
26+
case Zero(): Zero => Zero() // warning
27+
case Succ(Zero()): Succ[Zero] => Succ(Zero()) // warning
28+
case Succ(Succ(predPredN)): Succ[Succ[_]] => dependentlyTypedMod2(predPredN) // warning
29+
30+
inline def inlineDependentlyTypedMod2[N <: NatT](inline n: N): Mod2[N] = inline n match
31+
case Zero(): Zero => Zero() // warning
32+
case Succ(Zero()): Succ[Zero] => Succ(Zero()) // warning
33+
case Succ(Succ(predPredN)): Succ[Succ[_]] => inlineDependentlyTypedMod2(predPredN) // warning
34+
35+
transparent inline def transparentInlineDependentlyTypedMod2[N <: NatT](inline n: N): Mod2[N] = inline n match
36+
case Zero(): Zero => Zero() // warning
37+
case Succ(Zero()): Succ[Zero] => Succ(Zero()) // warning
38+
case Succ(Succ(predPredN)): Succ[Succ[_]] => transparentInlineDependentlyTypedMod2(predPredN) // warning
39+
40+
def foo(n: NatT): NatT = mod2(n) match
41+
case Succ(Zero()) => Zero()
42+
case _ => n
43+
44+
inline def inlineFoo(inline n: NatT): NatT = inline inlineMod2(n) match
45+
case Succ(Zero()) => Zero()
46+
case _ => n
47+
48+
inline def transparentInlineFoo(inline n: NatT): NatT = inline transparentInlineMod2(n) match
49+
case Succ(Zero()) => Zero()
50+
case _ => n
51+
52+
@main def main(): Unit =
53+
println(mod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected
54+
println(foo(Succ(Succ(Succ(Zero()))))) // prints Zero(), as expected
55+
println(inlineMod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected
56+
println(inlineFoo(Succ(Succ(Succ(Zero()))))) // prints Succ(Succ(Succ(Zero()))); unexpected
57+
println(transparentInlineMod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected
58+
println(transparentInlineFoo(Succ(Succ(Succ(Zero()))))) // prints Zero(), as expected
59+
println(dependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // runtime error; unexpected
60+
println(inlineDependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected
61+
println(transparentInlineDependentlyTypedMod2(Succ(Succ(Succ(Zero()))))) // prints Succ(Zero()), as expected

0 commit comments

Comments
 (0)