square / anvil

A Kotlin compiler plugin to make dependency injection with Dagger 2 easier.
Apache License 2.0
1.31k stars 81 forks source link

2.4.4 is incompatible with KotlinPoet 1.13.x due to `TypeName.equals()` changes. #706

Closed ZacSweers closed 1 year ago

ZacSweers commented 1 year ago

KotlinPoet changed semantics about how TypeName.equals() works in its 1.13.0 release, so I suspect there is an issue in anvil where it's using equals where it should be just comparing something more specific.

We did a similar fix in moshi here: square/moshi@3d3c327 (#1614).

Our actual error appears to similarly involve type variables

e: com.squareup.anvil.compiler.api.AnvilCompilationException: Back-end (JVM) Internal error: The parameters in the factory method must match the @Assisted parameters in slack.workmanager.workers.SampleWorker.
--
  | File being compiled: (29,30) in /var/lib/buildkite-agent/builds/mbr-buildkite-agent-android-iad-zika-1/slack/android-pull-request/services/work-manager/src/main/kotlin/slack/workmanager/workers/SampleWorker.kt
  |  
  | at com.squareup.anvil.compiler.internal.reference.ClassReferenceKt.AnvilCompilationExceptionClassReference(ClassReference.kt:416)
  | at com.squareup.anvil.compiler.internal.reference.ClassReferenceKt.AnvilCompilationExceptionClassReference$default(ClassReference.kt:411)
  | at com.squareup.anvil.compiler.codegen.dagger.AssistedFactoryGenerator.generateFactoryClass(AssistedFactoryGenerator.kt:144)
  | at com.squareup.anvil.compiler.codegen.dagger.AssistedFactoryGenerator.generateCodePrivate(AssistedFactoryGenerator.kt:59)
  | at com.squareup.anvil.compiler.codegen.PrivateCodeGenerator.generateCode(PrivateCodeGenerator.kt:21)
  | at com.squareup.anvil.compiler.codegen.CodeGenerationExtension.analysisCompleted$generateCode(CodeGenerationExtension.kt:104)
  | at com.squareup.anvil.compiler.codegen.CodeGenerationExtension.analysisCompleted(CodeGenerationExtension.kt:151)
  | at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM$analyzeFilesWithJavaIntegration$2.invoke(TopDownAnalyzerFacadeForJVM.kt:115)
  | at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:125)
  | at

Where the sample code is like this

@WorkRequestIn(UserScope::class)
class SampleWorker
@AssistedInject
constructor(
  @Assisted appContext: Context,
  @Assisted params: WorkerParameters,
  private val tracer: Tracer
) : CoroutineWorker(appContext, params) {

  @AssistedFactory interface Factory : AssistedWorkerFactory<SampleWorker>
}

// Defined elsewhere
interface AssistedWorkerFactory<T : ListenableWorker> {
  fun create(context: Context, params: WorkerParameters): T
}
JoelWilcox commented 1 year ago

This looks like it might be a duplicate of https://github.com/square/anvil/issues/699 and fixed by https://github.com/square/anvil/pull/700. Can you test with 2.4.6-SNAPSHOT?

ZacSweers commented 1 year ago

It seems to get farther, but looks like there's another issue now where Anvil is generating code with compiler errors. Will dig in more and report back once I have a local version and can look at the generated file

ZacSweers commented 1 year ago

This appears to be a bug in kotlinpoet. Will talk with @egorand

This file

package slack.services.debugmenu.`impl`.presenters

import com.slack.circuit.runtime.CircuitContext
import com.slack.circuit.runtime.Navigator
import com.slack.circuit.runtime.Screen
import com.slack.circuit.runtime.presenter.Presenter
import com.squareup.anvil.annotations.ContributesMultibinding
import javax.inject.Inject
import slack.di.UserScope
import slack.services.debugmenu.`impl`.screens.DebugMenuCircuitScreen

@ContributesMultibinding(UserScope::class)
public class DebugMenuPresenterFactory @Inject constructor(
  private val factory: DebugMenuPresenter.Factory,
) : Presenter.Factory {
  public override fun create(
    screen: Screen,
    navigator: Navigator,
    context: CircuitContext,
  ): Presenter<*>? = when (screen) {
    DebugMenuCircuitScreen -> factory.create(navigator = navigator)
    else -> null
  }
}

Produces this anvil code

// Generated by Anvil.
// https://github.com/square/anvil
@file:Suppress(
  "DEPRECATION",
  "OPT_IN_USAGE",
  "OPT_IN_USAGE_ERROR",
)

package slack.services.debugmenu.`impl`.presenters

import javax.inject.Provider
import kotlin.Suppress
import kotlin.jvm.JvmStatic
import slack.services.debugmenu.`impl`.presenters.DebugMenuPresenterFactory
import dagger.`internal`.Factory as InternalFactory
import slack.services.debugmenu.`impl`.presenters.DebugMenuPresenter.Factory as DebugMenuPresenterFactory

public class DebugMenuPresenterFactory_Factory(
  private val factory:
      Provider<slack.services.debugmenu.`impl`.presenters.DebugMenuPresenter.Factory>,
) : InternalFactory<DebugMenuPresenterFactory> {
  public override fun `get`(): DebugMenuPresenterFactory = newInstance(factory.get())

  public companion object {
    @JvmStatic
    public
        fun create(factory: Provider<slack.services.debugmenu.`impl`.presenters.DebugMenuPresenter.Factory>):
        slack.services.debugmenu.`impl`.presenters.DebugMenuPresenterFactory_Factory =
        slack.services.debugmenu.`impl`.presenters.DebugMenuPresenterFactory_Factory(factory)

    @JvmStatic
    public
        fun newInstance(factory: slack.services.debugmenu.`impl`.presenters.DebugMenuPresenter.Factory):
        DebugMenuPresenterFactory = DebugMenuPresenterFactory(factory)
  }
}
JoelWilcox commented 1 year ago

This appears to be a bug in kotlinpoet. Will talk with @Egorand

:+1: Not immediately seeing the issue in the snippet you shared but lmk how the conversation goes / if it looks like we also need changes on the Anvil side