[IC] Baseline fix for common sources getting access to platform declarations

K2-only issue. In an incremental build, sourceSet boundary isn't
preserved in certain conditions:

SourceSet A depends on SourceSet B
A and B overload a function, for example:

A -> fun foo(p: Parent) // (1)
B -> fun foo(c: Child) // (2)

If some source file in A is calling foo(..), only (1) is supposed to be visible
for that call site.

However, if

a) it is an incremental build,
b) the declaration of (1) is not a part of the compilation set, and
c) call to foo(c: Child) is applicable,

then (2) would be called from the generated code. So, the build result is not
consistent between the full build and an incremental build.

As a workaround, we fallback to a non-incremental build, if any source from A
needs to be compiled.

To enable "risky" incremental builds, use Gradle property
kotlin.internal.incremental.enableUnsafeOptimizationsForMultiplatform=true

^KT-62686
^KT-63837 Fixed


Merge-request: KT-MR-13695
Merged-by: Evgenii Mazhukin <evgenii.mazhukin@jetbrains.com>
This commit is contained in:
Evgenii Mazhukin
2024-01-08 20:03:08 +00:00
committed by Space Team
parent ad6513e247
commit de4953adf6
26 changed files with 401 additions and 12 deletions
@@ -91,6 +91,7 @@ abstract class IncrementalCompilerRunner<
private fun createIncrementalCompilationContext(
fileLocations: FileLocations?,
transaction: CompilationTransaction,
fragmentContext: FragmentContext? = null,
) = IncrementalCompilationContext(
pathConverterForSourceFiles = fileLocations?.let { it.getRelocatablePathConverterForSourceFiles() } ?: BasicFileToPathConverter,
pathConverterForOutputFiles = fileLocations?.let { it.getRelocatablePathConverterForOutputFiles() } ?: BasicFileToPathConverter,
@@ -99,6 +100,7 @@ abstract class IncrementalCompilerRunner<
trackChangesInLookupCache = shouldTrackChangesInLookupCache,
storeFullFqNamesInLookupCache = shouldStoreFullFqNamesInLookupCache,
icFeatures = icFeatures,
fragmentContext = fragmentContext,
)
protected abstract val shouldTrackChangesInLookupCache: Boolean
@@ -165,6 +167,9 @@ abstract class IncrementalCompilerRunner<
class Failed(val reason: BuildAttribute, val cause: Throwable) : ICResult
}
// Be aware that [tryCompileIncrementally] catches a lot of exceptions internally.
// So this transformer should be used for very specific things, like cache closing, that are
// related to the transaction as a whole rather than any compilation step.
private fun incrementalCompilationExceptionTransformer(t: Throwable): ICResult = when (t) {
is CachesManagerCloseException -> ICResult.Failed(IC_FAILED_TO_CLOSE_CACHES, t)
else -> throw t
@@ -186,10 +191,19 @@ abstract class IncrementalCompilerRunner<
if (changedFiles is ChangedFiles.Unknown) {
return ICResult.RequiresRebuild(UNKNOWN_CHANGES_IN_GRADLE_INPUTS)
}
changedFiles as ChangedFiles.Known?
val fragmentContext = if (!icFeatures.enableUnsafeIncrementalCompilationForMultiplatform) { //see KT-62686
FragmentContext.fromCompilerArguments(args)
} else {
null
}
return createTransaction().runWithin(::incrementalCompilationExceptionTransformer) { transaction ->
val icContext = createIncrementalCompilationContext(fileLocations, transaction)
val icContext = createIncrementalCompilationContext(
fileLocations,
transaction,
fragmentContext
)
val caches = createCacheManager(icContext, args).also {
// this way we make the transaction to be responsible for closing the caches manager
transaction.cachesManager = it
@@ -198,7 +212,7 @@ abstract class IncrementalCompilerRunner<
fun compile(): ICResult {
// Step 1: Get changed files
val knownChangedFiles: ChangedFiles.Known = try {
getChangedFiles(changedFiles, allSourceFiles, caches)
getChangedFiles(changedFiles as ChangedFiles.Known?, allSourceFiles, caches)
} catch (e: Throwable) {
return ICResult.Failed(IC_FAILED_TO_GET_CHANGED_FILES, e)
}
@@ -241,6 +255,8 @@ abstract class IncrementalCompilerRunner<
abiSnapshotData,
messageCollector,
)
} catch (e: RequireRebuildForCorrectnessInKMPException) {
return ICResult.RequiresRebuild(UNSAFE_INCREMENTAL_CHANGE_KT_62686)
} catch (e: Throwable) {
return ICResult.Failed(IC_FAILED_TO_COMPILE_INCREMENTALLY, e)
}
@@ -463,9 +479,14 @@ abstract class IncrementalCompilerRunner<
val lookupTracker = LookupTrackerImpl(getLookupTrackerDelegate())
val expectActualTracker = ExpectActualTrackerImpl()
//TODO(valtman) sourceToCompile calculate based on abiSnapshot
val (sourcesToCompile, removedKotlinSources) = dirtySources.partition { it.exists() && allKotlinSources.contains(it) }
icContext.fragmentContext?.let {
if (it.dirtySetTouchesNonLeafFragments(sourcesToCompile)) {
throw RequireRebuildForCorrectnessInKMPException()
}
}
val services = makeServices(
args, lookupTracker, expectActualTracker, caches,
dirtySources.toSet(), compilationMode is CompilationMode.Incremental
@@ -686,4 +707,4 @@ fun extractKotlinSourcesFromFreeCompilerArguments(
}
compilerArguments.freeArgs = freeArgs
return allKotlinFiles
}
}