E041: Mixed Left And Right Associative Ops

This error is emitted when operators with different associativity (left vs right) but the same precedence are used together in an expression without parentheses.

In Scala, operators ending in a colon (:) are right-associative. All other operators are left-associative. When two operators have the same precedence but different associativity, the compiler cannot determine the evaluation order.

Infix operator precedence is determined by the operator's first character. Characters are listed below in increasing order of precedence:

  • (all letters)
  • |
  • ^
  • &
  • = !
  • < >
  • :
  • + -
  • * / %
  • (all other special characters)

Example

extension (x: Int)
  def +: (y: Int): Int = x + y
  def +* (y: Int): Int = x * y

def example = 1 +: 2 +* 3

Error

-- [E041] Syntax Error: example.scala:5:19 -------------------------------------
5 |def example = 1 +: 2 +* 3
  |                   ^
  |+: (which is right-associative) and +* (which is left-associative) have same precedence and may not be mixed
  |-----------------------------------------------------------------------------
  | Explanation (enabled by `-explain`)
  |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  | The operators +: and +* are used as infix operators in the same expression,
  | but they bind to different sides:
  | +: is applied to the operand to its right
  | +* is applied to the operand to its left
  | As both have the same precedence the compiler can't decide which to apply first.
  |
  | You may use parenthesis to make the application order explicit,
  | or use method application syntax operand1.+:(operand2).
  |
  | Operators ending in a colon : are right-associative. All other operators are left-associative.
  |
  | Infix operator precedence is determined by the operator's first character. Characters are listed
  | below in increasing order of precedence, with characters on the same line having the same precedence.
  |   (all letters)
  |   |
  |   ^
  |   &
  |   = !
  |   < >
  |   :
  |   + -
  |   * / %
  |   (all other special characters)
  | Operators starting with a letter have lowest precedence, followed by operators starting with `|`, etc.
   -----------------------------------------------------------------------------

Solution

// Use parentheses to make the order explicit
extension (x: Int)
  def +: (y: Int): Int = x + y
  def +* (y: Int): Int = x * y

def example = (1 +: 2) +* 3
// Or use method call syntax
extension (x: Int)
  def +: (y: Int): Int = x + y
  def +* (y: Int): Int = x * y

def example = (1.+:(2)).+*(3)