Skip to content
This repository has been archived by the owner on Aug 19, 2020. It is now read-only.

KT-20635 - Kotlin plugin extension with a method accepting Action<in TYPE> method does not get inferred as SAM #522

Closed
mkobit opened this issue Oct 4, 2017 · 6 comments

Comments

@mkobit
Copy link
Contributor

mkobit commented Oct 4, 2017

Expected Behavior

  • Action<in TYPE> should behave same way in Groovy and Kotlin plugins
  • script authors should not have to cast lambdas for Action methods
  • Kotlin plugin authors should have clear documentation for either extension functions (().Type -> Unit) or using Action<> types for best behavior across both Groovy and Kotlin build scripts

Current Behavior

Running ./gradlew -s --scan with example project (steps shown at bottom to reproduce) results in exception for type mismatch.

Build output

e: /home/mkobit/Workspace/personal/mkobit/jenkins-pipeline-shared-library-example/build.gradle.kts:60:22: Type mismatch: inferred type is () -> Unit but Action<in PluginDependencySpec> was expected

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring root project 'jenkins-pipeline-shared-library-example'.
> Could not open cache directory 6z7hjh1lgsmu0365r759yuli3 (/home/mkobit/.gradle/caches/4.2.1/gradle-kotlin-dsl/6z7hjh1lgsmu0365r759yuli3).
   > Internal error: unable to compile script, see log for details

* Try:
Run with --info or --debug option to get more log output.

* Exception is:
org.gradle.api.ProjectConfigurationException: A problem occurred configuring root project 'jenkins-pipeline-shared-library-example'.
	at org.gradle.configuration.project.LifecycleProjectEvaluator.addConfigurationFailure(LifecycleProjectEvaluator.java:94)
	at org.gradle.configuration.project.LifecycleProjectEvaluator.doConfigure(LifecycleProjectEvaluator.java:66)
	at org.gradle.configuration.project.LifecycleProjectEvaluator.access$100(LifecycleProjectEvaluator.java:34)
	at org.gradle.configuration.project.LifecycleProjectEvaluator$ConfigureProject.run(LifecycleProjectEvaluator.java:110)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
	at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:50)
	at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:656)
	at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:135)
	at org.gradle.execution.TaskPathProjectEvaluator.configure(TaskPathProjectEvaluator.java:35)
	at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:60)
	at org.gradle.configuration.DefaultBuildConfigurer.configure(DefaultBuildConfigurer.java:38)
	at org.gradle.initialization.DefaultGradleLauncher$ConfigureBuild.run(DefaultGradleLauncher.java:249)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
	at org.gradle.initialization.DefaultGradleLauncher.configureBuild(DefaultGradleLauncher.java:167)
	at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:126)
	at org.gradle.initialization.DefaultGradleLauncher.executeTasks(DefaultGradleLauncher.java:109)
	at org.gradle.internal.invocation.GradleBuildController$1.call(GradleBuildController.java:78)
	at org.gradle.internal.invocation.GradleBuildController$1.call(GradleBuildController.java:75)
	at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:152)
	at org.gradle.internal.invocation.GradleBuildController.doBuild(GradleBuildController.java:100)
	at org.gradle.internal.invocation.GradleBuildController.run(GradleBuildController.java:75)
	at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:28)
	at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
	at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$1.run(RunAsBuildOperationBuildActionRunner.java:43)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:40)
	at org.gradle.tooling.internal.provider.SubscribableBuildActionRunner.run(SubscribableBuildActionRunner.java:51)
	at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:47)
	at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:30)
	at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:39)
	at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:25)
	at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:80)
	at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:53)
	at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:57)
	at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:32)
	at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:36)
	at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:25)
	at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:43)
	at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:29)
	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:64)
	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:29)
	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:59)
	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:44)
	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:45)
	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:30)
	at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:67)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
	at org.gradle.util.Swapper.swap(Swapper.java:38)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:62)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:82)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
	at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:295)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
