Skip to content

perf: drop unneeded inline from TupleOps / containsOnly - #55

Merged
halotukozak merged 3 commits into
mainfrom
perf/toarrayof-not-inline
Sep 4, 2026
Merged

perf: drop unneeded inline from TupleOps / containsOnly#55
halotukozak merged 3 commits into
mainfrom
perf/toarrayof-not-inline

Conversation

@halotukozak

@halotukozak halotukozak commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

None of foreach, indices, mapAs, toArrayOf, to or realCons need to be inline for their own logic — they were only inline because they take an inline containsOnly evidence parameter, and Scala requires the enclosing def to be inline to accept an inline parameter. That evidence is a compile-time-only proof with zero runtime component, but forcing the whole method inline duplicates its entire body into every call site's bytecode. For toArrayOf that's an array-building loop, copied once per derivation call site in downstream inline-heavy macro consumers — discovered via mcodec, where it inflated compile-sweep bytecode by 27% (4,986 KB → 6,330 KB at N=100 derived codecs) for a 1.5% compile-time win.

Fix: drop inline from all of these — the containsOnly evidence still gets discharged as a normal (non-inline) using parameter at each call site, and the method bodies become ordinary shared code instead of per-call-site copies.

Same treatment in containsOnly.scala: the derived givens (Tuple.Tail, Tuple.Reverse, Tuple.Concat, Tuple.Zip, the Tuple.Map-constant-map ones, the low-priority fallback) don't need to be inline given either — refl is a plain shared value, not something that needs re-derivation per call site. They're rewritten using the Of[T] context-bound shorthand for readability. The Tuple.Head/Tuple.Last Conversion givens became <:< givens instead — same identity-cast trick, but expressed as evidence discharged at the use site rather than an implicit conversion function that has to exist as a value.

