Right-associative infix operations and match expression precedence surprise

It seems that a match expression does not have precedence to the right of a right-associative operation (checked it both in Scala 2 and 3):

sealed trait Dir
case object Left extends Dir
case object Right extends Dir

implicit class Ext(arg: Int) {
  def := (arg2: Int): Unit = ???
}

object Test {
  val dir: Dir = ???
  val x: Int = ???
  
  x := dir match { //error
    case Left => 2
    case Right => 4
  }
}

So the compiler does (x := dir) match ... instead of x := (dir match ...).
I’m not an expert in understanding the parser spec. Is this the expected behavior? I found it incredibly surprising.

Isn’t := left-associative ?
And =: would be right-associative

Yes, I made several tests. Pasted the wrong example. For right associative it’s a different error, but still an error.

In any case, even without right-associativity, assignment operators should have the lowest priority nonetheless, no? How can match have a lower priority to an assignment?

https://www.scala-lang.org/files/archive/spec/2.13/06-expressions.html

Expr1        ::=  
               ...
               |  [SimpleExpr ‘.’] id ‘=’ Expr
               |  PostfixExpr
               |  PostfixExpr ‘match’ ‘{’ CaseClauses ‘}’ // more specific
PostfixExpr  ::=  InfixExpr ...
InfixExpr    ::=  PrefixExpr
               |  InfixExpr id [nl] InfixExpr // a op b

From this it seems the regular assignment = has a slightly higher priority than the match (both are Expr1, but the assignment comes before), but this is not the case of infix expressions (InfixExpr), even if the operator contains the = symbol (because it simply isn’t checked)

This is the motivation for dotted match

scala> 1 + 2.match { case i => i * 2 }
val res0: Int = 5

though match is not an operator or member.

In Scala 2 the left operand is postfix:

scala> "hello" length match { case i => i * 2 }
val res0: Int = 10

Yeah, I figured out there could be working code that cannot allow changing the precedence.

However, I am considering creating a SIP to allow an if after an infix operator. It cirrently fails to compile and ai see no reason why not to allow it.

There is a suspended PR for indented infix operand.

My first reaction was that it is quite baroque (and I love baroque), but since I’ve learned a bit more about indentation (and used it more), I think it will be a feature that in retrospect we could never do without.

It’s not the same SIP. What you referenced still required an indentation before the if and did other stuff. I just want to wite something like val x = 1 + if cond then 2 else 3.

does not parse for me. I don’t know what SIP we’re discussing.

val x = 1 + if cond then 2 else 3

but it’s not commutative

val x = if cond then 2 else 3 + 1

clearly doesn’t parse because 3 + 1.

Does that matter?

Maybe just the right-hand operand can be an Expr1, which works for if but not for while.

Maybe the right hand can be just certain Expr1 such as if, certain for, inline match, postfix, things that produce a value.