Caused by: org.gradle.cache.CacheOpenException: Could not open cache directory 6z7hjh1lgsmu0365r759yuli3 (/home/mkobit/.gradle/caches/4.2.1/gradle-kotlin-dsl/6z7hjh1lgsmu0365r759yuli3).
	at org.gradle.cache.internal.DefaultPersistentDirectoryStore.open(DefaultPersistentDirectoryStore.java:61)
	at org.gradle.cache.internal.DefaultPersistentDirectoryStore.open(DefaultPersistentDirectoryStore.java:32)
	at org.gradle.cache.internal.DefaultCacheFactory.doOpen(DefaultCacheFactory.java:90)
	at org.gradle.cache.internal.DefaultCacheFactory.open(DefaultCacheFactory.java:64)
	at org.gradle.cache.internal.DefaultCacheRepository$PersistentCacheBuilder.open(DefaultCacheRepository.java:123)
	at org.gradle.kotlin.dsl.cache.ScriptCache.cacheDirFor(ScriptCache.kt:51)
	at org.gradle.kotlin.dsl.cache.ScriptCache.cacheDirFor$default(ScriptCache.kt:43)
	at org.gradle.kotlin.dsl.provider.CachingKotlinCompiler.cacheDirFor(CachingKotlinCompiler.kt:170)
	at org.gradle.kotlin.dsl.provider.CachingKotlinCompiler.compileScript(CachingKotlinCompiler.kt:131)
	at org.gradle.kotlin.dsl.provider.CachingKotlinCompiler.compileBuildScript(CachingKotlinCompiler.kt:111)
	at org.gradle.kotlin.dsl.provider.KotlinBuildScriptCompiler.compileScriptFile(KotlinBuildScriptCompiler.kt:242)
	at org.gradle.kotlin.dsl.provider.KotlinBuildScriptCompiler.executeScriptBodyOn(KotlinBuildScriptCompiler.kt:114)
	at org.gradle.kotlin.dsl.provider.KotlinBuildScriptCompiler.prepareAndExecuteScriptBodyOn(KotlinBuildScriptCompiler.kt:108)
	at org.gradle.kotlin.dsl.provider.KotlinBuildScriptCompiler.access$prepareAndExecuteScriptBodyOn(KotlinBuildScriptCompiler.kt:51)
	at org.gradle.kotlin.dsl.provider.KotlinBuildScriptCompiler$compileTopLevelScript$1.invoke(KotlinBuildScriptCompiler.kt:91)
	at org.gradle.kotlin.dsl.provider.KotlinBuildScriptCompiler$compileTopLevelScript$1.invoke(KotlinBuildScriptCompiler.kt:51)
	at org.gradle.kotlin.dsl.provider.KotlinScriptPlugin.apply(KotlinScriptPlugin.kt:48)
	at org.gradle.configuration.BuildOperationScriptPlugin$1.run(BuildOperationScriptPlugin.java:61)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
	at org.gradle.configuration.BuildOperationScriptPlugin.apply(BuildOperationScriptPlugin.java:58)
	at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:41)
	at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:26)
	at org.gradle.configuration.project.ConfigureActionsProjectEvaluator.evaluate(ConfigureActionsProjectEvaluator.java:34)
	at org.gradle.configuration.project.LifecycleProjectEvaluator.doConfigure(LifecycleProjectEvaluator.java:64)
	... 80 more
Caused by: java.lang.IllegalStateException: Internal error: unable to compile script, see log for details
	at org.gradle.kotlin.dsl.support.KotlinCompilerKt.compileKotlinScriptToDirectory(KotlinCompiler.kt:84)
	at org.gradle.kotlin.dsl.provider.CachingKotlinCompiler$compileScriptTo$$inlined$run$lambda$1.invoke(CachingKotlinCompiler.kt:155)
	at org.gradle.kotlin.dsl.provider.CachingKotlinCompiler$compileScriptTo$$inlined$run$lambda$1.invoke(CachingKotlinCompiler.kt:47)
	at org.gradle.kotlin.dsl.provider.CachingKotlinCompiler.withProgressLoggingFor(CachingKotlinCompiler.kt:216)
	at org.gradle.kotlin.dsl.provider.CachingKotlinCompiler.compileScriptTo(CachingKotlinCompiler.kt:153)
	at org.gradle.kotlin.dsl.provider.CachingKotlinCompiler.access$compileScriptTo(CachingKotlinCompiler.kt:47)
	at org.gradle.kotlin.dsl.provider.CachingKotlinCompiler$compileScript$cacheDir$1.invoke(CachingKotlinCompiler.kt:133)
	at org.gradle.kotlin.dsl.provider.CachingKotlinCompiler$compileScript$cacheDir$1.invoke(CachingKotlinCompiler.kt:47)
	at org.gradle.kotlin.dsl.cache.ScriptCacheKt$sam$Action$904ef041.execute(ScriptCache.kt)
	at org.gradle.cache.internal.DefaultPersistentDirectoryCache$Initializer.initialize(DefaultPersistentDirectoryCache.java:106)
	at org.gradle.cache.internal.FixedSharedModeCrossProcessCacheAccess$1.run(FixedSharedModeCrossProcessCacheAccess.java:85)
	at org.gradle.cache.internal.DefaultFileLockManager$DefaultFileLock.doWriteAction(DefaultFileLockManager.java:196)
	at org.gradle.cache.internal.DefaultFileLockManager$DefaultFileLock.writeFile(DefaultFileLockManager.java:186)
	at org.gradle.cache.internal.FixedSharedModeCrossProcessCacheAccess.open(FixedSharedModeCrossProcessCacheAccess.java:83)
	at org.gradle.cache.internal.DefaultCacheAccess.open(DefaultCacheAccess.java:141)
	at org.gradle.cache.internal.DefaultPersistentDirectoryStore.open(DefaultPersistentDirectoryStore.java:59)
	... 106 more


