Skip to content

[Scala 3] port SealedUtils + SealedEnumCompanion (Mirror-based)#882

Draft
halotukozak wants to merge 8 commits into
AVSystem:scala-3from
halotukozak:05-06-sealed-utils
Draft

[Scala 3] port SealedUtils + SealedEnumCompanion (Mirror-based)#882
halotukozak wants to merge 8 commits into
AVSystem:scala-3from
halotukozak:05-06-sealed-utils

Conversation

@halotukozak

Copy link
Copy Markdown
Member

Restores misc.SealedUtils family from Phase-1 ??? stubs to real Scala 3 implementations backed by scala.deriving.Mirror.SumOf + scala.compiletime.{summonAll, summonFrom, erasedValue}. Pattern 4 — pure inline, no quoted macros. Cribbed verbatim from fork origin/master:core/src/main/scala-3/com/avsystem/commons/misc/SealedUtils.scala (commit 3ec8c125).

⚠ Stacked on #865

This branch sits on top of 02-02-source-positions (#865). Until #865 merges, this PR diff includes #865 changes. Review #865 first, then this slice (GitHub will auto-recompute the diff once #865 lands).

Without #865, OrderedEnum-based tests would need explicit SourceInfo instances since SourceInfo.here is a Phase-1 ??? stub.

What changed

SealedUtils:

  • instancesFor[TC[_], T: Mirror.SumOf as m]compiletime.summonAll[Tuple.Map[m.MirroredElemTypes, TC]]
  • caseObjects[T: Mirror.SumOf as m] — recursive collectCaseObjects via summonFrom { case vo: ValueOf[h] => ... }
  • caseObjectsFor[T] REMOVED (pre-port git grep confirmed zero internal callers)

SealedEnumCompanion:

  • evidence: this.type = this REMAINS COMMENTED OUT — Mirror.Sum auto-derive clashes with same-type given. Workaround documented in MIGRATION.md.
  • values widened from lazy val to def (subclasses keep lazy val overrides).
  • caseObjects now inline protected def caseObjects(using Mirror.SumOf[T]): List[T] delegating to SealedUtils.caseObjects[T].

NamedEnumCompanion:

  • implicit lazy val keyCodec / implicit lazy val codec → named given keyCodec: GenKeyCodec[T] / given codec: GenCodec[T]. Public member names preserved — downstream MyEnum.codec / MyEnum.keyCodec continues to work.

OrderedEnum:

  • implicit def ordering → named given ordering: [T <: OrderedEnum] => Ordering[T].

Tests

SealedEnumTest + NamedEnumTest un-wrapped from Phase-1 stubs. Coverage expanded beyond fork:

  • Original: case objects listing, typeclass instance listing (SealedEnumTest); name-override paths (NamedEnumTest).
  • New: standalone SealedUtils.caseObjects[T] (no companion), nested sum recursion (Shape > Polygon), case-class skipping in mixed hierarchies, OrderedEnum.ordering declaration-order sort, shouldNot typeCheck guard for non-sealed types, keyCodec round-trip, codec given identity.

13/13 green.

MIGRATION.md

  • §3 core — misc SealedUtils (slice 5.6) entry — full reshape rationale.
  • caseObjectsFor removal recorded.
  • Backlog rows for restored stubs removed.

Slice 5.6 / Phase 5 leaf-feature-restoration.

…uotes

- positioned.here: Int = ${ hereImpl } using Position.ofMacroExpansion.start
- SourceInfo.here: SourceInfo via Position.ofMacroExpansion + Symbol.spliceOwner walk
- macro impls live inline next to public inline defs (no separate macros.* package)
- disable sbt-ci-release plugin to avoid JGit NoWorkTreeException in linked worktrees
- new PositionedTest asserts two adjacent positioned.here calls yield distinct positive offsets
- update SourceInfoTest pattern values to match Scala 3 Position.ofMacroExpansion semantics (offset 205, column 17 — receiver start, not method name)
- drop backlog rows for positioned.scala:12 and SourceInfo.scala:28
- update Total tags count 155 -> 154
- document sbt-ci-release plugin disable (JGit worktree incompat)
… assertion

- use Matchers for improved assertion readability
- add test to verify `positioned.here` offset corresponds to the term's start offset
Port verbatim from origin/master:core/src/main/scala-3/com/avsystem/commons/misc/SealedUtils.scala
per fork commit 3ec8c12 (scala.ValueOf based caseObjects).

- SealedUtils.instancesFor / caseObjects: pure inline (no quoted macro).
  Uses compiletime.{summonAll, summonFrom, erasedValue} + Mirror.SumOf +
  scala.ValueOf to derive case-object listings at compile time.
- SealedUtils.caseObjectsFor REMOVED (zero internal callers per pre-port
  audit; replaced by caseObjects[T: Mirror.SumOf]). Documented as source-compat
  break in MIGRATION.md (next commit).
- SealedEnumCompanion.caseObjects now delegates to SealedUtils.caseObjects[T].
- SealedEnumCompanion.values widened from lazy val to def per fork shape;
  subclasses overriding with lazy val are still allowed in Scala 3.
- given GenKeyCodec / GenCodec[T] in NamedEnumCompanion (was implicit lazy val).
- Added explicit imports for scala.compiletime + scala.deriving.Mirror
  (CommonAliases.scala does not yet re-export them).
- Used nullableSimple (T <: NamedEnum <: Serializable is AnyRef) instead of
  fork's createSimple to preserve current behavior + fit current signature.

Compat traits OrderedEnumCompat / NamedEnumCompanionCompat from fork compat.scala
are intentionally NOT ported here (own slice — pure deprecation wrappers).
- SealedEnumTest: align with fork shape (val values, ClassTag[? <: SomeEnum])
  + provide explicit SourceInfo instances per case object (SourceInfo.here is
  still a Scala 2 macro stub awaiting Phase-6 — workaround keeps OrderedEnum
  ordering test green without depending on the macro).
- SealedEnumTest + NamedEnumTest both pass (6/6).
- SealedUtils.scala: keep `given evidence: this.type = this` commented out to
  match fork shape — uncommenting triggers an "illegal inheritance: self type
  X.type does not conform to self type scala.deriving.Mirror.Sum" error in
  every companion object that extends SealedEnumCompanion (because the
  companion is simultaneously an auto-derived Mirror.Sum and the source of
  a same-type given). Fork has the same line commented (verified against
  origin/master:core/src/main/scala-3/.../SealedUtils.scala).
- rpc/Tag.scala: replace direct `codec` reference (named implicit val from old
  Scala 2 NamedEnumCompanion) with `summon[GenCodec[Tag[?]]]` since the new
  trait exposes the codec as an anonymous `given`. Rule 3 — blocking test
  compile fix caused by Task 1 reshape.
Slice 5.6 entry:
- §1 Will-not-migrate: SealedUtils.caseObjectsFor[T] removed in fork; downstream
  migration target is caseObjects[T: Mirror.SumOf].
- §3 core — new "misc SealedUtils (slice 5.6)" subsection covering: pure-inline
  reshape, evidence given commented-out (Mirror.Sum self-type clash), values
  widened from lazy val to def, codec/keyCodec given anonymisation, OrderedEnum
  ordering given anonymisation, SourceInfo workaround in SealedEnumTest, and
  compat-trait deferral.
- §3 core (general): drop superseded "SealedEnumCompanion.values is lazy val"
  and "SealedUtils.instancesFor return type widened" lines (now under slice 5.6).
- Backlog: drop the three SealedUtils.scala TODO rows.
@halotukozak halotukozak added this to the Scala 3 milestone Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant