The bug is that when -rewrite -source 3.4-migration is used, code like case _: Foo with Bar is rewritten to case _: Foo & Bar which, surprisingly, doesn’t parse. It needs to be written case _: (Foo & Bar) instead. The proposed fix in that ticket is to have it generate the version with the parens. But is that really the best fix? Why can’t we just accept the version without parens?
I suspect the reason is that & and | are treated the same by the parser, and case _: Foo | Bar is ambiguous. It could be parsed as case (_: Foo) | Bar (and in fact it is), or as case _: (Foo | Bar). But this ambiguity doesn’t exist for &, so that case is unambiguous afaics and we could just allow it.
I’m not convinced that this has anything to do with operator precedence. The error message doesn’t fit:
scala> ((): Any) match { case x: Int & String => 0 }
-- [E040] Syntax Error: --------------------------------------------------------
1 |((): Any) match { case x: Int & String => 0 }
| ^
| '=>' expected, but identifier found
That’s a parser error, not an operator precedence thing. In fact, we can simulate what the error message would look like if this was related to operator precedence by spelling out the parens that would be inferred based on operator precedence, i. e. case (x: Int) & String. If we do that, we still get an error, but not a parser error:
scala> ((): Any) match { case (x: Int) & String => 0 }
-- [E189] Not Found Error: -----------------------------------------------------
1 |((): Any) match { case (x: Int) & String => 0 }
| ^
| no pattern match extractor named & was found
|
| longer explanation available when compiling with `-explain`
-- [E119] Type Error: ----------------------------------------------------------
1 |((): Any) match { case (x: Int) & String => 0 }
| ^^^^^^
| Java defined class String is not a value
2 errors found
Actually, reading that code carefully, it says firstCh match. So this isn’t about : itself, it’s about operators like :\ or :+ or ::. It’s entirely irrelevant for :, as can be seen for example in expressions like ??? : Int & String. That is parsed as ??? : (Int & String), not (??? : Int) & String.
In fact, it never occurred to me to think of : as an infix operator at all. An infix operator is something that sits between two alike things, like two expressions or two types or two patterns. That’s not the case for :.
scala> type X[A, B]
scala> def x: Int X String = ???
1 warning found
-- Warning: --------------------------------------------------------------------
1 |def x: Int X String = ???
| ^
|Alphanumeric type X is not declared infix; it should not be used as infix operator.
|Instead, use prefix syntax X[...] or backticked identifier `X`.
def x: X[Int, String]
scala> def f(x: Any) = x match { case y: Int X String => }
-- [E040] Syntax Error: --------------------------------------------------------
1 |def f(x: Any) = x match { case y: Int X String => }
| ^
| '=>' expected, but identifier found