[Scala 3] @inline def → inline def#871
Open
halotukozak wants to merge 5 commits into
Open
Conversation
…e Function/by-name params Sweep Scala 2 @inline def JVM-optimizer hints to Scala 3 mandatory inline def AST splice across the Opt family (Opt, NOpt, OptArg, OptRef), and mark Function-typed (A => B, (A, B) => C, PartialFunction) parameters as inline to eliminate Function* allocation at call sites. Final shape: - Methods with at least one Function-typed OR by-name parameter: `inline def` with inline-marked Function params. - By-name params (=> T) themselves remain unmarked — `=> T` already provides call-site substitution in Scala 3; `inline (x: => T)` is redundant. Where the by-name was used exactly once in a straight-line if/then/else body, it is reshaped to `(inline x: B)` so the expression is substituted literally (no Function0 thunk allocation). - Trivial accessors (isEmpty/isDefined/nonEmpty/get) kept as plain def to avoid -Xmax-inlines bailout in pattern-match desugaring (`case Opt(x) =>`). - @publicInBinary added on private constructors and referenced private members per Scala 3 inline-body access requirement. - OptArg.argToOptArg preserved as implicit def per slice 3.3 erasure-bridge rationale (untouched). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Convert jXxx / gXxx adapters that wrap Scala lambdas into Java
functional interfaces to inline def + inline Function param across:
- JFunctionUtils (38/38 inline def + 38/38 inline params; 5 zero-arg
Suppliers reverted via by-name → inline-value where applicable)
- Java8CollectionUtils (9/8)
- GuavaInterop (3/3 — see Future-override exception below)
- ScalaJStream / ScalaJIntStream / ScalaJLongStream / ScalaJDoubleStream
(23/23 + 16/16 ×3)
Eliminates Function* allocation at every jiop call site by splicing the
SAM-conversion at the use site rather than allocating a wrapper.
Future-override exception:
GuavaInterop.ListenableFutureAsScala.{onComplete, transform,
transformWith} are kept as plain def (no inline keyword on def OR
params). They override scala.concurrent.Future methods whose parent
signatures have non-inline params; Scala 3 forbids overriding a
non-inline param with an inline param.
Style:
- Drop trailing `; ()` coercion from Consumer SAM lambdas in
JFunctionUtils — Scala 3 SAM conversion of an Any-returning lambda
to a void-returning Java functional interface accepts the result
directly.
- scalafmt rewraps applied where post-inline insertion exceeded line
width.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Document slice 3.4 outcomes in MIGRATION.md §3: - @inline def → inline def conversion (Opt family + jiop adapters) - Function-typed/by-name parameter inlining - inline def is implicitly final (value-class scope mitigates) - Future-override exception in GuavaInterop (non-inline override constraint) - @publicInBinary applied on private members referenced from inline bodies Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
11ae468 to
deb43bf
Compare
… XOps wrappers Marks 49 inline def + 42 inline params across SharedExtensions XOps wrappers, matching fork shape (49/43). Applies on the pre-PR#868 form (class XOps extends AnyVal). The inline keywords will carry into the post-rebase extension blocks since method signatures are preserved by slice 3.1. Methods touched per Ops class: - UniversalOps: |>, applyIf, discard, thenReturn, setup, matchOpt, uncheckedMatch - LazyUniversalOps: evalFuture, evalTry, optIf, optionIf, recoverFrom, recoverToOpt - IntOps: times - FutureOps: onCompleteNow, andThenNow, foreachNow, transformNow (2), transformWithNow, mapNow, flatMapNow, filterNow, collectNow, recoverNow, recoverWithNow, zipWithNow (13 total; wrapToTry/toUnit/toVoid/thenReturn/ignoreFailures kept plain per fork) - OptionOps: forEmpty, mapOr - TryOps: tapFailure - PartialFunctionOps: unless, fold - IterableOnceOps: toMapBy, mkMap, groupToMap, findOpt, flatCollect, collectFirstOpt, reduceOpt, reduceLeftOpt, reduceRightOpt, maxOptBy, minOptBy, indexWhereOpt, asyncFoldLeft, asyncFoldRight, asyncForeach, partitionEither - FutureCompanionOps: eval NoValueMarker / NoValueMarkerFunc unprivatized (referenced from inline def fold body, matches fork). private def it dropped from IterableOnceOps in favor of inline coll.iterator (avoids @publicInBinary on private fwd).
… ObservableExtensions Marks inline def + inline Function/by-name params on AnyVal Ops wrappers in concurrent extensions: - TaskOps: lazyTimeout, tapL, tapErrorL - TaskCompanionOps: traverseOpt, traverseMap, traverseMapValues, usingNow - ObservableOps: findOptL, distinctBy, sortedByL, mkMapL No fork counterpart (these files don't exist on origin/master; project- local extensions). Inline marks applied per project-wide policy for Function-taking and by-name-taking forwarders.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rewrites Scala 2
@inline def(JVM optimizer hint) to Scala 3inline def(mandatory compile-time AST splice) across the Opt family AND function-taking ops elsewhere. Closure-eliminating perf win:inline def+inline (f: A => B)parameter usage dropsFunction1allocations at call sites.Scope
Opt family (initial sweep, fork
5fafdbd7)Opt,NOpt,OptArg,OptRef— all@inline def→inline def, with selected by-name params reshaped toinline x: Tfor one-use straight-line cases (getOrElse,orElse,fold(ifEmpty),mapOr(ifEmpty),toRight,toLeft,forEmpty). Trivial accessors (isEmpty/get/toOption/etc.) kept as plaindef—inline defwould re-trigger-Xmax-inlinesbailout on pattern-match desugaring sites.@publicInBinaryadded on private constructors +private[misc]members referenced from inline bodies (Scala 3 ABI requirement).Broader Function-param sweep (fork
a4ddad6b,580625a9,33a5b792,ad505679,ee0be95e)SharedExtensions.scala: 49inline def+ 42inlineparams (matches fork shape 49/43)concurrent/TaskExtensions.scala,concurrent/ObservableExtensions.scala: 11inline def+ 11inlineparamscore/jvm/jiop/{JFunctionUtils, GuavaInterop, Java8CollectionUtils}: closure-taking adapters inlinedcore/jvm/jiop/{ScalaJStream, ScalaJIntStream, ScalaJLongStream, ScalaJDoubleStream}: closure ops inlinedInline-scope rules applied
inline defonly when method has at least one Function-typed (A => B) OR by-name (=> T) param. Pure value-param methods stay plaindef.inlinekeyword stripped from by-name params (inline x: => T→x: => T) — redundant in Scala 3 (=> Talready enables call-site substitution).def(Scala 3 forbids overriding non-inline base method with inline).Whitelist (preserved verbatim — fork keeps these as
@inline)CborInput.scala:56(1 site — tight-loop parser hot path)JsonStringInput.scala(5 sites)RPCFramework.scala(2 sites — RPC dropped from scala-3 in fork)OptArg.argToOptArgpreservation honored per slice 3.3 rationale.Acceptance
git grep '@inline' core/src/main/scala/outside whitelist → 0 hits ✓sbt compile + Test/compile + scalafmtCheckAllgreen ✓@nowarn/-Wconfsuppressions ✓ (one verbatim fork carve-out:@nowarnoninline def discardin SharedExtensions)Source-compat impact
Scala 3
inline defis implicitlyfinal→ cannot be overridden. Downstream subclassers ofOpt/NOpt/OptArg/OptRefwould break, but targets are value classes (finalby construction) — zero impact in practice.SharedExtensionsextension blocks have no inheritance — safe.Translated from fork
origin/mastercommits5fafdbd7(Opt family),a4ddad6b(SharedExtensions),580625a9(JFunctionUtils),33a5b792/ad505679/ee0be95e(ScalaJ*Stream).Slice: 3.4 of Phase 3 (Scala 3 syntax modernization)
Merge order: 3.1 → 3.2 → 3.3 → 3.4
Depends on: #870 (slice 3.3 — must merge first)
Base branch: upstream/scala-3 (not stacked on prior slice)