Releases: ZacSweers/metro
0.11.2
New
Class/KClass map key interop
This release introduces a special-cased opt-in java.lang.Class and kotlin.reflect.KClass interop on JVM/android compilations. While these types are not intrinsics of each other in regular code, they are in annotations and are often used in Map multibindings. Metro can support these if you enable the enableKClassToClassMapKeyInterop option. When enabled, java.lang.Class and kotlin.reflect.KClass are treated as interchangeable in map key types, matching Kotlin's own annotation compilation behavior. This only applies to map keys because these are the only scenario where annotation arguments are materialized into non-annotation code (i.e. @ClassKey(Foo::class) -> Map<Class<*>, V>).
This is disabled by default (even if other framework interops like includeDagger are enabled) because this is purely for annotations interop and potentially comes at some runtime overhead cost to interop since KClass types are still used under the hood and must be mapped in some cases. It's recommended to migrate these to KClass and call .java where necessary if possible.
Enhancements
- [FIR]: Report adhoc graph extension factories as these are unsupported in Metro (but apparently supported in Dagger!)
- [FIR]: Report a diagnostic error for usage of Dagger's
@LazyClassKeyas this is unsupported in Metro. - [IR]: Report warning diagnostics for unused synthetic multibindings, as it's often a sign that the user accidentally bound them to the wrong supertype.
warning: [Metro/SuspiciousUnusedMultibinding] Synthetic multibinding kotlin.collections.Map<kotlin.reflect.KClass<*>, BaseViewModel> is unused but has 4 source binding(s). Did you possibly bind them to the wrong type? SuspiciousUnusedMultibinding.kt:36:1 HomeViewmodel contributes a binding of BaseViewModel ~~~~~~~~~~~~~ SuspiciousUnusedMultibinding.kt:31:1 AccountViewModel contributes a binding of BaseViewModel ~~~~~~~~~~~~~ SuspiciousUnusedMultibinding.kt:26:1 SettingsViewModel contributes a binding of BaseViewModel ~~~~~~~~~~~~~ ...and 1 more Similar multibindings: - Map<KClass<*>, ViewModel> - [Gradle]: Add IDE support docs link to
@RequiresIdeSupportopt-in message.
Fixes
- [IR]: Fix a code gen bug where
@Providesgraph parameters wouldn't correctly be used by scoped bindings directly held in that graph.
Contributors
Special thanks to the following contributors for contributing to this release!
What's Changed
- Add docs link to
@RequiresIdeSupportwarning by @jonapoul in #1916 - Update GitHub Artifact Actions (major) by @renovate[bot] in #1917
- Update timestamps on ide caches to prevent re-downloads by @ZacSweers in #1918
- Report adhoc graph extension factories by @ZacSweers in #1897
- Report warning diagnostics for unused synthetic multibindings by @ZacSweers in #1919
- Update IDE version mappings by @ZacSweers in #1920
- Update plugin shadow to v9.3.1 by @renovate[bot] in #1923
- Update Gradle to v9.4.0-rc-2 by @renovate[bot] in #1922
- Fix FIR factory gen using wrong owner by @ZacSweers in #1924
- Update poko to v0.21.2 by @renovate[bot] in #1925
- Add KClass/Class interop for map keys by @ZacSweers in #1926
- Fix graph inputs being used in scoped bindings by @inorichi in #1921
- Update plugin shadow to v9.3.2 by @renovate[bot] in #1927
- Report diagnostic for LazyClassKey by @ZacSweers in #1929
- Include similar bindings when reporting suspicious unused multis by @ZacSweers in #1930
Full Changelog: 0.11.1...0.11.2
0.11.1
Enhancements
- [Runtime]: Give unique
outputModuleNamenames to all JS/wasm artifacts. - [IR]: Improve context hint for unreadable IR declarations when reporting errors.
Fixes
- [Runtime]: Only propagate the minimum supported stdlib version (
2.2.20) in runtime artifacts for JVM and native. Web artifacts unfortunately must target2.3.0since that's what Metro compiles against (star KT-84582). - [FIR]: Don't run
BindingContainerCallableCheckerandMultibindsCheckerdiagnostics on value parameters. - [FIR]: Fix parsing of enum arguments in qualifier annotations. We made a previous change for
0.11.0to better handle top-level constants but this solution accidentally regressed enum constants support. - [IR]: Fix root graph accessors with
@OptionalBindingaccidentally reporting missing bindings. - [IC]: Workaround a kotlinc IC issue when
generateAssistedFactoriesis enabled.
Contributors
Special thanks to the following contributors for contributing to this release!
What's Changed
- Update dependency androidx.tracing:tracing-wire-desktop to v2.0.0-alpha02 by @renovate[bot] in #1904
- Fix optional root graph accessors by @JonasAtAmo in #1905
- Work around IC bug with assisted factory generation by @hrach in #1901
- Fix greedy callabledeclaration checkers by @ZacSweers in #1908
- Use toResolvedCallableSymbol() to support enums by @ZacSweers in #1909
- Clean up runtime artifact names and propagated deps by @ZacSweers in #1913
- Add more diagnostic messaging in case the parent class is not resolvablee to an IrClass by @segunfamisa in #1912
- Clean up suppressions by @ZacSweers in #1914
New Contributors
- @JonasAtAmo made their first contribution in #1905
- @hrach made their first contribution in #1901
- @segunfamisa made their first contribution in #1912
Full Changelog: 0.11.0...0.11.1
0.11.0
New
Metro now has an informal proposal system inspired by Kotlin KEEPs called MEEPs! Importantly, the P in MEEP stands for proposal, not process. It's an informal system for myself and future maintainers to seek broader community input on newer, splashier features and changes to Metro going forward.
[MEEP-1826] @Assisted parameters now rely on matching parameter names.
Historically, Dagger/Guice's @Assisted parameters allowed specifying a custom identifier via @Assisted("some string"), and Metro matched this behavior. However, this is a vestige of Java support, which did not include parameter names in bytecode until Java 8's -parameters flag.
Since Metro is in an all-Kotlin world and parameter names are a first-class citizen in Kotlin APIs, Metro is now leveraging that and phasing out support for implicit type matching and custom identifiers.
This means that @Assisted parameter names in assisted-inject constructors/top-level-functions must match their analogous parameters in @AssistedFactory creators. No more matching by types, no more disambiguating with @Assisted("customIdentifier").
// Before: Using type matching or custom identifiers
@AssistedInject
class Taco(
@Assisted("name") val name: String,
@Assisted("type") val type: String,
@Assisted val spiciness: Int,
val tortilla: Tortilla
) {
@AssistedFactory
interface Factory {
fun create(
@Assisted("name") name: String,
@Assisted("type") type: String,
@Assisted spiciness: Int
): TacoFactory
}
}
// After: Using parameter name matching
@AssistedInject
class Taco(
@Assisted val name: String,
@Assisted val type: String,
@Assisted val spiciness: Int,
val tortilla: Tortilla
) {
@AssistedFactory
interface Factory {
// Parameter names must match the constructor exactly
fun create(name: String, type: String, spiciness: Int): TacoFactory
}
}To ease migration to this, this will be rolled out in phases.
- Starting with this release,
@Assisted.valueis soft-deprecated. This is controlled by theassistedIdentifierSeverityGradle DSL option, which is set toWARNby default in this release. This control allows for easy disabling or promotion to error. - In a future release,
assistedIdentifierSeveritywill be removed and@Assisted.valuewill be formally deprecated. - In a future release after that,
@Assisted.valuewill be fully deleted and legacy behavior will be unsupported with Metro's first-party annotation.
Note that interop annotations are not affected by this change, and any previous Dagger/Guice interop @Assisted annotation's custom identifiers will still be respected.
If you want to completely restore the legacy behavior, you can disable this new mode via useAssistedParamNamesAsIdentifiers Gradle DSL option. Note, however, that this option will eventually be removed.
[MEEP-1770] Allow use of () -> T as Provider types.
Metro's primary provider type remains Provider, but as of this release there are a couple of important changes in this space to allow more idiomatic use.
Providernow implements() -> Ton supported platfroms (all but Kotlin/JS).- There is a new
enableFunctionProvidersoption to allow use of Kotlin's() -> Thigher order functions. This is disabled by default, but will possibly be promoted to the default behavior in the future. Please share feedback in the linked MEEP.- This is inspired by kotlin-inject's support of the same feature, albeit with adjustments to work within Metro's existing
Providersystem. - On Kotlin/JS, the underlying
Function0type will be wrapped/unwrapped like otherProviderinterop scenarios do. This limitation is because JS does not allow extending function types.
- This is inspired by kotlin-inject's support of the same feature, albeit with adjustments to work within Metro's existing
This now allows you to write code like this.
@DependencyGraph
interface AppGraph {
val stringProvider: () -> String
@Provides fun provideString(): String = "Hello, world!"
}
fun main() {
val provider = createGraph<AppGraph>().stringProvider
println(provider())
}The primary caveat of this new feature is that, if enabled, it essentially prohibits using function types as regular bindings in your graph. If you rely on this behavior, you may need to migrate to something more strongly typed.
[MEEP-1769] Introduce @GraphPrivate API.
Up to now, all bindings in graphs are implicitly available to all graph extensions.
Indicates this @Provides or @Binds declaration shall be private to the graph it's provided in. This means the following:
- This binding may not be exposed directly via accessor.
- This binding will not be exposed directly to extensions of this graph.
This is a mechanism to enforce that annotated bindings cannot be directly leaked. It may be depended on by any bindings within this graph as an implementation detail or encapsulation.
This is useful for a few situations.
- Users may want certain bindings to stay confined to a given graph, such as a base
HttpClient. - Users may want to omit certain contributions to multibindings from leaking to extensions.
- Sometimes the same type may exist in multiple graph scopes, requiring use of qualifiers like
@ForScopeto disambiguate which one you need. By marking each provision in a graph as private, you can trust that parent graph instances are not being accidentally leaked to your extension's scope.
@DependencyGraph(AppScope::class)
interface AppGraph {
@GraphPrivate
@Provides
@SingleIn(AppScope::class)
fun provideCoroutineScope(): CoroutineScope = ...
// Error
val coroutineScope: CoroutineScope
val loggedInGraph: LoggedInGraph
}
@GraphExtension
interface LoggedInGraph {
// Error, no longer implicitly visible
val coroutineScope: CoroutineScope
}This feature is experimental, please share any feedback on the original MEEP.
Misc new stuff
- [Runtime]: Make
Providerimplement() -> Ton applicable platforms (everything but Kotlin/JS). - [Runtime]: Add new
@ExperimentalMetroApiexperimental annotation to better indicate which APIs are experimental and likely to change. - [Gradle]: Add new
@RequiresIdeSupportexperimental annotation to better indicate which APIs require IDE support. - [Gradle]: Add new
@ExperimentalMetroGradleApiexperimental annotation to better indicate which APIs are experimental and likely to change. - [Gradle]: Add new
@DangerousMetroGradleApiexperimental annotation withERRORseverity to better propagate severity of certain APIs. - [FIR/Gradle]: Add new
publicScopedProviderSeverityproperty with a more narrow focus. The previouspublicProviderSeverityis now deprecated and just calls through to this.
Enhancements
- [FIR]: Disallow
_assisted context parameter names in top-level function injection. - [FIR/IR]: When generating class and provider factories now, the compiler dedupes non-assisted, non-optional injections of the same type key (i.e. type ± qualifier). This shrinks generated code size in (uncommon) scenarios where you inject the same type multiple types.
- [IR]: Significantly rework the IR pipeline.
Previously, Metro's IR would run in two passes:
- Collect contribution data and transform
MetroContributioninterfaces. - Run all other transformations.
Now, Metro runs in a single pass. Most of Metro's core transformations are run in the first full pass, collects any seen dependency graphs along the way, then they are processed at the end (rather than visit the whole IR tree a second time).
- [Gradle]: Allow
DiagnosticSeveritymetro extension properties to be configurable asmetro.*gradle properties of the same name. - [Runtime]: Remove atomicfu dependency from Metro's core runtime artifact. The base concurrency primitives are now built on
ReentrantLock(JVM), a port of the stdlib's Lazy spinlock on (Native), and no-op on web targets.
Fixes
- [FIR]: Improve optional binding member injections detection.
- [FIR]: Add
@HiddenFromObjCto generated top-level composable classes for native compilations. - [FIR]: Fix evaluation of top-level constants used in annotations like
@Assistedor@Named. - [FIR/IR]: Support generic
@BindingContainerclasses included via@Includeswith concrete type arguments (e.g.,@Includes TypedBindings<Int>). Type parameters are now properly propagated to generated factory classes and substituted during binding resolution. - [IR]: Fix propagation of
Mapgraph inputs down to graph extensions. - [IR]: Guard against identity mappings (T -> T) to prevent infinite recursion when remapping generic types.
- [IR]: Fix directly providing a scoped
Mapinstance not getting reused at injection sites. - [IR]: Fix graph extensions not being able to replace
@Binds-provided bindings from parent graphs. - [IR]: Fix dynamic binding containers not being propagated to graph extensions in some cases.
- [IC]: Fix an IC edge case where generated assisted factory impl classes sometimes missed changes to injected constructor parameters in the target class.
- [FIR/IR/Reports]: Restructure reports to use hierarchical nesting instead of top-level concatenated names. This fixes 'file name too long' exceptions when generating reports for deeply nested graphs. For example, the report file
reports/keys-populated-test_Graph_ChildGraph.txtwill now be generated asreports/keys-populated/test/Graph/ChildGraph.txt - [IR/Sharding]: Fix an issue where assisted inject classes a...
0.10.4
Enhancements
- [FIR]: Add suspicious scope diagnostics for cases where a developer might accidentally try to contribute to a concrete
@Scopeclass or graph-like class, as that's not usually what you want! - [FIR]: Add a diagnostic error for function member injection parameters with default values as they are not currently supported.
- [IR]: Extend conflicting overrides diagnostic in synthetic graphs (graph extension impls, dynamic graphs) to also validate compatible annotations. This catches scenarios where you may accidentally contribute something like a
fun dependency(): Dependencyaccessor and@Provides fun dependency(): Dependencyprovider elsewhere, which previously resulted in undefined runtime behavior. - [IR]: When reporting conflicting override types in synthetic graphs, underline the type and include the source location (when possible) to better indicate the issue.
- [IR]: Add a graph validation failure hint to report when a direct Map binding exists that cannot satisfy a Provider/Lazy map.
-
For example, the below snippet
@DependencyGraph interface ExampleGraph { val mapSize: Int @Provides fun provideInt(map: Map<String, Provider<String>>): Int = map.size @DependencyGraph.Factory interface Factory { fun create(@Provides map: Map<String, String>): ExampleGraph } }
Now yields this error trace
error: [Metro/MissingBinding] Cannot find an @Inject constructor or @Provides-annotated function/property for: kotlin.collections.Map<kotlin.String, kotlin.String> kotlin.collections.Map<kotlin.String, kotlin.String> is injected at [ExampleGraph] ExampleGraph.provideInt(…, map) kotlin.Int is requested at [ExampleGraph] ExampleGraph.mapSize (Hint) A directly-provided 'Map<String, String>' binding exists, but direct Map bindings cannot satisfy 'Map<String, Provider<String>>' requests. IncompatibleMapValueType.kt:15:16 @Provides map: kotlin.collections.Map<kotlin.String, kotlin.String> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Provider/Lazy-wrapped map values (e.g., Map<K, Provider<V>>) only work with a Map **multibinding** created with `@IntoMap` or `@Multibinds`.
-
Fixes
- [IR]: Gracefully handle skipping code gen for absent member-injected properties/single-arg setters.
- [IR]: Decompose
Mapgraph factory inputs correctly so they can properly satisfy map requests on the graph. - [IR]: Validate directly-provided map inputs from map-requesting injection sites.
- [IR/Native]: Fix mirror parameter check for providers in
objectclasses in non-jvm compilations.
Changes
- Deprecate the
generateThrowsAnnotationsoption and make it no-op. This was only in place when debugging a past kotlin/native issue.
Contributors
Special thanks to the following contributors for contributing to this release!
What's Changed
- Deprecate/clean up generateThrowsAnnotation by @ZacSweers in #1798
- Enable enableGraphSharding by default by @ZacSweers in #1799
- Update compose.jb to v1.10.1 by @renovate[bot] in #1800
- Beef up tests by @ZacSweers in #1802
- Add suspicious scope warning by @ZacSweers in #1803
- Update dependency pillow to v12.1.1 by @renovate[bot] in #1804
- Update dependency androidx.collection:collection to v1.6.0-rc01 by @renovate[bot] in #1807
- Update dependency androidx.activity:activity-compose to v1.12.4 by @renovate[bot] in #1806
- (temp) Revert "Enable enableGraphSharding by default" until 0.11 by @ZacSweers in #1811
- Extra test for nullable scoped bindings + revamp test docs by @ZacSweers in #1812
- Validate compatible annotations in synthetic graph overrides by @scana in #1810
- Fix mirror parameter check for providers in
objectclasses by @ZacSweers in #1813 - Clean up member injections with default values by @ZacSweers in #1814
- Tweak clashing declarations message by @ZacSweers in #1817
- Update IDE version mappings by @ZacSweers in #1819
- Update alias refreshing by @ZacSweers in #1820
- Fix mapping graph map inputs by @ZacSweers in #1818
New Contributors
Full Changelog: 0.10.3...0.10.4
0.10.3
New
- Metro now has experimental support for Kotlin 2.4.0. At the time of writing, this is only really helpful if you are testing IDE support in IntelliJ 2026.1 EAPs.
- Metro's compiler now embeds
androidx.tracingand can produce perfetto traces of its IR transformations. - [FIR]: Metro now does early detection of whether or not it's running in the IDE or CLI. If it's in the IDE, Metro will disable any FIR generators that do not generate user-visible code.
Enhancements
- [FIR]: When reporting diagnostics about types that are aliases, include the aliased type in the message. This is helpful for messages like below
typealias UserId = String interface Bindings { // error: Binds receiver type `kotlin.String` is the same type and qualifier as the bound type `UserId (typealias to kotlin.String)`. @Binds fun String.bind(): UserId }
- [FIR]: Add full integration tests for FIR-based IDE features.
- This is really only in the changelog because getting Android Studio to not show its blocking analytics consent dialog on CI might be the most difficult technical problem this project has faced so far and what's a changelog for if not the occasional itsfinallyover.gif bragging rights.
- [IR]: Use
androidx.collectionprimitive and scatter collections in a few more places to further help improve memory performance. - [IR]: Don't attempt to generate a graph impl if validation at any level in processing fails, as this could result in obscure extra errors getting reported after the relevant initial error.
Fixes
- [IR]: Avoid
IllegalStateException: No value parameter foundissues when reconstructing dependency cycle stacks to report cycle errors. - [IR]: Fix a scenario where bindings available in both graphs and their extensions didn't properly consolidate to one binding.
- [Gradle]: Make the
metrox-androidartifact single-variant (release only).
Changes
- [FIR/IR] Add aliases for a bunch of "known" mappings for Kotlin IDE plugin versions to Kotlin versions. This is still best-effort but should hopefully be more robust, especially in situations like Android Studio canaries (which do not report real Kotlin versions). Please star this issue: https://issuetracker.google.com/issues/474940910
- [FIR]: One downside of the above is that it revealed that Android Studio Otter 3 is effectively running on Kotlin 2.2.0, which is just a bit too far back to still support. However, now that Studio is switching to monthly releases it should track upstream IJ changes much quicker and Studio Panda is in RC1 now.
- Previously, an incompatible version could cause the IDE file analysis to hang or error out if IDE support was enabled. Now, Metro's IDE support will gracefully degrade on incompatible IDE versions. This includes Android Studio Otter and IntelliJ
2025.2.xas of this version. Android Studio Panda and IntelliJ 2025.3 are tested and working though!2026-02-08 01:14:27,225 [ 56672] INFO - STDERR - [METRO] Skipping enabling Metro extensions in IDE. Detected Kotlin version '2.2.255-dev-255' is not supported for IDE use (CLI_ONLY).
- Previously, an incompatible version could cause the IDE file analysis to hang or error out if IDE support was enabled. Now, Metro's IDE support will gracefully degrade on incompatible IDE versions. This includes Android Studio Otter and IntelliJ
- [IR]: Rework assisted inject bindings to be encapsulated by their consuming assisted factory bindings in graph validation.
- This ensures these classes can't accidentally participate in
SwitchingProviders or valid cycle breaking withDelegateFactory, as both of those requireProvidertypes and assisted-inject types' factories don't implementProvider.
- This ensures these classes can't accidentally participate in
- [Gradle]: Avoid deprecated
KotlinCompilation.implementationConfigurationNameAPI. enableTopLevelFunctionInjection,generateContributionHintsInFir, andsupportedHintContributionPlatformswill error if enabled on Kotlin/JS with JS incremental compilation enabled as it turns out this does not yet support generating top-level declarations from compiler plugins with incremental compilation enabled.- Fold
2.3.20-dev-7791compat into2.3.20-Beta2compat, meaning the former is no longer tested on CI. - Fold
2.3.20-dev-5437compat into2.3.20-dev-5706compat. This is to help Metro's main branch stay stable as the5437artifact came from a dev maven repo with ephemeral artifacts. - Test Kotlin
2.3.20-Beta2. - Test Kotlin
2.3.10. - Test Kotlin
2.4.0-dev-539. - Drop testing of Kotlin
2.3.10-RC. - Metro now compiles against Kotlin
2.3.0. This allows it to test2.4.0builds, but is still compatible down to Kotlin2.2.20. Metro's runtime artifacts also explicitly have their language version still set to2.2(and2.0for the Gradle plugin).
Contributors
Special thanks to the following contributors for contributing to this release!
What's Changed
- Small optimizations by @ZacSweers in #1753
- Rework how assisted-inject bindings are modeled by @ZacSweers in #1756
- Exit processing earlier if there are errors by @ZacSweers in #1759
- Update dependency androidx.work:work-runtime to v2.11.1 by @renovate[bot] in #1760
- Add sponsoring doc by @ZacSweers in #1763
- Add 2.3.20-Beta2 by @ZacSweers in #1761
- Update Gradle to v9.3.1 by @renovate[bot] in #1762
- Fix incorrect links in README.md by @DaniilPavlenko in #1764
- Gate FIR IDE support on bad studio versions by @ZacSweers in #1758
- Update dependency androidx.activity:activity-compose to v1.12.3 by @renovate[bot] in #1765
- Fix outdated README.md in metrox-viewmodel by @DaniilPavlenko in #1766
- Enable gradle parallel by @kevinguitar in #1768
- Add androidx tracing by @ZacSweers in #1767
- Improve alias diagnostics in FIR by @ZacSweers in #1773
- Update dagger to v2.59.1 by @renovate[bot] in #1779
- Update actions/checkout digest to de0fac2 by @renovate[bot] in #1778
- Add a functional test DSL by @ZacSweers in #1780
- Rework compat matching with aliases by @ZacSweers in #1781
- Update dependency com.google.googlejavaformat:google-java-format to v1.34.1 by @renovate[bot] in #1783
- Update dependency com.android.tools:r8 to v9 by @renovate[bot] in #1782
- IDE integration testing by @ZacSweers in #1784
- Update actions/download-artifact action to v7 by @renovate[bot] in #1786
- Update actions/setup-python action to v6 - autoclosed by @renovate[bot] in #1787
- Add graceful degredation for incompatible IDEs by @ZacSweers in #1788
- Fix/cycle reporter accuracy by @heorhiipopov in #1785
- Log trace file if enabled by @ZacSweers in #1789
- Migrate Renovate config by @renovate[bot] in #1790
- Fix inherited bindings duplicate binding error by @C2H6O in #1754
- Update dependency Markdown to v3.10.2 by @renovate[bot] in #1792
- Compile against 2.3.0 by @ZacSweers in #1791
- Kotlin 2.4.0 support + small fixes by @ZacSweers in #1794
- Update dependency org.jetbrains:annotations to v26 by @renovate[bot] in #1796
- Move wrapper cache to after by @ZacSweers in #1797
New Contributors
- @DaniilPavlenko made their first contribution in #1764
- @heorhiipopov made their first contribution in #1785
Full Changelog: 0.10.2...0.10.3
0.10.2
Enhancements
- [FIR] Add a diagnostic warning for
@IntoSetcallables returning collections, as these probably intended to use@ElementsIntoSet. - [IR] Automatically patch #1556 issues between Kotlin versions
[2.3.0 - 2.3.20-Beta2)for any klib-using compilation or JVM compilation that enables the-Xannotations-in-metadatacompiler option (which isn't enabled by default). This auto-patching is best effort and a fix in kotlinx is targeting2.3.20-Beta2. If you have any issues, it can be disabled via thepatchKlibParamsGradle DSL property.
Fixes
- [IR] Don't try class binding lookups for nullable types. These must always be explicitly provided.
- [IR] Disambiguate return-type overloads of generated
@Bindsfunctions for@Contributesannotations that contribute multiple interfaces of the same simple name but different package name. - [IR] Skip assisted parameters when validating parameter type matching on native compilations.
What's Changed
- Update dependency pymdown-extensions to v10.20.1 by @renovate[bot] in #1727
- Don't look up class bindings for nullable types by @ZacSweers in #1730
- Enable some new compiler options by @ZacSweers in #1707
- Small compiler option fixes by @ZacSweers in #1731
- Disambiguate names of generated contributed binding function names by @ZacSweers in #1732
- Validate fakeOverride compatibility by @ZacSweers in #1733
- Add docs for compiler version override usage by @ZacSweers in #1734
- Skip assisted parameters when validating mirror matches by @ZacSweers in #1738
- Doc included build setup by @ZacSweers in #1741
- Automatically patch #1556 issues by @ZacSweers in #1742
- More unused cleanup by @ZacSweers in #1744
- Update atomicfu by @ZacSweers in #1743
- Extract build-logic by @ZacSweers in #1745
- Add suspicious IntoSet diagnostic by @ZacSweers in #1746
- Update dependency org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-navigation3 to v2.10.0-alpha08 by @renovate[bot] in #1747
- Limit jvm param patching to certain conditions by @ZacSweers in #1748
- Update kotlinInject.anvil to v0.1.7 by @renovate[bot] in #1750
- Update plugin spotless to v8.2.1 by @renovate[bot] in #1752
- Update ksp monorepo to v2.3.5 by @renovate[bot] in #1757
- Update plugin com.gradle.develocity to v4.3.2 by @renovate[bot] in #1755
Full Changelog: 0.10.1...0.10.2
0.10.1
Enhancements
- [IR] Add a dedicated
UNUSED_GRAPH_INPUTdiagnostic forunusedGraphInputsSeverityoption. - [IR] Reduce memory usage when processing long graph extension chains. This is a combination of a few things:
- Using a (shaded)
ScatterMapimplementation fromandroidx.collections - Relinquishing binding lookup caches after graph validation completes
- Caching IrBinding instances
- Route almost all bindings through
BindingLookupfor lazy lookups rather than eagerly adding to the binding graph.
- Using a (shaded)
- [IR] Don't report subtypes of
Anyin similar binding hints. - [IR] Don't report multibinding elements in similar binding hints (only report the multibinding itself if relevant).
- [Graph Reporting] Since all bindings are lazily retrieved from
BindingLookupnow, this will also cut down graph analysis report sizes, as they should now be almost entirely free of unused bindings.
Fixes
- [IR] Fix exclusions not inherited from parent graphs.
- [IR] When reporting unused graph inputs on graph extensions, report the diagnostic on the original source declaration if possible.
- [IR/Native] Fix parameter type equality check in native compilations in constructor-injected class factories.
- [IR/Compat] Fix compatibiltiy for source-less diagnostics in Kotlin
2.3.20-Beta1.
Contributors
Special thanks to the following contributors for contributing to this release!
What's Changed
- Refactor graph node modeling by @ZacSweers in #1695
- Update dagger to v2.59 by @renovate[bot] in #1700
- Remove processedMetroDependencyGraphsByClass cache by @ZacSweers in #1702
- Add a dedicated UNUSED_GRAPH_INPUT diagnostic by @kevinguitar in #1701
- Update dependency org.robolectric:robolectric to v4.16.1 by @renovate[bot] in #1699
- Backport support for sourceless diagnostics to 2.3.20-Beta1 by @ZacSweers in #1698
- Fix native compilation typekey check by @ZacSweers in #1703
- Update dependency Markdown to v3.10.1 by @renovate[bot] in #1704
- Update AGP to 8.13.2 by @ZacSweers in #1705
- Update CONTRIBUTING and COC by @ZacSweers in #1706
- Update plugin spotless to v8.2.0 by @renovate[bot] in #1716
- Memory perf by @ZacSweers in #1709
- Update ktor monorepo to v3.4.0 by @renovate[bot] in #1712
- Tweak changelog by @ZacSweers in #1718
- Collect exclusions from parent DependencyGraphs by @jonamireh in #1715
- Don't hold bindsFunctions by @ZacSweers in #1717
- Fix unusedGraphInputsSeverity option for graph extensions by @kevinguitar in #1711
- Port DoubleCheckCycleTest by @ZacSweers in #1720
- Update plugin mavenPublish to v0.36.0 by @renovate[bot] in #1687
- Simplify similarbinding checks wrt Any and multibindings by @ZacSweers in #1722
- Do not cache bindings with generics in the BindingLookup by @kevinguitar in #1721
- Add missing @ContributesIntoMap into android sample test by @kevinguitar in #1723
- Add Activity injection example to docs by @zsmb13 in #1724
- Fix duplicate additions of existing ancestor member injections by @ZacSweers in #1725
Full Changelog: 0.10.0...0.10.1
0.10.0
Behavior Changes
- Enable
contributesAsInjectby default. See its docs for more details, but in short this means that@Injectis now optional on@ContributesBinding,@ContributesIntoSet, and@ContributesIntoMapannotated declarations.@ContributesBinding(AppScope::class) // @Inject // <-- now implicit! class TacoImpl(...) : Taco
- [Gradle / FIR] Enable FIR hint generation by default on Kotlin
2.3.20-Beta1or later.- By extension, this resolves Metro's most subscribed issue (#460) by enabling cross-module contribution/aggregation features in non-jvm/android compilations 🎉.
- Note that there is a separate known kotlinc issue around qualifier annotations that affects native builds and is targeted for
2.3.20-Beta2. Follow #1556 for updates.
- [Gradle / FIR] Enable top-level function injection by default on Kotlin
2.3.20-Beta1or later. - [Gradle / FIR] Disable automatic transformation of providers to private + deprecate the option, as this results in less efficient code generation and somewhat unclear error messages. It's recommended to write a lint check in another static analysis tool if you want this, for example this implementation from slack-lints.
- Metro may add an option for the inverse in the future. i.e., allow writing a private provider in source but then transform it to
internalat compile-time.
- Metro may add an option for the inverse in the future. i.e., allow writing a private provider in source but then transform it to
New
- Support
Map<K, Lazy<V>>andMap<K, Provider<Lazy<V>>multibindings expressions. - [FIR/IR] Report diagnostics for unmatched exclusions and replacements during contribution merging. These are written to
reportsDestinationif enabled, and should be used for debugging only. - [IR / Gradle] Add new experimental
enableSwitchingProvidersoption. If enabled, this changes code generation to use "switching providers" to defer classloading until a giving binding is actually requested.- This is analogous to Dagger's
fastInitfeature. - You should really only use this if you've benchmarked it and measured a meaningful difference, as it comes with the same tradeoffs (always holding a graph instance ref, etc.)
- This is analogous to Dagger's
- [IR / Gradle] Add an
unusedGraphInputsSeverityoption to report diagnostics for unused direct graph inputs. This includes any@Providesor@Includesparameters to graph factories or managed binding containers declared via the@DependencyGraph.includesannotation.- This is in addition to the existing
reportsDestination-only diagnostic for unused bindings, but limited to bindings that we know are not reused elsewhere and can thus safely soft-enforce at compile-time. - This matches a similar feature in Dagger.
- This is in addition to the existing
Enhancements
- [IR] Restructure graph validation and generation to be separate phases, allowing for whole-graph validation before any code gen runs and better optimizing shared bindings across graph extension hierarchies.
- [IR] Improve member injection error trace in graph validation.
- Previously it would show something like this
dev.zacsweers.metro.MembersInjector<test.FeatureScreen> is requested at [test.FeatureGraph] test.FeatureGraph#inject() - Now it will specify the injected type is being injected instead
test.Dependency is requested at [test.FeatureGraph] test.FeatureScreen.dependency test.FeatureScreen is injected at [test.FeatureGraph] test.FeatureGraph#inject() - It now also reports the location at the exact member injection callable declaration, rather than the graph.
- Previously it would show something like this
- [IR] Validate parameter type keys on native builds to help clarify encounters with KT-83427. Example below:
e: Mirror/create function parameter type mismatch: - Source: com.example.navigation.NavigationProviders.navigationSerializationModule - Mirror param: @com.example.app.navigation.NavigationSerializers kotlin.collections.Set<kotlinx.serialization.modules.SerializersModule> - create() param: kotlin.collections.Set<kotlinx.serialization.modules.SerializersModule> This is a known bug in the Kotlin compiler, follow https://github.com/ZacSweers/metro/issues/1556 - [IR] Avoid generating unnecessary
Providerrefcounts for bindings only used by graph injector functions. - [IR] When reporting graph failures in dynamic graphs, report the original call location in error reporting.
- [IR] Optimize equals/hashCode in type keys. Benchmarks show a ~2% macro improvement.
- [IR/Sharding] Rebalance shard groups after computing shard bindings.
- [Gradle] Generalize support for sourcing default values from gradle/system properties + document.
Fixes
- [FIR] Ensure hint functions generated by FIR hint generation match the visibility of the source contributor.
- [FIR/IR] Always check for
@Inject-annotated constructor even if class is annotated. This is important for thecontributesAsInjectfeature, as it would previously always use the primary constructor in these cases. - [FIR/IR] Don't clear reports dir between FIR and IR compiler phases.
- [IR] Never eagerly init graph extension impls (scoped or not).
- [IR] Don't cache creator-less scoped graph extension impls in their parent graphs. This was initially implemented this way due to a misunderstanding to how Dagger generated subcomponents! Getters for graph extensions now always return new instances.
- [IR] Check for
openorfinalmodality on classes first before searching for injectable constructors. - [IR] Mark all supertypes' member injections as dependencies of subtypes' member injections. That's a wordier way of saying that member-injecting a class
Dogthat extendsAnimalalso depends on member-injected dependencies ofAnimal. - [IR] Don't process companion objects of graphs or binding containers independently of their parent classes.
- [IR/Native] Work around
Abstract function '___' is not implemented in non-abstract class 'Impl'info warnings from native compilations. - [IR/Dynamic Graphs] Always check if a key is replaced by a dynamic type key when building binding graphs. Previously, some bindings would be added even if a dynamic key was available, resulting in unexpected
DuplicateBindingerrors. - [IC] Record lookups of contributed classes when looking up hints from IR. Previously Metro only recorded a lookup of the generated hint function, which appears to not be enough for Kotlin 2.3.20.
- [IC] Link IR-generated hint function files back to source class via expect-actual tracker to link their compilations. This fixes an edge case where simply changing a contribution scope (or removing it) could leave behind a stale hint file that downstream compilations would incidentally read.
Misc Changes
- [IR] Already mentioned above, but worth calling out again — creator-less scoped graph extensions are no longer cached in their parent graphs. Accessors to this will always get new instances now.
- [IR] Report log files reported from within graph generation now use snake-cased fully-qualified names of the impl graph as the file name suffix.
- [IR] Do not report similar bindings when a missing binding has type
kotlin.Any. In practice this reported all available bindings. - [interop-dagger] Update to Dagger
2.58. - [Docs] Publish kdocs for guice/jakarta/javax interop and metrox artifacts to doc site.
- [Docs] Expand IDE support docs.
- [Docs] Update
adoption.mddocs about subcomponents interop. - Test Kotlin
2.3.10-RC. - Test Kotlin
2.3.20-Beta1.
Contributors
Special thanks to the following contributors for contributing to this release!
What's Changed
- Restructure graph validation and generation to run in phases by @ZacSweers in #1638
- Refactor tracing to use context params by @ZacSweers in #1643
- Track dev builds separately by @ZacSweers in #1644
- Validate mirror/create qualifier symmetry by @ZacSweers in #1621
- Add Kotlin 2.3.20-Beta1 by @ZacSweers in #1635
- Add bootstrap check workflow by @ZacSweers in #1646
- Update adoption.md about Subcomponents by @C2H6O in #1648
- Update dependency com.squareup.wire to v5.5.0 by @renovate[bot] in #1649
- Clean up JB repos by @ZacSweers in #1650
- Fix IC issues discovered in 2.3.20 by @ZacSweers in #1651
- Link IR hint files with expect/actual tracker to avoid stale hints by @neworld in #1637
- Add @throws annotations on stubbed function bodies (with option) by @ZacSweers in #1654
- Do not report similar bindings when a missing binding has type
kotlin.Anyby @JoelWilcox in #1653 - Add metadata version to build + better validation by @ZacSweers in #1655
- Enable contributesAsInject by default by @ZacSweers in #1656
- Improve error message for missing bindings injected as members by @ZacSweers in #1657
- Work around abstract functions warning in native compilations by @ZacSweers in https:/...
0.9.4
Enhancements
- [IR] Support generation of scalar multibinding sets that use
@ElementsIntoSetsource bindings. Previously these would always use aSetFactoryunder the hood. - [IR] Refactor multibinding getter logic to align with all other binding field/getter logic, allowing more precise generation of multibindings based on different contextual needs (scalar,
Provider, etc representations).
Fixes
- [IR] Fix accidental potential for runtime eager calls to non-initialized bindings in some multi-level multibinding scenarios.
- [IR] Always use a provider field if multiple provider and scalar refs are found. Previously we would possibly use just a scalar getter field wrapped in
InstanceFactoryfor provider refs. - [IR / Dagger Interop] Ensure
@BindsOptionalOfbindings that are satisfied by scoped bindings use the scoped instance. - [IR / Reports] Don't de-dupe alias/memberinject bindings in graph metadata reports if one is already present.
Changes
- Remove
-checkdiscardrules from embedded proguard rules.
Contributors
Special thanks to the following contributors for contributing to this release!
What's Changed
- Update dependency pillow to v12.1.0 by @renovate[bot] in #1612
- Use fast* helpers more by @ZacSweers in #1613
- Add gc allocs to JMH results by @ZacSweers in #1614
- Tweak metro-only raw compilation + more profiler/gc data by @ZacSweers in #1619
- Remove fast* collection utils by @ZacSweers in #1620
- Clear compiler-test leaks by @ZacSweers in #1622
- Update kct to v0.12.1 by @renovate[bot] in #1623
- Grant more memory to tests + cleanup by @ZacSweers in #1628
- Update ProGuard rules for @ComptimeOnly classes by @chrisbanes in #1630
- Update kotlinInject to v0.9.0 by @renovate[bot] in #1631
- Update poko to v0.21.1 by @renovate[bot] in #1634
- Refactor multibinding getter property logic to BindingPropertyCollector by @ZacSweers in #1632
- Update dependency com.android.tools:r8 to v8.13.19 by @renovate[bot] in #1636
- Update adoption.md by @C2H6O in #1639
New Contributors
Full Changelog: 0.9.3...0.9.4
0.9.3
Happy new year!
Enhancements
- [FIR] Add diagnostic for multiple graph-like annotations on a single declaration.
- [IR] Stub
@Bindsexpressions in origin points rather than graphs. This reduces unnecessary extra generated functions. - [IR] Generate reusable getters for scalar-only dependencies that are used multiple times. This helps avoid
MethodTooLargeExceptionerrors in the JVM. - [IR] Detect suspicious member injections from inherited inject functions too.
- [IR] Don't try to validate graphs if
QualifierOverrideMismatcherrors were reported prior to graph validation. This helps reduce noise in failure cases, as it would otherwise also likely reportMissingBindingerrors caused by the source of theQualifierOverrideMismatcherror.
Fixes
- [FIR, Anvil Interop] Fix rank-based binding replacements getting dropped for multi-contribution classes in root graphs when contributions are from external modules.
- [FIR] Named annotation arguments in different order from declared parameters getting silently skipped.
- [FIR] Fix
Map<K, Provider<V>>parameters to@Providesfunctions mistakenly unwrapping the Provider value type. - [FIR] Disallow star projections in
@ElementsIntoSetbinding types. - [FIR] Require exactly one generic type argument
@ElementsIntoSetbinding types. - [IR, Anvil Interop] Fix rank-based binding replacements getting dropped for multi-contribution classes in graph extensions when contributions are from external modules.
- [IR] Prohibit duplicate map keys.
- [IR] Fix propagation of scoped multibinding sources to graph extensions.
- [IR] Don't eagerly validate duplicate bindings (only report them if used).
- [IC] Fix member injection metadata not always being written and causing IC issues with member inject function transformation.
- [Gradle] Report all tested Kotlin versions when emitting compatibility warnings.
Changes
- [FIR] Change
SUSPICIOUS_MEMBER_INJECT_FUNCTIONdiagnostic to be a warning instead of an error. - Remove testing of 2.3.0 pre-releases. IntelliJ stable currently builds off Kotlin
2.3.2xand Android Studio stable currently points to Kotlin2.2.2x.
Contributors
Special thanks to the following contributors for contributing to this release!
What's Changed
- Add multiplatform benchmark + regression benchmarks by @ZacSweers in #1553
- Update actions/setup-node action to v6 by @renovate[bot] in #1567
- Update actions/github-script action to v8 by @renovate[bot] in #1566
- Fan in brenchmark regression publishing by @ZacSweers in #1568
- Update dependency node to v24 by @renovate[bot] in #1569
- Update actions/download-artifact action to v7 by @renovate[bot] in #1570
- Extract repeatableAnnotationsIn() IR helper by @ZacSweers in #1573
- Only apply repeatable workaround in JVM platforms by @ZacSweers in #1574
- Add double-graph-like annotation diagnostic by @ZacSweers in #1575
- Simplify scenarios, add noop/vanilla, cleanups by @ZacSweers in #1576
- Update plugin buildConfig to v6.0.7 by @renovate[bot] in #1579
- Fix rank-based binding replacements getting dropped for multi-contribution classes in root graphs by @JoelWilcox in #1583
- More benchmark work by @ZacSweers in #1581
- Introduce
@ComptimeOnly+ stub binds in origin by @ZacSweers in #1582 - Move accesors to be contributed by @ZacSweers in #1585
- Add binary metrics + limit scenarios tested by @ZacSweers in #1586
- Fix bug preventing scope argument from being used in position other than first by @japplin in #1589
- Fix rank-based binding replacements getting dropped for multi-contribution classes in graph extensions by @JoelWilcox in #1584
- Fix duplicate map key checking by @ZacSweers in #1591
- Clean up tested versions by @ZacSweers in #1592
- Clarify error by @ZacSweers in #1593
- Fix reported aliases in gradle warnings by @ZacSweers in #1595
- Fix propagation of parent scoped multibindings to extensions by @ZacSweers in #1600
- Exclude jars-9 and transforms-3 caches by @ZacSweers in #1599
- Update dependency termcolor to v3.3.0 by @renovate[bot] in #1597
- Fix map providers in provides params by @ZacSweers in #1601
- Generate reusable getters for reused non-simple scalar bindings by @ZacSweers in #1602
- Update dependency com.facebook:ktfmt to v0.61 by @renovate[bot] in #1605
- Reconstruct type key for multibindings by @vRallev in #1603
- Ignore unused duplicate bindings by @vRallev in #1604
- Detect suspicious member injects in IR too by @ZacSweers in #1610
- Update dependency pymdown-extensions to v10.20 by @renovate[bot] in #1608
- Fix member injection metadata not always being written by @ZacSweers in #1611
Full Changelog: 0.9.2...0.9.3