From e668fd7eaf93a81d0409728664a0f2bda4a63761 Mon Sep 17 00:00:00 2001 From: Enno Runne Date: Wed, 15 Feb 2017 23:44:13 +0100 Subject: Change 'mixed left- and right-associative operators' to Message --- .../src/dotty/tools/dotc/parsing/Parsers.scala | 15 +++++----- .../tools/dotc/reporting/diagnostic/messages.scala | 33 ++++++++++++++++++++++ 2 files changed, 40 insertions(+), 8 deletions(-) (limited to 'compiler/src') diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 45ae842b6..8f146e920 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -404,14 +404,13 @@ object Parsers { var opStack: List[OpInfo] = Nil - def checkAssoc(offset: Int, op: Name, leftAssoc: Boolean) = + def checkAssoc(offset: Int, op: Name, leftAssoc: Boolean, op2: Name) = if (isLeftAssoc(op) != leftAssoc) - syntaxError( - "left- and right-associative operators with same precedence may not be mixed", offset) + syntaxError(MixedLeftAndRightAssociativeOps(op, op2, leftAssoc), offset) - def reduceStack(base: List[OpInfo], top: Tree, prec: Int, leftAssoc: Boolean): Tree = { + def reduceStack(base: List[OpInfo], top: Tree, prec: Int, leftAssoc: Boolean, op2: Name): Tree = { if (opStack != base && precedence(opStack.head.operator.name) == prec) - checkAssoc(opStack.head.offset, opStack.head.operator.name, leftAssoc) + checkAssoc(opStack.head.offset, opStack.head.operator.name, leftAssoc, op2) def recur(top: Tree): Tree = { if (opStack == base) top else { @@ -445,20 +444,20 @@ object Parsers { var top = first while (isIdent && in.name != notAnOperator) { val op = if (isType) typeIdent() else termIdent() - top = reduceStack(base, top, precedence(op.name), isLeftAssoc(op.name)) + top = reduceStack(base, top, precedence(op.name), isLeftAssoc(op.name), op.name) opStack = OpInfo(top, op, in.offset) :: opStack newLineOptWhenFollowing(canStartOperand) if (maybePostfix && !canStartOperand(in.token)) { val topInfo = opStack.head opStack = opStack.tail - val od = reduceStack(base, topInfo.operand, 0, true) + val od = reduceStack(base, topInfo.operand, 0, true, in.name) return atPos(startOffset(od), topInfo.offset) { PostfixOp(od, topInfo.operator) } } top = operand() } - reduceStack(base, top, 0, true) + reduceStack(base, top, 0, true, in.name) } /* -------- IDENTIFIERS AND LITERALS ------------------------------------------- */ diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 3ca780419..f8222ce92 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1093,4 +1093,37 @@ object messages { |""".stripMargin } + case class MixedLeftAndRightAssociativeOps(op1: Name, op2: Name, op2LeftAssoc: Boolean)(implicit ctx: Context) + extends Message(41) { + val kind = "Syntax" + val op1Asso = if (op2LeftAssoc) "which is right-associative" else "which is left-associative" + val op2Asso = if (op2LeftAssoc) "which is left-associative" else "which is right-associative" + val msg = s"${hl"`${op1}`"} (${op1Asso}) and ${hl"`${op2}`"} ($op2Asso) have same precedence and may not be mixed" + val explanation = + s"""|The operators ${hl"${op1}"} and ${hl"${op2}"} are used as infix operators in the same expression, + |but they bind to different sides: + |${hl"${op1}"} is applied to the operand to its ${if (op2LeftAssoc) "right" else "left"} + |${hl"${op2}"} is applied to the operand to its ${if (op2LeftAssoc) "left" else "right"} + |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 ${hl"`operand1.${op1}(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: + | (all letters) + | | + | ^ + | & + | = ! + | < > + | : + | + - + | * / % + | (all other special characters) + |Operators starting with a letter have lowest precedence, followed by operators starting with `|', etc. + |""".stripMargin + } + } -- cgit v1.2.3