aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorEnno Runne <enno.runne@baymarkets.com>2017-02-15 23:44:13 +0100
committerFelix Mulder <felix.mulder@gmail.com>2017-02-20 16:50:09 +0100
commite668fd7eaf93a81d0409728664a0f2bda4a63761 (patch)
tree521337bc3c7e2fe6117f8635d62217b624898271 /compiler/src/dotty/tools/dotc
parentf76ffe97f9460cc04e159ce5b2c0b83d63fb940c (diff)
downloaddotty-e668fd7eaf93a81d0409728664a0f2bda4a63761.tar.gz
dotty-e668fd7eaf93a81d0409728664a0f2bda4a63761.tar.bz2
dotty-e668fd7eaf93a81d0409728664a0f2bda4a63761.zip
Change 'mixed left- and right-associative operators' to Message
Diffstat (limited to 'compiler/src/dotty/tools/dotc')
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Parsers.scala15
-rw-r--r--compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala33
2 files changed, 40 insertions, 8 deletions
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
+ }
+
}