From 66916b03fef8898cf3a3fb1ede16d7a782638479 Mon Sep 17 00:00:00 2001 From: Tom Mulcahy Date: Wed, 10 Jun 2026 21:06:20 -0700 Subject: [PATCH 1/6] Use scoped contribution hints with Metro 1.2.0 --- ...ributesMultibindingScopedMetroExtension.kt | 68 ++----------------- gradle/libs.versions.toml | 2 +- 2 files changed, 8 insertions(+), 62 deletions(-) diff --git a/compiler/src/main/kotlin/com/squareup/metro/extensions/scoped/ContributesMultibindingScopedMetroExtension.kt b/compiler/src/main/kotlin/com/squareup/metro/extensions/scoped/ContributesMultibindingScopedMetroExtension.kt index 505272a..1df09db 100644 --- a/compiler/src/main/kotlin/com/squareup/metro/extensions/scoped/ContributesMultibindingScopedMetroExtension.kt +++ b/compiler/src/main/kotlin/com/squareup/metro/extensions/scoped/ContributesMultibindingScopedMetroExtension.kt @@ -1,41 +1,27 @@ package com.squareup.metro.extensions.scoped import com.fueledbycaffeine.autoservice.AutoService -import com.squareup.metro.extensions.fir.extractScopeClassId import dev.zacsweers.metro.compiler.MetroOptions import dev.zacsweers.metro.compiler.api.fir.MetroContributionExtension import dev.zacsweers.metro.compiler.compat.CompatContext import dev.zacsweers.metro.compiler.fir.MetroFirTypeResolver import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar -import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider -import org.jetbrains.kotlin.fir.resolve.defaultType -import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider -import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.name.ClassId /** - * Implements [MetroContributionExtension] to tell Metro's `ContributedInterfaceSupertypeGenerator` - * about contributions from our generated `MultibindingScopedContribution` interfaces. + * Registers the scoped multibinding predicate with Metro's contribution pipeline. * - * This is necessary because Metro's predicate-based provider only sees source declarations and - * declarations generated by generators that registered the predicate for `@ContributesTo`. Our - * `MultibindingScopedContribution` is generated by [ContributesMultibindingScopedFir] (which - * registered a predicate for `@ContributesMultibindingScoped`), so Metro's in-compilation discovery - * doesn't see it. + * Generated scoped multibinding contributions are binding containers. They are discovered through + * [ContributesMultibindingScopedFir.getContributionHints], not through synthetic + * `MetroContribution` supertypes, so this extension does not need to return contributions directly. */ -public class ContributesMultibindingScopedMetroExtension(private val session: FirSession) : +@Suppress("UNUSED_PARAMETER") +public class ContributesMultibindingScopedMetroExtension(session: FirSession) : MetroContributionExtension { private val predicate = ContributesMultibindingScopedIds.PREDICATE - private val annotatedClasses by lazy { - session.predicateBasedProvider - .getSymbolsByPredicate(predicate) - .filterIsInstance() - .toList() - } - override fun FirDeclarationPredicateRegistrar.registerPredicates() { register(predicate) } @@ -44,47 +30,7 @@ public class ContributesMultibindingScopedMetroExtension(private val session: Fi scopeClassId: ClassId, typeResolverFactory: MetroFirTypeResolver.Factory, ): List { - return annotatedClasses.flatMap { parentSymbol -> - val annotationScopeClassId = - extractScopeClassId( - parentSymbol, - ContributesMultibindingScopedIds.CONTRIBUTES_MULTIBINDING_SCOPED_CLASS_ID, - session, - ) ?: return@flatMap emptyList() - - if (annotationScopeClassId != scopeClassId) return@flatMap emptyList() - - val contributionInterfaceClassId = - ContributesMultibindingScopedIds.contributionClassId(parentSymbol.classId) - val holderClassId = ContributesMultibindingScopedIds.holderClassId(parentSymbol.classId) - - val contributionSymbol = - session.symbolProvider.getClassLikeSymbolByClassId(contributionInterfaceClassId) - as? FirRegularClassSymbol - val holderSymbol = - session.symbolProvider.getClassLikeSymbolByClassId(holderClassId) as? FirRegularClassSymbol - - buildList { - if (holderSymbol != null) { - add( - MetroContributionExtension.Contribution( - supertype = holderSymbol.defaultType(), - replaces = emptyList(), - originClassId = holderClassId, - ) - ) - } - if (contributionSymbol != null) { - add( - MetroContributionExtension.Contribution( - supertype = contributionSymbol.defaultType(), - replaces = emptyList(), - originClassId = contributionInterfaceClassId, - ) - ) - } - } - } + return emptyList() } @AutoService(MetroContributionExtension.Factory::class) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4b5c055..826fee7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ jdk = "21" kotlin = "2.3.21" ktfmt = "0.26.0" maven-publish = "0.36.0" -metro = "1.1.1" +metro = "1.2.0" [libraries] kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" } From 5d5d96ff2eef3ed024498981932f61a479c71f46 Mon Sep 17 00:00:00 2001 From: Tom Mulcahy Date: Thu, 11 Jun 2026 13:18:14 -0700 Subject: [PATCH 2/6] remove ContributesMultibindingScopedMetroExtension --- compiler/api/compiler.api | 11 ----- .../ContributesMultibindingScopedIds.kt | 5 +- ...ributesMultibindingScopedMetroExtension.kt | 46 ------------------- 3 files changed, 2 insertions(+), 60 deletions(-) delete mode 100644 compiler/src/main/kotlin/com/squareup/metro/extensions/scoped/ContributesMultibindingScopedMetroExtension.kt diff --git a/compiler/api/compiler.api b/compiler/api/compiler.api index ac9fc53..59330f0 100644 --- a/compiler/api/compiler.api +++ b/compiler/api/compiler.api @@ -114,17 +114,6 @@ public final class com/squareup/metro/extensions/scoped/ContributesMultibindingS public fun create (Lorg/jetbrains/kotlin/fir/FirSession;Ldev/zacsweers/metro/compiler/MetroOptions;Ldev/zacsweers/metro/compiler/compat/CompatContext;)Ldev/zacsweers/metro/compiler/api/fir/MetroFirDeclarationGenerationExtension; } -public final class com/squareup/metro/extensions/scoped/ContributesMultibindingScopedMetroExtension : dev/zacsweers/metro/compiler/api/fir/MetroContributionExtension { - public fun (Lorg/jetbrains/kotlin/fir/FirSession;)V - public fun getContributions (Lorg/jetbrains/kotlin/name/ClassId;Ldev/zacsweers/metro/compiler/fir/MetroFirTypeResolver$Factory;)Ljava/util/List; - public fun registerPredicates (Lorg/jetbrains/kotlin/fir/extensions/FirDeclarationPredicateRegistrar;)V -} - -public final class com/squareup/metro/extensions/scoped/ContributesMultibindingScopedMetroExtension$Factory : dev/zacsweers/metro/compiler/api/fir/MetroContributionExtension$Factory { - public fun ()V - public fun create (Lorg/jetbrains/kotlin/fir/FirSession;Ldev/zacsweers/metro/compiler/MetroOptions;Ldev/zacsweers/metro/compiler/compat/CompatContext;)Ldev/zacsweers/metro/compiler/api/fir/MetroContributionExtension; -} - public final class com/squareup/metro/extensions/service/ContributesServiceFir : dev/zacsweers/metro/compiler/api/fir/MetroFirDeclarationGenerationExtension { public fun (Lorg/jetbrains/kotlin/fir/FirSession;)V public fun generateConstructors (Lorg/jetbrains/kotlin/fir/extensions/DeclarationGenerationContext$Member;)Ljava/util/List; diff --git a/compiler/src/main/kotlin/com/squareup/metro/extensions/scoped/ContributesMultibindingScopedIds.kt b/compiler/src/main/kotlin/com/squareup/metro/extensions/scoped/ContributesMultibindingScopedIds.kt index f617b75..416842f 100644 --- a/compiler/src/main/kotlin/com/squareup/metro/extensions/scoped/ContributesMultibindingScopedIds.kt +++ b/compiler/src/main/kotlin/com/squareup/metro/extensions/scoped/ContributesMultibindingScopedIds.kt @@ -8,9 +8,8 @@ import org.jetbrains.kotlin.name.Name /** * Shared identifiers for the `@ContributesMultibindingScoped` compiler plugin support. * - * Used by both: - * - [ContributesMultibindingScopedFir] (FIR generator that creates the contribution interface) - * - [ContributesMultibindingScopedMetroExtension] (Metro extension that bridges predicate gap) + * Used by [ContributesMultibindingScopedFir] to create scoped binding containers and contribution + * hints. */ internal object ContributesMultibindingScopedIds { diff --git a/compiler/src/main/kotlin/com/squareup/metro/extensions/scoped/ContributesMultibindingScopedMetroExtension.kt b/compiler/src/main/kotlin/com/squareup/metro/extensions/scoped/ContributesMultibindingScopedMetroExtension.kt deleted file mode 100644 index 1df09db..0000000 --- a/compiler/src/main/kotlin/com/squareup/metro/extensions/scoped/ContributesMultibindingScopedMetroExtension.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.squareup.metro.extensions.scoped - -import com.fueledbycaffeine.autoservice.AutoService -import dev.zacsweers.metro.compiler.MetroOptions -import dev.zacsweers.metro.compiler.api.fir.MetroContributionExtension -import dev.zacsweers.metro.compiler.compat.CompatContext -import dev.zacsweers.metro.compiler.fir.MetroFirTypeResolver -import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar -import org.jetbrains.kotlin.name.ClassId - -/** - * Registers the scoped multibinding predicate with Metro's contribution pipeline. - * - * Generated scoped multibinding contributions are binding containers. They are discovered through - * [ContributesMultibindingScopedFir.getContributionHints], not through synthetic - * `MetroContribution` supertypes, so this extension does not need to return contributions directly. - */ -@Suppress("UNUSED_PARAMETER") -public class ContributesMultibindingScopedMetroExtension(session: FirSession) : - MetroContributionExtension { - - private val predicate = ContributesMultibindingScopedIds.PREDICATE - - override fun FirDeclarationPredicateRegistrar.registerPredicates() { - register(predicate) - } - - override fun getContributions( - scopeClassId: ClassId, - typeResolverFactory: MetroFirTypeResolver.Factory, - ): List { - return emptyList() - } - - @AutoService(MetroContributionExtension.Factory::class) - public class Factory : MetroContributionExtension.Factory { - override fun create( - session: FirSession, - options: MetroOptions, - compatContext: CompatContext, - ): MetroContributionExtension { - return ContributesMultibindingScopedMetroExtension(session) - } - } -} From 5eb445cf98bd26a4958d08b84ae7b8bc3803d73b Mon Sep 17 00:00:00 2001 From: Tom Mulcahy Date: Thu, 11 Jun 2026 13:37:33 -0700 Subject: [PATCH 3/6] Publish unique PR72 snapshot --- .github/workflows/ci.yml | 23 +++++++++++++++++++++++ gradle.properties | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 11156c0..f8dc7c3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -101,6 +101,29 @@ jobs: ./gradlew publishToMavenLocal --stacktrace --show-version --no-configuration-cache ./gradlew -p gradle-plugin publishToMavenLocal --stacktrace --show-version --no-configuration-cache + publish-pr72-snapshot: + if: ${{ github.event_name == 'pull_request' && github.event.pull_request.number == 72 && github.head_ref == 'tomm/use-scoped-contribution-hints' && github.repository == 'square/metro-extensions' }} + runs-on: ubuntu-latest + timeout-minutes: 60 + + steps: + - uses: actions/checkout@v6 + + - name: Setup + uses: ./.github/actions/setup-action + with: + gradle-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + + - name: Publish PR72 snapshot + run: | + ./gradlew clean publish -PRELEASE_SIGNING_ENABLED=true --no-build-cache --stacktrace --show-version --no-configuration-cache + ./gradlew -p gradle-plugin clean publish -PRELEASE_SIGNING_ENABLED=true --no-build-cache --stacktrace --show-version --no-configuration-cache + env: + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_CENTRAL_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_CENTRAL_PASSWORD }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_SECRET_KEY }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_SECRET_PASSPHRASE }} + build-logic: runs-on: ubuntu-latest timeout-minutes: 25 diff --git a/gradle.properties b/gradle.properties index e037cff..95caebb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=0.0.12-SNAPSHOT +VERSION_NAME=0.0.12-pr72-5d5d96f-SNAPSHOT GROUP=com.squareup.metro.extensions org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8 From 98d829adbca6e42a7261119a32ee62493c11ff5c Mon Sep 17 00:00:00 2001 From: Tom Mulcahy Date: Thu, 11 Jun 2026 13:42:25 -0700 Subject: [PATCH 4/6] Revert "Publish unique PR72 snapshot" This reverts commit 5eb445cf98bd26a4958d08b84ae7b8bc3803d73b. --- .github/workflows/ci.yml | 23 ----------------------- gradle.properties | 2 +- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8dc7c3..11156c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -101,29 +101,6 @@ jobs: ./gradlew publishToMavenLocal --stacktrace --show-version --no-configuration-cache ./gradlew -p gradle-plugin publishToMavenLocal --stacktrace --show-version --no-configuration-cache - publish-pr72-snapshot: - if: ${{ github.event_name == 'pull_request' && github.event.pull_request.number == 72 && github.head_ref == 'tomm/use-scoped-contribution-hints' && github.repository == 'square/metro-extensions' }} - runs-on: ubuntu-latest - timeout-minutes: 60 - - steps: - - uses: actions/checkout@v6 - - - name: Setup - uses: ./.github/actions/setup-action - with: - gradle-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} - - - name: Publish PR72 snapshot - run: | - ./gradlew clean publish -PRELEASE_SIGNING_ENABLED=true --no-build-cache --stacktrace --show-version --no-configuration-cache - ./gradlew -p gradle-plugin clean publish -PRELEASE_SIGNING_ENABLED=true --no-build-cache --stacktrace --show-version --no-configuration-cache - env: - ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_CENTRAL_USERNAME }} - ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_CENTRAL_PASSWORD }} - ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_SECRET_KEY }} - ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_SECRET_PASSPHRASE }} - build-logic: runs-on: ubuntu-latest timeout-minutes: 25 diff --git a/gradle.properties b/gradle.properties index 95caebb..e037cff 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=0.0.12-pr72-5d5d96f-SNAPSHOT +VERSION_NAME=0.0.12-SNAPSHOT GROUP=com.squareup.metro.extensions org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8 From eb86f3946d275a189448759ecb5fd332368a54f6 Mon Sep 17 00:00:00 2001 From: Tom Mulcahy Date: Thu, 11 Jun 2026 15:41:07 -0700 Subject: [PATCH 5/6] Publish Kotlin 2.3 PR72 snapshot --- .github/workflows/ci.yml | 25 +++++++++++++++++++++++++ gradle.properties | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 11156c0..4d6f072 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -101,6 +101,31 @@ jobs: ./gradlew publishToMavenLocal --stacktrace --show-version --no-configuration-cache ./gradlew -p gradle-plugin publishToMavenLocal --stacktrace --show-version --no-configuration-cache + publish-pr72-snapshot: + if: ${{ github.event_name == 'pull_request' && github.event.pull_request.number == 72 && github.head_ref == 'tomm/use-scoped-contribution-hints' && github.repository == 'square/metro-extensions' }} + runs-on: ubuntu-latest + timeout-minutes: 60 + + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - name: Setup + uses: ./.github/actions/setup-action + with: + gradle-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + + - name: Publish PR72 Kotlin 2.3.21 snapshot + run: | + ./gradlew clean publish -Pkotlin.version=2.3.21 -PRELEASE_SIGNING_ENABLED=true --no-build-cache --stacktrace --show-version --no-configuration-cache + ./gradlew -p gradle-plugin clean publish -Pkotlin.version=2.3.21 -PRELEASE_SIGNING_ENABLED=true --no-build-cache --stacktrace --show-version --no-configuration-cache + env: + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_CENTRAL_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_CENTRAL_PASSWORD }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_SECRET_KEY }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_SECRET_PASSPHRASE }} + build-logic: runs-on: ubuntu-latest timeout-minutes: 25 diff --git a/gradle.properties b/gradle.properties index e037cff..d8736a4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=0.0.12-SNAPSHOT +VERSION_NAME=0.0.12-pr72-5d5d96f-k2321-SNAPSHOT GROUP=com.squareup.metro.extensions org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8 From f40cbfdbe68a1b1982ff08b21077885a02d6c5f0 Mon Sep 17 00:00:00 2001 From: Tom Mulcahy Date: Thu, 11 Jun 2026 16:33:07 -0700 Subject: [PATCH 6/6] Fix deps --- .../extensions/services/FileSortingAssertionsService.kt | 9 +++++++++ gradle/libs.versions.toml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/src/test/kotlin/com/squareup/metro/extensions/services/FileSortingAssertionsService.kt b/compiler/src/test/kotlin/com/squareup/metro/extensions/services/FileSortingAssertionsService.kt index 3c69d28..bf0f214 100644 --- a/compiler/src/test/kotlin/com/squareup/metro/extensions/services/FileSortingAssertionsService.kt +++ b/compiler/src/test/kotlin/com/squareup/metro/extensions/services/FileSortingAssertionsService.kt @@ -1,6 +1,7 @@ package com.squareup.metro.extensions.services import java.io.File +import kotlin.time.Duration import org.jetbrains.kotlin.test.services.AssertionsService import org.jetbrains.kotlin.test.services.JUnit5Assertions @@ -104,6 +105,14 @@ object FileSortingAssertionsService : AssertionsService() { override fun assertAll(conditions: List<() -> Unit>) = delegate.assertAll(conditions) + override fun assertTimeoutPreemptively( + timeout: Duration, + message: () -> String, + action: () -> Unit, + ) { + delegate.assertTimeoutPreemptively(timeout, message, action) + } + override fun assertNotNull(value: Any?, message: (() -> String)?) { delegate.assertNotNull(value, message ?: { "" }) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 826fee7..728ab7c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -autoservice = "0.1.4" +autoservice = "0.1.5" binary-compat-validator = "0.18.1" buildconfig = "6.0.9" jdk = "21"