Skill v1.0.1
currentAutomated scan100/100+4 new
name: hearth-cross-compilation description: > Cross-compilation pitfalls for Scala 2.13 + 3 macros with Hearth. Path-dependent types, splice isolation, type constructor matching, reification failures, Array ClassTag, upcast constraints, phantom types, asInstanceOf semantics, IsMap ordering. paths:
- "/compiletime//*.scala"
- "/scala-2//*.scala"
- "/scala-3//*.scala"
user-invocable: false metadata: version: "1.0.1"
Skill: Cross-Compilation Pitfalls
Live reference for things that bite when writing cross-compiled Kindlings macros. Each entry in pitfalls.md describes the failure mode, the platform(s) it affects, and the workaround.
For higher-level rules around extension loading and LambdaBuilder scope, see hearth-standard-extensions and hearth-lambda-builder.
Pitfall index
Splice and quote scoping
| # | Pitfall | Severity | Platforms | |
|---|---|---|---|---|
| 1 | Sibling `Expr.splice` isolation | CRITICAL | Scala 3 | |
| 2 | `Expr.quote { (x: T) => ... }` is supported | LOW | Both | |
| 3 | Path-dependent types in `Expr.quote` | CRITICAL | Scala 2 | |
| 4 | Macro-internal types leaking into `Expr.quote` | HIGH | Scala 2 | |
| 5 | `Expr.upcast` only widens | MEDIUM | Both | |
| 6 | `ValDefsCache` wrapping scope | HIGH | Both |
Type system details
| # | Pitfall | Severity | Platforms | |
|---|---|---|---|---|
| 7 | Macro methods need concrete types | MEDIUM | Both | |
| 8 | Phantom type-parameter inference | HIGH | Both | |
| 9 | [Type.of[A] bootstrap cycle in extensions](pitfalls.md#9-typeof-a-bootstrap-cycle-in-extensions) | CRITICAL | Both | |
| 10 | `IsMap` before `IsCollection` ordering | HIGH | Both | |
| 11 | — | Scala 3 | ||
| 12 | `primaryConstructor` strict type checking | HIGH | Both | |
| 13 | `Array` needs `ClassTag` | MEDIUM | Both |
Implicit summoning
| # | Pitfall | Severity | Platforms | |
|---|---|---|---|---|
| 14 | `summonExprIgnoring` vs OOM | CRITICAL | Both | |
| 15 | Newtype aliases in `Expr.quote` | HIGH | Scala 2 | |
| 16 | Cross-quotes unused `Type` implicit warnings | MEDIUM | Both |
HKT (kind * -> *) derivation
| # | Pitfall | Severity | Platforms | |
|---|---|---|---|---|
| 17 | HKT type constructor summoning across compilation boundary | HIGH | Both | |
| 18 | Erased approach for polymorphic type classes | MEDIUM | Scala 2 | |
| 19 | `IsValueType` intercepts single-element named tuples | HIGH | Scala 3 | |
| 20 | `MacroExtension` ClassTag erasure | MEDIUM | Both |
Additional Scala 2 reification pitfalls
| # | Pitfall | Severity | Platforms | |
|---|---|---|---|---|
| 21 | `.asInstanceOf` is NOT fully erased for outer types | HIGH | JVM | |
| 22 | Scala 2 reification failure with refined types | HIGH | Scala 2 | |
| 23 | Helper method pattern for path-dependent types in providers | MEDIUM | Scala 2 | |
| 24 | Newtype type aliases in `Expr.quote` | HIGH | Scala 2 | |
| 25 | Macro methods require concrete types at call site | MEDIUM | Both | |
| 26 | Sibling `Expr.splice` blocks have isolated `Quotes` | CRITICAL | Scala 3 | |
| 27 | `ValDefsCache` wrapping scope for multi-function derivation | HIGH | Both | |
| 28 | Path-dependent types from `IsMap`/`IsCollection` | MEDIUM | Scala 3 | |
| 29 | Discriminator-style enum decoding | MEDIUM | Both | |
| 30 | Built-in type rule is mandatory | HIGH | Both | |
| 31 | `group()` is from `MacroSuite` | LOW | Both | |
| 32 | `ProviderResult` is not `Option` | MEDIUM | Both | |
| 33 | `primaryConstructor` type-checks field expressions strictly | HIGH | Both | |
| 34 | `parTraverse` and `ValDefsCache` state threading | HIGH | Both |
Non-derivation macro modules (di / mock / optics)
| # | Pitfall | Severity | Platforms | |
|---|---|---|---|---|
| 35 | [classOf[M] impossible for an abstract type param (use ClassTag[M].runtimeClass)](pitfalls.md#35-classofm-is-impossible-for-an-abstract-macro-type-parameter) | HIGH | Both | |
| 36 | [Class shadowed by Hearth's cake Class[A] (use java.lang.Class)](pitfalls.md#36-class-is-shadowed-by-hearths-cake-classa-inside-macro-code) | MEDIUM | Both | |
| 37 | `@compileTimeOnly` fires on S3 `extension` not S2 `implicit class` | MEDIUM | Scala 2 | |
| 38 | Marker DSLs need INVARIANT evidence to pin element types | HIGH | Scala 2 | |
| 39 | Context-function values are eta-applied in tests | MEDIUM | Scala 3 | |
| 40 | Gate S3 DSL markers behind a phantom context function (peel with `betaReduce` + `Block` unwrap) | MEDIUM | Scala 3 |
Resolved Hearth issues (for context only)
| # | Issue | Status | |
|---|---|---|---|
| R1 | parTraverse and ValDefsCache | Fixed in Hearth 0.2.0-268+ | |
| R2 | loadStandardExtensions repeated registration | Fixed in Hearth 0.2.0-257 | |
| R3 | Cross-quotes Type.Ctor1 resolution in HKT | Fixed in Hearth 0.2.0-263+ |
Quick reference: most common pitfalls
The top pitfalls encountered in practice, by frequency:
- Path-dependent types in `Expr.quote` (#3) -- use helper methods with regular type params
- Sibling splice isolation (#1, #26) -- use def-caching, not LambdaBuilder
- `summonExprIgnoring` vs OOM (#14) -- always pass ignored implicits
- `IsMap` before `IsCollection` (#10) -- check map first in pattern match
- ~~`Type.Ctor2.of[Function1].unapply`~~ (#11) -- fixed in kubuszok/hearth#389: Scala 3
.ofused to return
Nothing for the contravariant argument of a SUBTYPE (e.g. IntPredicate extends (Int => Boolean)). Plain .of is now correct on both platforms; do not wrap with fromUntyped.
- ~~`fromUntyped` for ALL SPI-boundary type matching~~ -- DISPROVEN on Hearth 0.4.3 (
refined/iron
providers now use plain Type.Ctor2.of and all integration tests pass; Hearth-suite test shows SPI-loaded extensions behave like same-file code). Original claim, kept for history: any Type.Ctor1/Ctor2 created in one compilation unit and unapply'd in another (via StandardMacroExtension SPI) needs fromUntyped wrapping. Affects: iron/refined integrations, cats collection/map providers, cats-derivation contravariant/bifunctor. Pattern: val MyCtor = Type.Ctor2.fromUntyped[F](Type.Ctor2.of[F].asUntyped)
See pitfalls.md for detailed descriptions of all entries.
Related skills
- hearth-macro-basics -- core architecture
- hearth-case-class-rules -- case class derivation
- hearth-enum-rules -- enum derivation
- hearth-hkt-derivation -- polymorphic derivation
- hearth-def-caching -- def-caching (fix for splice isolation)
- hearth-lambda-builder -- LambdaBuilder scope rules