Skip to content

Update dependency dev.zacsweers.metro to v0.6.0 #178

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 17, 2025
Merged

Conversation

renovate[bot]
Copy link
Contributor

@renovate renovate bot commented Aug 16, 2025

This PR contains the following updates:

Package Change Age Confidence
dev.zacsweers.metro 0.5.5 -> 0.6.0 age confidence

Release Notes

ZacSweers/metro (dev.zacsweers.metro)

v0.6.0

Compare Source

2025-08-15

Graph extensions are no longer detached.

TL;DR: Metro graph extensions are now wired similar to Dagger subcomponents and use a new @GraphExtension annotation. @Extends and isExtendable are now deleted, @ContributesGraphExtension and enableScopedInjectClassHints() are deprecated.

Up to this point, Metro's graph extensions have been detached. This meant that extensions could simply depend on a parent graph via @Extends and parent graphs had to mark themselves as extendable via isExtendable = true. This approach mirrored kotlin-inject's approach and was convenient in its flexibility. However, it's proven too problematic in practice for a few reasons:

  1. Parent graphs have to generate a bunch of extra code for extensions. Namely, scoped providers and any instances of containers/parents they are holding on to need accessors. It also generates extra metadata (metro serializes its own metadata to its types) for separate graphs to read.
  2. Because of the above, parent graphs had to opt-in to extension via isExtendable = true.
  3. Up to this point, parent graphs always held scoped providers for all @Provides bindings in it or containers, even if they do not use them.
  4. Similar to #​3, we've had to add support for automatic discovery of scoped constructor-injected classes (via enableScopedInjectClassHints()) to ensure they are also held at the appropriate scope.
  5. This has ended up causing a lot of headaches because eager validation complicates these in scenarios where you have multiple graphs that may not actually use that class anywhere (and thus not provide some of its dependencies)
  6. Because every graph must expose every available binding to unknown extensions, every graph in a chain is often bloated with bindings it doesn't use.

Metro could optimize the @ContributesGraphExtension cases where Metro's compiler has a view of the entire graph chain, but that would frankly leave Metro with a lot of edge cases to deal with and users with needing to know about two different ways to extend graphs. We opted against that, and instead are now going to process graph extensions in a similar way to Dagger's subcomponents.

This will allow Metro to

  1. Fully optimize the whole graph chain.
  2. Automatically scope bindings in parents (no need to expose accessors for scoped bindings unused in parents).
  3. Only generate exactly the bindings that are used in each graph with lazy validation of bindings.
@GraphExtension

@GraphExtension is a new annotation to denote a graph that is an extension. This is analogous to Dagger's @Subcomponent and dagger interop treats it as such.

To connect an extension to a parent graph, you can do one of multiple ways:

  • Declare an accessor on the parent graph directly.
@​GraphExtension
interface LoggedInGraph

@​DependencyGraph
interface AppGraph {
  val loggedInGraph: LoggedInGraph
}
  • (If the extension has a creator) declare the creator on the parent graph directly.
@​GraphExtension
interface LoggedInGraph {
  @​GraphExtension.Factory
  interface Factory {
    fun createLoggedInGraph(): LoggedInGraph
  }
}

@​DependencyGraph
interface AppGraph {
  val loggedInGraphFactory: LoggedInGraph.Factory
}
  • (If the extension has a creator) make the parent graph implement the creator.
@​GraphExtension
interface LoggedInGraph {
  @​GraphExtension.Factory
  interface Factory {
    fun createLoggedInGraph(): LoggedInGraph
  }
}

@​DependencyGraph
interface AppGraph : LoggedInGraph.Factory
  • Contribute the factory to the parent graph via @ContributesTo.
@​GraphExtension(LoggedInScope::class)
interface LoggedInGraph {
  @​ContributesTo(AppScope::class)
  @​GraphExtension.Factory
  interface Factory {
    fun createLoggedInGraph(): LoggedInGraph
  }
}

@​DependencyGraph(AppScope::class)
interface AppGraph
Migration