Verified downstream

  • commons test suite: all green (including ToArrayOfTest, ToTest, ContainsOnlyTest, MapAsTest)
  • made (macro library built on commons): compiles and tests clean against this branch
  • mcodec (macro-heavy derivation library, the actual bytecode regression site): 186/186 tests green; compile-sweep bytecode at N=100 derived codecs dropped 9,105 KB → 2,900 KB end to end (most of that from made 0.6.0's own unrelated rework, but this fix alone recovered a 6,330 KB regression down to below the pre-regression baseline)

Test plan

  • scala-cli test . — all green
  • Downstream (made, mcodec) verified against a local publish of this branch
  • CI

🤖 Generated with Claude Code

Copilot AI lite review requested due to automatic review settings September 4, 2026 12:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added the needs-major Binary-incompatible change — needs a major version bump label Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

⚠️ MiMa: binary incompatibility vs main@b05a43b

This PR breaks binary compatibility — it will need a major version bump.

Details
[mima] backward (code built against the release vs the new JAR): 5 problem(s)
  - static method given_Conversion_Head_T(halotukozak.commons.containsOnly)scala.Conversion in interface halotukozak.commons.containsOnly does not have a correspondent in current version
  - static method given_Conversion_Last_T(halotukozak.commons.containsOnly)scala.Conversion in interface halotukozak.commons.containsOnly does not have a correspondent in current version
  - static method <clinit>()Unit in object halotukozak.commons.containsOnly does not have a correspondent in current version
  - method given_Conversion_Head_T(halotukozak.commons.containsOnly)scala.Conversion in object halotukozak.commons.containsOnly does not have a correspondent in current version
  - method given_Conversion_Last_T(halotukozak.commons.containsOnly)scala.Conversion in object halotukozak.commons.containsOnly does not have a correspondent in current version
[mima] forward  (new API vs the release — expected to list additions): 34 problem(s)
  - static method foreach(scala.Product,scala.Function1)Unit in class halotukozak.commons.TupleOps#package does not have a correspondent in current version
  - static method indices(scala.Product)scala.Product in class halotukozak.commons.TupleOps#package does not have a correspondent in current version
  - static method mapAs(scala.Product,halotukozak.commons.containsOnly,scala.Function1)scala.Product in class halotukozak.commons.TupleOps#package does not have a correspondent in current version
  - static method realCons(java.lang.Object,scala.Product)scala.Product in class halotukozak.commons.TupleOps#package does not have a correspondent in current version
  - static method to(scala.Product,halotukozak.commons.containsOnly,scala.collection.Factory)java.lang.Object in class halotukozak.commons.TupleOps#package does not have a correspondent in current version
  - static method toArrayOf(scala.Product,halotukozak.commons.containsOnly,scala.reflect.ClassTag)java.lang.Object in class halotukozak.commons.TupleOps#package does not have a correspondent in current version
  - method foreach(scala.Product,scala.Function1)Unit in object halotukozak.commons.TupleOps#package does not have a correspondent in current version
  - method indices(scala.Product)scala.Product in object halotukozak.commons.TupleOps#package does not have a correspondent in current version
  - method mapAs(scala.Product,halotukozak.commons.containsOnly,scala.Function1)scala.Product in object halotukozak.commons.TupleOps#package does not have a correspondent in current version
  - method toArrayOf(scala.Product,halotukozak.commons.containsOnly,scala.reflect.ClassTag)java.lang.Object in object halotukozak.commons.TupleOps#package does not have a correspondent in current version
  - method to(scala.Product,halotukozak.commons.containsOnly,scala.collection.Factory)java.lang.Object in object halotukozak.commons.TupleOps#package does not have a correspondent in current version
  - method realCons(java.lang.Object,scala.Product)scala.Product in object halotukozak.commons.TupleOps#package does not have a correspondent in current version
  - static method given_<:<_Head_T(halotukozak.commons.containsOnly)scala.<:< in interface halotukozak.commons.containsOnly does not have a correspondent in current version
  - static method given_<:<_Last_T(halotukozak.commons.containsOnly)scala.<:< in interface halotukozak.commons.containsOnly does not have a correspondent in current version
  - static method given_containsOnly_Concat_T(halotukozak.commons.containsOnly,halotukozak.commons.containsOnly)halotukozak.commons.containsOnly in interface halotukozak.commons.containsOnly does not have a correspondent in current version
  - static method given_containsOnly_Map_C()halotukozak.commons.containsOnly in interface halotukozak.commons.containsOnly does not have a correspondent in current version
  - static method given_containsOnly_Map_F()halotukozak.commons.containsOnly in interface halotukozak.commons.containsOnly does not have a correspondent in current version
  - static method given_containsOnly_Reverse_T(halotukozak.commons.containsOnly)halotukozak.commons.containsOnly in interface halotukozak.commons.containsOnly does not have a correspondent in current version
  - static method given_containsOnly_Tail_T(halotukozak.commons.containsOnly)halotukozak.commons.containsOnly in interface halotukozak.commons.containsOnly does not have a correspondent in current version
  - static method given_containsOnly_Tup_T(scala.=:=)halotukozak.commons.containsOnly in interface halotukozak.commons.containsOnly does not have a correspondent in current version
  - static method given_containsOnly_Tuple_Any()halotukozak.commons.containsOnly in interface halotukozak.commons.containsOnly does not have a correspondent in current version
  - static method given_containsOnly_Zip_T1_T2(halotukozak.commons.containsOnly,halotukozak.commons.containsOnly)halotukozak.commons.containsOnly in interface halotukozak.commons.containsOnly does not have a correspondent in current version
  - method given_containsOnly_Tuple_Any()halotukozak.commons.containsOnly in object halotukozak.commons.containsOnly does not have a correspondent in current version
  - method given_containsOnly_Tup_T(scala.=:=)halotukozak.commons.containsOnly in object halotukozak.commons.containsOnly does not have a correspondent in current version
  - method given_containsOnly_Map_C()halotukozak.commons.containsOnly in object halotukozak.commons.containsOnly does not have a correspondent in current version
  - method given_containsOnly_Map_F()halotukozak.commons.containsOnly in object halotukozak.commons.containsOnly does not have a correspondent in current version
  - method given_containsOnly_Tail_T(halotukozak.commons.containsOnly)halotukozak.commons.containsOnly in object halotukozak.commons.containsOnly does not have a correspondent in current version
  - method given_containsOnly_Reverse_T(halotukozak.commons.containsOnly)halotukozak.commons.containsOnly in object halotukozak.commons.containsOnly does not have a correspondent in current version
  - method given_containsOnly_Concat_T(halotukozak.commons.containsOnly,halotukozak.commons.containsOnly)halotukozak.commons.containsOnly in object halotukozak.commons.containsOnly does not have a correspondent in current version
  - method given_containsOnly_Zip_T1_T2(halotukozak.commons.containsOnly,halotukozak.commons.containsOnly)halotukozak.commons.containsOnly in object halotukozak.commons.containsOnly does not have a correspondent in current version
  - method given_<:<_Head_T(halotukozak.commons.containsOnly)scala.<:< in object halotukozak.commons.containsOnly does not have a correspondent in current version
  - method given_<:<_Last_T(halotukozak.commons.containsOnly)scala.<:< in object halotukozak.commons.containsOnly does not have a correspondent in current version
  - synthetic static method $init$(halotukozak.commons.containsOnlyLowPriority)Unit in interface halotukozak.commons.containsOnlyLowPriority does not have a correspondent in current version
  - method given_containsOnly_Tuple_Any()halotukozak.commons.containsOnly in interface halotukozak.commons.containsOnlyLowPriority does not have a correspondent in current version

@halotukozak
halotukozak merged commit a632e37 into main Sep 4, 2026
8 checks passed
@halotukozak
halotukozak deleted the perf/toarrayof-not-inline branch September 4, 2026 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-major Binary-incompatible change — needs a major version bump

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants