Standard Operator Precedence Changed

ID

swift.standard_operator_precedence_changed

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Swift

Tags

reliability, suspicious-code

Description

Reports a declaration that changes the precedence or associativity of an operator the Swift standard library already defines. Two shapes do that: an infix operator declaration that re-declares a standard operator under a different precedence group, and a precedencegroup declaration that re-declares one of the standard library’s own groups.

Rationale

infix operator + : MultiplicationPrecedence

precedencegroup AdditionPrecedence {
    associativity: right
    higherThan: MultiplicationPrecedence
}

Precedence and associativity are what let a reader parse an expression without looking anything up: a + b * c means a + (b * c) in every Swift file ever written, and a - b - c means (a - b) - c. Moving a standard operator to another precedence group re-parses every existing use of it in the module — silently, with not one call site changed. Code that was correct yesterday now computes something else, and a reviewer looking at the call site has no reason to suspect the grouping is not the one everybody knows.

Re-declaring a standard precedence group does the same thing to every operator that group holds at once, and switching its associativity from left to right changes the meaning of every chained subtraction and division in the module.

The damage is invisible in review because the diff that causes it is one line, far from any of the expressions it changes.

Notes

Legitimate operator work never fires:

  • Declaring a genuinely new operator is correct Swift and is not reported. That is exactly how a custom operator is introduced, and it changes nothing about the existing ones. Only an operator name the standard library already defines is a candidate.

  • Re-declaring a standard operator under its own standard group is not reported either. It is redundant, but it moves nothing and breaks nothing.

  • Declaring a new precedence group is not reported, however it relates itself to the standard ones — higherThan / lowerThan on a new group orders the new group; it does not reorder the standard operators.

  • prefix and postfix declarations are out of scope. Swift gives prefix and postfix operators neither a precedence group nor an associativity, so no such declaration can change either one.

An infix operator declaration with no group clause is not reported either, and for the same reason as re-declaring an operator under its own group: a bare infix operator < written above a file’s own overload of < names no destination group, so there is no move for a reader of a call site to be caught out by. The default group a groupless declaration lands in applies to an operator being introduced, and one the standard library already defines is not being introduced.

Remediation

To add behaviour for a standard operator on your own type, implement the operator — do not re-declare it. The declaration already exists in the standard library, and the implementation inherits its precedence:

struct Vector {
    let x: Double
    let y: Double
}

extension Vector {
    static func + (lhs: Vector, rhs: Vector) -> Vector {
        return Vector(x: lhs.x + rhs.x, y: lhs.y + rhs.y)
    }
}

When you genuinely need different grouping, introduce a new operator and a new precedence group. Nothing that already exists changes meaning:

precedencegroup ExponentiationPrecedence {
    associativity: right
    higherThan: MultiplicationPrecedence
}

infix operator ** : ExponentiationPrecedence

© 2026 Xygeni. All rights reserved