* Get more help at https://help.gradle.org

BUILD FAILED in 2s

The build scan was not published due to a configuration problem.

The Gradle Cloud Services license agreement has not been agreed to.

To agree to the license, include the following in your root project's configuration:
buildScan { licenseAgreementUrl = 'https://gradle.com/terms-of-service'; licenseAgree = 'yes' }

For more information, please see https://gradle.com/scans/help/plugin-license.

Alternatively, if you are using Gradle Enterprise, specify the server location.
For more information, please see https://gradle.com/scans/help/plugin-enterprise-config.

Context

Writing a plugin in Kotlin and wanted to provided a friendly DSL for both Groovy and Kotlin.
I believe that in order to get the friendly DSL in both Groovy and Kotlin an Action<? super TYPE> method and TYPE.() -> Unit methods have to be added (not 100% on that).

Steps to Reproduce (for bugs)

Your Environment

  • Gradle 4.2.1
  • Build scan URL:

NOTE: Cannot build scan in this fashion with invalid a compiler failure in build script

mkobit added a commit to mkobit/jenkins-pipeline-shared-libraries-gradle-plugin that referenced this issue Oct 5, 2017
@eskatos
Copy link
Member

eskatos commented Oct 5, 2017

Thanks for the report @mkobit!
I just confirmed locally, that's unfortunate.
We'll look into this.

bamboo added a commit to bamboo/kotlin-sam-with-receiver-repro that referenced this issue Oct 5, 2017
`Action<T>` combined with `SamWithReceiverAnnotations` should cause
the Kotlin compiler to always treat `Action<T>` as an alias to
`T.() -> Unit`, in other words:

```kotlin
typealias Action<T> = T.() -> Unit
```

Unfortunately that's currently not always the case and it depends on
whether the callee is defined in Kotlin or not.

When the callee is defined in Kotlin, trying to pass a lambda
expression where a, say, `Action<CopySpec>` is expected will result in
the following error:

```
Error: Type mismatch: inferred type is () -> ??? but Action<CopySpec> was expected
```

See gradle/kotlin-dsl-samples#522
@bamboo
Copy link
Member

bamboo commented Oct 5, 2017

I've updated my SamWithReceiver playground project to demonstrate the issue in the Kotlin compiler.

Action<T> combined with SamWithReceiverAnnotations should cause the Kotlin compiler to always treat Action<T> as an alias to T.() -> Unit, in other words:

typealias Action<T> = T.() -> Unit

Unfortunately that's currently not always the case and it depends on whether the callee is defined in Kotlin or not.

When the callee is defined in Kotlin, trying to pass a lambda expression where a, say, Action<CopySpec> is expected will result in the following error:

Error: Type mismatch: inferred type is () -> ??? but Action<CopySpec> was expected

@bamboo
Copy link
Member

bamboo commented Oct 5, 2017

Kotlin YouTrack issue

mkobit added a commit to mkobit/detekt that referenced this issue Nov 14, 2017
…citly needed cast for profile configuration

The `Action {}` cast is unforunately needed right now for plugins written in Kotlin.

issue gradle/kotlin-dsl-samples#522
Kotlin issue https://youtrack.jetbrains.com/issue/KT-20635
arturbosch pushed a commit to detekt/detekt that referenced this issue Nov 16, 2017
…citly needed cast for profile configuration

The `Action {}` cast is unforunately needed right now for plugins written in Kotlin.

issue gradle/kotlin-dsl-samples#522
Kotlin issue https://youtrack.jetbrains.com/issue/KT-20635
@eskatos eskatos changed the title Kotlin plugin extension with a method accepting Action<in TYPE> method does not get inferred as SAM KT-20635 - Kotlin plugin extension with a method accepting Action<in TYPE> method does not get inferred as SAM Jan 16, 2018
@eskatos eskatos added this to the 1.0.0 milestone Jan 19, 2018
@eskatos eskatos removed this from the 1.0.0 milestone May 15, 2018
@eskatos eskatos added this to the 1.0.0 milestone May 22, 2018
@ligee
Copy link
Collaborator

ligee commented Jun 14, 2018

@bamboo can it be worked around using the experimental feature introduced in the 1.2.50? To enable this you'll need to add -XXLanguage:+NewInference -XXLanguage:+SamConversionForKotlinFunctions to compiler parameters in all appropriate places.

@JLLeitschuh
Copy link
Contributor

@ligee Won't this mean that users of the Gradle Kotlin DSL will all suddenly get warnings in IntelliJ IDE for using unstable language features?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants