New
Experimental support for suspend providers
This release introduces experimental support for suspend providers. This is disabled by default and can be enabled by the metro.enableSuspendProviders option. See the coroutines documentation for details.
@Providesfunctions and graph accessors can besuspend. Suspension propagates through dependent bindings. Metro reports a dependency trace when a non-suspend path reaches one.- Inject
suspend () -> Tto defer initialization until invocation, orSuspendLazy<T>to also cache the first successful result.Provider, function providers,Lazy,SuspendProvider, suspend functions, andSuspendLazycan be nested to any depth in a scalar wrapper stack.- When the underlying binding suspends, the wrapper closest to it must also support suspension. Maps can defer initialization of individual values with
Map<K, suspend () -> V>orMap<K, SuspendProvider<V>>. - Wrapper layers and supported map values preserve nullable binding types.
- When the underlying binding suspends, the wrapper closest to it must also support suspension. Maps can defer initialization of individual values with
- Like ordinary scoped bindings, scoped suspend bindings are single-flight and retry after failures or cancellation. They also run on the coroutine context they were called on, so if this is important then you should use an appropriate
withContextwithin your provider body. - The Gradle plugin automatically adds the new
runtime-coroutinesartifact when suspend providers are enabled. If runtime dependencies are managed manually, add it for scoped suspend bindings,suspendLazy, and injection requests containingSuspendLazyat any nesting level.runtime-coroutinesuses kotlinx-coroutines on every platform.
- Note: Switching providers do not yet support suspend providers. You can still enable them, just scoped suspend provider fields will not be sharded into nested switching provider classes yet.
Other new stuff
- [FIR/IR/Circuit] Support sub-circuits (i.e. the new
@SubCircuitInjectannotation).
Enhancements
- Support private
@Providesproperties on Kotlin2.4.20-Beta1and newer. - [IR] Improve IC on Kotlin
2.3.20by backporting compat support for the compiler's new declaration finder APIs. - [IR] Avoid generating unused provider fields for included graph accessors that can be read directly.
- [IR] Avoid linear helper traversal in large switching providers by routing directly to the matching chunk.
- [runtime] If the input function to
provider()is already aProviderinstance, return it directly rather than needlessly wrap it. - [runtime] Support nullable values in ordinary map multibinding factories, including provider and lazy map value forms.
Fixes
- [FIR] Report a diagnostic when private
@Providesproperties are used without compiler support (i.e. pre-2.4.20). - [FIR] Report an error when a map key is applied (via type argument) to a binding without a corresponding
@IntoMapor@ContributesIntoMapannotation. - [IR] Fix stale contribution hints after changing a contribution's scope during incremental compilation. This only affects Kotlin versions prior to
2.3.20. - [IR] Fix Kotlin/Native compilation failures when generated hidden classes were missing their
Anysupertype. - [IR] Prevent directly provided maps from satisfying suspend-provider-valued map requests unless the provided map uses that exact value type.
- [IR] Avoid redundant nested
DoubleCheck.lazy()calls when materializingLazygraph accessors and binding parameters. - [IR] Correctly adapt function-provider accessors from included graphs when storing them as Metro
Providerfields. - [IR] Fix graph implementations incorrectly inheriting the containing class of nested
@ContributesTointerfaces with IR class generation. - [IR] Don't inline
object, enum, or class-literal provider bindings when they're requested throughProvider,Lazy, or provider-based multibindings. - [gradle] Respect
metro.generateClassesInIrGradle and system property overrides instead of replacing them with the Kotlin-version default. - Improve Kotlin
2.4.20-Beta2support.
Changes
- Refreshed benchmarks!
- They now run against latest Metro, Dagger, and KSP versions.
- Dagger + KSP have improved significantly 🚀.
- They now also include Koin.
- They now run against latest Metro, Dagger, and KSP versions.
- Build against Kotlin
2.4.10. Note the runtime artifacts still target Kotlin2.3.0and Metro supports a wide range of compiler versions. See the compatibility docs for a full table of compatible versions. - Test IntelliJ
2026.2stable. - Test Android Studio Quail 4 canaries.
- Switch shaded Mordan dependency to just
mordant-core. - Update shaded Okio dependency to
3.18.1. - Update androidx.tracing to
2.0.0-rc01.
Contributors
Special thanks to the following contributors for contributing to this release!
What's Changed
- Update actions/setup-node action to v7 by @renovate[bot] in #2544
- Update Metro bootstrap to v1.3.2 by @renovate[bot] in #2545
- Update to 2.4.10 by @ZacSweers in #2549
- Update IDE version mappings by @ZacSweers in #2552
- Fix nested ContributesTo handling in IR merging by @ZacSweers in #2555
- Update tracing to v2.0.0-beta01 by @renovate[bot] in #2554
- Add a klib IC test by @ZacSweers in #2556
- Improve published artifact validation by @ZacSweers in #2550
- Improve actions caching by @ZacSweers in #2559
- Add SubCircuit support by @ZacSweers in #2558
- Update IDE version mappings by @ZacSweers in #2561
- Update dependency mkdocs-material to v9.7.7 by @renovate[bot] in #2562
- Update dependency zensical to v0.0.51 by @renovate[bot] in #2563
- Update tested IDE versions by @ZacSweers in #2564
- Update actions/checkout digest to 3d3c42e by @renovate[bot] in #2567
- Update plugin shadow to v9.6.0 by @renovate[bot] in #2560
- Suspend providers by @ZacSweers in #2508
- Update actions/setup-python action to v7 by @renovate[bot] in #2566
- Update IDE version mappings by @ZacSweers in #2570
- Try improving CI flakes by @ZacSweers in #2568
- Couple small suspend providers followups by @ZacSweers in #2569
- Propagate suspend in factories by @ZacSweers in #2572
- Enable R8 minimizing in the compiler by @ZacSweers in #2571
- Update dependency com.squareup.okio:okio to v3.18.0 by @renovate[bot] in #2575
- Fix suspend param deduping by @kevinguitar in #2574
- Test kotlin 2.4.20-Beta2 by @ZacSweers in #2578
- Route switching providers directly to their chunked invokes by @ZacSweers in #2579
- Run JS tests for future versions of Kotlin by @kyay10 in #2580
- Do not minimize mordant with R8 by @kevinguitar in #2581
- Check map key mismatches in type args by @ZacSweers in #2582
- Switch to mordant-core + shaded compiler test by @ZacSweers in #2583
- Update IDE version mappings by @ZacSweers in #2586
- Don't inline certain providers when requested in deferred types by @ZacSweers in #2588
- Add skill for mavenLocal testing by @ZacSweers in #2589
- Fix missing Any supertypes in IR generated classes by @ZacSweers in #2590
- Support private
@Providesproperties in 2.4.20+ by @ZacSweers in #2591 - Rename SuspendLazy.value to await by @ZacSweers in #2593
- Add option to disable redundant IC helpers in newer versions by @ZacSweers in #2594
- Update dependency com.squareup.okio:okio to v3.18.1 by @renovate[bot] in #2595
- Update dependency com.slack.foundry:better-gradle-properties to v0.36.0 by @renovate[bot] in #2596
- Fix JS box tests by @ZacSweers in #2597
- Update robolectric + enable ACF test by @ZacSweers in #2598
- Fix duplicate annotations in IR class gen by @ZacSweers in #2599
- Update dependency com.google.googlejavaformat:google-java-format to v1.36.0 by @renovate[bot] in #2603
- Update dependency io.insert-koin.compiler.plugin to v1.1.0 by @renovate[bot] in #2601
- Fix nested contributed graph extension factories by @ZacSweers in #2600
- Update tracing to v2.0.0-rc01 by @renovate[bot] in #2602
- Update dependency zensical to v0.0.52 by @renovate[bot] in #2604
- Update dependency com.google.googlejavaformat:google-java-format to v1.36.1 by @renovate[bot] in #2605
- Update dependency Markdown to v3.10.3 by @renovate[bot] in #2606
- Regenerate benchmarks by @ZacSweers in #2607
Full Changelog: 1.3.2...1.4.0