The following APIs have been removed or deprecated:

  • @Extends. Migrate to @GraphExtension, remove this parameter, and expose the factory in the parent graph API as documented above.
  • isExtendable is removed from @DependencyGraph and @ContributesGraphExtension.
  • @ContributesGraphExtension is now deprecated and treated like @GraphExtension.
  • @ContributesGraphExtension.Factory is deprecated with error severity and requires migration to the new @ContributesTo pattern.
  • enableScopedInjectClassHints() is now deprecated and does nothing. It will be removed in the future.
  • Graph extensions may no longer have multiple direct parents.

To create graph extensions, you now must do so via a parent graph (using one of the above connecting mechanisms).

Other changes
  • Breaking change: Rename custom-graph compiler option to custom-dependency-graph.
  • Breaking change: Rename custom-dependency-graph-factory compiler option to custom-dependency-graph-factory.
  • Breaking change: Rename MetroPluginExtension.graph gradle extension property to MetroPluginExtension.dependencyGraph.
  • Breaking change: Rename MetroPluginExtension.graphFactory gradle extension property to MetroPluginExtension.dependencyGraphFactory.
  • Behavior change: @Provides and @Binds bindings are now only validated if they are used by the owning graph. Previously, they were always validated.
    • If you want to keep the previous behavior, you can enable the enableStrictValidation() option.
  • Behavior change: chunkFieldInits() is now enabled by default.
  • Behavior change: When adding bindings from extended parent graphs, ignore any that are provided directly in the child graph. Previously, Metro only ignored the binding if the binding was itself a graph type.
  • New: Add diagnostic reports for (valid) cycles. This means if you have a cycle in your graph and enable a reportsDestination, Metro will generate files with a list of all the keys in that cycle.
  • Enhancement: In tracing logs, include the graph name in the "Transform dependency graph" sections.
  • Enhancement: Allow contributing annotations on assisted-injected classes.
  • Enhancement: Improve dagger interop with dagger.Lazy types by allowing Provider subtypes to be wrapped too.
  • Enhancement: Support rank interop on Anvil annotations in contributed graph extensions.
  • Enhancement: Support ignoreQualifier interop on Anvil annotations in contributed graph extensions.
  • Enhancement: Only process contributions to the consuming graph's scopes when processing rank replacements in FIR.
  • Enhancement: Improve error message for invalid assisted inject bindings to injected target.
  • Enhancement: Report similar bindings in missing binding errors where the similar binding doesn't have a qualifier but the requested binding does. Previously we only reported if the similar binding had a qualifier and the requested binding didn't.
  • Fix: Don't link expect/actual declarations if they're in the same file.
  • Fix: Don't copy map keys over into generated @Binds contributions unless it's an @IntoMap binding.
  • Fix: Fall back to annotation sources if needed when reporting errors with bound types in FIR.
  • Fix: Use MapProviderFactory.builder().build() for Dagger interop on Map<Key, Provider<Value>> types as there is no MapProviderFactory.empty().
  • Fix: Don't assume @ContributesGraphExtension to have aggregation scopes during graph generation.
  • Fix: When extending graphs, ignore bindings of the same type as the inheriting graph.
  • Fix: Propagate parent graph empty @Multibinds declarations to extensions.
  • Fix: Propagate managed binding containers to extension graphs.
  • Fix: Propagate transitively included binding containers contributed to contributed graphs (sorry, word soup).
  • Fix: Make generated multibinding element IDs stable across compilations.
  • Fix: Handle location-less declarations when reporting invalid assisted inject bindings.
  • Fix: Don't chunk parent graph validation statements as these must be in the original constructor body.
  • Fix: Fix wrong receiver context for chunked field initializers.
  • Fix: Fix support for generic private injected constructors.
  • [internal change] Simplify metadata and just use accessor annotations.
  • [internal change] Graph extension impls are now generated as nested classes within the generated metro graph that they are contributed to.
  • Update to Kotlin 2.2.10.

Special thanks to @​hossain-khan, @​Egorand, @​kevinguitar, @​jonapoul, and @​martinbonnin for contributing to this release!


Configuration

📅 Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@hossain-khan hossain-khan merged commit 27dc535 into main Aug 17, 2025
5 checks passed
@hossain-khan hossain-khan deleted the renovate/metro branch August 17, 2025 03:41
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