Skip to content

Replace *Ops conversions by direct extension methods - #26637

Open
halotukozak wants to merge 12 commits into
scala:mainfrom
halotukozak:deprecate-ops-extension-methods
Open

Replace *Ops conversions by direct extension methods#26637
halotukozak wants to merge 12 commits into
scala:mainfrom
halotukozak:deprecate-ops-extension-methods

Conversation

@halotukozak

Copy link
Copy Markdown
Contributor

Similar to #23872

there is a one design question: should the extension methods be on the top-level or in the type class?

I've chosen the second one, but I don't have a strong opinion.

Current draft doesn't break binary compatibility, but it does break the source one (only if someone extends the TC and it's not a problem in minor release, isn't it?).
Inner extension methods in several instances bring the method name clash (they have to be marked with @targetName) but they allow to omit all the redundant bridges like this:

extension [T: Ops as ops](t: T)
  def meth = ops.meth(t)

Also, with top-level extensions, there is a problem with overloading (e.g. math.max vs math.max for Ordering)

library-js has its own copy of NumericRange.scala that overrides the
one in library/src for Scala.js builds. It still relied on
`import num.mkNumericOps` as an implicit conversion to get `-`/`/` on
T, which broke once mkNumericOps was deprecated and un-implicited.
Mirrors the same fix already applied to library/src/.../NumericRange.scala.
It implements Numeric[A] overriding toInt/toLong/toFloat/toDouble as
regular methods, which no longer compile now that these are abstract
extension methods on scala.math.Numeric. This is upstream Scala.js
test-suite code fetched at build time, so it can't be fixed in place;
excluded following the existing pattern for other Scala 3 incompatibilities
in this list.
…mericOps

The macro spliced \$x * \$x relying on the implicit conversion from
Numeric.Implicits.infixNumericOps to provide \`*\` on the generic Num
type parameter. That no longer resolves now that Numeric's toInt/toLong/
toFloat/toDouble/abs are extension methods. Call num.times(...) directly
instead, which is unambiguous and was always the semantic behind \`*\`.
withGiven's context-function-introduced instance wasn't picked up by
extension method resolution for Numeric's * (which was the actual cause
of the earlier "value * is not a member of Num" failure, not the
deprecated infixNumericOps per se). Introducing the Numeric[Num]
instance with a real `given` inside the quote fixes resolution, so the
macro can go back to using * instead of calling num.times explicitly,
and withGiven can be dropped entirely.
….type

The original withGiven[U, T](inline x: T)(inline body: T ?=> U) widened
the given to its nominal type T, which extension method resolution for
* didn't pick up. Using x.type instead of a generic T ties the context
function's given to the precise singleton type of the argument, which
resolves correctly. inline had to be dropped from the x parameter since
x.type requires a stable (non-inline) path.
@tgodzik tgodzik added the needs-slc This change needs to go through the Standard Library Changes (SLC) process. label Aug 12, 2026
The *Ops conversions (mkOrderingOps, mkNumericOps, infixOrderingOps, etc.)
stay deprecated-but-non-implicit, so code needs to reach the new extension
methods directly instead of falling back to the old implicit conversions.
Updates checkfiles and test imports accordingly:

- if-parse.scala: import the Ordering givens directly since the deprecated
  infixOrderingOps is no longer implicit.
- more-specific.scala: accept the new [E008] extension-method diagnostic
  in place of the old [E007] implicit-conversion-rejection message; the
  restriction it guards (conversions must be more specific than AnyRef)
  still holds, just surfaced through a different code path.
- transparent-inline-i12754-message.check: drop the now-invalid
  infixOrderingOps import suggestion.
- i17371.scala: import the specific extension methods (ordA.>, ordB.<)
  instead of the no-op `import x.given` on a plain value, and drop the
  redundant `turns`/`circular` given-imports (they're already in scope
  via the using clause).
- missing-implicit.scala: -/+/* on a Numeric-bounded T no longer need an
  explicit import, so only the > comparison still errors.
@halotukozak
halotukozak force-pushed the deprecate-ops-extension-methods branch from 18f0722 to ddf4fbb Compare August 13, 2026 09:00
@halotukozak
halotukozak marked this pull request as ready for review August 13, 2026 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-slc This change needs to go through the Standard Library Changes (SLC) process.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants