Always compile non-incrementally if incremental state is missing
Test: Updated IncrementalCompilationClasspathSnapshotJvmMultiProjectIT.
.testMissingIncrementalState
^KT-53231 Fixed
This commit is contained in:
+1
@@ -170,6 +170,7 @@ abstract class IncrementalCompilerRunner<
|
|||||||
when (compilationMode) {
|
when (compilationMode) {
|
||||||
is CompilationMode.Incremental -> {
|
is CompilationMode.Incremental -> {
|
||||||
try {
|
try {
|
||||||
|
reporter.debug { "Performing incremental compilation" }
|
||||||
val exitCode = if (withAbiSnapshot) {
|
val exitCode = if (withAbiSnapshot) {
|
||||||
compileIncrementally(
|
compileIncrementally(
|
||||||
args, caches, allSourceFiles, compilationMode, messageCollector,
|
args, caches, allSourceFiles, compilationMode, messageCollector,
|
||||||
|
|||||||
+1
-3
@@ -160,11 +160,9 @@ class BuildCacheIT : KGPBaseTest() {
|
|||||||
bKtSourceFile.modify { it.replace("fun b() {}", "fun b() {}\nfun b2() {}") }
|
bKtSourceFile.modify { it.replace("fun b() {}", "fun b() {}\nfun b2() {}") }
|
||||||
|
|
||||||
build("assemble", buildOptions = defaultBuildOptions.copy(useICClasspathSnapshot = true, logLevel = LogLevel.DEBUG)) {
|
build("assemble", buildOptions = defaultBuildOptions.copy(useICClasspathSnapshot = true, logLevel = LogLevel.DEBUG)) {
|
||||||
assertOutputDoesNotContain(NON_INCREMENTAL_COMPILATION_WILL_BE_PERFORMED)
|
assertIncrementalCompilation(expectedCompiledKotlinFiles = setOf(bKtSourceFile).map { it.relativeTo(projectPath)})
|
||||||
assertOutputContains("Incremental compilation with ABI snapshot enabled")
|
assertOutputContains("Incremental compilation with ABI snapshot enabled")
|
||||||
assertCompiledKotlinSources(setOf(bKtSourceFile).map { it.relativeTo(projectPath)}, output)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-7
@@ -2,7 +2,6 @@ package org.jetbrains.kotlin.gradle
|
|||||||
|
|
||||||
import org.gradle.testkit.runner.BuildResult
|
import org.gradle.testkit.runner.BuildResult
|
||||||
import org.gradle.util.GradleVersion
|
import org.gradle.util.GradleVersion
|
||||||
import org.jetbrains.kotlin.build.report.metrics.BuildAttribute
|
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy
|
||||||
import org.jetbrains.kotlin.gradle.testbase.*
|
import org.jetbrains.kotlin.gradle.testbase.*
|
||||||
import org.jetbrains.kotlin.gradle.util.checkedReplace
|
import org.jetbrains.kotlin.gradle.util.checkedReplace
|
||||||
@@ -658,7 +657,9 @@ abstract class BaseIncrementalCompilationMultiProjectIT : IncrementalCompilation
|
|||||||
":lib:compileKotlin",
|
":lib:compileKotlin",
|
||||||
"-Pkotlin.compiler.execution.strategy=${KotlinCompilerExecutionStrategy.IN_PROCESS.propertyValue}"
|
"-Pkotlin.compiler.execution.strategy=${KotlinCompilerExecutionStrategy.IN_PROCESS.propertyValue}"
|
||||||
) {
|
) {
|
||||||
assert(projectPath.resolve("lib/build/kotlin/${compileKotlinTaskName}/classpath-snapshot").listDirectoryEntries().isEmpty())
|
projectPath.resolve("lib/build/kotlin/${compileKotlinTaskName}/classpath-snapshot").let {
|
||||||
|
assert(!it.exists() || it.listDirectoryEntries().isEmpty())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the next build using Kotlin daemon without making a change and check that tasks are up-to-date. This is to ensure
|
// Perform the next build using Kotlin daemon without making a change and check that tasks are up-to-date. This is to ensure
|
||||||
@@ -673,7 +674,7 @@ abstract class BaseIncrementalCompilationMultiProjectIT : IncrementalCompilation
|
|||||||
|
|
||||||
// In the next build, compilation should be non-incremental as incremental state is missing
|
// In the next build, compilation should be non-incremental as incremental state is missing
|
||||||
build(":lib:compileKotlin") {
|
build(":lib:compileKotlin") {
|
||||||
assertNonIncrementalCompilation(BuildAttribute.INCREMENTAL_COMPILATION_FAILED)
|
assertNonIncrementalCompilation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -692,11 +693,11 @@ abstract class BaseIncrementalCompilationMultiProjectIT : IncrementalCompilation
|
|||||||
it.replace("fun a() {}", "fun a() { // Compile error: Missing closing bracket")
|
it.replace("fun a() {}", "fun a() { // Compile error: Missing closing bracket")
|
||||||
}
|
}
|
||||||
|
|
||||||
// In the next build, compilation should be incremental and fail, and not fall back to non-incremental compilation
|
// In the next build, compilation should be incremental and fail (and not fall back to non-incremental compilation)
|
||||||
buildAndFail(":lib:compileKotlin") {
|
buildAndFail(":lib:compileKotlin") {
|
||||||
|
assertIncrementalCompilation()
|
||||||
assertTasksFailed(":lib:$compileKotlinTaskName")
|
assertTasksFailed(":lib:$compileKotlinTaskName")
|
||||||
assertOutputContains("Compilation error. See log for more details")
|
assertOutputContains("Compilation error. See log for more details")
|
||||||
assertOutputDoesNotContain(NON_INCREMENTAL_COMPILATION_WILL_BE_PERFORMED)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix the compile error in the source code
|
// Fix the compile error in the source code
|
||||||
@@ -734,7 +735,7 @@ abstract class BaseIncrementalCompilationMultiProjectIT : IncrementalCompilation
|
|||||||
|
|
||||||
// In the next build, compilation should be incremental and fail, then fall back to non-incremental compilation and succeed
|
// In the next build, compilation should be incremental and fail, then fall back to non-incremental compilation and succeed
|
||||||
build(":lib:compileKotlin") {
|
build(":lib:compileKotlin") {
|
||||||
assertNonIncrementalCompilation(BuildAttribute.INCREMENTAL_COMPILATION_FAILED)
|
assertIncrementalCompilationFellBackToNonIncremental()
|
||||||
// Also check that the output is not deleted (regression test for KT-49780)
|
// Also check that the output is not deleted (regression test for KT-49780)
|
||||||
assertFileExists(lookupFile)
|
assertFileExists(lookupFile)
|
||||||
}
|
}
|
||||||
@@ -746,7 +747,7 @@ abstract class BaseIncrementalCompilationMultiProjectIT : IncrementalCompilation
|
|||||||
"""
|
"""
|
||||||
$compileKotlinTaskName {
|
$compileKotlinTaskName {
|
||||||
doLast {
|
doLast {
|
||||||
new File("$lookupFile").write("Invalid contents")
|
new File("${lookupFile.toFile().invariantSeparatorsPath}").write("Invalid contents")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|||||||
+18
-3
@@ -96,6 +96,8 @@ fun BuildResult.assertNonIncrementalCompilation(reason: BuildAttribute? = null)
|
|||||||
} else {
|
} else {
|
||||||
assertOutputContains(NON_INCREMENTAL_COMPILATION_WILL_BE_PERFORMED)
|
assertOutputContains(NON_INCREMENTAL_COMPILATION_WILL_BE_PERFORMED)
|
||||||
}
|
}
|
||||||
|
// Also check that incremental compilation was not attempted, failed, and fell back to non-incremental compilation
|
||||||
|
assertOutputDoesNotContain(PERFORMING_INCREMENTAL_COMPILATION)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,11 +107,24 @@ fun BuildResult.assertNonIncrementalCompilation(reason: BuildAttribute? = null)
|
|||||||
*
|
*
|
||||||
* Note: Log level of output must be set to [LogLevel.DEBUG].
|
* Note: Log level of output must be set to [LogLevel.DEBUG].
|
||||||
*/
|
*/
|
||||||
fun BuildResult.assertIncrementalCompilation(expectedCompiledKotlinFiles: Iterable<Path>) {
|
fun BuildResult.assertIncrementalCompilation(expectedCompiledKotlinFiles: Iterable<Path>? = null) {
|
||||||
|
assertOutputContains(PERFORMING_INCREMENTAL_COMPILATION)
|
||||||
|
// Also check that incremental compilation did not fail and fall back to non-incremental compilation
|
||||||
assertOutputDoesNotContain(NON_INCREMENTAL_COMPILATION_WILL_BE_PERFORMED)
|
assertOutputDoesNotContain(NON_INCREMENTAL_COMPILATION_WILL_BE_PERFORMED)
|
||||||
|
|
||||||
val actualCompiledKotlinFiles = extractCompiledKotlinFiles(output)
|
expectedCompiledKotlinFiles?.let {
|
||||||
assertSameFiles(expectedCompiledKotlinFiles, actualCompiledKotlinFiles, "Compiled Kotlin files differ:\n")
|
assertSameFiles(expected = it, actual = extractCompiledKotlinFiles(output), "Compiled Kotlin files differ:\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that incremental compilation was attempted, failed, and fell back to non-incremental compilation.
|
||||||
|
*
|
||||||
|
* Note: Log level of output must be set to [LogLevel.DEBUG].
|
||||||
|
*/
|
||||||
|
fun BuildResult.assertIncrementalCompilationFellBackToNonIncremental() {
|
||||||
|
assertOutputContains("$NON_INCREMENTAL_COMPILATION_WILL_BE_PERFORMED: ${BuildAttribute.INCREMENTAL_COMPILATION_FAILED.name}")
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val PERFORMING_INCREMENTAL_COMPILATION = "Performing incremental compilation"
|
||||||
const val NON_INCREMENTAL_COMPILATION_WILL_BE_PERFORMED = "Non-incremental compilation will be performed"
|
const val NON_INCREMENTAL_COMPILATION_WILL_BE_PERFORMED = "Non-incremental compilation will be performed"
|
||||||
|
|||||||
+10
-7
@@ -844,16 +844,19 @@ abstract class KotlinCompile @Inject constructor(
|
|||||||
)
|
)
|
||||||
when {
|
when {
|
||||||
!inputChanges.isIncremental -> NotAvailableForNonIncrementalRun(classpathSnapshotFiles)
|
!inputChanges.isIncremental -> NotAvailableForNonIncrementalRun(classpathSnapshotFiles)
|
||||||
inputChanges.getFileChanges(classpathSnapshotProperties.classpathSnapshot).none() -> NoChanges(classpathSnapshotFiles)
|
// When `inputChanges.isIncremental == true`, we want to compile incrementally. However, if the incremental state (e.g.
|
||||||
|
// lookup caches or previous classpath snapshot) is missing, we need to compile non-incrementally. There are a few cases:
|
||||||
|
// 1. Previous compilation happened using Kotlin daemon and with IC enabled (the usual case) => Incremental state
|
||||||
|
// including classpath snapshot must have been produced (we have that guarantee in `IncrementalCompilerRunner`).
|
||||||
|
// 2. Previous compilation happened using Kotlin daemon but with IC disabled (e.g., by setting `kotlin.incremental=false`)
|
||||||
|
// => This run will have `inputChanges.isIncremental = false` as `isIncrementalCompilationEnabled` is a task input.
|
||||||
|
// 3. Previous compilation happened without using Kotlin daemon (set by the user or caused by a fallback).
|
||||||
|
// 4. Previous compilation was skipped because there were no sources to compile (see `AbstractKotlinCompile.executeImpl`).
|
||||||
|
// In case 3 and 4, it is possible that `inputChanges.isIncremental == true` in this run and incremental state is missing.
|
||||||
!classpathSnapshotFiles.shrunkPreviousClasspathSnapshotFile.exists() -> {
|
!classpathSnapshotFiles.shrunkPreviousClasspathSnapshotFile.exists() -> {
|
||||||
// When this happens, it means that the classpath snapshot in the previous run was not saved for some reason. It's
|
|
||||||
// likely that there were no source files to compile, so the task action was skipped (see
|
|
||||||
// AbstractKotlinCompile.executeImpl), and therefore the classpath snapshot was not saved.
|
|
||||||
// Missing classpath snapshot will make this run non-incremental, but because there were no source files to compile in
|
|
||||||
// the previous run, *all* source files in this run (if there are any) need to be compiled anyway, so being
|
|
||||||
// non-incremental is actually okay.
|
|
||||||
NotAvailableDueToMissingClasspathSnapshot(classpathSnapshotFiles)
|
NotAvailableDueToMissingClasspathSnapshot(classpathSnapshotFiles)
|
||||||
}
|
}
|
||||||
|
inputChanges.getFileChanges(classpathSnapshotProperties.classpathSnapshot).none() -> NoChanges(classpathSnapshotFiles)
|
||||||
else -> ToBeComputedByIncrementalCompiler(classpathSnapshotFiles)
|
else -> ToBeComputedByIncrementalCompiler(classpathSnapshotFiles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user