mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-04-05 08:31:31 +00:00
Compare commits
67 Commits
rr/mb/code
...
inline_gra
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fd956041a | ||
|
|
83cd5dcc45 | ||
|
|
e9731131ea | ||
|
|
5224ff9ae2 | ||
|
|
d40777c28f | ||
|
|
56f9e3360f | ||
|
|
56854a8b1a | ||
|
|
88c43e7f7b | ||
|
|
b08eb6cf4c | ||
|
|
804df1aec2 | ||
|
|
3626008ed2 | ||
|
|
73616107b4 | ||
|
|
c629ba5a3c | ||
|
|
357a7907a3 | ||
|
|
74bdb2398e | ||
|
|
6b453d9b23 | ||
|
|
3e9ff3ecda | ||
|
|
e67eb0c123 | ||
|
|
5f9357eb41 | ||
|
|
a841a0bbca | ||
|
|
27c942a0ff | ||
|
|
9aaa952b39 | ||
|
|
fbb19e3b50 | ||
|
|
52ea7fdb72 | ||
|
|
8783ebc352 | ||
|
|
afe71f5d59 | ||
|
|
51da54ce66 | ||
|
|
cacd84390e | ||
|
|
741c1a864f | ||
|
|
744a0fcd25 | ||
|
|
05447ce0c8 | ||
|
|
0b26a281de | ||
|
|
fb51105a5d | ||
|
|
496aad3c4a | ||
|
|
3ad7b60747 | ||
|
|
1895c230ef | ||
|
|
f473b88e47 | ||
|
|
84ce9c612c | ||
|
|
2581b67cda | ||
|
|
43ad0ed907 | ||
|
|
79e3ce022f | ||
|
|
bc9a791809 | ||
|
|
ad9fd7ecf3 | ||
|
|
5cbbbc3b83 | ||
|
|
33313ae4b4 | ||
|
|
8c20c655fe | ||
|
|
7b7b8fbea7 | ||
|
|
8c95b78346 | ||
|
|
dbadd5846a | ||
|
|
1d6b198915 | ||
|
|
49fc1b9e3e | ||
|
|
82ac482143 | ||
|
|
a3fa6c6d13 | ||
|
|
9b4949a3c5 | ||
|
|
adb05ab076 | ||
|
|
35008df969 | ||
|
|
4500b6ce74 | ||
|
|
6d019d9544 | ||
|
|
134fda8bad | ||
|
|
e3e7e6b740 | ||
|
|
3d8e8dd3ba | ||
|
|
61fce74b76 | ||
|
|
91f1cb88c1 | ||
|
|
652207dcac | ||
|
|
5793f77ece | ||
|
|
de06a69b12 | ||
|
|
66f00a2eb5 |
24
.idea/runConfigurations/Generate_FIR_Checker_Components_and_FIR_IDE_Diagnostics.xml
generated
Normal file
24
.idea/runConfigurations/Generate_FIR_Checker_Components_and_FIR_IDE_Diagnostics.xml
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Generate FIR Checker Components and FIR/IDE Diagnostics" type="GradleRunConfiguration" factoryName="Gradle">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value=":compiler:fir:checkers:generateCheckersComponents" />
|
||||
<option value=":idea:idea-frontend-fir:generateCode" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" value="" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -325,11 +325,8 @@ extra["tasksWithWarnings"] = listOf(
|
||||
":kotlin-stdlib:compileTestKotlin",
|
||||
":kotlin-stdlib-jdk7:compileTestKotlin",
|
||||
":kotlin-stdlib-jdk8:compileTestKotlin",
|
||||
":compiler:cli:compileKotlin",
|
||||
":kotlin-scripting-compiler:compileKotlin",
|
||||
":plugins:uast-kotlin:compileKotlin",
|
||||
":plugins:uast-kotlin:compileTestKotlin",
|
||||
":plugins:uast-kotlin-idea:compileKotlin"
|
||||
":plugins:uast-kotlin:compileTestKotlin"
|
||||
)
|
||||
|
||||
val tasksWithWarnings: List<String> by extra
|
||||
@@ -768,6 +765,7 @@ tasks {
|
||||
register("toolsTest") {
|
||||
dependsOn(":tools:kotlinp:test")
|
||||
dependsOn(":native:kotlin-klib-commonizer:test")
|
||||
dependsOn(":native:kotlin-klib-commonizer-api:test")
|
||||
}
|
||||
|
||||
register("examplesTest") {
|
||||
@@ -947,6 +945,12 @@ tasks {
|
||||
}
|
||||
}
|
||||
|
||||
register("publishGradlePluginArtifacts") {
|
||||
idePluginDependency {
|
||||
dependsOnKotlinGradlePluginPublish()
|
||||
}
|
||||
}
|
||||
|
||||
register("publishIdeArtifacts") {
|
||||
idePluginDependency {
|
||||
dependsOn(
|
||||
|
||||
@@ -128,8 +128,9 @@ java {
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile>().configureEach {
|
||||
kotlinOptions.freeCompilerArgs +=
|
||||
listOf("-Xopt-in=kotlin.RequiresOptIn", "-Xskip-runtime-version-check")
|
||||
kotlinOptions.freeCompilerArgs += listOf(
|
||||
"-Xopt-in=kotlin.RequiresOptIn", "-Xskip-runtime-version-check", "-Xsuppress-version-warnings"
|
||||
)
|
||||
}
|
||||
|
||||
tasks["build"].dependsOn(":prepare-deps:build")
|
||||
|
||||
@@ -20,41 +20,54 @@ import java.lang.Character.isUpperCase
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
|
||||
fun Task.dependsOnKotlinPluginInstall() {
|
||||
dependsOn(
|
||||
":kotlin-allopen:install",
|
||||
":kotlin-noarg:install",
|
||||
":kotlin-sam-with-receiver:install",
|
||||
":kotlin-android-extensions:install",
|
||||
":kotlin-parcelize-compiler:install",
|
||||
":kotlin-build-common:install",
|
||||
":kotlin-compiler-embeddable:install",
|
||||
":native:kotlin-native-utils:install",
|
||||
":kotlin-util-klib:install",
|
||||
":kotlin-util-io:install",
|
||||
":kotlin-compiler-runner:install",
|
||||
":kotlin-daemon-embeddable:install",
|
||||
":kotlin-daemon-client:install",
|
||||
":kotlin-gradle-plugin-api:install",
|
||||
":kotlin-gradle-plugin:install",
|
||||
":kotlin-gradle-plugin-model:install",
|
||||
":kotlin-reflect:install",
|
||||
":kotlin-annotation-processing-gradle:install",
|
||||
":kotlin-test:install",
|
||||
":kotlin-gradle-subplugin-example:install",
|
||||
":kotlin-stdlib-common:install",
|
||||
":kotlin-stdlib:install",
|
||||
":kotlin-stdlib-jdk8:install",
|
||||
":kotlin-stdlib-js:install",
|
||||
":examples:annotation-processor-example:install",
|
||||
":kotlin-script-runtime:install",
|
||||
":kotlin-scripting-common:install",
|
||||
":kotlin-scripting-jvm:install",
|
||||
":kotlin-scripting-compiler-embeddable:install",
|
||||
":kotlin-scripting-compiler-impl-embeddable:install",
|
||||
":kotlin-test-js-runner:install",
|
||||
":native:kotlin-klib-commonizer-embeddable:install"
|
||||
)
|
||||
val kotlinGradlePluginAndItsRequired = arrayOf(
|
||||
":kotlin-allopen",
|
||||
":kotlin-noarg",
|
||||
":kotlin-sam-with-receiver",
|
||||
":kotlin-android-extensions",
|
||||
":kotlin-parcelize-compiler",
|
||||
":kotlin-build-common",
|
||||
":kotlin-compiler-embeddable",
|
||||
":native:kotlin-native-utils",
|
||||
":kotlin-util-klib",
|
||||
":kotlin-util-io",
|
||||
":kotlin-compiler-runner",
|
||||
":kotlin-daemon-embeddable",
|
||||
":kotlin-daemon-client",
|
||||
":kotlin-gradle-plugin-api",
|
||||
":kotlin-gradle-plugin",
|
||||
":kotlin-gradle-plugin-model",
|
||||
":kotlin-reflect",
|
||||
":kotlin-annotation-processing-gradle",
|
||||
":kotlin-test",
|
||||
":kotlin-gradle-subplugin-example",
|
||||
":kotlin-stdlib-common",
|
||||
":kotlin-stdlib",
|
||||
":kotlin-stdlib-jdk8",
|
||||
":kotlin-stdlib-js",
|
||||
":examples:annotation-processor-example",
|
||||
":kotlin-script-runtime",
|
||||
":kotlin-scripting-common",
|
||||
":kotlin-scripting-jvm",
|
||||
":kotlin-scripting-compiler-embeddable",
|
||||
":kotlin-scripting-compiler-impl-embeddable",
|
||||
":kotlin-test-js-runner",
|
||||
":native:kotlin-klib-commonizer-embeddable",
|
||||
":native:kotlin-klib-commonizer-api"
|
||||
)
|
||||
|
||||
fun Task.dependsOnKotlinGradlePluginInstall() {
|
||||
kotlinGradlePluginAndItsRequired.forEach {
|
||||
dependsOn("${it}:install")
|
||||
}
|
||||
}
|
||||
|
||||
fun Task.dependsOnKotlinGradlePluginPublish() {
|
||||
kotlinGradlePluginAndItsRequired.forEach {
|
||||
project.rootProject.tasks.findByPath("${it}:publish")?.let { task ->
|
||||
dependsOn(task)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.projectTest(
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||
import org.jetbrains.kotlin.codegen.optimization.OptimizationClassBuilderFactory
|
||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.config.LanguageVersion.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||
@@ -49,6 +50,7 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeApproximator
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class GenerationState private constructor(
|
||||
val project: Project,
|
||||
@@ -204,7 +206,7 @@ class GenerationState private constructor(
|
||||
val target = configuration.get(JVMConfigurationKeys.JVM_TARGET) ?: JvmTarget.DEFAULT
|
||||
val runtimeStringConcat =
|
||||
if (target.majorVersion >= JvmTarget.JVM_9.majorVersion)
|
||||
configuration.get(JVMConfigurationKeys.STRING_CONCAT) ?: JvmStringConcat.INLINE
|
||||
configuration.get(JVMConfigurationKeys.STRING_CONCAT) ?: JvmStringConcat.INDY_WITH_CONSTANTS
|
||||
else JvmStringConcat.INLINE
|
||||
|
||||
val samConversionsScheme = run {
|
||||
@@ -320,8 +322,7 @@ class GenerationState private constructor(
|
||||
|
||||
val metadataVersion =
|
||||
configuration.get(CommonConfigurationKeys.METADATA_VERSION)
|
||||
?: if (languageVersionSettings.languageVersion >= LanguageVersion.LATEST_STABLE) JvmMetadataVersion.INSTANCE
|
||||
else JvmMetadataVersion(1, 1, 18)
|
||||
?: LANGUAGE_TO_METADATA_VERSION.getValue(languageVersionSettings.languageVersion)
|
||||
|
||||
val abiStability = configuration.get(JVMConfigurationKeys.ABI_STABILITY)
|
||||
|
||||
@@ -392,6 +393,24 @@ class GenerationState private constructor(
|
||||
|
||||
private fun shouldOnlyCollectSignatures(origin: JvmDeclarationOrigin) =
|
||||
classBuilderMode == ClassBuilderMode.LIGHT_CLASSES && origin.originKind in doNotGenerateInLightClassMode
|
||||
|
||||
companion object {
|
||||
private val LANGUAGE_TO_METADATA_VERSION = EnumMap<LanguageVersion, JvmMetadataVersion>(LanguageVersion::class.java).apply {
|
||||
val oldMetadataVersion = JvmMetadataVersion(1, 1, 18)
|
||||
this[KOTLIN_1_0] = oldMetadataVersion
|
||||
this[KOTLIN_1_1] = oldMetadataVersion
|
||||
this[KOTLIN_1_2] = oldMetadataVersion
|
||||
this[KOTLIN_1_3] = oldMetadataVersion
|
||||
this[KOTLIN_1_4] = JvmMetadataVersion(1, 4, 3)
|
||||
this[KOTLIN_1_5] = JvmMetadataVersion.INSTANCE
|
||||
this[KOTLIN_1_6] = JvmMetadataVersion(1, 6, 0)
|
||||
|
||||
check(size == LanguageVersion.values().size) {
|
||||
"Please add mappings from the missing LanguageVersion instances to the corresponding JvmMetadataVersion " +
|
||||
"in `GenerationState.LANGUAGE_TO_METADATA_VERSION`"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val doNotGenerateInLightClassMode = setOf(CLASS_MEMBER_DELEGATION_TO_DEFAULT_IMPL, BRIDGE, COLLECTION_STUB, AUGMENTED_BUILTIN_API)
|
||||
|
||||
@@ -56,7 +56,9 @@ tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
|
||||
kotlinOptions {
|
||||
languageVersion = "1.3"
|
||||
apiVersion = "1.3"
|
||||
freeCompilerArgs = freeCompilerArgs - "-progressive" + "-Xskip-prerelease-check"
|
||||
freeCompilerArgs = freeCompilerArgs - "-progressive" + listOf(
|
||||
"-Xskip-prerelease-check", "-Xsuppress-version-warnings"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -369,7 +369,9 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
||||
description = """Select code generation scheme for string concatenation.
|
||||
-Xstring-concat=indy-with-constants Concatenate strings using `invokedynamic` `makeConcatWithConstants`. Requires `-jvm-target 9` or greater.
|
||||
-Xstring-concat=indy Concatenate strings using `invokedynamic` `makeConcat`. Requires `-jvm-target 9` or greater.
|
||||
-Xstring-concat=inline Concatenate strings using `StringBuilder`"""
|
||||
-Xstring-concat=inline Concatenate strings using `StringBuilder`
|
||||
default: `indy-with-constants` for JVM target 9 or greater, `inline` otherwise"""
|
||||
|
||||
)
|
||||
var stringConcat: String? by NullableStringFreezableVar(JvmStringConcat.INLINE.description)
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
compile(project(":compiler:cli"))
|
||||
compile(project(":compiler:ir.serialization.js"))
|
||||
compile(project(":compiler:backend.js"))
|
||||
compile(project(":compiler:ir.compiler.wjs"))
|
||||
compileOnly(project(":compiler:ir.tree.persistent"))
|
||||
runtimeOnly(project(":kotlin-reflect"))
|
||||
if (Platform[193].orLower()) {
|
||||
|
||||
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.cli.common.messages.*
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
|
||||
import org.jetbrains.kotlin.ir.compiler.wjs.Ir2WJCompiler
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
@@ -75,8 +75,10 @@ fun buildKLib(
|
||||
commonSources: List<String>
|
||||
) {
|
||||
val configuration = buildConfiguration(environment, moduleName)
|
||||
generateKLib(
|
||||
project = environment.project,
|
||||
val compiler =
|
||||
Ir2WJCompiler(environment.project, configuration, AnalyzerWithCompilerReport(configuration), allDependencies, emptyList())
|
||||
compiler.options.nopack = true
|
||||
compiler.compileKlib(
|
||||
files = sources.map { source ->
|
||||
val file = createPsiFile(source)
|
||||
if (source in commonSources) {
|
||||
@@ -84,13 +86,7 @@ fun buildKLib(
|
||||
}
|
||||
file
|
||||
},
|
||||
analyzer = AnalyzerWithCompilerReport(configuration),
|
||||
configuration = configuration,
|
||||
allDependencies = allDependencies,
|
||||
friendDependencies = emptyList(),
|
||||
irFactory = PersistentIrFactory(), // TODO: IrFactoryImpl?
|
||||
outputKlibPath = outputPath,
|
||||
nopack = true
|
||||
outputKlibPath = outputPath
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,11 +8,12 @@ dependencies {
|
||||
compile(project(":compiler:cli-common"))
|
||||
compile(project(":compiler:cli"))
|
||||
compile(project(":compiler:frontend"))
|
||||
compile(project(":compiler:backend-common"))
|
||||
// compile(project(":compiler:backend-common"))
|
||||
compile(project(":compiler:ir.backend.common"))
|
||||
compile(project(":compiler:ir.serialization.js"))
|
||||
compile(project(":compiler:backend.js"))
|
||||
compile(project(":compiler:backend.wasm"))
|
||||
compile(project(":compiler:ir.compiler.wjs"))
|
||||
// compile(project(":compiler:ir.serialization.js"))
|
||||
// compile(project(":compiler:backend.js"))
|
||||
// compile(project(":compiler:backend.wasm"))
|
||||
compile(project(":js:js.translator"))
|
||||
compile(project(":js:js.serializer"))
|
||||
compile(project(":js:js.dce"))
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli.js
|
||||
|
||||
//import org.jetbrains.kotlin.ir.backend.js.Ir2WJCompiler
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
|
||||
import org.jetbrains.kotlin.backend.wasm.compileWasm
|
||||
import org.jetbrains.kotlin.backend.wasm.wasmPhases
|
||||
import org.jetbrains.kotlin.cli.common.*
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode.COMPILATION_ERROR
|
||||
@@ -36,8 +36,9 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalNextRoundChecker
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
|
||||
import org.jetbrains.kotlin.ir.backend.js.*
|
||||
import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
|
||||
import org.jetbrains.kotlin.ir.backend.js.jsPhases
|
||||
import org.jetbrains.kotlin.ir.backend.js.jsResolveLibraries
|
||||
import org.jetbrains.kotlin.ir.compiler.wjs.Ir2WJCompiler
|
||||
import org.jetbrains.kotlin.js.config.*
|
||||
import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION
|
||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||
@@ -187,51 +188,47 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
it.libraryFile.absolutePath in friendAbsolutePaths
|
||||
}
|
||||
|
||||
val compiler = Ir2WJCompiler(
|
||||
projectJs,
|
||||
config.configuration,
|
||||
AnalyzerWithCompilerReport(config.configuration),
|
||||
resolvedLibraries,
|
||||
friendDependencies
|
||||
)
|
||||
|
||||
compiler.options.run {
|
||||
nopack = arguments.irProduceKlibDir
|
||||
generateFullJs = !arguments.irDce
|
||||
generateDceJs = arguments.irDce
|
||||
dceDriven = arguments.irDceDriven
|
||||
multiModule = arguments.irPerModule
|
||||
relativeRequirePath = true
|
||||
propertyLazyInitialization = arguments.irPropertyLazyInitialization
|
||||
}
|
||||
|
||||
if (arguments.irProduceKlibDir || arguments.irProduceKlibFile) {
|
||||
if (arguments.irProduceKlibFile) {
|
||||
require(outputFile.extension == KLIB_FILE_EXTENSION) { "Please set up .klib file as output" }
|
||||
}
|
||||
|
||||
generateKLib(
|
||||
project = config.project,
|
||||
files = sourcesFiles,
|
||||
analyzer = AnalyzerWithCompilerReport(config.configuration),
|
||||
configuration = config.configuration,
|
||||
allDependencies = resolvedLibraries,
|
||||
friendDependencies = friendDependencies,
|
||||
irFactory = PersistentIrFactory(), // TODO IrFactoryImpl?
|
||||
outputKlibPath = outputFile.path,
|
||||
nopack = arguments.irProduceKlibDir
|
||||
)
|
||||
compiler.compileKlib(sourcesFiles, outputFile.path)
|
||||
}
|
||||
|
||||
if (arguments.irProduceJs) {
|
||||
val phaseConfig = createPhaseConfig(jsPhases, arguments, messageCollector)
|
||||
|
||||
val includes = arguments.includes
|
||||
|
||||
val mainModule = if (includes != null) {
|
||||
if (sourcesFiles.isNotEmpty()) {
|
||||
messageCollector.report(ERROR, "Source files are not supported when -Xinclude is present")
|
||||
}
|
||||
val allLibraries = resolvedLibraries.getFullList()
|
||||
val mainLib = allLibraries.find { it.libraryFile.absolutePath == File(includes).absolutePath }!!
|
||||
MainModule.Klib(mainLib)
|
||||
Ir2WJCompiler.MainModule.Klib(includes)
|
||||
} else {
|
||||
MainModule.SourceFiles(sourcesFiles)
|
||||
Ir2WJCompiler.MainModule.SourceFiles(sourcesFiles)
|
||||
}
|
||||
|
||||
if (arguments.wasm) {
|
||||
val res = compileWasm(
|
||||
projectJs,
|
||||
mainModule,
|
||||
AnalyzerWithCompilerReport(config.configuration),
|
||||
config.configuration,
|
||||
PhaseConfig(wasmPhases),
|
||||
allDependencies = resolvedLibraries,
|
||||
friendDependencies = friendDependencies,
|
||||
exportedDeclarations = setOf(FqName("main"))
|
||||
)
|
||||
val res = compiler.compileBinaryWasm(mainModule, PhaseConfig(wasmPhases), emptyList(), setOf(FqName("main")))
|
||||
val outputWasmFile = outputFile.withReplacedExtensionOrNull(outputFile.extension, "wasm")!!
|
||||
outputWasmFile.writeBytes(res.wasm)
|
||||
val outputWatFile = outputFile.withReplacedExtensionOrNull(outputFile.extension, "wat")!!
|
||||
@@ -248,22 +245,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
return OK
|
||||
}
|
||||
|
||||
val compiledModule = compile(
|
||||
projectJs,
|
||||
mainModule,
|
||||
AnalyzerWithCompilerReport(config.configuration),
|
||||
config.configuration,
|
||||
phaseConfig,
|
||||
allDependencies = resolvedLibraries,
|
||||
friendDependencies = friendDependencies,
|
||||
mainArguments = mainCallArguments,
|
||||
generateFullJs = !arguments.irDce,
|
||||
generateDceJs = arguments.irDce,
|
||||
dceDriven = arguments.irDceDriven,
|
||||
multiModule = arguments.irPerModule,
|
||||
relativeRequirePath = true,
|
||||
propertyLazyInitialization = arguments.irPropertyLazyInitialization,
|
||||
)
|
||||
val compiledModule = compiler.compileBinaryJs(mainModule, phaseConfig, mainCallArguments, emptySet())
|
||||
|
||||
val jsCode = if (arguments.irDce && !arguments.irDceDriven) compiledModule.dceJsCode!! else compiledModule.jsCode!!
|
||||
outputFile.writeText(jsCode.mainModule)
|
||||
|
||||
@@ -50,6 +50,7 @@ dependencies {
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
|
||||
kotlinOptions {
|
||||
apiVersion = "1.3"
|
||||
freeCompilerArgs += "-Xsuppress-version-warnings"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
|
||||
kotlinOptions {
|
||||
// This module is being run from within Gradle, older versions of which only have kotlin-stdlib 1.3 in the runtime classpath.
|
||||
apiVersion = "1.3"
|
||||
freeCompilerArgs += "-Xsuppress-version-warnings"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2944,6 +2944,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
||||
public void testFunctionCallBound() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/functionCallBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("thisAssignment.kt")
|
||||
public void testThisAssignment() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/thisAssignment.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/smartcasts/controlStructures")
|
||||
@@ -3251,6 +3256,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
||||
public void testCapturedParametersOfInnerClasses() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("castToBareType.kt")
|
||||
public void testCastToBareType() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/types/castToBareType.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/visibility")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FILE: innerClassInAnonymousObject.kt
|
||||
public final val x: R|<anonymous>| = object : R|kotlin/Any| {
|
||||
public final val x: R|kotlin/Any| = object : R|kotlin/Any| {
|
||||
private constructor(): R|<anonymous>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
@@ -16,4 +16,4 @@ FILE: innerClassInAnonymousObject.kt
|
||||
|
||||
}
|
||||
|
||||
public get(): R|<anonymous>|
|
||||
public get(): R|kotlin/Any|
|
||||
|
||||
@@ -8,7 +8,7 @@ FILE: annotationArgumentKClassLiteralTypeError.kt
|
||||
public get(): R|kotlin/Array<kotlin/reflect/KClass<*>>|
|
||||
|
||||
}
|
||||
public final val <reified T> R|T|.test: R|<anonymous><T>|
|
||||
public final val <reified T> R|T|.test: R|kotlin/Any|
|
||||
public get(): R|<anonymous><T>| {
|
||||
^ @R|Ann|(<implicitArrayOf>(<getClass>(R|T|), <getClass>(Q|kotlin/Array|))) object : R|kotlin/Any| {
|
||||
private constructor(): R|<anonymous><T>| {
|
||||
|
||||
@@ -90,14 +90,14 @@ FILE: conflictingOverloads.kt
|
||||
|
||||
}
|
||||
|
||||
public final val Companion: R|<anonymous>| = object : R|kotlin/Any| {
|
||||
public final val Companion: R|kotlin/Any| = object : R|kotlin/Any| {
|
||||
private constructor(): R|<anonymous>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public get(): R|<anonymous>|
|
||||
public get(): R|kotlin/Any|
|
||||
|
||||
}
|
||||
public final fun R|B|.foo(): R|kotlin/Unit| {
|
||||
|
||||
@@ -21,7 +21,7 @@ FILE: localEntitytNotAllowed.kt
|
||||
public abstract interface X : R|kotlin/Any| {
|
||||
}
|
||||
|
||||
public final val a: R|<anonymous>| = object : R|kotlin/Any| {
|
||||
public final val a: R|kotlin/Any| = object : R|kotlin/Any| {
|
||||
private constructor(): R|<anonymous>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
@@ -48,7 +48,7 @@ FILE: localEntitytNotAllowed.kt
|
||||
|
||||
}
|
||||
|
||||
public get(): R|<anonymous>|
|
||||
public get(): R|kotlin/Any|
|
||||
|
||||
public final fun b(): R|kotlin/Unit| {
|
||||
local final object E : R|kotlin/Any| {
|
||||
|
||||
@@ -13,8 +13,8 @@ FILE: superIsNotAnExpression.kt
|
||||
public final fun act(): R|kotlin/Unit| {
|
||||
<Super cannot be a callee>#()
|
||||
<Unresolved name: invoke>#()
|
||||
<Super cannot be a callee>#(<L> = <Super cannot be a callee>@fun <implicit>.<anonymous>(): <implicit> {
|
||||
println#(ERROR_EXPR(Incorrect character: 'weird'))
|
||||
<Super cannot be a callee>#(<L> = <Super cannot be a callee>@fun <anonymous>(): R|ERROR CLASS: Unresolved name: println| {
|
||||
^ <Unresolved name: println>#(ERROR_EXPR(Incorrect character: 'weird'))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ class B: A() {
|
||||
<!UNRESOLVED_REFERENCE{LT}!><!UNRESOLVED_REFERENCE{PSI}!>invoke<!>()<!>
|
||||
|
||||
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!> {
|
||||
println(<!ILLEGAL_CONST_EXPRESSION!>'weird'<!>)
|
||||
<!UNRESOLVED_REFERENCE{LT}!><!UNRESOLVED_REFERENCE{PSI}!>println<!>(<!ILLEGAL_CONST_EXPRESSION!>'weird'<!>)<!>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ FILE: privateObjectLiteral.kt
|
||||
public final val y: R|kotlin/Int| = this@R|/C|.R|/C.x|.R|/<anonymous>.foo|()
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
internal final val z: R|<anonymous>| = object : R|kotlin/Any| {
|
||||
internal final val z: R|kotlin/Any| = object : R|kotlin/Any| {
|
||||
private constructor(): R|<anonymous>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
@@ -31,9 +31,9 @@ FILE: privateObjectLiteral.kt
|
||||
|
||||
}
|
||||
|
||||
internal get(): R|<anonymous>|
|
||||
internal get(): R|kotlin/Any|
|
||||
|
||||
public final val w: R|kotlin/Int| = this@R|/C|.R|/C.z|.R|/<anonymous>.foo|()
|
||||
public get(): R|kotlin/Int|
|
||||
public final val w: R|ERROR CLASS: Unresolved name: foo| = this@R|/C|.R|/C.z|.<Unresolved name: foo>#()
|
||||
public get(): R|ERROR CLASS: Unresolved name: foo|
|
||||
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@ class C {
|
||||
fun foo() = 13
|
||||
}
|
||||
|
||||
val w = z.foo() // ERROR!
|
||||
val w = z.<!UNRESOLVED_REFERENCE{LT}!><!UNRESOLVED_REFERENCE{PSI}!>foo<!>()<!> // ERROR!
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ class FinalDerived : Base() {
|
||||
// Redundant final
|
||||
override <!REDUNDANT_MODALITY_MODIFIER!>final<!> fun bar() {}
|
||||
// Non-final member in final class
|
||||
override open val gav = 13
|
||||
override <!NON_FINAL_MEMBER_IN_FINAL_CLASS!>open<!> val gav = 13
|
||||
}
|
||||
// Open
|
||||
open class OpenDerived : Base() {
|
||||
|
||||
@@ -22,7 +22,7 @@ FILE: RedundantVisibilityModifierChecker.kt
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
internal final val z: R|<anonymous>| = object : R|kotlin/Any| {
|
||||
internal final val z: R|kotlin/Any| = object : R|kotlin/Any| {
|
||||
private constructor(): R|<anonymous>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
@@ -33,7 +33,7 @@ FILE: RedundantVisibilityModifierChecker.kt
|
||||
|
||||
}
|
||||
|
||||
internal get(): R|<anonymous>|
|
||||
internal get(): R|kotlin/Any|
|
||||
|
||||
}
|
||||
public final class Foo2<T1, T2 : R|T1|> : R|kotlin/Any| {
|
||||
|
||||
14
compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/thisAssignment.fir.txt
vendored
Normal file
14
compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/thisAssignment.fir.txt
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
FILE: thisAssignment.kt
|
||||
public abstract interface A : R|kotlin/Any| {
|
||||
public abstract fun foo(): R|kotlin/Unit|
|
||||
|
||||
}
|
||||
public final fun R|kotlin/Any|.test(): R|kotlin/Unit| {
|
||||
when () {
|
||||
(this@R|/test| is R|A|) -> {
|
||||
lval a: R|kotlin/Any| = this@R|/test|
|
||||
R|<local>/a|.R|/A.foo|()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
12
compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/thisAssignment.kt
vendored
Normal file
12
compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/thisAssignment.kt
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
interface A {
|
||||
fun foo()
|
||||
}
|
||||
|
||||
fun Any.test() {
|
||||
if (this is A) {
|
||||
val a = this
|
||||
a.foo()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ FILE: typeParameterVsNested.kt
|
||||
public abstract val z: <ERROR TYPE REF: Wrong number of type arguments>
|
||||
public get(): <ERROR TYPE REF: Wrong number of type arguments>
|
||||
|
||||
public final class Some : <ERROR TYPE REF: Type parameter cannot be a super-type: T> {
|
||||
public final class Some : <ERROR TYPE REF: Type parameter T cannot be a supertype> {
|
||||
public constructor(): R|test/My.Some| {
|
||||
super<R|test/My.T<T>|>()
|
||||
}
|
||||
@@ -32,7 +32,7 @@ FILE: typeParameterVsNested.kt
|
||||
}
|
||||
|
||||
}
|
||||
public abstract class Your<T : R|test/Some|> : <ERROR TYPE REF: Type parameter cannot be a super-type: T> {
|
||||
public abstract class Your<T : R|test/Some|> : <ERROR TYPE REF: Type parameter T cannot be a supertype> {
|
||||
public constructor<T : R|test/Some|>(): R|test/Your<T>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ abstract class My<T : Some> {
|
||||
|
||||
abstract val z: <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>test.My.T<!>
|
||||
|
||||
class Some : <!UNRESOLVED_REFERENCE{LT}!><!OTHER_ERROR, UNRESOLVED_REFERENCE{PSI}!>T<!>()<!>
|
||||
class Some : <!UNRESOLVED_REFERENCE{LT}!><!SUPERTYPE_NOT_A_CLASS_OR_INTERFACE, UNRESOLVED_REFERENCE{PSI}!>T<!>()<!>
|
||||
}
|
||||
|
||||
abstract class Your<T : Some> : <!OTHER_ERROR!>T<!>
|
||||
abstract class Your<T : Some> : <!SUPERTYPE_NOT_A_CLASS_OR_INTERFACE!>T<!>
|
||||
|
||||
21
compiler/fir/analysis-tests/testData/resolve/types/castToBareType.fir.txt
vendored
Normal file
21
compiler/fir/analysis-tests/testData/resolve/types/castToBareType.fir.txt
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
FILE: castToBareType.kt
|
||||
public abstract interface FirDeclaration : R|kotlin/Any| {
|
||||
}
|
||||
public abstract interface FirSymbolOwner<E : R|FirSymbolOwner<E>|> : R|kotlin/Any| {
|
||||
public abstract val symbol: R|AbstractFirBasedSymbol<E>|
|
||||
public get(): R|AbstractFirBasedSymbol<E>|
|
||||
|
||||
}
|
||||
public abstract interface FirFunction<F : R|FirFunction<F>|> : R|FirSymbolOwner<F>|, R|FirDeclaration| {
|
||||
}
|
||||
public abstract interface AbstractFirBasedSymbol<E : R|FirSymbolOwner<E>|, R|FirDeclaration|> : R|kotlin/Any| {
|
||||
public abstract val fir: R|E|
|
||||
public get(): R|E|
|
||||
|
||||
}
|
||||
public final fun foo(firAdaptee: R|FirFunction<*>|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun test(symbol: R|AbstractFirBasedSymbol<*>|): R|kotlin/Unit| {
|
||||
lval firAdaptee: R|FirFunction<out it(FirSymbolOwner<out it(FirSymbolOwner<out it(FirSymbolOwner<out it(FirSymbolOwner<out kotlin/Any?> & FirDeclaration)> & FirDeclaration)> & FirDeclaration)> & FirDeclaration)>| = (R|<local>/symbol|.R|SubstitutionOverride</AbstractFirBasedSymbol.fir: R|CapturedType(*)|>| as R|FirFunction<out it(FirSymbolOwner<out it(FirSymbolOwner<out it(FirSymbolOwner<out it(FirSymbolOwner<out kotlin/Any?> & FirDeclaration)> & FirDeclaration)> & FirDeclaration)> & FirDeclaration)>|)
|
||||
R|/foo|(R|<local>/firAdaptee|)
|
||||
}
|
||||
17
compiler/fir/analysis-tests/testData/resolve/types/castToBareType.kt
vendored
Normal file
17
compiler/fir/analysis-tests/testData/resolve/types/castToBareType.kt
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
interface FirDeclaration
|
||||
|
||||
interface FirSymbolOwner<E : FirSymbolOwner<E>> {
|
||||
val symbol: AbstractFirBasedSymbol<E>
|
||||
}
|
||||
interface FirFunction<F : FirFunction<F>> : FirSymbolOwner<F>, FirDeclaration
|
||||
|
||||
interface AbstractFirBasedSymbol<E> where E : FirSymbolOwner<E>, E : FirDeclaration {
|
||||
val fir: E
|
||||
}
|
||||
|
||||
fun foo(firAdaptee: FirFunction<*>) {}
|
||||
|
||||
fun test(symbol: AbstractFirBasedSymbol<*>) {
|
||||
val firAdaptee = symbol.fir as FirFunction
|
||||
foo(firAdaptee)
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
FILE: problems.kt
|
||||
public final val sb: R|java/lang/StringBuilder| = R|java/lang/StringBuilder.StringBuilder|()
|
||||
public get(): R|java/lang/StringBuilder|
|
||||
public final val o: R|<anonymous>| = object : R|kotlin/Any| {
|
||||
public final val o: R|kotlin/Any| = object : R|kotlin/Any| {
|
||||
private constructor(): R|<anonymous>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
@@ -15,7 +15,7 @@ FILE: problems.kt
|
||||
|
||||
}
|
||||
|
||||
public get(): R|<anonymous>|
|
||||
public get(): R|kotlin/Any|
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
local final class Local : R|kotlin/Any| {
|
||||
public constructor(): R|Local| {
|
||||
|
||||
@@ -3323,6 +3323,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
public void testFunctionCallBound() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/functionCallBound.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("thisAssignment.kt")
|
||||
public void testThisAssignment() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/thisAssignment.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -3624,6 +3630,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
public void testCapturedParametersOfInnerClasses() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("castToBareType.kt")
|
||||
public void testCastToBareType() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/types/castToBareType.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
@@ -3362,6 +3362,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
public void testFunctionCallBound() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/functionCallBound.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("thisAssignment.kt")
|
||||
public void testThisAssignment() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/thisAssignment.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -3675,6 +3681,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
public void testCapturedParametersOfInnerClasses() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("castToBareType.kt")
|
||||
public void testCastToBareType() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/types/castToBareType.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
@@ -24313,6 +24313,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/inheritorInDifferentModule.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("internalTypeInConstructor.kt")
|
||||
public void testInternalTypeInConstructor() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/internalTypeInConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt44316.kt")
|
||||
public void testKt44316() throws Exception {
|
||||
@@ -24433,6 +24439,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/OperationWhen.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("privateTypeInConstructor.kt")
|
||||
public void testPrivateTypeInConstructor() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/privateTypeInConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("protectedConstructors_disabled.kt")
|
||||
public void testProtectedConstructors_disabled() throws Exception {
|
||||
@@ -31809,9 +31821,9 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varIndefiniteIntialization.kt")
|
||||
public void testVarIndefiniteIntialization() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/initialization/atLeastOnce/varIndefiniteIntialization.kt");
|
||||
@TestMetadata("varIndefiniteInitialization.kt")
|
||||
public void testVarIndefiniteInitialization() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/initialization/atLeastOnce/varIndefiniteInitialization.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34693,6 +34705,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/resolve/kt4711.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("lambdaArgumentOfInapplicableCall.kt")
|
||||
public void testLambdaArgumentOfInapplicableCall() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/resolve/lambdaArgumentOfInapplicableCall.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("samAgainstFunctionalType.kt")
|
||||
public void testSamAgainstFunctionalType() throws Exception {
|
||||
|
||||
@@ -82,6 +82,9 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val CLASS_IN_SUPERTYPE_FOR_ENUM by error<FirSourceElement, PsiElement>()
|
||||
val SEALED_SUPERTYPE by error<FirSourceElement, PsiElement>()
|
||||
val SEALED_SUPERTYPE_IN_LOCAL_CLASS by error<FirSourceElement, PsiElement>()
|
||||
val SUPERTYPE_NOT_A_CLASS_OR_INTERFACE by error<FirSourceElement, KtElement> {
|
||||
parameter<String>("reason")
|
||||
}
|
||||
}
|
||||
|
||||
val CONSTRUCTOR_PROBLEMS by object : DiagnosticGroup("Constructor problems") {
|
||||
@@ -240,6 +243,8 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
parameter<FirMemberDeclaration>("overridingDeclaration")
|
||||
parameter<FirMemberDeclaration>("overriddenDeclaration")
|
||||
}
|
||||
val NON_FINAL_MEMBER_IN_FINAL_CLASS by warning<FirSourceElement, KtNamedDeclaration>(PositioningStrategy.OPEN_MODIFIER)
|
||||
val NON_FINAL_MEMBER_IN_OBJECT by warning<FirSourceElement, KtNamedDeclaration>(PositioningStrategy.OPEN_MODIFIER)
|
||||
}
|
||||
|
||||
val REDECLARATIONS by object : DiagnosticGroup("Redeclarations") {
|
||||
|
||||
@@ -90,6 +90,7 @@ object FirErrors {
|
||||
val CLASS_IN_SUPERTYPE_FOR_ENUM by error0<FirSourceElement, PsiElement>()
|
||||
val SEALED_SUPERTYPE by error0<FirSourceElement, PsiElement>()
|
||||
val SEALED_SUPERTYPE_IN_LOCAL_CLASS by error0<FirSourceElement, PsiElement>()
|
||||
val SUPERTYPE_NOT_A_CLASS_OR_INTERFACE by error1<FirSourceElement, KtElement, String>()
|
||||
|
||||
// Constructor problems
|
||||
val CONSTRUCTOR_IN_OBJECT by error0<FirSourceElement, KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
@@ -175,6 +176,8 @@ object FirErrors {
|
||||
val PROPERTY_TYPE_MISMATCH_ON_OVERRIDE by error2<FirSourceElement, KtNamedDeclaration, FirMemberDeclaration, FirMemberDeclaration>(SourceElementPositioningStrategies.DECLARATION_RETURN_TYPE)
|
||||
val VAR_TYPE_MISMATCH_ON_OVERRIDE by error2<FirSourceElement, KtNamedDeclaration, FirMemberDeclaration, FirMemberDeclaration>(SourceElementPositioningStrategies.DECLARATION_RETURN_TYPE)
|
||||
val VAR_OVERRIDDEN_BY_VAL by error2<FirSourceElement, KtNamedDeclaration, FirMemberDeclaration, FirMemberDeclaration>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
|
||||
val NON_FINAL_MEMBER_IN_FINAL_CLASS by warning0<FirSourceElement, KtNamedDeclaration>(SourceElementPositioningStrategies.OPEN_MODIFIER)
|
||||
val NON_FINAL_MEMBER_IN_OBJECT by warning0<FirSourceElement, KtNamedDeclaration>(SourceElementPositioningStrategies.OPEN_MODIFIER)
|
||||
|
||||
// Redeclarations
|
||||
val MANY_COMPANION_OBJECTS by error0<FirSourceElement, PsiElement>()
|
||||
|
||||
@@ -23,6 +23,10 @@ object FirConflictingProjectionChecker : FirBasicDeclarationChecker() {
|
||||
}
|
||||
|
||||
if (declaration is FirTypedDeclaration) {
|
||||
// The body of function contract is not fully resolved.
|
||||
if (declaration.resolvePhase == FirResolvePhase.CONTRACTS) {
|
||||
return
|
||||
}
|
||||
checkTypeRef(declaration.returnTypeRef, context, reporter)
|
||||
}
|
||||
|
||||
@@ -44,10 +48,7 @@ object FirConflictingProjectionChecker : FirBasicDeclarationChecker() {
|
||||
}
|
||||
|
||||
private fun checkTypeRef(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
// TODO: remaining implicit types should be resolved as an error type, along with proper error kind,
|
||||
// e.g., type mismatch, can't infer parameter type, syntax error, etc.
|
||||
val declaration = typeRef.safeAs<FirResolvedTypeRef>()
|
||||
?.coneTypeSafe<ConeClassLikeType>()
|
||||
val declaration = typeRef.coneTypeSafe<ConeClassLikeType>()
|
||||
?.lookupTag
|
||||
?.toSymbol(context.session)
|
||||
?.fir.safeAs<FirRegularClass>()
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.modality
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
@@ -123,3 +126,6 @@ internal fun checkPropertyInitializer(
|
||||
private val FirProperty.hasAccessorImplementation: Boolean
|
||||
get() = (getter !is FirDefaultPropertyAccessor && getter?.hasBody == true) ||
|
||||
(setter !is FirDefaultPropertyAccessor && setter?.hasBody == true)
|
||||
|
||||
|
||||
internal val FirClass<*>.canHaveOpenMembers: Boolean get() = modality() != Modality.FINAL || classKind == ClassKind.ENUM_CLASS
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirModifierList.Companion.getModifierList
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.isOpen
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
|
||||
object FirOpenMemberChecker : FirClassChecker() {
|
||||
override fun check(declaration: FirClass<*>, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (declaration.canHaveOpenMembers) return
|
||||
for (memberDeclaration in declaration.declarations) {
|
||||
if (memberDeclaration !is FirCallableMemberDeclaration<*> ||
|
||||
// Marking a constructor `open` is an error covered by diagnostic code WRONG_MODIFIER_TARGET
|
||||
memberDeclaration is FirConstructor
|
||||
) continue
|
||||
val source = memberDeclaration.source ?: continue
|
||||
if (memberDeclaration.isOpen || (source.hasOpenModifierInSource && source.shouldReportOpenFromSource)) {
|
||||
if (declaration.classKind == ClassKind.OBJECT) {
|
||||
reporter.reportOn(source, FirErrors.NON_FINAL_MEMBER_IN_OBJECT, context)
|
||||
} else {
|
||||
reporter.reportOn(source, FirErrors.NON_FINAL_MEMBER_IN_FINAL_CLASS, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val FirSourceElement.hasOpenModifierInSource: Boolean get() = getModifierList()?.modifiers?.any { it.token == KtTokens.OPEN_KEYWORD } == true
|
||||
private val FirSourceElement.shouldReportOpenFromSource: Boolean
|
||||
get() = when (kind) {
|
||||
FirRealSourceElementKind,
|
||||
FirFakeSourceElementKind.PropertyFromParameter -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.expressions.FirTryExpression
|
||||
import org.jetbrains.kotlin.fir.types.ConeTypeParameterType
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
|
||||
object FirCatchParameterChecker : FirTryExpressionChecker() {
|
||||
override fun check(expression: FirTryExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
@@ -24,11 +24,7 @@ object FirCatchParameterChecker : FirTryExpressionChecker() {
|
||||
reporter.reportOn(catchParameter.source, FirErrors.CATCH_PARAMETER_WITH_DEFAULT_VALUE, context)
|
||||
}
|
||||
|
||||
val typeRef = catchParameter.returnTypeRef
|
||||
// TODO: remaining implicit types should be resolved as an error type, along with proper error kind, most likely syntax error.
|
||||
if (typeRef !is FirResolvedTypeRef) return
|
||||
|
||||
val coneType = typeRef.type
|
||||
val coneType = catchParameter.returnTypeRef.coneType
|
||||
if (coneType is ConeTypeParameterType) {
|
||||
val isReified = coneType.lookupTag.typeParameterSymbol.fir.isReified
|
||||
|
||||
|
||||
@@ -99,6 +99,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_COMPANION_OB
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NONE_APPLICABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_FINAL_MEMBER_IN_FINAL_CLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_FINAL_MEMBER_IN_OBJECT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_MEMBER_FUNCTION_NO_BODY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_PRIVATE_CONSTRUCTOR_IN_ENUM
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_PRIVATE_OR_PROTECTED_CONSTRUCTOR_IN_SEALED
|
||||
@@ -146,6 +148,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_SUPERTYPE_
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPE_INITIALIZED_IN_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPE_NOT_A_CLASS_OR_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPER_IS_NOT_AN_EXPRESSION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPER_NOT_AVAILABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SYNTAX
|
||||
@@ -242,6 +245,8 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
map.put(CLASS_IN_SUPERTYPE_FOR_ENUM, "Enum class cannot inherit from classes")
|
||||
map.put(SEALED_SUPERTYPE, "This type is sealed, so it can be inherited by only its own nested classes or objects")
|
||||
map.put(SEALED_SUPERTYPE_IN_LOCAL_CLASS, "Local class cannot extend a sealed class")
|
||||
map.put(SUPERTYPE_NOT_A_CLASS_OR_INTERFACE, "Supertype is not a class or interface", TO_STRING)
|
||||
|
||||
|
||||
// Constructor problems
|
||||
map.put(CONSTRUCTOR_IN_OBJECT, "Constructors are not allowed for objects")
|
||||
@@ -391,6 +396,8 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
FQ_NAMES_IN_TYPES,
|
||||
FQ_NAMES_IN_TYPES
|
||||
)
|
||||
map.put(NON_FINAL_MEMBER_IN_FINAL_CLASS, "'open' has no effect in a final class")
|
||||
map.put(NON_FINAL_MEMBER_IN_OBJECT, "'open' has no effect in an object")
|
||||
map.put(
|
||||
GENERIC_THROWABLE_SUBCLASS,
|
||||
"Subclass of 'Throwable' may not have type parameters"
|
||||
|
||||
@@ -47,6 +47,7 @@ fun ConeDiagnostic.toFirDiagnostic(source: FirSourceElement): FirDiagnostic<FirS
|
||||
is ConeStubDiagnostic -> null
|
||||
is ConeIntermediateDiagnostic -> null
|
||||
is ConeContractDescriptionError -> FirErrors.ERROR_IN_CONTRACT_DESCRIPTION.on(source, this.reason)
|
||||
is ConeTypeParameterSupertype -> FirErrors.SUPERTYPE_NOT_A_CLASS_OR_INTERFACE.on(source, this.reason)
|
||||
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${this.javaClass}")
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
override val classCheckers: Set<FirClassChecker> = setOf(
|
||||
FirOverrideChecker,
|
||||
FirThrowableSubclassChecker,
|
||||
FirOpenMemberChecker,
|
||||
)
|
||||
|
||||
override val regularClassCheckers: Set<FirRegularClassChecker> = setOf(
|
||||
|
||||
@@ -18214,6 +18214,58 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
public void testKt37986() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/kt37986.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/inlineClasses/callableReferences/let")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Let {
|
||||
@Test
|
||||
public void testAllFilesPresentInLet() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/callableReferences/let"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("any.kt")
|
||||
public void testAny() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/let/any.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("anyN.kt")
|
||||
public void testAnyN() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/let/anyN.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("int.kt")
|
||||
public void testInt() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/let/int.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intN.kt")
|
||||
public void testIntN() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/let/intN.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("result.kt")
|
||||
public void testResult() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/let/result.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("string.kt")
|
||||
public void testString() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/let/string.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("stringN.kt")
|
||||
public void testStringN() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/let/stringN.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -19945,6 +19997,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/covariantOverrideWithPrimitive.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enhancedNullabilityMix.kt")
|
||||
public void testEnhancedNullabilityMix() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/enhancedNullabilityMix.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericFunInterface.kt")
|
||||
public void testGenericFunInterface() throws Exception {
|
||||
@@ -20035,6 +20093,158 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/unboundFunctionReferenceEquality.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/functionExprToJavaInterface")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class FunctionExprToJavaInterface {
|
||||
@Test
|
||||
public void testAllFilesPresentInFunctionExprToJavaInterface() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/functionExprToJavaInterface"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedSamArgument.kt")
|
||||
public void testCapturedSamArgument() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExprToJavaInterface/capturedSamArgument.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturingLambda.kt")
|
||||
public void testCapturingLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExprToJavaInterface/capturingLambda.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionLambda1.kt")
|
||||
public void testExtensionLambda1() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExprToJavaInterface/extensionLambda1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionLambda2.kt")
|
||||
public void testExtensionLambda2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExprToJavaInterface/extensionLambda2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericSam1.kt")
|
||||
public void testGenericSam1() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExprToJavaInterface/genericSam1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericSam2.kt")
|
||||
public void testGenericSam2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExprToJavaInterface/genericSam2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionExprToJavaInterface/simple.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class FunctionRefToJavaInterface {
|
||||
@Test
|
||||
@TestMetadata("adaptedFunRefWithCoercionToUnit.kt")
|
||||
public void testAdaptedFunRefWithCoercionToUnit() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/adaptedFunRefWithCoercionToUnit.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("adaptedFunRefWithDefaultParameters.kt")
|
||||
public void testAdaptedFunRefWithDefaultParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/adaptedFunRefWithDefaultParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("adaptedFunRefWithVararg.kt")
|
||||
public void testAdaptedFunRefWithVararg() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/adaptedFunRefWithVararg.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInFunctionRefToJavaInterface() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("boundExtFun.kt")
|
||||
public void testBoundExtFun() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/boundExtFun.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("boundInnerConstructorRef.kt")
|
||||
public void testBoundInnerConstructorRef() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/boundInnerConstructorRef.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("boundLocalExtFun.kt")
|
||||
public void testBoundLocalExtFun() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/boundLocalExtFun.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("boundMemberRef.kt")
|
||||
public void testBoundMemberRef() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/boundMemberRef.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("constructorRef.kt")
|
||||
public void testConstructorRef() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/constructorRef.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enhancedNullability.kt")
|
||||
public void testEnhancedNullability() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/enhancedNullability.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("innerConstructorRef.kt")
|
||||
public void testInnerConstructorRef() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/innerConstructorRef.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("localFunction1.kt")
|
||||
public void testLocalFunction1() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/localFunction1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("localFunction2.kt")
|
||||
public void testLocalFunction2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/localFunction2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("memberRef.kt")
|
||||
public void testMemberRef() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/memberRef.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nonTrivialReceiver.kt")
|
||||
public void testNonTrivialReceiver() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/nonTrivialReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/simple.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam/inlineClassInSignature")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@@ -23958,6 +24168,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/multifileClasses/kt16077.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("metadataFlag.kt")
|
||||
public void testMetadataFlag() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multifileClasses/metadataFlag.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("multifileClassPartsInitialization.kt")
|
||||
public void testMultifileClassPartsInitialization() throws Exception {
|
||||
@@ -25286,6 +25502,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/operatorConventions/kt44647.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt45022.kt")
|
||||
public void testKt45022() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/operatorConventions/kt45022.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt4987.kt")
|
||||
public void testKt4987() throws Exception {
|
||||
|
||||
@@ -3992,6 +3992,12 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
|
||||
runTest("compiler/testData/codegen/boxInline/simple/destructuringIndexClash.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("diamondInline.kt")
|
||||
public void testDiamondInline() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/simple/diamondInline.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extension.kt")
|
||||
public void testExtension() throws Exception {
|
||||
@@ -4016,6 +4022,12 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
|
||||
runTest("compiler/testData/codegen/boxInline/simple/inlineCallInInlineLambda.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineChain.kt")
|
||||
public void testInlineChain() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/simple/inlineChain.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt17431.kt")
|
||||
public void testKt17431() throws Exception {
|
||||
|
||||
@@ -3141,6 +3141,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
|
||||
public void testInterfaceHashCode() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/hashCode/interfaceHashCode.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceHashCodeWithSmartCast.kt")
|
||||
public void testInterfaceHashCodeWithSmartCast() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/hashCode/interfaceHashCodeWithSmartCast.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -3944,6 +3950,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/invokedynamic"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("functionRefToJavaInterface.kt")
|
||||
public void testFunctionRefToJavaInterface() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/invokedynamic/functionRefToJavaInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("lambdas.kt")
|
||||
public void testLambdas() throws Exception {
|
||||
@@ -5080,6 +5092,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
|
||||
runTest("compiler/testData/codegen/bytecodeText/stringOperations/concatDynamicIndyDataClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("concatDynamicUnit.kt")
|
||||
public void testConcatDynamicUnit() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/stringOperations/concatDynamicUnit.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("concatNotDynamic.kt")
|
||||
public void testConcatNotDynamic() throws Exception {
|
||||
|
||||
@@ -1346,6 +1346,12 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest {
|
||||
runTest("compiler/testData/ir/irText/expressions/kt37779.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt45022.kt")
|
||||
public void testKt45022() throws Exception {
|
||||
runTest("compiler/testData/ir/irText/expressions/kt45022.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("lambdaInCAO.kt")
|
||||
public void testLambdaInCAO() throws Exception {
|
||||
|
||||
@@ -14,10 +14,9 @@ dependencies {
|
||||
api(project(":compiler:fir:tree"))
|
||||
api(kotlinxCollectionsImmutable())
|
||||
implementation(project(":core:util.runtime"))
|
||||
implementation(project(":compiler:psi"))
|
||||
|
||||
compileOnly(project(":kotlin-reflect-api"))
|
||||
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "guava", rootProject = rootProject) }
|
||||
compileOnly(intellijCoreDep()) { includeJars("guava", rootProject = rootProject) }
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
||||
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.fir.resolve.typeForQualifier
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
|
||||
const val ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE = "_root_ide_package_"
|
||||
|
||||
@@ -92,7 +91,7 @@ class FirQualifiedNameResolver(private val components: BodyResolveComponents) {
|
||||
}
|
||||
|
||||
return buildResolvedQualifier {
|
||||
this.source = getWholeQualifierSource(source, qualifierPartsToDrop)
|
||||
this.source = source?.getWholeQualifierSourceIfPossible(qualifierPartsToDrop)
|
||||
packageFqName = resolved.packageFqName
|
||||
relativeClassFqName = resolved.relativeClassFqName
|
||||
symbol = resolved.classSymbol
|
||||
@@ -104,12 +103,4 @@ class FirQualifiedNameResolver(private val components: BodyResolveComponents) {
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getWholeQualifierSource(qualifierStartSource: FirSourceElement?, stepsToWholeQualifier: Int): FirSourceElement? {
|
||||
if (qualifierStartSource !is FirRealPsiSourceElement<*>) return qualifierStartSource
|
||||
|
||||
val qualifierStart = qualifierStartSource.psi
|
||||
val wholeQualifier = qualifierStart.parentsWithSelf.drop(stepsToWholeQualifier).first()
|
||||
return wholeQualifier.toFirPsiSourceElement()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ internal val FirElement.symbol: AbstractFirBasedSymbol<*>?
|
||||
is FirWhenSubjectExpression -> whenRef.value.subject?.symbol
|
||||
is FirSafeCallExpression -> regularQualifiedAccess.symbol
|
||||
else -> null
|
||||
}?.takeIf { this is FirThisReceiverExpression || (it !is FirFunctionSymbol<*> && it !is FirAccessorSymbol) }
|
||||
}?.takeIf { this.unwrapSmartcastExpression() is FirThisReceiverExpression || (it !is FirFunctionSymbol<*> && it !is FirAccessorSymbol) }
|
||||
|
||||
@DfaInternals
|
||||
internal val FirResolvable.symbol: AbstractFirBasedSymbol<*>?
|
||||
@@ -109,3 +109,5 @@ internal val FirResolvable.symbol: AbstractFirBasedSymbol<*>?
|
||||
is FirNamedReferenceWithCandidate -> reference.candidateSymbol
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun FirElement.unwrapSmartcastExpression(): FirElement = if (this is FirExpressionWithSmartcast) originalExpression else this
|
||||
|
||||
@@ -9,15 +9,13 @@ import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ResolutionDiagnostic
|
||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintSystemError
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
|
||||
class ConeUnresolvedReferenceError(val name: Name? = null) : ConeDiagnostic() {
|
||||
@@ -80,6 +78,10 @@ class ConeUnsupportedCallableReferenceTarget(val fir: FirCallableDeclaration<*>)
|
||||
override val reason: String get() = "Unsupported declaration for callable reference: ${fir.render()}"
|
||||
}
|
||||
|
||||
class ConeTypeParameterSupertype(val symbol: FirTypeParameterSymbol) : ConeDiagnostic() {
|
||||
override val reason: String get() = "Type parameter ${symbol.fir.name} cannot be a supertype"
|
||||
}
|
||||
|
||||
private fun describeSymbol(symbol: AbstractFirBasedSymbol<*>): String {
|
||||
return when (symbol) {
|
||||
is FirClassLikeSymbol<*> -> symbol.classId.asString()
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
package org.jetbrains.kotlin.fir.resolve.inference
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.originalForSubstitutionOverride
|
||||
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||
import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator
|
||||
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
@@ -248,7 +247,15 @@ fun extractLambdaInfoFromFunctionalType(
|
||||
if (!expectedType.isBuiltinFunctionalType(session)) return null
|
||||
|
||||
val receiverType = argument.receiverType ?: expectedType.receiverType(session)
|
||||
val returnType = argument.returnType ?: expectedType.returnType(session) ?: return null
|
||||
val lastStatement = argument.body?.statements?.singleOrNull()
|
||||
val returnType =
|
||||
// Simply { }, i.e., function literals without body. Raw FIR added an implicit return with an implicit unit type ref.
|
||||
if (lastStatement?.source?.kind is FirFakeSourceElementKind.ImplicitReturn &&
|
||||
(lastStatement as? FirReturnExpression)?.result?.source?.kind is FirFakeSourceElementKind.ImplicitUnit
|
||||
) {
|
||||
session.builtinTypes.unitType.type
|
||||
} else
|
||||
argument.returnType ?: expectedType.returnType(session) ?: return null
|
||||
val parameters = extractLambdaParameters(expectedType, argument, expectedType.isExtensionFunctionType(session), session)
|
||||
|
||||
return ResolvedLambdaAtom(
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildResolvedCallableReference
|
||||
@@ -436,7 +437,10 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
// Control flow info is necessary prerequisite because we collect return expressions in that function
|
||||
//
|
||||
// Example: second lambda in the call like list.filter({}, {})
|
||||
if (!dataFlowAnalyzer.isThereControlFlowInfoForAnonymousFunction(anonymousFunction)) return anonymousFunction.compose()
|
||||
if (!dataFlowAnalyzer.isThereControlFlowInfoForAnonymousFunction(anonymousFunction)) {
|
||||
// But, don't leave implicit type refs behind
|
||||
return transformImplicitTypeRefInAnonymousFunction(anonymousFunction)
|
||||
}
|
||||
|
||||
val expectedType = data?.getExpectedType(anonymousFunction)?.let { expectedArgumentType ->
|
||||
// From the argument mapping, the expected type of this anonymous function would be:
|
||||
@@ -509,6 +513,33 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
return result
|
||||
}
|
||||
|
||||
private fun transformImplicitTypeRefInAnonymousFunction(
|
||||
anonymousFunction: FirAnonymousFunction
|
||||
): CompositeTransformResult<FirStatement> {
|
||||
val implicitTypeTransformer = object : FirDefaultTransformer<Nothing?>() {
|
||||
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return (element.transformChildren(this, data) as E).compose()
|
||||
}
|
||||
|
||||
override fun transformImplicitTypeRef(
|
||||
implicitTypeRef: FirImplicitTypeRef,
|
||||
data: Nothing?
|
||||
): CompositeTransformResult<FirTypeRef> =
|
||||
buildErrorTypeRef {
|
||||
source = implicitTypeRef.source
|
||||
// NB: this error message assumes that it is used only if CFG for the anonymous function is not available
|
||||
diagnostic = ConeSimpleDiagnostic("Cannot infer type w/o CFG", DiagnosticKind.InferenceError)
|
||||
}.compose()
|
||||
|
||||
}
|
||||
// NB: if we transform simply all children, there would be too many type error reports.
|
||||
anonymousFunction.transformReturnTypeRef(implicitTypeTransformer, null)
|
||||
anonymousFunction.transformValueParameters(implicitTypeTransformer, null)
|
||||
anonymousFunction.transformBody(implicitTypeTransformer, null)
|
||||
return anonymousFunction.compose()
|
||||
}
|
||||
|
||||
override fun transformReturnExpression(
|
||||
returnExpression: FirReturnExpression,
|
||||
data: ExpectedArgumentType?
|
||||
|
||||
@@ -38,12 +38,15 @@ class FirSpecificTypeResolverTransformer(
|
||||
}
|
||||
}
|
||||
|
||||
override fun transformTypeRef(typeRef: FirTypeRef, data: FirScope): CompositeTransformResult<FirTypeRef> {
|
||||
override fun transformTypeRef(typeRef: FirTypeRef, data: FirScope): CompositeTransformResult<FirResolvedTypeRef> {
|
||||
typeRef.transformChildren(this, data)
|
||||
return transformType(typeRef, typeResolver.resolveType(typeRef, data, areBareTypesAllowed))
|
||||
}
|
||||
|
||||
override fun transformFunctionTypeRef(functionTypeRef: FirFunctionTypeRef, data: FirScope): CompositeTransformResult<FirTypeRef> {
|
||||
override fun transformFunctionTypeRef(
|
||||
functionTypeRef: FirFunctionTypeRef,
|
||||
data: FirScope
|
||||
): CompositeTransformResult<FirResolvedTypeRef> {
|
||||
functionTypeRef.transformChildren(this, data)
|
||||
val resolvedType = typeResolver.resolveType(functionTypeRef, data, areBareTypesAllowed).takeIfAcceptable()
|
||||
return if (resolvedType != null && resolvedType !is ConeClassErrorType) {
|
||||
@@ -62,11 +65,11 @@ class FirSpecificTypeResolverTransformer(
|
||||
}.compose()
|
||||
}
|
||||
|
||||
private fun transformType(typeRef: FirTypeRef, resolvedType: ConeKotlinType): CompositeTransformResult<FirTypeRef> {
|
||||
private fun transformType(typeRef: FirTypeRef, resolvedType: ConeKotlinType): CompositeTransformResult<FirResolvedTypeRef> {
|
||||
return if (resolvedType !is ConeClassErrorType) {
|
||||
buildResolvedTypeRef {
|
||||
source = typeRef.source
|
||||
type = resolvedType.takeIfAcceptable() ?: return typeRef.compose()
|
||||
type = resolvedType
|
||||
annotations += typeRef.annotations
|
||||
delegatedTypeRef = typeRef
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
import org.jetbrains.kotlin.fir.extensions.extensionService
|
||||
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
|
||||
import org.jetbrains.kotlin.fir.extensions.supertypeGenerators
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeTypeParameterSupertype
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.LocalClassesNavigationInfo
|
||||
import org.jetbrains.kotlin.fir.scopes.FirCompositeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
@@ -112,7 +114,7 @@ private class FirApplySupertypesTransformer(
|
||||
return super.transformAnonymousObject(anonymousObject, data)
|
||||
}
|
||||
|
||||
private fun getResolvedSupertypeRefs(classLikeDeclaration: FirClassLikeDeclaration<*>): List<FirTypeRef> {
|
||||
private fun getResolvedSupertypeRefs(classLikeDeclaration: FirClassLikeDeclaration<*>): List<FirResolvedTypeRef> {
|
||||
val status = supertypeComputationSession.getSupertypesComputationStatus(classLikeDeclaration)
|
||||
require(status is SupertypeComputationStatus.Computed) {
|
||||
"Unexpected status at FirApplySupertypesTransformer: $status for ${classLikeDeclaration.symbol.classId}"
|
||||
@@ -248,7 +250,7 @@ private class FirSupertypeResolverVisitor(
|
||||
|
||||
private fun resolveSpecificClassLikeSupertypes(
|
||||
classLikeDeclaration: FirClassLikeDeclaration<*>,
|
||||
resolveSuperTypeRefs: (FirTransformer<FirScope>, FirScope) -> List<FirTypeRef>
|
||||
resolveSuperTypeRefs: (FirTransformer<FirScope>, FirScope) -> List<FirResolvedTypeRef>
|
||||
): List<FirTypeRef> {
|
||||
when (val status = supertypeComputationSession.getSupertypesComputationStatus(classLikeDeclaration)) {
|
||||
is SupertypeComputationStatus.Computed -> return status.supertypeRefs
|
||||
@@ -282,23 +284,27 @@ private class FirSupertypeResolverVisitor(
|
||||
supertypeRefs: List<FirTypeRef>
|
||||
): List<FirTypeRef> {
|
||||
return resolveSpecificClassLikeSupertypes(classLikeDeclaration) { transformer, scope ->
|
||||
ArrayList(supertypeRefs).mapTo(mutableListOf()) {
|
||||
supertypeRefs.mapTo(mutableListOf()) {
|
||||
val superTypeRef = transformer.transformTypeRef(it, scope).single
|
||||
|
||||
if (superTypeRef.coneTypeSafe<ConeTypeParameterType>() != null)
|
||||
createErrorTypeRef(
|
||||
superTypeRef,
|
||||
"Type parameter cannot be a super-type: ${superTypeRef.coneTypeUnsafe<ConeTypeParameterType>().render()}"
|
||||
)
|
||||
else
|
||||
superTypeRef
|
||||
val typeParameterType = superTypeRef.coneTypeSafe<ConeTypeParameterType>()
|
||||
when {
|
||||
typeParameterType != null ->
|
||||
buildErrorTypeRef {
|
||||
source = superTypeRef.source
|
||||
diagnostic = ConeTypeParameterSupertype(typeParameterType.lookupTag.typeParameterSymbol)
|
||||
}
|
||||
superTypeRef !is FirResolvedTypeRef ->
|
||||
createErrorTypeRef(superTypeRef, "Unresolved super-type: ${superTypeRef.render()}")
|
||||
else ->
|
||||
superTypeRef
|
||||
}
|
||||
}.also {
|
||||
addSupertypesFromExtensions(classLikeDeclaration, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addSupertypesFromExtensions(klass: FirClassLikeDeclaration<*>, supertypeRefs: MutableList<FirTypeRef>) {
|
||||
private fun addSupertypesFromExtensions(klass: FirClassLikeDeclaration<*>, supertypeRefs: MutableList<FirResolvedTypeRef>) {
|
||||
if (supertypeGenerationExtensions.isEmpty()) return
|
||||
val provider = session.predicateBasedProvider
|
||||
for (extension in supertypeGenerationExtensions) {
|
||||
@@ -384,7 +390,7 @@ private class SupertypeComputationSession {
|
||||
supertypeStatusMap[classLikeDeclaration] = SupertypeComputationStatus.Computing
|
||||
}
|
||||
|
||||
fun storeSupertypes(classLikeDeclaration: FirClassLikeDeclaration<*>, resolvedTypesRefs: List<FirTypeRef>) {
|
||||
fun storeSupertypes(classLikeDeclaration: FirClassLikeDeclaration<*>, resolvedTypesRefs: List<FirResolvedTypeRef>) {
|
||||
require(supertypeStatusMap[classLikeDeclaration] is SupertypeComputationStatus.Computing) {
|
||||
"Unexpected in storeSupertypes supertype status for $classLikeDeclaration: ${supertypeStatusMap[classLikeDeclaration]}"
|
||||
}
|
||||
@@ -411,7 +417,7 @@ private class SupertypeComputationSession {
|
||||
}
|
||||
|
||||
val typeRefs = supertypeComputationStatus.supertypeRefs
|
||||
val resultingTypeRefs = mutableListOf<FirTypeRef>()
|
||||
val resultingTypeRefs = mutableListOf<FirResolvedTypeRef>()
|
||||
var wereChanges = false
|
||||
|
||||
for (typeRef in typeRefs) {
|
||||
@@ -453,7 +459,7 @@ sealed class SupertypeComputationStatus {
|
||||
object NotComputed : SupertypeComputationStatus()
|
||||
object Computing : SupertypeComputationStatus()
|
||||
|
||||
class Computed(val supertypeRefs: List<FirTypeRef>) : SupertypeComputationStatus()
|
||||
class Computed(val supertypeRefs: List<FirResolvedTypeRef>) : SupertypeComputationStatus()
|
||||
}
|
||||
|
||||
private typealias ScopePersistentList = PersistentList<FirScope>
|
||||
|
||||
@@ -168,7 +168,7 @@ class FirTypeResolveTransformer(
|
||||
return implicitTypeRef.compose()
|
||||
}
|
||||
|
||||
override fun transformTypeRef(typeRef: FirTypeRef, data: Nothing?): CompositeTransformResult<FirTypeRef> {
|
||||
override fun transformTypeRef(typeRef: FirTypeRef, data: Nothing?): CompositeTransformResult<FirResolvedTypeRef> {
|
||||
return typeRef.transform(typeResolverTransformer, towerScope)
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ open class FirBodyResolveTransformer(
|
||||
return (element.transformChildren(this, data) as E).compose()
|
||||
}
|
||||
|
||||
override fun transformTypeRef(typeRef: FirTypeRef, data: ResolutionMode): CompositeTransformResult<FirTypeRef> {
|
||||
override fun transformTypeRef(typeRef: FirTypeRef, data: ResolutionMode): CompositeTransformResult<FirResolvedTypeRef> {
|
||||
if (typeRef is FirResolvedTypeRef) {
|
||||
return typeRef.compose()
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
|
||||
@@ -45,6 +47,17 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
|
||||
private var containingClass: FirRegularClass? = null
|
||||
private val statusResolver: FirStatusResolver = FirStatusResolver(session, scopeSession)
|
||||
|
||||
private fun FirDeclaration.visibilityForApproximation(): Visibility {
|
||||
if (this !is FirMemberDeclaration) return Visibilities.Local
|
||||
val container = context.containers.getOrNull(context.containers.size - 2)
|
||||
val containerVisibility =
|
||||
if (container == null) Visibilities.Public
|
||||
else (container as? FirRegularClass)?.visibility ?: Visibilities.Local
|
||||
if (containerVisibility == Visibilities.Local || visibility == Visibilities.Local) return Visibilities.Local
|
||||
if (containerVisibility == Visibilities.Private) return Visibilities.Private
|
||||
return visibility
|
||||
}
|
||||
|
||||
private inline fun <T> withFirArrayOfCallTransformer(block: () -> T): T {
|
||||
transformer.expressionsTransformer.enableArrayOfCallTransformation = true
|
||||
return try {
|
||||
@@ -560,7 +573,9 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
|
||||
transformer,
|
||||
withExpectedType(
|
||||
returnExpression.resultType.approximatedIfNeededOrSelf(
|
||||
inferenceComponents.approximator, simpleFunction?.visibility, simpleFunction?.isInline == true
|
||||
inferenceComponents.approximator,
|
||||
simpleFunction?.visibilityForApproximation(),
|
||||
simpleFunction?.isInline == true
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -704,6 +719,9 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
|
||||
context.storeVariable(valueParameter)
|
||||
if (valueParameter.returnTypeRef is FirImplicitTypeRef) {
|
||||
transformer.replaceDeclarationResolvePhaseIfNeeded(valueParameter, transformerPhase)
|
||||
valueParameter.replaceReturnTypeRef(
|
||||
valueParameter.returnTypeRef.errorTypeFromPrototype(ConeSimpleDiagnostic("Unresolved value parameter type"))
|
||||
)
|
||||
return valueParameter.compose()
|
||||
}
|
||||
|
||||
@@ -987,67 +1005,50 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
|
||||
private fun storeVariableReturnType(variable: FirVariable<*>) {
|
||||
val initializer = variable.initializer
|
||||
if (variable.returnTypeRef is FirImplicitTypeRef) {
|
||||
when {
|
||||
val resultType = when {
|
||||
initializer != null -> {
|
||||
val unwrappedInitializer = (initializer as? FirExpressionWithSmartcast)?.originalExpression ?: initializer
|
||||
val expectedType = when (val resultType = unwrappedInitializer.resultType) {
|
||||
is FirImplicitTypeRef -> buildErrorTypeRef {
|
||||
diagnostic = ConeSimpleDiagnostic("No result type for initializer", DiagnosticKind.InferenceError)
|
||||
}
|
||||
else -> {
|
||||
buildResolvedTypeRef {
|
||||
type = resultType.coneType
|
||||
annotations.addAll(resultType.annotations)
|
||||
resultType.source?.fakeElement(FirFakeSourceElementKind.PropertyFromParameter)?.let {
|
||||
source = it
|
||||
}
|
||||
unwrappedInitializer.resultType
|
||||
}
|
||||
variable.getter != null && variable.getter !is FirDefaultPropertyAccessor -> variable.getter?.returnTypeRef
|
||||
else -> null
|
||||
}
|
||||
if (resultType != null) {
|
||||
val expectedType = when (resultType) {
|
||||
is FirImplicitTypeRef -> buildErrorTypeRef {
|
||||
diagnostic = ConeSimpleDiagnostic("No result type for initializer", DiagnosticKind.InferenceError)
|
||||
}
|
||||
else -> {
|
||||
buildResolvedTypeRef {
|
||||
type = resultType.coneType
|
||||
annotations.addAll(resultType.annotations)
|
||||
resultType.source?.fakeElement(FirFakeSourceElementKind.PropertyFromParameter)?.let {
|
||||
source = it
|
||||
}
|
||||
}
|
||||
}
|
||||
variable.transformReturnTypeRef(
|
||||
transformer,
|
||||
withExpectedType(
|
||||
expectedType.approximatedIfNeededOrSelf(inferenceComponents.approximator, (variable as? FirProperty)?.visibility)
|
||||
}
|
||||
variable.transformReturnTypeRef(
|
||||
transformer,
|
||||
withExpectedType(
|
||||
expectedType.approximatedIfNeededOrSelf(
|
||||
inferenceComponents.approximator,
|
||||
variable.visibilityForApproximation()
|
||||
)
|
||||
)
|
||||
}
|
||||
variable.getter != null && variable.getter !is FirDefaultPropertyAccessor -> {
|
||||
val expectedType = when (val resultType = variable.getter?.returnTypeRef) {
|
||||
is FirImplicitTypeRef -> buildErrorTypeRef {
|
||||
diagnostic = ConeSimpleDiagnostic("No result type for getter", DiagnosticKind.InferenceError)
|
||||
}
|
||||
else -> {
|
||||
resultType?.let {
|
||||
buildResolvedTypeRef {
|
||||
type = resultType.coneType
|
||||
annotations.addAll(resultType.annotations)
|
||||
resultType.source?.fakeElement(FirFakeSourceElementKind.PropertyFromParameter)?.let {
|
||||
source = it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
variable.transformReturnTypeRef(
|
||||
transformer,
|
||||
withExpectedType(
|
||||
expectedType?.approximatedIfNeededOrSelf(inferenceComponents.approximator, (variable as? FirProperty)?.visibility)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
variable.transformReturnTypeRef(
|
||||
transformer,
|
||||
withExpectedType(
|
||||
buildErrorTypeRef {
|
||||
diagnostic = ConeSimpleDiagnostic(
|
||||
"Cannot infer variable type without initializer / getter / delegate",
|
||||
DiagnosticKind.InferenceError,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
variable.transformReturnTypeRef(
|
||||
transformer,
|
||||
withExpectedType(
|
||||
buildErrorTypeRef {
|
||||
diagnostic = ConeSimpleDiagnostic(
|
||||
"Cannot infer variable type without initializer / getter / delegate",
|
||||
DiagnosticKind.InferenceError,
|
||||
)
|
||||
},
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (variable.getter?.returnTypeRef is FirImplicitTypeRef) {
|
||||
variable.getter?.transformReturnTypeRef(transformer, withExpectedType(variable.returnTypeRef))
|
||||
|
||||
@@ -262,7 +262,14 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
||||
if (functionCall.calleeReference is FirResolvedNamedReference && functionCall.resultType is FirImplicitTypeRef) {
|
||||
storeTypeFromCallee(functionCall)
|
||||
}
|
||||
if (functionCall.calleeReference !is FirSimpleNamedReference) return functionCall.compose()
|
||||
if (functionCall.calleeReference !is FirSimpleNamedReference) {
|
||||
// The callee reference can be resolved as an error very early, e.g., `super` as a callee during raw FIR creation.
|
||||
// We still need to visit/transform other parts, e.g., call arguments, to check if any other errors are there.
|
||||
if (functionCall.calleeReference !is FirResolvedNamedReference) {
|
||||
functionCall.transformChildren(transformer, data)
|
||||
}
|
||||
return functionCall.compose()
|
||||
}
|
||||
if (functionCall.calleeReference is FirNamedReferenceWithCandidate) return functionCall.compose()
|
||||
dataFlowAnalyzer.enterCall()
|
||||
functionCall.transformAnnotations(transformer, data)
|
||||
@@ -492,25 +499,41 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
||||
val firClass = type.lookupTag.toSymbol(session)?.fir ?: return this
|
||||
if (firClass !is FirTypeParameterRefsOwner || firClass.typeParameters.isEmpty()) return this
|
||||
|
||||
val baseType = argument.typeRef.coneTypeSafe<ConeKotlinType>()?.lowerBoundIfFlexible()?.fullyExpandedType(session) ?: return this
|
||||
if (baseType !is ConeClassLikeType) return this
|
||||
val baseFirClass = baseType.lookupTag.toSymbol(session)?.fir ?: return this
|
||||
|
||||
val newArguments = if (AbstractTypeChecker.isSubtypeOfClass(
|
||||
session.typeContext.newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true), baseType.lookupTag, type.lookupTag)) {
|
||||
// If actual type of declaration is more specific than bare type then we should just find
|
||||
// corresponding supertype with proper arguments
|
||||
with(session.typeContext) {
|
||||
val superType = baseType.fastCorrespondingSupertypes(type.lookupTag)?.firstOrNull() as? ConeKotlinType?
|
||||
superType?.typeArguments
|
||||
}
|
||||
} else {
|
||||
type.inheritTypeArguments(baseFirClass, baseType.typeArguments)
|
||||
} ?: return buildErrorTypeRef {
|
||||
val originalType = argument.typeRef.coneTypeSafe<ConeKotlinType>() ?: return this
|
||||
val newType = computeRepresentativeTypeForBareType(type, originalType) ?: return buildErrorTypeRef {
|
||||
source = this@withTypeArgumentsForBareType.source
|
||||
diagnostic = ConeWrongNumberOfTypeArgumentsError(firClass.typeParameters.size, firClass.symbol)
|
||||
}
|
||||
return if (newArguments.isEmpty()) this else withReplacedConeType(type.withArguments(newArguments))
|
||||
return if (newType.typeArguments.isEmpty()) this else withReplacedConeType(newType)
|
||||
}
|
||||
|
||||
private fun computeRepresentativeTypeForBareType(type: ConeClassLikeType, originalType: ConeKotlinType): ConeKotlinType? {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val originalType = originalType.lowerBoundIfFlexible().fullyExpandedType(session)
|
||||
if (originalType is ConeIntersectionType) {
|
||||
val candidatesFromIntersectedTypes = originalType.intersectedTypes.mapNotNull { computeRepresentativeTypeForBareType(type, it) }
|
||||
candidatesFromIntersectedTypes.firstOrNull { it.typeArguments.isNotEmpty() }?.let { return it }
|
||||
return candidatesFromIntersectedTypes.firstOrNull()
|
||||
}
|
||||
if (originalType !is ConeClassLikeType) return type
|
||||
val baseFirClass = originalType.lookupTag.toSymbol(session)?.fir ?: return type
|
||||
val isSubtype = AbstractTypeChecker.isSubtypeOfClass(
|
||||
session.typeContext.newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true),
|
||||
originalType.lookupTag,
|
||||
type.lookupTag
|
||||
)
|
||||
val newArguments = if (isSubtype) {
|
||||
// If actual type of declaration is more specific than bare type then we should just find
|
||||
// corresponding supertype with proper arguments
|
||||
with(session.typeContext) {
|
||||
val superType = originalType.fastCorrespondingSupertypes(type.lookupTag)?.firstOrNull() as? ConeKotlinType?
|
||||
superType?.typeArguments
|
||||
}
|
||||
} else {
|
||||
type.inheritTypeArguments(baseFirClass, originalType.typeArguments)
|
||||
} ?: return null
|
||||
if (newArguments.isEmpty()) return type
|
||||
return type.withArguments(newArguments)
|
||||
}
|
||||
|
||||
override fun transformTypeOperatorCall(
|
||||
|
||||
@@ -21,9 +21,7 @@ import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.firUnsafe
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolved
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.symbols.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
@@ -44,6 +42,11 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
||||
return this is ConeIntegerLiteralType
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isLocalType(): Boolean {
|
||||
if (this !is ConeClassLikeLookupTag) return false
|
||||
return classId.isLocal
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.possibleIntegerTypes(): Collection<KotlinTypeMarker> {
|
||||
return (this as? ConeIntegerLiteralType)?.possibleTypes ?: emptyList()
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.fir.types
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.classId
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousObject
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
@@ -309,7 +309,8 @@ private fun FirTypeRef.hideLocalTypeIfNeeded(
|
||||
?.type as? ConeClassLikeType)
|
||||
?.lookupTag as? ConeClassLookupTagWithFixedSymbol)
|
||||
?.symbol?.fir
|
||||
if (firClass?.classId?.isLocal != true) {
|
||||
if (firClass !is FirAnonymousObject) {
|
||||
// NB: local classes are acceptable here, but reported by EXPOSED_* checkers as errors
|
||||
return this
|
||||
}
|
||||
if (firClass.superTypeRefs.size > 1) {
|
||||
@@ -318,7 +319,7 @@ private fun FirTypeRef.hideLocalTypeIfNeeded(
|
||||
}
|
||||
}
|
||||
val superType = firClass.superTypeRefs.single()
|
||||
if (superType is FirResolvedTypeRef && !superType.isAny) {
|
||||
if (superType is FirResolvedTypeRef) {
|
||||
return superType
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,3 +56,20 @@ fun <R : FirTypeRef> R.copyWithNewSourceKind(newKind: FirFakeSourceElementKind):
|
||||
} as R
|
||||
}
|
||||
|
||||
/**
|
||||
* Let's take `a.b.c.call()` expression as an example.
|
||||
*
|
||||
* This function allows to transform `SourceElement(psi = 'a')` to `SourceElement(psi = 'a.b.c')`
|
||||
* ([stepsToWholeQualifier] should be = 2 for that).
|
||||
*
|
||||
* @receiver original source element
|
||||
* @param stepsToWholeQualifier distance between the original psi and the whole qualifier psi
|
||||
*/
|
||||
fun FirSourceElement.getWholeQualifierSourceIfPossible(stepsToWholeQualifier: Int): FirSourceElement {
|
||||
if (this !is FirRealPsiSourceElement<*>) return this
|
||||
|
||||
val qualifiersChain = generateSequence(psi) { it.parent }
|
||||
val wholeQualifier = qualifiersChain.drop(stepsToWholeQualifier).first()
|
||||
|
||||
return wholeQualifier.toFirPsiSourceElement() as FirRealPsiSourceElement
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.util.Computable
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiJavaModule
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
class KotlinBinaryClassCache : Disposable {
|
||||
private class RequestCache {
|
||||
@@ -43,17 +44,22 @@ class KotlinBinaryClassCache : Disposable {
|
||||
}
|
||||
|
||||
private val cache = object : ThreadLocal<RequestCache>() {
|
||||
private val requestCaches = CopyOnWriteArrayList<RequestCache>()
|
||||
|
||||
override fun initialValue(): RequestCache {
|
||||
return RequestCache()
|
||||
return RequestCache().also { requestCaches.add(it) }
|
||||
}
|
||||
|
||||
override fun remove() {
|
||||
for (cache in requestCaches) {
|
||||
cache.result = null
|
||||
cache.virtualFile = null
|
||||
}
|
||||
super.remove()
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
cache.get().apply {
|
||||
result = null
|
||||
virtualFile = null
|
||||
}
|
||||
|
||||
// This is only relevant for tests. We create a new instance of Application for each test, and so a new instance of this service is
|
||||
// also created for each test. However all tests share the same event dispatch thread, which would collect all instances of this
|
||||
// thread-local if they're not removed properly. Each instance would transitively retain VFS resulting in OutOfMemoryError
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory3
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.isError
|
||||
|
||||
@@ -80,7 +81,10 @@ class ExposedVisibilityChecker(private val trace: BindingTrace? = null) {
|
||||
// for checking situation with modified basic visibility
|
||||
visibility: DescriptorVisibility = functionDescriptor.visibility
|
||||
): Boolean {
|
||||
val functionVisibility = functionDescriptor.effectiveVisibility(visibility)
|
||||
var functionVisibility = functionDescriptor.effectiveVisibility(visibility)
|
||||
if (functionDescriptor is ConstructorDescriptor && functionDescriptor.constructedClass.isSealed() && function.visibilityModifier() == null) {
|
||||
functionVisibility = EffectiveVisibility.Private
|
||||
}
|
||||
var result = true
|
||||
if (function !is KtConstructor<*>) {
|
||||
val restricting = functionDescriptor.returnType?.leastPermissiveDescriptor(functionVisibility)
|
||||
|
||||
@@ -83,8 +83,13 @@ class FunctionInlining(
|
||||
|
||||
private var containerScope: ScopeWithIr? = null
|
||||
|
||||
// private val inlineGraphTracker: InlineGraphTracker = InlineGraphTracker()
|
||||
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
// TODO container: IrSymbolDeclaration
|
||||
// val file = container.file
|
||||
// inlineGraphTracker.enterFile(file)
|
||||
containerScope = createScope(container as IrSymbolOwner)
|
||||
irBody.accept(this, null)
|
||||
containerScope = null
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("UNUSED_PARAMETER")
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower.inline
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import java.security.MessageDigest
|
||||
|
||||
fun ByteArray.md5(): Long {
|
||||
val d = MessageDigest.getInstance("MD5").digest(this)!!
|
||||
return ((d[0].toLong() and 0xFFL)
|
||||
or ((d[1].toLong() and 0xFFL) shl 8)
|
||||
or ((d[2].toLong() and 0xFFL) shl 16)
|
||||
or ((d[3].toLong() and 0xFFL) shl 24)
|
||||
or ((d[4].toLong() and 0xFFL) shl 32)
|
||||
or ((d[5].toLong() and 0xFFL) shl 40)
|
||||
or ((d[6].toLong() and 0xFFL) shl 48)
|
||||
or ((d[7].toLong() and 0xFFL) shl 56))
|
||||
}
|
||||
|
||||
class InlineFunctionFlatHashBuilder : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildren(this, null)
|
||||
}
|
||||
|
||||
|
||||
private val fileToHash: MutableMap<IrFile, MutableMap<IrSimpleFunction, Long>> = mutableMapOf()
|
||||
|
||||
private var currentMap: MutableMap<IrSimpleFunction, Long>? = null
|
||||
|
||||
override fun visitFile(declaration: IrFile) {
|
||||
currentMap = fileToHash.getOrPut(declaration) { mutableMapOf() }
|
||||
declaration.acceptChildren(this, null)
|
||||
currentMap = null
|
||||
}
|
||||
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
|
||||
if (declaration.isInline) {
|
||||
val m = currentMap!!
|
||||
m[declaration] = declaration.dump().toByteArray().md5()
|
||||
}
|
||||
// do not go deeper since local declaration cannot be public api
|
||||
}
|
||||
|
||||
val idToHashMap: Map<IrSimpleFunction, Long> get() = fileToHash.values.flatMap { it.entries }.map { it.key to it.value }.toMap()
|
||||
|
||||
}
|
||||
|
||||
interface InlineFunctionHashProvider {
|
||||
fun hashForExternalFunction(declaration: IrSimpleFunction): Long?
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
class InlineFunctionHashBuilder(
|
||||
private val hashProvider: InlineFunctionHashProvider,
|
||||
private val flatHashes: Map<IrSimpleFunction, Long>
|
||||
) {
|
||||
private val inlineGraph: MutableMap<IrSimpleFunction, Set<IrSimpleFunction>> = mutableMapOf()
|
||||
|
||||
private inner class GraphBuilder : IrElementVisitor<Unit, MutableSet<IrSimpleFunction>> {
|
||||
|
||||
override fun visitElement(element: IrElement, data: MutableSet<IrSimpleFunction>) {
|
||||
element.acceptChildren(this, data)
|
||||
}
|
||||
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction, data: MutableSet<IrSimpleFunction>) {
|
||||
if (declaration.isInline) {
|
||||
val newGraph = mutableSetOf<IrSimpleFunction>()
|
||||
inlineGraph[declaration] = newGraph
|
||||
declaration.acceptChildren(this, newGraph)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun visitCall(expression: IrCall, data: MutableSet<IrSimpleFunction>) {
|
||||
val callee = expression.symbol.owner
|
||||
|
||||
if (callee.isInline) {
|
||||
data.add(callee)
|
||||
}
|
||||
|
||||
expression.acceptChildren(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun topologicalOrder(): List<IrSimpleFunction> {
|
||||
return DFS.topologicalOrder(inlineGraph.keys) {
|
||||
inlineGraph[it] ?: run {
|
||||
// assert() not in current module
|
||||
emptySet()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkCircles() {
|
||||
|
||||
val visited = mutableSetOf<IrSimpleFunction>()
|
||||
for (f in inlineGraph.keys) {
|
||||
|
||||
fun walk(current: IrSimpleFunction) {
|
||||
if (!visited.add(current)) {
|
||||
error("Inline circle detected: ${current.render()} into ${f.render()}")
|
||||
}
|
||||
|
||||
inlineGraph[current]?.let {
|
||||
it.forEach { callee -> walk(callee) }
|
||||
}
|
||||
|
||||
visited.remove(current)
|
||||
}
|
||||
|
||||
walk(f)
|
||||
|
||||
assert(visited.isEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun buildHashes(dirtyFiles: Collection<IrFile>): Map<IrSimpleFunction, Long> {
|
||||
|
||||
dirtyFiles.forEach { it.acceptChildren(GraphBuilder(), mutableSetOf()) }
|
||||
|
||||
checkCircles()
|
||||
|
||||
val rpo = topologicalOrder()
|
||||
|
||||
val computedHashes = mutableMapOf<IrSimpleFunction, Long>()
|
||||
|
||||
for (f in rpo) {
|
||||
val stringHash = buildString {
|
||||
val callees = inlineGraph[f] ?: error("Expected to be in")
|
||||
// TODO: should it be a kind of stable order?
|
||||
for (callee in callees) {
|
||||
val hash = computedHashes[callee] ?: hashProvider.hashForExternalFunction(callee)
|
||||
?: error("Internal error: No has found for ${callee.render()}")
|
||||
append(hash.toString(Character.MAX_RADIX))
|
||||
}
|
||||
|
||||
append(flatHashes[f] ?: error("Internal error: No flat hash for ${f.render()}"))
|
||||
}
|
||||
|
||||
computedHashes[f] = stringHash.toByteArray().md5()
|
||||
}
|
||||
|
||||
return computedHashes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//class InlineGraphTracker : IrElementVisitor<Unit, String?> {
|
||||
// override fun visitElement(element: IrElement, data: String?) {
|
||||
// element.acceptChildren(this, data)
|
||||
// }
|
||||
//
|
||||
// override fun visitFile(declaration: IrFile, data: String?) {
|
||||
// val path = declaration.fileEntry.name
|
||||
// currentFileSet = fileUsageMap.getOrPut(path) { mutableSetOf() }
|
||||
// declaration.acceptChildren(this, path)
|
||||
// currentFileSet = null
|
||||
// }
|
||||
//
|
||||
// override fun visitCall(expression: IrCall, data: String?) {
|
||||
// super.visitCall(expression, data)
|
||||
//
|
||||
// val callee = expression.symbol.owner
|
||||
//
|
||||
// if (callee.isInline) {
|
||||
// val calleePath = callee.file.fileEntry.name
|
||||
// if (calleePath != data) {
|
||||
// val fileSet = currentFileSet ?: error("...")
|
||||
// fileSet.add(calleePath)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private var currentFileSet: MutableSet<String>? = null
|
||||
// private val fileUsageMap: MutableMap<String, MutableSet<String>> = mutableMapOf()
|
||||
//
|
||||
// operator fun get(path: String): Set<String> = fileUsageMap[path] ?: emptySet()
|
||||
//
|
||||
// fun invalidateForFile(path: String) { fileUsageMap.remove(path) }
|
||||
//}
|
||||
|
||||
//class InlineGraphTracker2 : IrElementVisitorVoid {
|
||||
//
|
||||
//
|
||||
// class GraphEdge(val from: String, val to: String) {
|
||||
//
|
||||
// constructor(fileFrom: IrFile, fileTo: IrFile) : this(fileFrom.fileEntry.name, fileTo.fileEntry.name)
|
||||
//
|
||||
// override fun equals(other: Any?): Boolean {
|
||||
// return other is GraphEdge && from == other.from && to == other.to
|
||||
// }
|
||||
//
|
||||
// override fun hashCode(): Int {
|
||||
// return from.hashCode() xor to.hashCode()
|
||||
// }
|
||||
//
|
||||
// override fun toString(): String {
|
||||
// return buildString {
|
||||
// append(from)
|
||||
// append(" -> ")
|
||||
// append(to)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun isEdgeFor(f: IrFile): Boolean = from == f.fileEntry.name || to == f.fileEntry.name
|
||||
// }
|
||||
//
|
||||
//
|
||||
// fun dump(): String {
|
||||
// return buildString {
|
||||
// appendLine("Inline Graph [")
|
||||
// graph.forEach {
|
||||
// append("\t")
|
||||
// appendLine(it.toString())
|
||||
// }
|
||||
// appendLine("]")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private val graph = mutableSetOf<GraphEdge>()
|
||||
//
|
||||
// private var currentTo: IrFile? = null
|
||||
//
|
||||
// override fun visitElement(element: IrElement) {
|
||||
// element.acceptChildren(this, null)
|
||||
// }
|
||||
//
|
||||
//
|
||||
// override fun visitFile(declaration: IrFile) {
|
||||
// enterFile(declaration)
|
||||
// super.visitFile(declaration)
|
||||
// }
|
||||
//
|
||||
//
|
||||
// override fun visitCall(expression: IrCall) {
|
||||
//
|
||||
// val callee = expression.symbol.owner
|
||||
//
|
||||
// if (callee.isInline) {
|
||||
// trackFile(callee.file)
|
||||
// }
|
||||
//
|
||||
// super.visitCall(expression)
|
||||
// }
|
||||
//
|
||||
// fun enterFile(file: IrFile) {
|
||||
// currentTo = file
|
||||
// }
|
||||
//
|
||||
// fun trackFile(file: IrFile) {
|
||||
// if (file !== currentTo) { // do not track itself
|
||||
// graph.add(GraphEdge(file, currentTo ?: error("Has to be non-null")))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun copy(): InlineGraphTracker2 {
|
||||
// return InlineGraphTracker2().also { it.graph.addAll(graph) }
|
||||
// }
|
||||
//
|
||||
// fun invalidateForFile(path: String): Boolean {
|
||||
// return graph.removeIf { it.to === path }
|
||||
// }
|
||||
//
|
||||
// class InvalidationSet(private val from: String, val files: Set<String>) {
|
||||
// override fun toString(): String {
|
||||
// return buildString {
|
||||
// appendLine("Invalidation set for ${File(from).canonicalPath} -> {")
|
||||
// files.forEach { appendLine("\t${File(it).canonicalPath}") }
|
||||
// appendLine("}")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun isEmpty(): Boolean = files.isEmpty()
|
||||
// }
|
||||
//
|
||||
// fun getInvalidationSetForDirtyFile(path: String): InvalidationSet {
|
||||
// val visited = mutableSetOf<String>()
|
||||
//
|
||||
// fun walk(f: String) {
|
||||
// if (f in visited) return
|
||||
// visited.add(f)
|
||||
// graph.forEach { if (it.from == f) walk(it.to) }
|
||||
// }
|
||||
//
|
||||
// walk(path)
|
||||
//
|
||||
// visited.remove(path)
|
||||
//
|
||||
// return InvalidationSet(path, visited)
|
||||
// }
|
||||
//}
|
||||
@@ -5,15 +5,12 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
compile(project(":compiler:util"))
|
||||
compile(project(":compiler:frontend"))
|
||||
compile(project(":compiler:backend-common"))
|
||||
compile(project(":compiler:ir.tree"))
|
||||
compile(project(":compiler:ir.psi2ir"))
|
||||
compile(project(":compiler:ir.backend.common"))
|
||||
compile(project(":compiler:ir.serialization.common"))
|
||||
compile(project(":compiler:ir.serialization.js"))
|
||||
compile(project(":compiler:ir.tree.persistent"))
|
||||
compile(project(":compiler:ir.tree.impl"))
|
||||
compile(project(":compiler:ir.serialization.js"))
|
||||
compile(project(":js:js.ast"))
|
||||
compile(project(":js:js.frontend"))
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
@@ -39,13 +38,13 @@ class JsIrBackendContext(
|
||||
val module: ModuleDescriptor,
|
||||
override val irBuiltIns: IrBuiltIns,
|
||||
val symbolTable: SymbolTable,
|
||||
irModuleFragment: IrModuleFragment,
|
||||
stdlibModule: IrModuleFragment,
|
||||
val additionalExportedDeclarationNames: Set<FqName>,
|
||||
override val configuration: CompilerConfiguration, // TODO: remove configuration from backend context
|
||||
override val scriptMode: Boolean = false,
|
||||
override val es6mode: Boolean = false,
|
||||
val propertyLazyInitialization: Boolean = false,
|
||||
override val irFactory: IrFactory = IrFactoryImpl
|
||||
override val irFactory: IrFactory
|
||||
) : JsCommonBackendContext {
|
||||
val fileToInitializationFuns: MutableMap<IrFile, IrSimpleFunction?> = mutableMapOf()
|
||||
val fileToInitializerPureness: MutableMap<IrFile, Boolean> = mutableMapOf()
|
||||
@@ -172,7 +171,7 @@ class JsIrBackendContext(
|
||||
|
||||
fun getOperatorByName(name: Name, type: IrSimpleType) = operatorMap[name]?.get(type.classifier)
|
||||
|
||||
override val ir = object : Ir<JsIrBackendContext>(this, irModuleFragment) {
|
||||
override val ir = object : Ir<JsIrBackendContext>(this, stdlibModule) {
|
||||
override val symbols = object : Symbols<JsIrBackendContext>(this@JsIrBackendContext, irBuiltIns, symbolTable) {
|
||||
override val throwNullPointerException =
|
||||
symbolTable.referenceSimpleFunction(getFunctions(kotlinPackageFqn.child(Name.identifier("THROW_NPE"))).single())
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.analyzer.AbstractAnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.generateTests
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.StageController
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
|
||||
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
||||
import org.jetbrains.kotlin.ir.util.noUnboundLeft
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
class CompilerResult(
|
||||
val jsCode: JsCode?,
|
||||
val dceJsCode: JsCode?,
|
||||
val tsDefinitions: String? = null
|
||||
)
|
||||
|
||||
class JsCode(val mainModule: String, val dependencies: Iterable<Pair<String, String>> = emptyList())
|
||||
|
||||
fun compile(
|
||||
project: Project,
|
||||
mainModule: MainModule,
|
||||
analyzer: AbstractAnalyzerWithCompilerReport,
|
||||
configuration: CompilerConfiguration,
|
||||
phaseConfig: PhaseConfig,
|
||||
allDependencies: KotlinLibraryResolveResult,
|
||||
friendDependencies: List<KotlinLibrary>,
|
||||
mainArguments: List<String>?,
|
||||
exportedDeclarations: Set<FqName> = emptySet(),
|
||||
generateFullJs: Boolean = true,
|
||||
generateDceJs: Boolean = false,
|
||||
dceDriven: Boolean = false,
|
||||
es6mode: Boolean = false,
|
||||
multiModule: Boolean = false,
|
||||
relativeRequirePath: Boolean = false,
|
||||
propertyLazyInitialization: Boolean,
|
||||
): CompilerResult {
|
||||
val irFactory = if (dceDriven) PersistentIrFactory() else IrFactoryImpl
|
||||
|
||||
val (moduleFragment: IrModuleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) =
|
||||
loadIr(project, mainModule, analyzer, configuration, allDependencies, friendDependencies, irFactory)
|
||||
|
||||
val moduleDescriptor = moduleFragment.descriptor
|
||||
|
||||
val allModules = when (mainModule) {
|
||||
is MainModule.SourceFiles -> dependencyModules + listOf(moduleFragment)
|
||||
is MainModule.Klib -> dependencyModules
|
||||
}
|
||||
|
||||
val context = JsIrBackendContext(
|
||||
moduleDescriptor,
|
||||
irBuiltIns,
|
||||
symbolTable,
|
||||
allModules.first(),
|
||||
exportedDeclarations,
|
||||
configuration,
|
||||
es6mode = es6mode,
|
||||
propertyLazyInitialization = propertyLazyInitialization,
|
||||
irFactory = irFactory
|
||||
)
|
||||
|
||||
// Load declarations referenced during `context` initialization
|
||||
val irProviders = listOf(deserializer)
|
||||
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
|
||||
|
||||
deserializer.postProcess()
|
||||
symbolTable.noUnboundLeft("Unbound symbols at the end of linker")
|
||||
|
||||
allModules.forEach { module ->
|
||||
moveBodilessDeclarationsToSeparatePlace(context, module)
|
||||
}
|
||||
|
||||
// TODO should be done incrementally
|
||||
generateTests(context, allModules.last())
|
||||
|
||||
if (dceDriven) {
|
||||
val controller = MutableController(context, pirLowerings)
|
||||
|
||||
check(irFactory is PersistentIrFactory)
|
||||
irFactory.stageController = controller
|
||||
|
||||
controller.currentStage = controller.lowerings.size + 1
|
||||
|
||||
eliminateDeadDeclarations(allModules, context)
|
||||
|
||||
irFactory.stageController = StageController(controller.currentStage)
|
||||
|
||||
val transformer = IrModuleToJsTransformer(
|
||||
context,
|
||||
mainArguments,
|
||||
fullJs = true,
|
||||
dceJs = false,
|
||||
multiModule = multiModule,
|
||||
relativeRequirePath = relativeRequirePath
|
||||
)
|
||||
return transformer.generateModule(allModules)
|
||||
} else {
|
||||
jsPhases.invokeToplevel(phaseConfig, context, allModules)
|
||||
val transformer = IrModuleToJsTransformer(
|
||||
context,
|
||||
mainArguments,
|
||||
fullJs = generateFullJs,
|
||||
dceJs = generateDceJs,
|
||||
multiModule = multiModule,
|
||||
relativeRequirePath = relativeRequirePath
|
||||
)
|
||||
return transformer.generateModule(allModules)
|
||||
}
|
||||
}
|
||||
|
||||
fun generateJsCode(
|
||||
context: JsIrBackendContext,
|
||||
moduleFragment: IrModuleFragment,
|
||||
nameTables: NameTables
|
||||
): String {
|
||||
moveBodilessDeclarationsToSeparatePlace(context, moduleFragment)
|
||||
jsPhases.invokeToplevel(PhaseConfig(jsPhases), context, listOf(moduleFragment))
|
||||
|
||||
val transformer = IrModuleToJsTransformer(context, null, true, nameTables)
|
||||
return transformer.generateModule(listOf(moduleFragment)).jsCode!!.mainModule
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("UNUSED_VARIABLE", "UNUSED_PARAMETER")
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.lower.inline.InlineFunctionFlatHashBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.inline.InlineFunctionHashBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.inline.InlineFunctionHashProvider
|
||||
import org.jetbrains.kotlin.backend.common.lower.inline.md5
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
import org.jetbrains.kotlin.ir.util.file
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.library.SerializedIrFile
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
|
||||
class CompilerResult(
|
||||
val jsCode: JsCode?,
|
||||
val dceJsCode: JsCode?,
|
||||
val tsDefinitions: String? = null
|
||||
)
|
||||
|
||||
class JsCode(val mainModule: String, val dependencies: Iterable<Pair<String, String>> = emptyList())
|
||||
|
||||
typealias Hash = Long
|
||||
|
||||
interface PersistentCacheProvider {
|
||||
fun invalidateForFile(path: String)
|
||||
|
||||
fun updateFingerPrint(path: String, fingerprint: Long)
|
||||
|
||||
fun md5ForFile(path: String): Long
|
||||
|
||||
fun serializedParts(path: String): SerializedIrFile
|
||||
|
||||
fun inlineGraphForFile(path: String): Collection<Pair<IdSignature, Hash>>
|
||||
|
||||
fun inlineHashes(path: String): Map<IdSignature, Hash>
|
||||
|
||||
fun inlineHashes(): Map<IdSignature, Hash>
|
||||
|
||||
|
||||
companion object {
|
||||
object Empty : PersistentCacheProvider {
|
||||
override fun invalidateForFile(path: String) {}
|
||||
override fun updateFingerPrint(path: String, fingerprint: Long) {}
|
||||
override fun md5ForFile(path: String): Long = 42L
|
||||
override fun serializedParts(path: String): SerializedIrFile {
|
||||
val zero = ByteArray(0)
|
||||
return SerializedIrFile(zero, "", path, zero, zero, zero, zero, zero)
|
||||
}
|
||||
|
||||
override fun inlineGraphForFile(path: String): Collection<Pair<IdSignature, Hash>> = emptyList()
|
||||
override fun inlineHashes(): Map<IdSignature, Hash> = emptyMap()
|
||||
override fun inlineHashes(path: String): Map<IdSignature, Hash> = emptyMap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun PersistentCacheConsumer.buildForFile(file: IrFile) {
|
||||
TODO("Build cache for ${file.fileEntry.name}")
|
||||
}
|
||||
|
||||
|
||||
fun SerializedIrFile.fingerprint(): Long {
|
||||
return ((((types.md5() * 31) + signatures.md5()) * 31 + strings.md5()) * 31 + declarations.md5()) * 31 + bodies.md5()
|
||||
}
|
||||
|
||||
|
||||
fun <T> Iterable<T>.isIntersectedWith(other: Set<T>): Boolean = any { it in other }
|
||||
|
||||
//fun rebuildCache(
|
||||
// moduleFragment: IrModuleFragment,
|
||||
// cache: PersistentCacheProvider,
|
||||
// inlineGraphTracker: InlineGraphTracker,
|
||||
// module2changedFiles: Map<IrModuleFragment, Set<String>>
|
||||
//): Set<String> {
|
||||
// // TODO: How to detect deleted files?
|
||||
//
|
||||
// val dirtyFiles = mutableSetOf<String>()
|
||||
//
|
||||
// val currentModulePaths = moduleFragment.files.map { it.fileEntry.name }
|
||||
//
|
||||
// for (file in currentModulePaths) {
|
||||
//
|
||||
// // 1. get cached fingerprints
|
||||
// val fileOldFingerprint = cache.md5ForFile(file)
|
||||
//
|
||||
// // 2. calculate new fingerprints
|
||||
// val fileNewFingerprint = cache.serializedParts(file).fingerprint()
|
||||
//
|
||||
// if (fileOldFingerprint != fileNewFingerprint) {
|
||||
// cache.updateFingerPrint(file, fileNewFingerprint)
|
||||
//
|
||||
// // 3. form initial dirty set
|
||||
// dirtyFiles.add(file)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // TODO: rethink using fingerprint of inlined files
|
||||
//
|
||||
// // TODO: increase granularity level from file to inline function
|
||||
//
|
||||
// // 4. Take into account changes from dependencies
|
||||
// for (file in currentModulePaths) {
|
||||
// val inlineSet = inlineGraphTracker[file]
|
||||
//
|
||||
// if (module2changedFiles.any { it.value.isIntersectedWith(inlineSet) }) {
|
||||
// dirtyFiles.add(file)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// var dirtySetSize: Int
|
||||
//
|
||||
// // 5. expand dirty inline functions effect across the module
|
||||
// do {
|
||||
// dirtySetSize = dirtyFiles.size
|
||||
//
|
||||
// for (file in currentModulePaths) {
|
||||
// val inlineSet = inlineGraphTracker[file]
|
||||
// if (dirtyFiles.isIntersectedWith(inlineSet)) {
|
||||
// dirtyFiles.add(file)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// } while (dirtySetSize != dirtyFiles.size)
|
||||
//
|
||||
// // 6. invalidate caches
|
||||
// for (dirty in dirtyFiles) {
|
||||
// cache.invalidateForFile(dirty) // persistent cache
|
||||
// inlineGraphTracker.invalidateForFile(dirty) // inline graph
|
||||
// }
|
||||
//
|
||||
// // 7. rebuild persistent caches
|
||||
// for (dirty in dirtyFiles) {
|
||||
// val irFile = moduleFragment.files.single { it.fileEntry.name == dirty }
|
||||
// cache.buildForFile(irFile)
|
||||
// }
|
||||
//
|
||||
// return dirtyFiles
|
||||
//}
|
||||
|
||||
|
||||
private fun invalidateCacheForModule(
|
||||
libraryFiles: Set<String>,
|
||||
externalHashes: Map<IdSignature, Hash>,
|
||||
thisHashes: MutableMap<String, Map<IdSignature, Hash>>,
|
||||
cacheProvider: PersistentCacheProvider,
|
||||
cacheConsumer: PersistentCacheConsumer
|
||||
): Set<String> {
|
||||
|
||||
val dirtyFiles = mutableSetOf<String>()
|
||||
|
||||
for (file in libraryFiles) {
|
||||
|
||||
// 1. get cached fingerprints
|
||||
val fileOldFingerprint = cacheProvider.md5ForFile(file)
|
||||
|
||||
// 2. calculate new fingerprints
|
||||
val fileNewFingerprint = cacheProvider.serializedParts(file).fingerprint()
|
||||
|
||||
if (fileOldFingerprint != fileNewFingerprint) {
|
||||
cacheConsumer.commitFingerPrint(file, fileNewFingerprint)
|
||||
thisHashes.remove(file)
|
||||
|
||||
// 3. form initial dirty set
|
||||
dirtyFiles.add(file)
|
||||
}
|
||||
}
|
||||
|
||||
// 4. extend dirty set with inline functions
|
||||
|
||||
// TODO: should it be met somehow?
|
||||
|
||||
var oldSize: Int
|
||||
do {
|
||||
oldSize = dirtyFiles.size
|
||||
for (file in libraryFiles) {
|
||||
|
||||
if (file in dirtyFiles) continue
|
||||
|
||||
val inlineGraph = cacheProvider.inlineGraphForFile(file)
|
||||
|
||||
for ((sig, oldHash) in inlineGraph) {
|
||||
val actualHash = externalHashes[sig] ?: thisHashes.values.firstNotNullResult { it[sig] }
|
||||
|
||||
if (actualHash != null) {
|
||||
if (oldHash == actualHash) continue
|
||||
}
|
||||
|
||||
thisHashes.remove(file)
|
||||
dirtyFiles.add(file)
|
||||
}
|
||||
}
|
||||
} while (oldSize != dirtyFiles.size)
|
||||
|
||||
// 5. invalidate caches
|
||||
for (dirty in dirtyFiles) {
|
||||
cacheConsumer.invalidateForFile(dirty)
|
||||
}
|
||||
|
||||
return dirtyFiles
|
||||
}
|
||||
|
||||
fun KotlinLibrary.files(): Set<String> {
|
||||
TODO("...")
|
||||
}
|
||||
|
||||
interface PersistentCacheConsumer {
|
||||
fun commitInlineFunctions(path: String, hashes: Collection<Pair<IdSignature, Hash>>)
|
||||
fun commitFingerPrint(path: String, fingerprint: Long)
|
||||
fun invalidateForFile(path: String)
|
||||
}
|
||||
|
||||
private fun buildCacheForModule(
|
||||
irModule: IrModuleFragment,
|
||||
dirtyFiles: Set<String>,
|
||||
cleanInlineHashes: Map<IdSignature, Hash>,
|
||||
cacheConsumer: PersistentCacheConsumer
|
||||
) {
|
||||
val dirtyIrFiles = irModule.files.filter { it.fileEntry.name in dirtyFiles }
|
||||
|
||||
val flatHasher = InlineFunctionFlatHashBuilder()
|
||||
|
||||
dirtyIrFiles.forEach { it.acceptVoid(flatHasher) }
|
||||
|
||||
val flatHashes = flatHasher.idToHashMap
|
||||
|
||||
val hashProvider = object : InlineFunctionHashProvider {
|
||||
override fun hashForExternalFunction(declaration: IrSimpleFunction): Hash? {
|
||||
return declaration.symbol.signature?.let { cleanInlineHashes[it] }
|
||||
}
|
||||
}
|
||||
|
||||
val hashBuilder = InlineFunctionHashBuilder(hashProvider, flatHashes)
|
||||
|
||||
val hashes = hashBuilder.buildHashes(dirtyIrFiles)
|
||||
|
||||
val splitPerFiles = hashes.entries.groupBy({ it.key.file }) {
|
||||
val signature = it.key.symbol.signature ?: error("Unexpected private inline fun ${it.key.render()}")
|
||||
signature to it.value
|
||||
}
|
||||
|
||||
for (irFile in dirtyIrFiles) {
|
||||
cacheConsumer.commitInlineFunctions(irFile.fileEntry.name, splitPerFiles[irFile]!!)
|
||||
cacheConsumer.buildForFile(irFile)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadModules(rpo: List<KotlinLibrary>, dependencyGraph: Map<KotlinLibrary, Collection<KotlinLibrary>>): Map<ModuleDescriptor, KotlinLibrary> {
|
||||
TODO("...")
|
||||
}
|
||||
|
||||
private fun createLinker(loadedModules: Map<ModuleDescriptor, KotlinLibrary>): JsIrLinker {
|
||||
TODO("....")
|
||||
}
|
||||
|
||||
|
||||
fun Map<KotlinLibrary, Collection<KotlinLibrary>>.transitiveClosure(library: KotlinLibrary): Collection<KotlinLibrary> {
|
||||
val visited = mutableSetOf<KotlinLibrary>()
|
||||
|
||||
fun walk(lib: KotlinLibrary) {
|
||||
if (visited.add(lib)) {
|
||||
get(lib)?.let { it.forEach { d -> walk(d) } }
|
||||
}
|
||||
}
|
||||
|
||||
walk(library)
|
||||
|
||||
return visited
|
||||
}
|
||||
|
||||
fun actualizationCacheLoop(
|
||||
modulesRpo: List<KotlinLibrary>,
|
||||
dependencyGraph: Map<KotlinLibrary, Collection<KotlinLibrary>>,
|
||||
persistentCacheProviders: Map<KotlinLibrary, PersistentCacheProvider>,
|
||||
persistentCacheConsumers: Map<KotlinLibrary, PersistentCacheConsumer>
|
||||
) {
|
||||
// 1. Invalidate
|
||||
val dirtyFiles: MutableMap<KotlinLibrary, Set<String>> = mutableMapOf()
|
||||
|
||||
for (m in modulesRpo) {
|
||||
val libraryFiles = m.files()
|
||||
val dirtySet = persistentCacheProviders[m]?.let {
|
||||
val sigHashes = mutableMapOf<IdSignature, Hash>()
|
||||
dependencyGraph.transitiveClosure(m).forEach { d ->
|
||||
sigHashes.putAll(persistentCacheProviders[d]!!.inlineHashes())
|
||||
}
|
||||
val thisHashes = mutableMapOf<String, Map<IdSignature, Hash>>()
|
||||
libraryFiles.associateWithTo(thisHashes) { f -> it.inlineHashes(f) }
|
||||
invalidateCacheForModule(libraryFiles, sigHashes, thisHashes, it, persistentCacheConsumers[m]!!)
|
||||
} ?: libraryFiles
|
||||
|
||||
dirtyFiles[m] = dirtySet
|
||||
}
|
||||
|
||||
// 2. Build
|
||||
|
||||
val loadedModules = loadModules(modulesRpo, dependencyGraph)
|
||||
|
||||
val jsIrLinker = createLinker(loadedModules)
|
||||
|
||||
val irModules = ArrayList<Pair<IrModuleFragment, KotlinLibrary>>(loadedModules.size)
|
||||
|
||||
for ((descriptor, library) in loadedModules) {
|
||||
val filesToRebuild = dirtyFiles[library]!!
|
||||
irModules.add(jsIrLinker.deserializeDirtyFiles(descriptor, library, filesToRebuild) to library)
|
||||
}
|
||||
|
||||
jsIrLinker.postProcess()
|
||||
|
||||
for ((irModule, library) in irModules) {
|
||||
val dirtySet = dirtyFiles[library]!!
|
||||
|
||||
val cleanInlineHashes = mutableMapOf<IdSignature, Hash>()
|
||||
dependencyGraph[library]!!.forEach { cleanInlineHashes.putAll(persistentCacheProviders[it]!!.inlineHashes()) }
|
||||
val thisCacheProvider = persistentCacheProviders[library]!!
|
||||
for (file in library.files()) {
|
||||
if (file !in dirtySet) {
|
||||
cleanInlineHashes.putAll(thisCacheProvider.inlineHashes(file))
|
||||
}
|
||||
}
|
||||
|
||||
val cacheConsumer = persistentCacheConsumers[library] ?: error("No cache consumer found for $library")
|
||||
buildCacheForModule(irModule, dirtySet, cleanInlineHashes, cacheConsumer)
|
||||
}
|
||||
}
|
||||
|
||||
fun generateJsCode(
|
||||
context: JsIrBackendContext,
|
||||
moduleFragment: IrModuleFragment,
|
||||
nameTables: NameTables
|
||||
): String {
|
||||
moveBodilessDeclarationsToSeparatePlace(context, moduleFragment)
|
||||
jsPhases.invokeToplevel(PhaseConfig(jsPhases), context, listOf(moduleFragment))
|
||||
|
||||
val transformer = IrModuleToJsTransformer(context, null, true, nameTables)
|
||||
return transformer.generateModule(listOf(moduleFragment)).jsCode!!.mainModule
|
||||
}
|
||||
@@ -10,8 +10,12 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.buildAssertionsDisabledField
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.hasAssertionsDisabledField
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.DescriptorAsmUtil
|
||||
import org.jetbrains.kotlin.codegen.VersionIndependentOpcodes
|
||||
import org.jetbrains.kotlin.codegen.addRecordComponent
|
||||
import org.jetbrains.kotlin.codegen.inline.*
|
||||
import org.jetbrains.kotlin.codegen.writeKotlinMetadata
|
||||
import org.jetbrains.kotlin.config.JvmAnalysisFlags
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
@@ -194,9 +198,6 @@ class ClassCodegen private constructor(
|
||||
)
|
||||
|
||||
private fun generateKotlinMetadataAnnotation() {
|
||||
// TODO: if `-Xmultifile-parts-inherit` is enabled, write the corresponding flag for parts and facades to [Metadata.extraInt].
|
||||
val extraFlags = context.backendExtension.generateMetadataExtraFlags(state.abiStability)
|
||||
|
||||
val facadeClassName = context.multifileFacadeForPart[irClass.attributeOwnerId]
|
||||
val metadata = irClass.metadata
|
||||
val entry = irClass.fileParent.fileEntry
|
||||
@@ -208,6 +209,14 @@ class ClassCodegen private constructor(
|
||||
entry is MultifileFacadeFileEntry -> KotlinClassHeader.Kind.MULTIFILE_CLASS
|
||||
else -> KotlinClassHeader.Kind.SYNTHETIC_CLASS
|
||||
}
|
||||
|
||||
val isMultifileClassOrPart = kind == KotlinClassHeader.Kind.MULTIFILE_CLASS || kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART
|
||||
|
||||
var extraFlags = context.backendExtension.generateMetadataExtraFlags(state.abiStability)
|
||||
if (isMultifileClassOrPart && state.languageVersionSettings.getFlag(JvmAnalysisFlags.inheritMultifileParts)) {
|
||||
extraFlags = extraFlags or JvmAnnotationNames.METADATA_MULTIFILE_PARTS_INHERIT_FLAG
|
||||
}
|
||||
|
||||
writeKotlinMetadata(visitor, state, kind, extraFlags) {
|
||||
if (metadata != null) {
|
||||
metadataSerializer.serialize(metadata)?.let { (proto, stringTable) ->
|
||||
@@ -229,9 +238,7 @@ class ClassCodegen private constructor(
|
||||
}
|
||||
|
||||
if (irClass in context.classNameOverride) {
|
||||
val isFileClass = kind == KotlinClassHeader.Kind.MULTIFILE_CLASS ||
|
||||
kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART ||
|
||||
kind == KotlinClassHeader.Kind.FILE_FACADE
|
||||
val isFileClass = isMultifileClassOrPart || kind == KotlinClassHeader.Kind.FILE_FACADE
|
||||
assert(isFileClass) { "JvmPackageName is not supported for classes: ${irClass.render()}" }
|
||||
it.visit(JvmAnnotationNames.METADATA_PACKAGE_NAME_FIELD_NAME, irClass.fqNameWhenAvailable!!.parent().asString())
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isFromJava
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.constantValue
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.isInlineCallableReference
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.isMappedToPrimitive
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.isMultifileBridge
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.suspendFunctionOriginal
|
||||
@@ -625,14 +627,28 @@ class ExpressionCodegen(
|
||||
val type = frameMap.typeOf(expression.symbol)
|
||||
mv.load(findLocalIndex(expression.symbol), type)
|
||||
unboxResultIfNeeded(expression)
|
||||
unboxInlineClassArgumentOfInlineCallableReference(expression)
|
||||
return MaterialValue(this, type, expression.type)
|
||||
}
|
||||
|
||||
// JVM_IR generates inline callable differently from the old backend:
|
||||
// it generates them as normal functions and not objects.
|
||||
// Thus, we need to unbox inline class argument with reference underlying type.
|
||||
private fun unboxInlineClassArgumentOfInlineCallableReference(arg: IrGetValue) {
|
||||
if (!arg.type.erasedUpperBound.isInline) return
|
||||
if (arg.type.isMappedToPrimitive) return
|
||||
if (!irFunction.isInlineCallableReference) return
|
||||
if (irFunction.extensionReceiverParameter?.symbol == arg.symbol) return
|
||||
if (arg.type.isNullable() && arg.type.makeNotNull().unboxInlineClass().isNullable()) return
|
||||
StackValue.unboxInlineClass(OBJECT_TYPE, arg.type.erasedUpperBound.defaultType.toIrBasedKotlinType(), mv)
|
||||
}
|
||||
|
||||
// We do not mangle functions if Result is the only parameter of the function,
|
||||
// thus, if the function overrides generic parameter, its argument is boxed and there is no
|
||||
// bridge to unbox it. Instead, we unbox it in the non-mangled function manually.
|
||||
private fun unboxResultIfNeeded(arg: IrGetValue) {
|
||||
if (arg.type.erasedUpperBound.fqNameWhenAvailable != StandardNames.RESULT_FQ_NAME) return
|
||||
// Do not unbox arguments of lambda, but unbox arguments of callable references
|
||||
if (irFunction.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA) return
|
||||
if (!onlyResultInlineClassParameters()) return
|
||||
if (irFunction !is IrSimpleFunction) return
|
||||
@@ -1283,8 +1299,9 @@ class ExpressionCodegen(
|
||||
generator.putValueOrProcessConstant(StackValue.constant(arg.value, type, null))
|
||||
} else {
|
||||
val value = arg.accept(this, data)
|
||||
value.materializeAt(value.type, value.irType)
|
||||
generator.invokeAppend(value.type)
|
||||
val generatingType = if (value.type == Type.VOID_TYPE) AsmTypes.UNIT_TYPE else value.type
|
||||
value.materializeAt(generatingType, value.irType)
|
||||
generator.invokeAppend(generatingType)
|
||||
}
|
||||
}
|
||||
generator.genToString()
|
||||
|
||||
@@ -12,6 +12,8 @@ import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.*
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.isInlineCallableReference
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.isMappedToPrimitive
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.suspendFunctionOriginal
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
@@ -60,7 +62,7 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
|
||||
fun mapFieldSignature(field: IrField): String? {
|
||||
val sw = BothSignatureWriter(BothSignatureWriter.Mode.TYPE)
|
||||
if (field.correspondingPropertySymbol?.owner?.isVar == true) {
|
||||
writeParameterType(sw, field.type, field)
|
||||
writeParameterType(sw, field.type, field, false)
|
||||
} else {
|
||||
mapReturnType(field, field.type, sw)
|
||||
}
|
||||
@@ -219,6 +221,13 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
|
||||
function.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_INLINE_CLASS_MEMBER &&
|
||||
function.name.asString() == "box-impl"
|
||||
|
||||
private fun forceBoxedInlineClassParametersForInliner(function: IrDeclaration, type: IrType, isBoundReceiver: Boolean): Boolean {
|
||||
if (isBoundReceiver) return false
|
||||
if (function !is IrSimpleFunction) return false
|
||||
if (!function.isInlineCallableReference) return false
|
||||
return type.erasedUpperBound.isInline && !type.isMappedToPrimitive
|
||||
}
|
||||
|
||||
fun mapSignatureSkipGeneric(function: IrFunction): JvmMethodSignature =
|
||||
mapSignature(function, true)
|
||||
|
||||
@@ -243,7 +252,7 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
|
||||
|
||||
val receiverParameter = function.extensionReceiverParameter
|
||||
if (receiverParameter != null) {
|
||||
writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.type, function)
|
||||
writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.type, function, true)
|
||||
}
|
||||
|
||||
for (parameter in function.valueParameters) {
|
||||
@@ -256,7 +265,7 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
|
||||
if (shouldBoxSingleValueParameterForSpecialCaseOfRemove(function))
|
||||
parameter.type.makeNullable()
|
||||
else parameter.type
|
||||
writeParameter(sw, kind, type, function)
|
||||
writeParameter(sw, kind, type, function, parameter.symbol == function.extensionReceiverParameter?.symbol)
|
||||
}
|
||||
|
||||
sw.writeReturnType()
|
||||
@@ -318,15 +327,23 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
|
||||
return irFunction.allOverridden(false).any { it.parent.kotlinFqName == StandardNames.FqNames.mutableCollection }
|
||||
}
|
||||
|
||||
private fun writeParameter(sw: JvmSignatureWriter, kind: JvmMethodParameterKind, type: IrType, function: IrFunction) {
|
||||
private fun writeParameter(
|
||||
sw: JvmSignatureWriter,
|
||||
kind: JvmMethodParameterKind,
|
||||
type: IrType,
|
||||
function: IrFunction,
|
||||
isReceiver: Boolean
|
||||
) {
|
||||
sw.writeParameterType(kind)
|
||||
writeParameterType(sw, type, function)
|
||||
writeParameterType(sw, type, function, isReceiver)
|
||||
sw.writeParameterTypeEnd()
|
||||
}
|
||||
|
||||
private fun writeParameterType(sw: JvmSignatureWriter, type: IrType, declaration: IrDeclaration) {
|
||||
private fun writeParameterType(sw: JvmSignatureWriter, type: IrType, declaration: IrDeclaration, isReceiver: Boolean) {
|
||||
if (sw.skipGenericSignature()) {
|
||||
if (type.isInlined() && declaration.isFromJava()) {
|
||||
if (type.isInlined() &&
|
||||
(declaration.isFromJava() || forceBoxedInlineClassParametersForInliner(declaration, type, isReceiver))
|
||||
) {
|
||||
typeMapper.mapType(type, TypeMappingMode.GENERIC_ARGUMENT, sw)
|
||||
} else {
|
||||
typeMapper.mapType(type, TypeMappingMode.DEFAULT, sw)
|
||||
|
||||
@@ -13,6 +13,10 @@ import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.*
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.indy.LambdaMetafactoryArguments
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.indy.LambdaMetafactoryArgumentsBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.indy.SamDelegatingLambdaBlock
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.indy.SamDelegatingLambdaBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
|
||||
import org.jetbrains.kotlin.config.JvmClosureGenerationScheme
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
@@ -142,9 +146,18 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
} else if (invokable is IrBlock && invokable.origin.isLambda && invokable.statements.last() is IrFunctionReference) {
|
||||
invokable.statements.dropLast(1).forEach { it.transform(this, null) }
|
||||
invokable.statements.last() as IrFunctionReference
|
||||
} else if (shouldGenerateIndySamConversions && canGenerateIndySamConversionOnFunctionalExpression(samSuperType, invokable)) {
|
||||
val lambdaBlock = SamDelegatingLambdaBuilder(context)
|
||||
.build(invokable, samSuperType, currentScope!!.scope.scopeOwnerSymbol)
|
||||
val lambdaMetafactoryArguments = LambdaMetafactoryArgumentsBuilder(context, crossinlineLambdas)
|
||||
.getLambdaMetafactoryArgumentsOrNull(lambdaBlock.ref, samSuperType, false)
|
||||
?: return super.visitTypeOperator(expression)
|
||||
invokable.transformChildrenVoid()
|
||||
return wrapSamDelegatingLambdaWithIndySamConversion(samSuperType, lambdaBlock, lambdaMetafactoryArguments)
|
||||
} else {
|
||||
return super.visitTypeOperator(expression)
|
||||
}
|
||||
|
||||
reference.transformChildrenVoid()
|
||||
|
||||
if (shouldGenerateIndySamConversions) {
|
||||
@@ -159,18 +172,36 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
return FunctionReferenceBuilder(reference, samSuperType).build()
|
||||
}
|
||||
|
||||
private fun canGenerateIndySamConversionOnFunctionalExpression(samSuperType: IrType, expression: IrExpression): Boolean {
|
||||
val samClass = samSuperType.classOrNull
|
||||
?: throw AssertionError("Class type expected: ${samSuperType.render()}")
|
||||
if (!samClass.owner.isFromJava())
|
||||
return false
|
||||
if (expression is IrBlock && expression.origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE)
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
private fun wrapSamDelegatingLambdaWithIndySamConversion(
|
||||
samSuperType: IrType,
|
||||
lambdaBlock: SamDelegatingLambdaBlock,
|
||||
lambdaMetafactoryArguments: LambdaMetafactoryArguments
|
||||
): IrExpression {
|
||||
val indySamConversion = wrapWithIndySamConversion(samSuperType, lambdaMetafactoryArguments)
|
||||
lambdaBlock.replaceRefWith(indySamConversion)
|
||||
return lambdaBlock.block
|
||||
}
|
||||
|
||||
private fun wrapSamConversionArgumentWithIndySamConversion(
|
||||
expression: IrTypeOperatorCall,
|
||||
lambdaMetafactoryArguments: LambdaMetafactoryArguments
|
||||
): IrExpression {
|
||||
val samType = expression.typeOperand
|
||||
return when (val argument = expression.argument) {
|
||||
is IrFunctionReference -> {
|
||||
is IrFunctionReference ->
|
||||
wrapWithIndySamConversion(samType, lambdaMetafactoryArguments)
|
||||
}
|
||||
is IrBlock -> {
|
||||
is IrBlock ->
|
||||
wrapFunctionReferenceInsideBlockWithIndySamConversion(samType, lambdaMetafactoryArguments, argument)
|
||||
}
|
||||
else -> throw AssertionError("Block or function reference expected: ${expression.render()}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ private class InterfaceObjectCallsLowering(val context: JvmBackendContext) : IrE
|
||||
if (expression.superQualifierSymbol != null && !expression.isSuperToAny())
|
||||
return super.visitCall(expression)
|
||||
val callee = expression.symbol.owner
|
||||
if (!callee.hasInterfaceParent())
|
||||
if (!callee.hasInterfaceParent() && expression.dispatchReceiver?.run { type.erasedUpperBound.isJvmInterface } != true)
|
||||
return super.visitCall(expression)
|
||||
val resolved = callee.resolveFakeOverride()
|
||||
if (resolved?.isMethodOfAny() != true)
|
||||
|
||||
@@ -59,6 +59,8 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte
|
||||
}
|
||||
}
|
||||
|
||||
const val STUB_FOR_INLINING = "stub_for_inlining"
|
||||
|
||||
private class InlineCallableReferenceToLambdaTransformer(
|
||||
val context: JvmBackendContext,
|
||||
val inlinableReferences: Set<IrCallableReference<*>>
|
||||
@@ -140,7 +142,7 @@ private class InlineCallableReferenceToLambdaTransformer(
|
||||
val function = context.irFactory.buildFun {
|
||||
setSourceRange(expression)
|
||||
origin = IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
|
||||
name = Name.identifier("stub_for_inlining")
|
||||
name = Name.identifier(STUB_FOR_INLINING)
|
||||
visibility = DescriptorVisibilities.LOCAL
|
||||
returnType = referencedFunction.returnType
|
||||
isSuspend = referencedFunction.isSuspend
|
||||
|
||||
@@ -174,7 +174,10 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
return when (expression.symbol) {
|
||||
jvmIndyLambdaMetafactoryIntrinsic -> rewriteIndyLambdaMetafactoryCall(expression)
|
||||
jvmIndyLambdaMetafactoryIntrinsic -> {
|
||||
expression.transformChildrenVoid()
|
||||
rewriteIndyLambdaMetafactoryCall(expression)
|
||||
}
|
||||
else -> super.visitCall(expression)
|
||||
}
|
||||
}
|
||||
@@ -267,10 +270,10 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
|
||||
private fun wrapClosureInDynamicCall(
|
||||
erasedSamType: IrSimpleType,
|
||||
samMethod: IrSimpleFunction,
|
||||
irFunRef: IrFunctionReference
|
||||
targetRef: IrFunctionReference
|
||||
): IrCall {
|
||||
fun fail(message: String): Nothing =
|
||||
throw AssertionError("$message, irFunRef:\n${irFunRef.dump()}")
|
||||
throw AssertionError("$message, irFunRef:\n${targetRef.dump()}")
|
||||
|
||||
val dynamicCallArguments = ArrayList<IrExpression>()
|
||||
|
||||
@@ -281,32 +284,45 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
|
||||
}.apply {
|
||||
parent = context.ir.symbols.kotlinJvmInternalInvokeDynamicPackage
|
||||
|
||||
val targetFun = targetRef.symbol.owner
|
||||
val refDispatchReceiver = targetRef.dispatchReceiver
|
||||
val refExtensionReceiver = targetRef.extensionReceiver
|
||||
|
||||
var syntheticParameterIndex = 0
|
||||
val targetFun = irFunRef.symbol.owner
|
||||
|
||||
val targetDispatchReceiverParameter = targetFun.dispatchReceiverParameter
|
||||
if (targetDispatchReceiverParameter != null) {
|
||||
addValueParameter("p${syntheticParameterIndex++}", targetDispatchReceiverParameter.type)
|
||||
val dispatchReceiver = irFunRef.dispatchReceiver
|
||||
?: fail("Captured dispatch receiver is not provided")
|
||||
dynamicCallArguments.add(dispatchReceiver)
|
||||
}
|
||||
|
||||
val targetExtensionReceiverParameter = targetFun.extensionReceiverParameter
|
||||
if (targetExtensionReceiverParameter != null && irFunRef.extensionReceiver != null) {
|
||||
addValueParameter("p${syntheticParameterIndex++}", targetExtensionReceiverParameter.type)
|
||||
val extensionReceiver = irFunRef.extensionReceiver!!
|
||||
dynamicCallArguments.add(extensionReceiver)
|
||||
var argumentStart = 0
|
||||
when (targetFun) {
|
||||
is IrSimpleFunction -> {
|
||||
if (refDispatchReceiver != null) {
|
||||
addValueParameter("p${syntheticParameterIndex++}", targetFun.dispatchReceiverParameter!!.type)
|
||||
dynamicCallArguments.add(refDispatchReceiver)
|
||||
}
|
||||
if (refExtensionReceiver != null) {
|
||||
addValueParameter("p${syntheticParameterIndex++}", targetFun.extensionReceiverParameter!!.type)
|
||||
dynamicCallArguments.add(refExtensionReceiver)
|
||||
}
|
||||
}
|
||||
is IrConstructor -> {
|
||||
// At this point, outer class instances in inner class constructors are represented as regular value parameters.
|
||||
// However, in a function reference to such constructors, bound receiver value is stored as a dispatch receiver.
|
||||
if (refDispatchReceiver != null) {
|
||||
addValueParameter("p${syntheticParameterIndex++}", targetFun.valueParameters[0].type)
|
||||
dynamicCallArguments.add(refDispatchReceiver)
|
||||
argumentStart++
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
throw AssertionError("Unexpected function: ${targetFun.render()}")
|
||||
}
|
||||
}
|
||||
|
||||
val samMethodValueParametersCount = samMethod.valueParameters.size +
|
||||
if (samMethod.extensionReceiverParameter != null && irFunRef.extensionReceiver == null) 1 else 0
|
||||
if (samMethod.extensionReceiverParameter != null && refExtensionReceiver == null) 1 else 0
|
||||
val targetFunValueParametersCount = targetFun.valueParameters.size
|
||||
for (i in 0 until targetFunValueParametersCount - samMethodValueParametersCount) {
|
||||
for (i in argumentStart until targetFunValueParametersCount - samMethodValueParametersCount) {
|
||||
val targetFunValueParameter = targetFun.valueParameters[i]
|
||||
addValueParameter("p${syntheticParameterIndex++}", targetFunValueParameter.type)
|
||||
val capturedValueArgument = irFunRef.getValueArgument(i)
|
||||
?: fail("Captured value argument #$i (${targetFunValueParameter.name}) not provided")
|
||||
val capturedValueArgument = targetRef.getValueArgument(i)
|
||||
?: fail("Captured value argument #$i (${targetFunValueParameter.render()}) not provided")
|
||||
dynamicCallArguments.add(capturedValueArgument)
|
||||
}
|
||||
}
|
||||
@@ -320,7 +336,7 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
|
||||
"dynamicCallArguments:\n" +
|
||||
dynamicCallArguments
|
||||
.withIndex()
|
||||
.joinToString(separator = "\n ", prefix = "[\n ", postfix = "\n]") { (index, irArg) ->
|
||||
.joinToString(separator = "\n ", prefix = "[\n ", postfix = "\n]") { (index, irArg) ->
|
||||
"#$index: ${irArg.dump()}"
|
||||
}
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.lower
|
||||
package org.jetbrains.kotlin.backend.jvm.lower.indy
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.allOverridden
|
||||
import org.jetbrains.kotlin.backend.common.lower.VariableRemapper
|
||||
@@ -12,6 +12,8 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.getSingleAbstractMethod
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isFromJava
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.findInterfaceImplementation
|
||||
import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
||||
@@ -23,21 +25,19 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.overrides.buildFakeOverrideMember
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.util.getInlineClassUnderlyingType
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
class LambdaMetafactoryArguments(
|
||||
internal class LambdaMetafactoryArguments(
|
||||
val samMethod: IrSimpleFunction,
|
||||
val fakeInstanceMethod: IrSimpleFunction,
|
||||
val implMethodReference: IrFunctionReference,
|
||||
val extraOverriddenMethods: List<IrSimpleFunction>
|
||||
)
|
||||
|
||||
class LambdaMetafactoryArgumentsBuilder(
|
||||
internal class LambdaMetafactoryArgumentsBuilder(
|
||||
private val context: JvmBackendContext,
|
||||
private val crossinlineLambdas: Set<IrSimpleFunction>
|
||||
) {
|
||||
@@ -49,13 +49,14 @@ class LambdaMetafactoryArgumentsBuilder(
|
||||
samType: IrType,
|
||||
plainLambda: Boolean
|
||||
): LambdaMetafactoryArguments? {
|
||||
// Can't use JDK LambdaMetafactory for function references by default (because of 'equals').
|
||||
// TODO special mode that would generate indy everywhere?
|
||||
if (reference.origin != IrStatementOrigin.LAMBDA)
|
||||
return null
|
||||
|
||||
val samClass = samType.getClass()
|
||||
?: throw AssertionError("SAM type is not a class: ${samType.render()}")
|
||||
|
||||
// Can't use JDK LambdaMetafactory for function references by default (because of 'equals').
|
||||
// TODO special mode that would generate indy everywhere?
|
||||
if (reference.origin != IrStatementOrigin.LAMBDA && !samClass.isFromJava())
|
||||
return null
|
||||
|
||||
val samMethod = samClass.getSingleAbstractMethod()
|
||||
?: throw AssertionError("SAM class has no single abstract method: ${samClass.render()}")
|
||||
|
||||
@@ -67,32 +68,31 @@ class LambdaMetafactoryArgumentsBuilder(
|
||||
if (samClass.requiresDelegationToDefaultImpls())
|
||||
return null
|
||||
|
||||
val target = reference.symbol.owner as? IrSimpleFunction
|
||||
?: throw AssertionError("Simple function expected: ${reference.symbol.owner.render()}")
|
||||
val implFun = reference.symbol.owner
|
||||
|
||||
// Can't use JDK LambdaMetafactory for annotated lambdas.
|
||||
// JDK LambdaMetafactory doesn't copy annotations from implementation method to an instance method in a
|
||||
// corresponding synthetic class, which doesn't look like a binary compatible change.
|
||||
// TODO relaxed mode?
|
||||
if (target.annotations.isNotEmpty())
|
||||
if (implFun.annotations.isNotEmpty())
|
||||
return null
|
||||
|
||||
// Don't use JDK LambdaMetafactory for big arity lambdas.
|
||||
if (plainLambda) {
|
||||
var parametersCount = target.valueParameters.size
|
||||
if (target.extensionReceiverParameter != null) ++parametersCount
|
||||
var parametersCount = implFun.valueParameters.size
|
||||
if (implFun.extensionReceiverParameter != null) ++parametersCount
|
||||
if (parametersCount >= BuiltInFunctionArity.BIG_ARITY)
|
||||
return null
|
||||
}
|
||||
|
||||
// Can't use indy-based SAM conversion inside inline fun (Ok in inline lambda).
|
||||
if (target.parents.any { it.isInlineFunction() || it.isCrossinlineLambda() })
|
||||
if (implFun.parents.any { it.isInlineFunction() || it.isCrossinlineLambda() })
|
||||
return null
|
||||
|
||||
// Do the hard work of matching Kotlin functional interface hierarchy against LambdaMetafactory constraints.
|
||||
// Briefly: sometimes we have to force boxing on the primitive and inline class values, sometimes we have to keep them unboxed.
|
||||
// If this results in conflicting requirements, we can't use INVOKEDYNAMIC with LambdaMetafactory for creating a closure.
|
||||
return getLambdaMetafactoryArgsOrNullInner(reference, samMethod, samType, target)
|
||||
return getLambdaMetafactoryArgsOrNullInner(reference, samMethod, samType, implFun)
|
||||
}
|
||||
|
||||
private fun IrClass.requiresDelegationToDefaultImpls(): Boolean {
|
||||
@@ -117,7 +117,7 @@ class LambdaMetafactoryArgumentsBuilder(
|
||||
reference: IrFunctionReference,
|
||||
samMethod: IrSimpleFunction,
|
||||
samType: IrType,
|
||||
implLambda: IrSimpleFunction
|
||||
implFun: IrFunction
|
||||
): LambdaMetafactoryArguments? {
|
||||
val nonFakeOverriddenFuns = samMethod.allOverridden().filterNot { it.isFakeOverride }
|
||||
val relevantOverriddenFuns = if (samMethod.isFakeOverride) nonFakeOverriddenFuns else nonFakeOverriddenFuns + samMethod
|
||||
@@ -190,16 +190,23 @@ class LambdaMetafactoryArgumentsBuilder(
|
||||
|
||||
// We should have bailed out before if we encountered any kind of type adaptation conflict.
|
||||
// Still, check that we are fine - just in case.
|
||||
if (signatureAdaptationConstraints.returnType == TypeAdaptationConstraint.CONFLICT ||
|
||||
signatureAdaptationConstraints.valueParameters.values.any { it == TypeAdaptationConstraint.CONFLICT }
|
||||
)
|
||||
if (signatureAdaptationConstraints.hasConflicts())
|
||||
return null
|
||||
|
||||
adaptFakeInstanceMethodSignature(fakeInstanceMethod, signatureAdaptationConstraints)
|
||||
if (implFun.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA) {
|
||||
adaptLambdaSignature(implFun as IrSimpleFunction, fakeInstanceMethod, signatureAdaptationConstraints)
|
||||
} else if (
|
||||
!checkMethodSignatureCompliance(implFun, fakeInstanceMethod, signatureAdaptationConstraints, reference)
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
adaptLambdaSignature(implLambda, fakeInstanceMethod, signatureAdaptationConstraints)
|
||||
|
||||
val newReference = remapExtensionLambda(implLambda, reference)
|
||||
val newReference =
|
||||
if (implFun.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA)
|
||||
remapExtensionLambda(implFun as IrSimpleFunction, reference)
|
||||
else
|
||||
reference
|
||||
|
||||
if (samMethod.isFakeOverride && nonFakeOverriddenFuns.size == 1) {
|
||||
return LambdaMetafactoryArguments(nonFakeOverriddenFuns.single(), fakeInstanceMethod, newReference, listOf())
|
||||
@@ -207,32 +214,73 @@ class LambdaMetafactoryArgumentsBuilder(
|
||||
return LambdaMetafactoryArguments(samMethod, fakeInstanceMethod, newReference, nonFakeOverriddenFuns)
|
||||
}
|
||||
|
||||
private fun adaptLambdaSignature(
|
||||
lambda: IrSimpleFunction,
|
||||
private fun checkMethodSignatureCompliance(
|
||||
implFun: IrFunction,
|
||||
fakeInstanceMethod: IrSimpleFunction,
|
||||
constraints: SignatureAdaptationConstraints
|
||||
) {
|
||||
val lambdaParameters = collectValueParameters(lambda)
|
||||
constraints: SignatureAdaptationConstraints,
|
||||
reference: IrFunctionReference
|
||||
): Boolean {
|
||||
val implParameters = collectValueParameters(
|
||||
implFun,
|
||||
withDispatchReceiver = reference.dispatchReceiver == null,
|
||||
withExtensionReceiver = reference.extensionReceiver == null
|
||||
)
|
||||
val methodParameters = collectValueParameters(fakeInstanceMethod)
|
||||
if (lambdaParameters.size != methodParameters.size)
|
||||
if (implParameters.size != methodParameters.size)
|
||||
throw AssertionError(
|
||||
"Mismatching lambda and instance method parameters:\n" +
|
||||
"lambda: ${lambda.render()}\n" +
|
||||
" (${lambdaParameters.size} parameters)\n" +
|
||||
"implFun: ${implFun.render()}\n" +
|
||||
" (${implParameters.size} parameters)\n" +
|
||||
"instance method: ${fakeInstanceMethod.render()}\n" +
|
||||
" (${methodParameters.size} parameters)"
|
||||
)
|
||||
for ((lambdaParameter, methodParameter) in lambdaParameters.zip(methodParameters)) {
|
||||
// TODO box inline class parameters only?
|
||||
val parameterConstraint = constraints.valueParameters[methodParameter]
|
||||
if (parameterConstraint == TypeAdaptationConstraint.FORCE_BOXING) {
|
||||
lambdaParameter.type = lambdaParameter.type.makeNullable()
|
||||
}
|
||||
for ((implParameter, methodParameter) in implParameters.zip(methodParameters)) {
|
||||
val constraint = constraints.valueParameters[methodParameter]
|
||||
if (!checkTypeCompliesWithConstraint(implParameter.type, constraint))
|
||||
return false
|
||||
}
|
||||
if (constraints.returnType == TypeAdaptationConstraint.FORCE_BOXING) {
|
||||
lambda.returnType = lambda.returnType.makeNullable()
|
||||
if (!checkTypeCompliesWithConstraint(implFun.returnType, constraints.returnType))
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
private fun checkTypeCompliesWithConstraint(irType: IrType, constraint: TypeAdaptationConstraint?): Boolean =
|
||||
when (constraint) {
|
||||
null -> true
|
||||
TypeAdaptationConstraint.FORCE_BOXING -> irType.isNullable()
|
||||
TypeAdaptationConstraint.KEEP_UNBOXED -> !irType.isNullable()
|
||||
TypeAdaptationConstraint.BOX_PRIMITIVE -> irType.isJvmPrimitiveOrNullable()
|
||||
TypeAdaptationConstraint.CONFLICT -> false
|
||||
}
|
||||
|
||||
private fun adaptLambdaSignature(
|
||||
implFun: IrSimpleFunction,
|
||||
fakeInstanceMethod: IrSimpleFunction,
|
||||
constraints: SignatureAdaptationConstraints
|
||||
) {
|
||||
if (implFun.origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA) {
|
||||
throw AssertionError("Can't adapt non-lambda function signature: ${implFun.render()}")
|
||||
}
|
||||
|
||||
val implParameters = collectValueParameters(implFun)
|
||||
val methodParameters = collectValueParameters(fakeInstanceMethod)
|
||||
if (implParameters.size != methodParameters.size)
|
||||
throw AssertionError(
|
||||
"Mismatching lambda and instance method parameters:\n" +
|
||||
"implFun: ${implFun.render()}\n" +
|
||||
" (${implParameters.size} parameters)\n" +
|
||||
"instance method: ${fakeInstanceMethod.render()}\n" +
|
||||
" (${methodParameters.size} parameters)"
|
||||
)
|
||||
for ((implParameter, methodParameter) in implParameters.zip(methodParameters)) {
|
||||
val parameterConstraint = constraints.valueParameters[methodParameter]
|
||||
if (parameterConstraint.requiresImplLambdaBoxing()) {
|
||||
implParameter.type = implParameter.type.makeNullable()
|
||||
}
|
||||
}
|
||||
if (constraints.returnType.requiresImplLambdaBoxing()) {
|
||||
implFun.returnType = implFun.returnType.makeNullable()
|
||||
}
|
||||
}
|
||||
|
||||
private fun remapExtensionLambda(lambda: IrSimpleFunction, reference: IrFunctionReference): IrFunctionReference {
|
||||
@@ -284,25 +332,36 @@ class LambdaMetafactoryArgumentsBuilder(
|
||||
"Unexpected value parameter: ${valueParameter.render()}; fakeInstanceMethod:\n" +
|
||||
fakeInstanceMethod.dump()
|
||||
)
|
||||
if (constraint == TypeAdaptationConstraint.FORCE_BOXING) {
|
||||
if (constraint.requiresInstanceMethodBoxing()) {
|
||||
valueParameter.type = valueParameter.type.makeNullable()
|
||||
}
|
||||
}
|
||||
if (constraints.returnType == TypeAdaptationConstraint.FORCE_BOXING) {
|
||||
if (constraints.returnType.requiresInstanceMethodBoxing()) {
|
||||
fakeInstanceMethod.returnType = fakeInstanceMethod.returnType.makeNullable()
|
||||
}
|
||||
}
|
||||
|
||||
private enum class TypeAdaptationConstraint {
|
||||
FORCE_BOXING,
|
||||
BOX_PRIMITIVE,
|
||||
KEEP_UNBOXED,
|
||||
CONFLICT
|
||||
}
|
||||
|
||||
private fun TypeAdaptationConstraint?.requiresInstanceMethodBoxing() =
|
||||
this == TypeAdaptationConstraint.FORCE_BOXING || this == TypeAdaptationConstraint.BOX_PRIMITIVE
|
||||
|
||||
private fun TypeAdaptationConstraint?.requiresImplLambdaBoxing() =
|
||||
this == TypeAdaptationConstraint.FORCE_BOXING
|
||||
|
||||
private class SignatureAdaptationConstraints(
|
||||
val valueParameters: Map<IrValueParameter, TypeAdaptationConstraint>,
|
||||
val returnType: TypeAdaptationConstraint?
|
||||
)
|
||||
) {
|
||||
fun hasConflicts() =
|
||||
returnType == TypeAdaptationConstraint.CONFLICT ||
|
||||
TypeAdaptationConstraint.CONFLICT in valueParameters.values
|
||||
}
|
||||
|
||||
private fun computeSignatureAdaptationConstraints(
|
||||
adapteeFun: IrSimpleFunction,
|
||||
@@ -352,10 +411,13 @@ class LambdaMetafactoryArgumentsBuilder(
|
||||
// All Kotlin types mapped to JVM primitive are final,
|
||||
// and their supertypes are trivially mapped reference types.
|
||||
if (adapteeType.isJvmPrimitiveType()) {
|
||||
return if (expectedType.isJvmPrimitiveType())
|
||||
return if (
|
||||
expectedType.isJvmPrimitiveType() &&
|
||||
!expectedType.hasAnnotation(context.ir.symbols.enhancedNullabilityAnnotationFqName)
|
||||
)
|
||||
TypeAdaptationConstraint.KEEP_UNBOXED
|
||||
else
|
||||
TypeAdaptationConstraint.FORCE_BOXING
|
||||
TypeAdaptationConstraint.BOX_PRIMITIVE
|
||||
}
|
||||
|
||||
// ** Inline classes **
|
||||
@@ -458,13 +520,29 @@ class LambdaMetafactoryArgumentsBuilder(
|
||||
|
||||
private fun IrType.isJvmPrimitiveType() =
|
||||
isBoolean() || isChar() || isByte() || isShort() || isInt() || isLong() || isFloat() || isDouble()
|
||||
}
|
||||
|
||||
fun collectValueParameters(irFun: IrFunction): List<IrValueParameter> {
|
||||
if (irFun.extensionReceiverParameter == null)
|
||||
return irFun.valueParameters
|
||||
return ArrayList<IrValueParameter>().apply {
|
||||
add(irFun.extensionReceiverParameter!!)
|
||||
addAll(irFun.valueParameters)
|
||||
private fun IrType.isJvmPrimitiveOrNullable() =
|
||||
isBooleanOrNullable() || isCharOrNullable() ||
|
||||
isByteOrNullable() || isShortOrNullable() || isIntOrNullable() || isLongOrNullable() ||
|
||||
isFloatOrNullable() || isDoubleOrNullable()
|
||||
|
||||
fun collectValueParameters(
|
||||
irFun: IrFunction,
|
||||
withDispatchReceiver: Boolean = false,
|
||||
withExtensionReceiver: Boolean = true
|
||||
): List<IrValueParameter> {
|
||||
if ((!withDispatchReceiver || irFun.dispatchReceiverParameter == null) &&
|
||||
(!withExtensionReceiver || irFun.extensionReceiverParameter == null)
|
||||
)
|
||||
return irFun.valueParameters
|
||||
return ArrayList<IrValueParameter>().apply {
|
||||
if (withDispatchReceiver) {
|
||||
addIfNotNull(irFun.dispatchReceiverParameter)
|
||||
}
|
||||
if (withExtensionReceiver) {
|
||||
addIfNotNull(irFun.extensionReceiverParameter)
|
||||
}
|
||||
addAll(irFun.valueParameters)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.lower.indy
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.JvmIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.getSingleAbstractMethod
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildValueParameter
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrContainerExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
internal sealed class SamDelegatingLambdaBlock {
|
||||
abstract val block: IrContainerExpression
|
||||
abstract val ref: IrFunctionReference
|
||||
abstract fun replaceRefWith(expression: IrExpression)
|
||||
}
|
||||
|
||||
|
||||
internal class RegularDelegatingLambdaBlock(
|
||||
override val block: IrContainerExpression,
|
||||
override val ref: IrFunctionReference
|
||||
) : SamDelegatingLambdaBlock() {
|
||||
|
||||
override fun replaceRefWith(expression: IrExpression) {
|
||||
block.statements[block.statements.size - 1] = expression
|
||||
block.type = expression.type
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class NullableDelegatingLambdaBlock(
|
||||
override val block: IrContainerExpression,
|
||||
override val ref: IrFunctionReference,
|
||||
private val ifExpr: IrExpression,
|
||||
private val ifNotNullBlock: IrContainerExpression
|
||||
) : SamDelegatingLambdaBlock() {
|
||||
|
||||
override fun replaceRefWith(expression: IrExpression) {
|
||||
ifNotNullBlock.statements[ifNotNullBlock.statements.size - 1] = expression
|
||||
ifNotNullBlock.type = expression.type
|
||||
ifExpr.type = expression.type
|
||||
block.type = expression.type
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class SamDelegatingLambdaBuilder(private val jvmContext: JvmBackendContext) {
|
||||
fun build(expression: IrExpression, superType: IrType, scopeSymbol: IrSymbol): SamDelegatingLambdaBlock {
|
||||
return if (superType.isNullable() && expression.type.isNullable())
|
||||
buildNullableDelegatingLambda(expression, superType, scopeSymbol)
|
||||
else
|
||||
buildRegularDelegatingLambda(expression, superType, scopeSymbol)
|
||||
}
|
||||
|
||||
private fun buildRegularDelegatingLambda(
|
||||
expression: IrExpression,
|
||||
superType: IrType,
|
||||
scopeSymbol: IrSymbol
|
||||
): SamDelegatingLambdaBlock {
|
||||
lateinit var ref: IrFunctionReference
|
||||
val block = jvmContext.createJvmIrBuilder(scopeSymbol, expression.startOffset, expression.endOffset).run {
|
||||
// {
|
||||
// val tmp = <expression>
|
||||
// fun `<anonymous>`(p1: T1, ..., pN: TN): R =
|
||||
// tmp.invoke(p1, ..., pN)
|
||||
// ::`<anonymous>`
|
||||
// }
|
||||
|
||||
irBlock(origin = IrStatementOrigin.LAMBDA) {
|
||||
val tmp = irTemporary(expression)
|
||||
val lambda = createDelegatingLambda(scopeSymbol, expression, superType, tmp)
|
||||
.also { +it }
|
||||
ref = createDelegatingLambdaReference(expression, lambda)
|
||||
.also { +it }
|
||||
}
|
||||
}
|
||||
block.type = expression.type
|
||||
return RegularDelegatingLambdaBlock(block, ref)
|
||||
}
|
||||
|
||||
private fun buildNullableDelegatingLambda(
|
||||
expression: IrExpression,
|
||||
superType: IrType,
|
||||
scopeSymbol: IrSymbol
|
||||
): SamDelegatingLambdaBlock {
|
||||
lateinit var ref: IrFunctionReference
|
||||
lateinit var ifExpr: IrExpression
|
||||
lateinit var ifNotNullBlock: IrContainerExpression
|
||||
val block = jvmContext.createJvmIrBuilder(scopeSymbol, expression.startOffset, expression.endOffset).run {
|
||||
// {
|
||||
// val tmp = <expression>
|
||||
// if (tmp == null)
|
||||
// null
|
||||
// else {
|
||||
// fun `<anonymous>`(p1: T1, ..., pN: TN): R =
|
||||
// tmp.invoke(p1, ..., pN)
|
||||
// ::`<anonymous>`
|
||||
// }
|
||||
// }
|
||||
|
||||
irBlock(origin = IrStatementOrigin.LAMBDA) {
|
||||
val tmp = irTemporary(expression)
|
||||
ifNotNullBlock = irBlock {
|
||||
val lambda = createDelegatingLambda(scopeSymbol, expression, superType, tmp)
|
||||
.also { +it }
|
||||
ref = createDelegatingLambdaReference(expression, lambda)
|
||||
.also { +it }
|
||||
}
|
||||
ifExpr = irIfNull(expression.type, irGet(tmp), irNull(), ifNotNullBlock)
|
||||
.also { +it }
|
||||
}
|
||||
}
|
||||
block.type = expression.type
|
||||
return NullableDelegatingLambdaBlock(block, ref, ifExpr, ifNotNullBlock)
|
||||
}
|
||||
|
||||
private fun createDelegatingLambda(
|
||||
scopeSymbol: IrSymbol,
|
||||
expression: IrExpression,
|
||||
superType: IrType,
|
||||
tmp: IrVariable
|
||||
): IrSimpleFunction {
|
||||
val superMethod = superType.getSingleAbstractMethod()
|
||||
?: throw AssertionError("SAM type expected: ${superType.render()}")
|
||||
val effectiveValueParametersCount = superMethod.valueParameters.size +
|
||||
if (superMethod.extensionReceiverParameter == null) 0 else 1
|
||||
val invocableFunctionClass =
|
||||
if (superMethod.isSuspend)
|
||||
jvmContext.ir.symbols.suspendFunctionN(effectiveValueParametersCount).owner
|
||||
else
|
||||
jvmContext.ir.symbols.functionN(effectiveValueParametersCount).owner
|
||||
val invokeFunction = invocableFunctionClass.functions.single { it.name == OperatorNameConventions.INVOKE }
|
||||
val typeSubstitutor = createTypeSubstitutor(superType)
|
||||
|
||||
return jvmContext.irFactory.buildFun {
|
||||
name = Name.special("<anonymous>")
|
||||
returnType = typeSubstitutor.substitute(superMethod.returnType)
|
||||
visibility = DescriptorVisibilities.LOCAL
|
||||
modality = Modality.FINAL
|
||||
origin = IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
|
||||
isSuspend = superMethod.isSuspend
|
||||
}.also { lambda ->
|
||||
lambda.dispatchReceiverParameter = null
|
||||
lambda.extensionReceiverParameter = null
|
||||
lambda.valueParameters = createLambdaValueParameters(superMethod, lambda, typeSubstitutor)
|
||||
lambda.body = jvmContext.createJvmIrBuilder(lambda.symbol, expression.startOffset, expression.endOffset)
|
||||
.irBlockBody {
|
||||
+irReturn(
|
||||
irCall(invokeFunction).also { invokeCall ->
|
||||
invokeCall.dispatchReceiver = irGet(tmp)
|
||||
var parameterIndex = 0
|
||||
invokeFunction.extensionReceiverParameter?.let {
|
||||
invokeCall.extensionReceiver = irGet(lambda.valueParameters[parameterIndex++])
|
||||
}
|
||||
for (argumentIndex in invokeFunction.valueParameters.indices) {
|
||||
invokeCall.putValueArgument(argumentIndex, irGet(lambda.valueParameters[parameterIndex++]))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
lambda.parent = scopeSymbol.owner as IrDeclarationParent
|
||||
}
|
||||
}
|
||||
|
||||
private fun createLambdaValueParameters(
|
||||
superMethod: IrSimpleFunction,
|
||||
lambda: IrSimpleFunction,
|
||||
typeSubstitutor: IrTypeSubstitutor
|
||||
): List<IrValueParameter> {
|
||||
val lambdaParameters = ArrayList<IrValueParameter>()
|
||||
var index = 0
|
||||
superMethod.extensionReceiverParameter?.let { superExtensionReceiver ->
|
||||
lambdaParameters.add(superExtensionReceiver.copySubstituted(lambda, typeSubstitutor, index++, Name.identifier("\$receiver")))
|
||||
}
|
||||
superMethod.valueParameters.mapTo(lambdaParameters) { superValueParameter ->
|
||||
superValueParameter.copySubstituted(lambda, typeSubstitutor, index++)
|
||||
}
|
||||
return lambdaParameters
|
||||
}
|
||||
|
||||
private fun IrValueParameter.copySubstituted(
|
||||
function: IrSimpleFunction,
|
||||
substitutor: IrTypeSubstitutor,
|
||||
newIndex: Int,
|
||||
newName: Name = name
|
||||
) =
|
||||
buildValueParameter(function) {
|
||||
name = newName
|
||||
index = newIndex
|
||||
type = substitutor.substitute(this@copySubstituted.type)
|
||||
}
|
||||
|
||||
private fun JvmIrBuilder.createDelegatingLambdaReference(expression: IrExpression, lambda: IrSimpleFunction): IrFunctionReference {
|
||||
return IrFunctionReferenceImpl(
|
||||
startOffset, endOffset,
|
||||
expression.type,
|
||||
lambda.symbol,
|
||||
typeArgumentsCount = 0,
|
||||
valueArgumentsCount = lambda.valueParameters.size,
|
||||
reflectionTarget = null,
|
||||
origin = IrStatementOrigin.LAMBDA
|
||||
)
|
||||
}
|
||||
|
||||
private fun createTypeSubstitutor(irType: IrType): IrTypeSubstitutor {
|
||||
if (irType !is IrSimpleType)
|
||||
throw AssertionError("Simple type expected: ${irType.render()}")
|
||||
val irClassSymbol = irType.classOrNull
|
||||
?: throw AssertionError("Class type expected: ${irType.render()}")
|
||||
return IrTypeSubstitutor(
|
||||
irClassSymbol.owner.typeParameters.map { it.symbol },
|
||||
irType.arguments,
|
||||
jvmContext.irBuiltIns
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.backend.jvm.lower.inlineclasses
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.STUB_FOR_INLINING
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.codegen.state.InfoForMangling
|
||||
import org.jetbrains.kotlin.codegen.state.collectFunctionSignatureForManglingSuffix
|
||||
@@ -166,3 +167,11 @@ val IrFunction.isInlineClassFieldGetter: Boolean
|
||||
|
||||
val IrFunction.isPrimaryInlineClassConstructor: Boolean
|
||||
get() = this is IrConstructor && isPrimary && constructedClass.isInline
|
||||
|
||||
val IrFunction.isInlineCallableReference: Boolean
|
||||
get() = origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA && name.asString().contains("\$$STUB_FOR_INLINING")
|
||||
|
||||
val IrType.isMappedToPrimitive: Boolean
|
||||
get() = erasedUpperBound.isInline &&
|
||||
!(isNullable() && makeNotNull().unboxInlineClass().isNullable()) &&
|
||||
makeNotNull().unboxInlineClass().isPrimitiveType()
|
||||
@@ -5,17 +5,9 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
compile(project(":compiler:util"))
|
||||
compile(project(":compiler:frontend"))
|
||||
compile(project(":compiler:backend-common"))
|
||||
compile(project(":compiler:ir.tree"))
|
||||
compile(project(":compiler:ir.psi2ir"))
|
||||
compile(project(":compiler:ir.backend.common"))
|
||||
compile(project(":compiler:ir.serialization.common"))
|
||||
compile(project(":compiler:ir.serialization.js"))
|
||||
compile(project(":compiler:ir.tree.persistent"))
|
||||
compile(project(":compiler:ir.tree.impl"))
|
||||
compile(project(":js:js.ast"))
|
||||
compile(project(":js:js.frontend"))
|
||||
compile(project(":compiler:backend.js"))
|
||||
compile(project(":wasm:wasm.ir"))
|
||||
|
||||
|
||||
@@ -5,95 +5,395 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.wasm
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.analyzer.AbstractAnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.WasmCompiledModuleFragment
|
||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.WasmModuleFragmentGenerator
|
||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.generateStringLiteralsSupport
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.ir.backend.js.MainModule
|
||||
import org.jetbrains.kotlin.ir.backend.js.loadIr
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
||||
import org.jetbrains.kotlin.ir.util.generateTypicalIrProviderList
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.wasm.ir.convertors.WasmIrToBinary
|
||||
import org.jetbrains.kotlin.wasm.ir.convertors.WasmIrToText
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
//
|
||||
//import com.intellij.openapi.project.Project
|
||||
//import com.intellij.openapi.vfs.VfsUtilCore
|
||||
//import org.jetbrains.kotlin.analyzer.AbstractAnalyzerWithCompilerReport
|
||||
//import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
//import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
||||
//import org.jetbrains.kotlin.backend.common.extensions.IrPluginContextImpl
|
||||
//import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideChecker
|
||||
//import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
//import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||
//import org.jetbrains.kotlin.backend.common.serialization.DeserializationStrategy
|
||||
//import org.jetbrains.kotlin.backend.common.serialization.knownBuiltins
|
||||
//import org.jetbrains.kotlin.backend.common.serialization.mangle.ManglerChecker
|
||||
//import org.jetbrains.kotlin.backend.common.serialization.mangle.descriptor.Ir2DescriptorManglerAdapter
|
||||
//import org.jetbrains.kotlin.backend.common.serialization.metadata.DynamicTypeDeserializer
|
||||
//import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor
|
||||
//import org.jetbrains.kotlin.backend.wasm.ir2wasm.WasmCompiledModuleFragment
|
||||
//import org.jetbrains.kotlin.backend.wasm.ir2wasm.WasmModuleFragmentGenerator
|
||||
//import org.jetbrains.kotlin.backend.wasm.ir2wasm.generateStringLiteralsSupport
|
||||
//import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
//import org.jetbrains.kotlin.config.*
|
||||
//import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
//import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
//import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
//import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
//import org.jetbrains.kotlin.ir.backend.js.*
|
||||
//import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||
//import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
|
||||
//import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr
|
||||
//import org.jetbrains.kotlin.ir.declarations.IrFactory
|
||||
//import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
//import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
//import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
//import org.jetbrains.kotlin.ir.descriptors.IrFunctionFactory
|
||||
//import org.jetbrains.kotlin.ir.linkage.IrDeserializer
|
||||
//import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
//import org.jetbrains.kotlin.ir.util.*
|
||||
//import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
//import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
|
||||
//import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy
|
||||
//import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
//import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
|
||||
//import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
//import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
|
||||
//import org.jetbrains.kotlin.library.unresolvedDependencies
|
||||
//import org.jetbrains.kotlin.name.FqName
|
||||
//import org.jetbrains.kotlin.progress.IncrementalNextRoundException
|
||||
//import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||
//import org.jetbrains.kotlin.psi.KtFile
|
||||
//import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
|
||||
//import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
|
||||
//import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
|
||||
//import org.jetbrains.kotlin.resolve.BindingContext
|
||||
//import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
//import org.jetbrains.kotlin.storage.StorageManager
|
||||
//import org.jetbrains.kotlin.utils.DFS
|
||||
//import org.jetbrains.kotlin.wasm.ir.convertors.WasmIrToBinary
|
||||
//import org.jetbrains.kotlin.wasm.ir.convertors.WasmIrToText
|
||||
//import java.io.ByteArrayOutputStream
|
||||
//
|
||||
class WasmCompilerResult(val wat: String, val js: String, val wasm: ByteArray)
|
||||
|
||||
fun compileWasm(
|
||||
project: Project,
|
||||
mainModule: MainModule,
|
||||
analyzer: AbstractAnalyzerWithCompilerReport,
|
||||
configuration: CompilerConfiguration,
|
||||
phaseConfig: PhaseConfig,
|
||||
allDependencies: KotlinLibraryResolveResult,
|
||||
friendDependencies: List<KotlinLibrary>,
|
||||
exportedDeclarations: Set<FqName> = emptySet()
|
||||
): WasmCompilerResult {
|
||||
val (moduleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) =
|
||||
loadIr(
|
||||
project, mainModule, analyzer, configuration, allDependencies, friendDependencies,
|
||||
IrFactoryImpl
|
||||
)
|
||||
|
||||
val allModules = when (mainModule) {
|
||||
is MainModule.SourceFiles -> dependencyModules + listOf(moduleFragment)
|
||||
is MainModule.Klib -> dependencyModules
|
||||
}
|
||||
|
||||
val moduleDescriptor = moduleFragment.descriptor
|
||||
val context = WasmBackendContext(moduleDescriptor, irBuiltIns, symbolTable, moduleFragment, exportedDeclarations, configuration)
|
||||
|
||||
// Load declarations referenced during `context` initialization
|
||||
allModules.forEach {
|
||||
val irProviders = generateTypicalIrProviderList(it.descriptor, irBuiltIns, symbolTable, deserializer)
|
||||
ExternalDependenciesGenerator(symbolTable, irProviders)
|
||||
.generateUnboundSymbolsAsDependencies()
|
||||
}
|
||||
|
||||
val irFiles = allModules.flatMap { it.files }
|
||||
|
||||
moduleFragment.files.clear()
|
||||
moduleFragment.files += irFiles
|
||||
|
||||
// Create stubs
|
||||
val irProviders = generateTypicalIrProviderList(moduleDescriptor, irBuiltIns, symbolTable, deserializer)
|
||||
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
|
||||
moduleFragment.patchDeclarationParents()
|
||||
|
||||
wasmPhases.invokeToplevel(phaseConfig, context, moduleFragment)
|
||||
|
||||
val compiledWasmModule = WasmCompiledModuleFragment()
|
||||
val codeGenerator = WasmModuleFragmentGenerator(context, compiledWasmModule)
|
||||
codeGenerator.generateModule(moduleFragment)
|
||||
|
||||
val linkedModule = compiledWasmModule.linkWasmCompiledFragments()
|
||||
val watGenerator = WasmIrToText()
|
||||
watGenerator.appendWasmModule(linkedModule)
|
||||
val wat = watGenerator.toString()
|
||||
|
||||
val js = compiledWasmModule.generateJs()
|
||||
|
||||
val os = ByteArrayOutputStream()
|
||||
WasmIrToBinary(os, linkedModule).appendWasmModule()
|
||||
val byteArray = os.toByteArray()
|
||||
|
||||
return WasmCompilerResult(
|
||||
wat = wat,
|
||||
js = js,
|
||||
wasm = byteArray
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//private fun createBuiltIns(storageManager: StorageManager) = object : KotlinBuiltIns(storageManager) {}
|
||||
//internal val JsFactories = KlibMetadataFactories(::createBuiltIns, DynamicTypeDeserializer)
|
||||
//
|
||||
//private class ModulesStructure(
|
||||
// private val project: Project,
|
||||
// private val mainModule: MainModule,
|
||||
// private val analyzer: AbstractAnalyzerWithCompilerReport,
|
||||
// val compilerConfiguration: CompilerConfiguration,
|
||||
// val allDependencies: KotlinLibraryResolveResult,
|
||||
// private val friendDependencies: List<KotlinLibrary>
|
||||
//) {
|
||||
// val moduleDependencies: Map<KotlinLibrary, List<KotlinLibrary>> = run {
|
||||
// val transitives = allDependencies.getFullResolvedList()
|
||||
// transitives.associate { klib ->
|
||||
// klib.library to klib.resolvedDependencies.map { d -> d.library }
|
||||
// }.toMap()
|
||||
// }
|
||||
//
|
||||
// val builtInsDep = allDependencies.getFullList().find { it.isBuiltIns }
|
||||
//
|
||||
// class JsFrontEndResult(val moduleDescriptor: ModuleDescriptor, val bindingContext: BindingContext, val hasErrors: Boolean)
|
||||
//
|
||||
// fun runAnalysis(errorPolicy: ErrorTolerancePolicy): JsFrontEndResult {
|
||||
// require(mainModule is MainModule.SourceFiles)
|
||||
// val files = mainModule.files
|
||||
//
|
||||
// val frontend = TopDownAnalyzerFacadeForJSIR(JsFactories)
|
||||
//
|
||||
// analyzer.analyzeAndReport(files) {
|
||||
// frontend.analyzeFiles(
|
||||
// files,
|
||||
// project,
|
||||
// compilerConfiguration,
|
||||
// allDependencies.getFullList().map { getModuleDescriptor(it) },
|
||||
// friendModuleDescriptors = friendDependencies.map { getModuleDescriptor(it) },
|
||||
// thisIsBuiltInsModule = builtInModuleDescriptor == null,
|
||||
// customBuiltInsModule = builtInModuleDescriptor
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
//
|
||||
// val analysisResult = analyzer.analysisResult
|
||||
// if (IncrementalCompilation.isEnabledForJs()) {
|
||||
// /** can throw [IncrementalNextRoundException] */
|
||||
// compareMetadataAndGoToNextICRoundIfNeeded(analysisResult, compilerConfiguration, project, files, errorPolicy.allowErrors)
|
||||
// }
|
||||
//
|
||||
// var hasErrors = false
|
||||
// if (analyzer.hasErrors() || analysisResult !is JsAnalysisResult) {
|
||||
// if (!errorPolicy.allowErrors)
|
||||
// throw AnalysisResult.CompilationErrorException()
|
||||
// else hasErrors = true
|
||||
// }
|
||||
//
|
||||
// hasErrors = frontend.checkForErrors(files, analysisResult.bindingContext, errorPolicy) || hasErrors
|
||||
//
|
||||
// return JsFrontEndResult(analysisResult.moduleDescriptor, analysisResult.bindingContext, hasErrors)
|
||||
// }
|
||||
//
|
||||
// private val languageVersionSettings: LanguageVersionSettings = compilerConfiguration.languageVersionSettings
|
||||
//
|
||||
// private val storageManager: LockBasedStorageManager = LockBasedStorageManager("ModulesStructure")
|
||||
// private var runtimeModule: ModuleDescriptorImpl? = null
|
||||
//
|
||||
// // TODO: these are roughly equivalent to KlibResolvedModuleDescriptorsFactoryImpl. Refactor me.
|
||||
// val descriptors = mutableMapOf<KotlinLibrary, ModuleDescriptorImpl>()
|
||||
//
|
||||
// fun getModuleDescriptor(current: KotlinLibrary): ModuleDescriptorImpl = descriptors.getOrPut(current) {
|
||||
// val isBuiltIns = current.unresolvedDependencies.isEmpty()
|
||||
//
|
||||
// val lookupTracker = compilerConfiguration[CommonConfigurationKeys.LOOKUP_TRACKER] ?: LookupTracker.DO_NOTHING
|
||||
// val md = JsFactories.DefaultDeserializedDescriptorFactory.createDescriptorOptionalBuiltIns(
|
||||
// current,
|
||||
// languageVersionSettings,
|
||||
// storageManager,
|
||||
// runtimeModule?.builtIns,
|
||||
// packageAccessHandler = null, // TODO: This is a speed optimization used by Native. Don't bother for now.
|
||||
// lookupTracker = lookupTracker
|
||||
// )
|
||||
// if (isBuiltIns) runtimeModule = md
|
||||
//
|
||||
// val dependencies = moduleDependencies.getValue(current).map { getModuleDescriptor(it) }
|
||||
// md.setDependencies(listOf(md) + dependencies)
|
||||
// md
|
||||
// }
|
||||
//
|
||||
// val builtInModuleDescriptor =
|
||||
// if (builtInsDep != null)
|
||||
// getModuleDescriptor(builtInsDep)
|
||||
// else
|
||||
// null // null in case compiling builtInModule itself
|
||||
//}
|
||||
//
|
||||
//private fun compareMetadataAndGoToNextICRoundIfNeeded(
|
||||
// analysisResult: AnalysisResult,
|
||||
// config: CompilerConfiguration,
|
||||
// project: Project,
|
||||
// files: List<KtFile>,
|
||||
// allowErrors: Boolean
|
||||
//) {
|
||||
// val nextRoundChecker = config.get(JSConfigurationKeys.INCREMENTAL_NEXT_ROUND_CHECKER) ?: return
|
||||
// val bindingContext = analysisResult.bindingContext
|
||||
// val serializer = KlibMetadataIncrementalSerializer(config, project, allowErrors)
|
||||
// for (ktFile in files) {
|
||||
// val packageFragment = serializer.serializeScope(ktFile, bindingContext, analysisResult.moduleDescriptor)
|
||||
// // to minimize a number of IC rounds, we should inspect all proto for changes first,
|
||||
// // then go to a next round if needed, with all new dirty files
|
||||
// nextRoundChecker.checkProtoChanges(VfsUtilCore.virtualToIoFile(ktFile.virtualFile), packageFragment.toByteArray())
|
||||
// }
|
||||
//
|
||||
// if (nextRoundChecker.shouldGoToNextRound()) throw IncrementalNextRoundException()
|
||||
//}
|
||||
//
|
||||
//private fun runAnalysisAndPreparePsi2Ir(
|
||||
// depsDescriptors: ModulesStructure,
|
||||
// irFactory: IrFactory,
|
||||
// errorIgnorancePolicy: ErrorTolerancePolicy
|
||||
//): Pair<GeneratorContext, Boolean> {
|
||||
// val analysisResult = depsDescriptors.runAnalysis(errorIgnorancePolicy)
|
||||
// val psi2Ir = Psi2IrTranslator(
|
||||
// depsDescriptors.compilerConfiguration.languageVersionSettings,
|
||||
// Psi2IrConfiguration(errorIgnorancePolicy.allowErrors)
|
||||
// )
|
||||
// val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), irFactory)
|
||||
// return psi2Ir.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext, symbolTable) to analysisResult.hasErrors
|
||||
//}
|
||||
//
|
||||
//fun GeneratorContext.generateModuleFragmentWithPlugins(
|
||||
// project: Project,
|
||||
// files: Collection<KtFile>,
|
||||
// irLinker: IrDeserializer,
|
||||
// messageLogger: IrMessageLogger,
|
||||
// expectDescriptorToSymbol: MutableMap<DeclarationDescriptor, IrSymbol>? = null
|
||||
//): IrModuleFragment {
|
||||
// val psi2Ir = Psi2IrTranslator(languageVersionSettings, configuration)
|
||||
//
|
||||
// val extensions = IrGenerationExtension.getInstances(project)
|
||||
//
|
||||
// if (extensions.isNotEmpty()) {
|
||||
// // plugin context should be instantiated before postprocessing steps
|
||||
// val pluginContext = IrPluginContextImpl(
|
||||
// moduleDescriptor,
|
||||
// bindingContext,
|
||||
// languageVersionSettings,
|
||||
// symbolTable,
|
||||
// typeTranslator,
|
||||
// irBuiltIns,
|
||||
// linker = irLinker,
|
||||
// messageLogger
|
||||
// )
|
||||
//
|
||||
// for (extension in extensions) {
|
||||
// psi2Ir.addPostprocessingStep { module ->
|
||||
// extension.generate(module, pluginContext)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return psi2Ir.generateModuleFragment(this, files, listOf(irLinker), extensions, expectDescriptorToSymbol)
|
||||
//}
|
||||
//
|
||||
//
|
||||
//private fun sortDependencies(dependencies: List<KotlinLibrary>, mapping: Map<KotlinLibrary, ModuleDescriptor>): Collection<KotlinLibrary> {
|
||||
// val m2l = mapping.map { it.value to it.key }.toMap()
|
||||
//
|
||||
// return DFS.topologicalOrder(dependencies) { m ->
|
||||
// val descriptor = mapping[m] ?: error("No descriptor found for library ${m.libraryName}")
|
||||
// descriptor.allDependencyModules.filter { it != descriptor }.map { m2l[it] }
|
||||
// }.reversed()
|
||||
//}
|
||||
//
|
||||
//private fun loadIr(
|
||||
// project: Project,
|
||||
// mainModule: MainModule,
|
||||
// analyzer: AbstractAnalyzerWithCompilerReport,
|
||||
// configuration: CompilerConfiguration,
|
||||
// allDependencies: KotlinLibraryResolveResult,
|
||||
// friendDependencies: List<KotlinLibrary>,
|
||||
// irFactory: IrFactory,
|
||||
//): IrModuleInfo {
|
||||
// val depsDescriptors = ModulesStructure(project, mainModule, analyzer, configuration, allDependencies, friendDependencies)
|
||||
// val errorPolicy = configuration.get(JSConfigurationKeys.ERROR_TOLERANCE_POLICY) ?: ErrorTolerancePolicy.DEFAULT
|
||||
// val messageLogger = configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None
|
||||
//
|
||||
// when (mainModule) {
|
||||
// is MainModule.SourceFiles -> {
|
||||
// val (psi2IrContext, _) = runAnalysisAndPreparePsi2Ir(depsDescriptors, irFactory, errorPolicy)
|
||||
// val irBuiltIns = psi2IrContext.irBuiltIns
|
||||
// val symbolTable = psi2IrContext.symbolTable
|
||||
// val functionFactory = IrFunctionFactory(irBuiltIns, symbolTable)
|
||||
// irBuiltIns.functionFactory = functionFactory
|
||||
// val feContext = psi2IrContext.run {
|
||||
// JsIrLinker.JsFePluginContext(moduleDescriptor, bindingContext, symbolTable, typeTranslator, irBuiltIns)
|
||||
// }
|
||||
// val irLinker = JsIrLinker(psi2IrContext.moduleDescriptor, messageLogger, irBuiltIns, symbolTable, feContext, null)
|
||||
// val deserializedModuleFragments = sortDependencies(allDependencies.getFullList(), depsDescriptors.descriptors).map {
|
||||
// irLinker.deserializeIrModuleHeader(depsDescriptors.getModuleDescriptor(it), it)
|
||||
// }
|
||||
//
|
||||
// val moduleFragment = psi2IrContext.generateModuleFragmentWithPlugins(project, mainModule.files, irLinker, messageLogger)
|
||||
// symbolTable.noUnboundLeft("Unbound symbols left after linker")
|
||||
//
|
||||
// // TODO: not sure whether this check should be enabled by default. Add configuration key for it.
|
||||
// val mangleChecker = ManglerChecker(JsManglerIr, Ir2DescriptorManglerAdapter(JsManglerDesc))
|
||||
// moduleFragment.acceptVoid(mangleChecker)
|
||||
//
|
||||
// if (configuration.getBoolean(JSConfigurationKeys.FAKE_OVERRIDE_VALIDATOR)) {
|
||||
// val fakeOverrideChecker = FakeOverrideChecker(JsManglerIr, JsManglerDesc)
|
||||
// irLinker.modules.forEach { fakeOverrideChecker.check(it) }
|
||||
// }
|
||||
//
|
||||
// irBuiltIns.knownBuiltins.forEach { it.acceptVoid(mangleChecker) }
|
||||
//
|
||||
// return IrModuleInfo(moduleFragment, deserializedModuleFragments, irBuiltIns, symbolTable, irLinker)
|
||||
// }
|
||||
// is MainModule.Klib -> {
|
||||
// val moduleDescriptor = depsDescriptors.getModuleDescriptor(mainModule.lib)
|
||||
// val mangler = JsManglerDesc
|
||||
// val signaturer = IdSignatureDescriptor(mangler)
|
||||
// val symbolTable = SymbolTable(signaturer, irFactory)
|
||||
// val constantValueGenerator = ConstantValueGenerator(moduleDescriptor, symbolTable)
|
||||
// val typeTranslator = TypeTranslator(
|
||||
// symbolTable,
|
||||
// depsDescriptors.compilerConfiguration.languageVersionSettings,
|
||||
// builtIns = moduleDescriptor.builtIns
|
||||
// )
|
||||
// typeTranslator.constantValueGenerator = constantValueGenerator
|
||||
// constantValueGenerator.typeTranslator = typeTranslator
|
||||
// val irBuiltIns = IrBuiltIns(moduleDescriptor.builtIns, typeTranslator, symbolTable)
|
||||
// val functionFactory = IrFunctionFactory(irBuiltIns, symbolTable)
|
||||
// irBuiltIns.functionFactory = functionFactory
|
||||
// val irLinker =
|
||||
// JsIrLinker(null, messageLogger, irBuiltIns, symbolTable, null, null)
|
||||
//
|
||||
// val deserializedModuleFragments = sortDependencies(allDependencies.getFullList(), depsDescriptors.descriptors).map {
|
||||
// val strategy =
|
||||
// if (it == mainModule.lib)
|
||||
// DeserializationStrategy.ALL
|
||||
// else
|
||||
// DeserializationStrategy.EXPLICITLY_EXPORTED
|
||||
//
|
||||
// irLinker.deserializeIrModuleHeader(depsDescriptors.getModuleDescriptor(it), it, strategy)
|
||||
// }
|
||||
//
|
||||
// val moduleFragment = deserializedModuleFragments.last()
|
||||
//
|
||||
// irLinker.init(null, emptyList())
|
||||
// ExternalDependenciesGenerator(symbolTable, listOf(irLinker)).generateUnboundSymbolsAsDependencies()
|
||||
// irLinker.postProcess()
|
||||
//
|
||||
// return IrModuleInfo(moduleFragment, deserializedModuleFragments, irBuiltIns, symbolTable, irLinker)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//
|
||||
//fun compileWasm(
|
||||
// project: Project,
|
||||
// mainModule: MainModule,
|
||||
// analyzer: AbstractAnalyzerWithCompilerReport,
|
||||
// configuration: CompilerConfiguration,
|
||||
// phaseConfig: PhaseConfig,
|
||||
// allDependencies: KotlinLibraryResolveResult,
|
||||
// friendDependencies: List<KotlinLibrary>,
|
||||
// exportedDeclarations: Set<FqName> = emptySet()
|
||||
//): WasmCompilerResult {
|
||||
// val (moduleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) =
|
||||
// loadIr(
|
||||
// project, mainModule, analyzer, configuration, allDependencies, friendDependencies,
|
||||
// IrFactoryImpl
|
||||
// )
|
||||
//
|
||||
// val allModules = when (mainModule) {
|
||||
// is MainModule.SourceFiles -> dependencyModules + listOf(moduleFragment)
|
||||
// is MainModule.Klib -> dependencyModules
|
||||
// }
|
||||
//
|
||||
// val moduleDescriptor = moduleFragment.descriptor
|
||||
// val context = WasmBackendContext(moduleDescriptor, irBuiltIns, symbolTable, moduleFragment, exportedDeclarations, configuration)
|
||||
//
|
||||
// // Load declarations referenced during `context` initialization
|
||||
// allModules.forEach {
|
||||
// val irProviders = generateTypicalIrProviderList(it.descriptor, irBuiltIns, symbolTable, deserializer)
|
||||
// ExternalDependenciesGenerator(symbolTable, irProviders)
|
||||
// .generateUnboundSymbolsAsDependencies()
|
||||
// }
|
||||
//
|
||||
// val irFiles = allModules.flatMap { it.files }
|
||||
//
|
||||
// moduleFragment.files.clear()
|
||||
// moduleFragment.files += irFiles
|
||||
//
|
||||
// // Create stubs
|
||||
// val irProviders = generateTypicalIrProviderList(moduleDescriptor, irBuiltIns, symbolTable, deserializer)
|
||||
// ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
|
||||
// moduleFragment.patchDeclarationParents()
|
||||
//
|
||||
// wasmPhases.invokeToplevel(phaseConfig, context, moduleFragment)
|
||||
//
|
||||
// val compiledWasmModule = WasmCompiledModuleFragment()
|
||||
// val codeGenerator = WasmModuleFragmentGenerator(context, compiledWasmModule)
|
||||
// codeGenerator.generateModule(moduleFragment)
|
||||
//
|
||||
// val linkedModule = compiledWasmModule.linkWasmCompiledFragments()
|
||||
// val watGenerator = WasmIrToText()
|
||||
// watGenerator.appendWasmModule(linkedModule)
|
||||
// val wat = watGenerator.toString()
|
||||
//
|
||||
// val js = compiledWasmModule.generateJs()
|
||||
//
|
||||
// val os = ByteArrayOutputStream()
|
||||
// WasmIrToBinary(os, linkedModule).appendWasmModule()
|
||||
// val byteArray = os.toByteArray()
|
||||
//
|
||||
// return WasmCompilerResult(
|
||||
// wat = wat,
|
||||
// js = js,
|
||||
// wasm = byteArray
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//
|
||||
fun WasmCompiledModuleFragment.generateJs(): String {
|
||||
val runtime = """
|
||||
const runtime = {
|
||||
@@ -126,7 +426,7 @@ fun WasmCompiledModuleFragment.generateJs(): String {
|
||||
Char_toString(char) {
|
||||
return String.fromCharCode(char)
|
||||
},
|
||||
|
||||
|
||||
identity(x) {
|
||||
return x;
|
||||
},
|
||||
|
||||
26
compiler/ir/ir.compiler.wjs/build.gradle.kts
Normal file
26
compiler/ir/ir.compiler.wjs/build.gradle.kts
Normal file
@@ -0,0 +1,26 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile(project(":compiler:util"))
|
||||
compile(project(":compiler:frontend"))
|
||||
compile(project(":compiler:ir.tree"))
|
||||
compile(project(":compiler:ir.psi2ir"))
|
||||
compile(project(":compiler:ir.backend.common"))
|
||||
compile(project(":compiler:ir.serialization.common"))
|
||||
compile(project(":compiler:ir.serialization.js"))
|
||||
compile(project(":compiler:ir.tree.persistent"))
|
||||
compile(project(":compiler:ir.tree.impl"))
|
||||
compile(project(":js:js.frontend"))
|
||||
compile(project(":compiler:backend.js"))
|
||||
compile(project(":compiler:backend.wasm"))
|
||||
|
||||
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { projectDefault() }
|
||||
"test" {}
|
||||
}
|
||||
@@ -0,0 +1,548 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.compiler.wjs
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import org.jetbrains.kotlin.analyzer.AbstractAnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContextImpl
|
||||
import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideChecker
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||
import org.jetbrains.kotlin.backend.common.serialization.DeserializationStrategy
|
||||
import org.jetbrains.kotlin.backend.common.serialization.ICData
|
||||
import org.jetbrains.kotlin.backend.common.serialization.mangle.ManglerChecker
|
||||
import org.jetbrains.kotlin.backend.common.serialization.mangle.descriptor.Ir2DescriptorManglerAdapter
|
||||
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmCompilerResult
|
||||
import org.jetbrains.kotlin.backend.wasm.generateJs
|
||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.WasmCompiledModuleFragment
|
||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.WasmModuleFragmentGenerator
|
||||
import org.jetbrains.kotlin.backend.wasm.wasmPhases
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.backend.js.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.generateTests
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFactory
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.StageController
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrFunctionFactory
|
||||
import org.jetbrains.kotlin.ir.linkage.IrDeserializer
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
|
||||
import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.library.SerializedIrFile
|
||||
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.progress.IncrementalNextRoundException
|
||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
|
||||
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
|
||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.wasm.ir.convertors.WasmIrToBinary
|
||||
import org.jetbrains.kotlin.wasm.ir.convertors.WasmIrToText
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
class Ir2WJCompiler(
|
||||
private val project: Project,
|
||||
private val configuration: CompilerConfiguration,
|
||||
private val analyzer: AbstractAnalyzerWithCompilerReport,
|
||||
dependencies: KotlinLibraryResolveResult,
|
||||
private val friendDependencies: List<KotlinLibrary>
|
||||
) {
|
||||
|
||||
class Options {
|
||||
// Klib
|
||||
var nopack: Boolean = false
|
||||
var perFile: Boolean = false
|
||||
|
||||
// Binary JS
|
||||
var generateFullJs: Boolean = true
|
||||
var generateDceJs: Boolean = false
|
||||
var dceDriven: Boolean = false
|
||||
var es6mode: Boolean = false
|
||||
var multiModule: Boolean = false
|
||||
var relativeRequirePath: Boolean = false
|
||||
var propertyLazyInitialization: Boolean = false
|
||||
|
||||
// Binary WASM
|
||||
|
||||
|
||||
|
||||
// Persistent cache
|
||||
|
||||
}
|
||||
|
||||
val options: Options = Options()
|
||||
|
||||
private fun irFactory(isPersistent: Boolean): IrFactory = if (isPersistent) PersistentIrFactory() else IrFactoryImpl
|
||||
|
||||
private val klibMetadataFactories: KlibMetadataFactories = ModuleLoader.jsMetadataFactories
|
||||
|
||||
private val moduleLoader: ModuleLoader by lazy {
|
||||
ModuleLoader(
|
||||
dependencies,
|
||||
klibMetadataFactories.DefaultDeserializedDescriptorFactory,
|
||||
configuration,
|
||||
LockBasedStorageManager("WJS IR Compiler")
|
||||
)
|
||||
}
|
||||
|
||||
private val languageVersionSettings: LanguageVersionSettings get() = configuration.languageVersionSettings
|
||||
|
||||
private val expectActualLinker: Boolean
|
||||
get() = configuration.get(CommonConfigurationKeys.EXPECT_ACTUAL_LINKER) ?: false
|
||||
|
||||
private val errorTolerancePolicy: ErrorTolerancePolicy =
|
||||
configuration.get(JSConfigurationKeys.ERROR_TOLERANCE_POLICY) ?: ErrorTolerancePolicy.DEFAULT
|
||||
|
||||
private val messageLogger = configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None
|
||||
|
||||
private val dependenciesRpo: List<KotlinLibrary> get() = moduleLoader.dependenciesRpo
|
||||
|
||||
private val dependencyDescriptors: Map<String, ModuleDescriptorImpl> get() = moduleLoader.dependencyDescriptors
|
||||
private val friendDescriptors: Collection<ModuleDescriptorImpl> by lazy {
|
||||
friendDependencies.map {
|
||||
dependencyDescriptors[it.libraryName] ?: error("No module loaded for $it")
|
||||
}
|
||||
}
|
||||
private val builtInsModule: ModuleDescriptorImpl? get() = moduleLoader.builtInsModule
|
||||
|
||||
private class FrontEndResult(val moduleDescriptor: ModuleDescriptor, val bindingContext: BindingContext, val hasErrors: Boolean)
|
||||
|
||||
private fun doAnalysis(files: Collection<KtFile>): FrontEndResult {
|
||||
|
||||
val frontend = TopDownAnalyzerFacadeForJSIR(klibMetadataFactories)
|
||||
|
||||
analyzer.analyzeAndReport(files) {
|
||||
frontend.analyzeFiles(
|
||||
files,
|
||||
project,
|
||||
configuration,
|
||||
dependenciesRpo.map { dependencyDescriptors[it.libraryName]!! },
|
||||
friendModuleDescriptors = friendDescriptors,
|
||||
thisIsBuiltInsModule = builtInsModule == null,
|
||||
customBuiltInsModule = builtInsModule
|
||||
)
|
||||
}
|
||||
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
|
||||
val analysisResult = analyzer.analysisResult
|
||||
if (IncrementalCompilation.isEnabledForJs()) {
|
||||
/** can throw [IncrementalNextRoundException] */
|
||||
compareMetadataAndGoToNextICRoundIfNeeded(analysisResult, files)
|
||||
}
|
||||
|
||||
var hasErrors = false
|
||||
if (analyzer.hasErrors() || analysisResult !is JsAnalysisResult) {
|
||||
if (!errorTolerancePolicy.allowErrors)
|
||||
throw AnalysisResult.CompilationErrorException()
|
||||
else hasErrors = true
|
||||
}
|
||||
|
||||
hasErrors = frontend.checkForErrors(files, analysisResult.bindingContext, errorTolerancePolicy) || hasErrors
|
||||
|
||||
return FrontEndResult(analysisResult.moduleDescriptor, analysisResult.bindingContext, hasErrors)
|
||||
}
|
||||
|
||||
private fun compareMetadataAndGoToNextICRoundIfNeeded(analysisResult: AnalysisResult, files: Collection<KtFile>) {
|
||||
val nextRoundChecker = configuration.get(JSConfigurationKeys.INCREMENTAL_NEXT_ROUND_CHECKER) ?: return
|
||||
val serializer = KlibMetadataIncrementalSerializer(configuration, project, errorTolerancePolicy.allowErrors)
|
||||
for (ktFile in files) {
|
||||
val packageFragment = serializer.serializeScope(ktFile, analysisResult.bindingContext, analysisResult.moduleDescriptor)
|
||||
// to minimize a number of IC rounds, we should inspect all proto for changes first,
|
||||
// then go to a next round if needed, with all new dirty files
|
||||
nextRoundChecker.checkProtoChanges(VfsUtilCore.virtualToIoFile(ktFile.virtualFile), packageFragment.toByteArray())
|
||||
}
|
||||
|
||||
if (nextRoundChecker.shouldGoToNextRound()) throw IncrementalNextRoundException()
|
||||
}
|
||||
|
||||
private fun createPsi2IrContext(frontEndResult: FrontEndResult, isPersistent: Boolean): GeneratorContext {
|
||||
val psi2Ir = Psi2IrTranslator(languageVersionSettings, Psi2IrConfiguration(errorTolerancePolicy.allowErrors))
|
||||
val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), irFactory(isPersistent))
|
||||
return psi2Ir.createGeneratorContext(frontEndResult.moduleDescriptor, frontEndResult.bindingContext, symbolTable).also {
|
||||
it.irBuiltIns.functionFactory = IrFunctionFactory(it.irBuiltIns, symbolTable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createIrLinker(
|
||||
currentModule: ModuleDescriptor?,
|
||||
irBuiltIns: IrBuiltIns,
|
||||
symbolTable: SymbolTable,
|
||||
feContext: JsIrLinker.JsFePluginContext?,
|
||||
serializedIrFiles: List<SerializedIrFile>?,
|
||||
onlyHeaders: Boolean
|
||||
): JsIrLinker {
|
||||
|
||||
val irLinker = JsIrLinker(
|
||||
currentModule,
|
||||
messageLogger,
|
||||
irBuiltIns,
|
||||
symbolTable,
|
||||
feContext,
|
||||
serializedIrFiles?.let { ICData(it, errorTolerancePolicy.allowErrors) }
|
||||
)
|
||||
|
||||
dependenciesRpo.forEach {
|
||||
val moduleDescriptor = dependencyDescriptors[it.libraryName]!!
|
||||
if (onlyHeaders)
|
||||
irLinker.deserializeOnlyHeaderModule(moduleDescriptor, it)
|
||||
else
|
||||
irLinker.deserializeIrModuleHeader(moduleDescriptor, it)
|
||||
}
|
||||
|
||||
return irLinker
|
||||
}
|
||||
|
||||
private fun createRawLinker(mainKlib: KotlinLibrary, isPersistent: Boolean): JsIrLinker {
|
||||
val mainModule = dependencyDescriptors[mainKlib.libraryName] ?: error("No descriptor for $mainKlib")
|
||||
val mangler = JsManglerDesc
|
||||
val signaturer = IdSignatureDescriptor(mangler)
|
||||
val symbolTable = SymbolTable(signaturer, irFactory(isPersistent))
|
||||
val constantValueGenerator = ConstantValueGenerator(mainModule, symbolTable)
|
||||
val typeTranslator = TypeTranslator(
|
||||
symbolTable,
|
||||
languageVersionSettings,
|
||||
builtIns = mainModule.builtIns
|
||||
)
|
||||
typeTranslator.constantValueGenerator = constantValueGenerator
|
||||
constantValueGenerator.typeTranslator = typeTranslator
|
||||
|
||||
val irBuiltIns = IrBuiltIns(mainModule.builtIns, typeTranslator, symbolTable)
|
||||
val functionFactory = IrFunctionFactory(irBuiltIns, symbolTable)
|
||||
irBuiltIns.functionFactory = functionFactory
|
||||
|
||||
return JsIrLinker(null, messageLogger, irBuiltIns, symbolTable, null, null).apply {
|
||||
dependenciesRpo.forEach {
|
||||
val strategy =
|
||||
if (it.libraryName == mainKlib.libraryName)
|
||||
DeserializationStrategy.ALL
|
||||
else
|
||||
DeserializationStrategy.EXPLICITLY_EXPORTED
|
||||
|
||||
deserializeIrModuleHeader(dependencyDescriptors[it.libraryName]!!, it, strategy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun GeneratorContext.generateModuleFragmentWithPlugins(
|
||||
files: Collection<KtFile>,
|
||||
irLinker: IrDeserializer,
|
||||
expectDescriptorToSymbol: MutableMap<DeclarationDescriptor, IrSymbol>? = null
|
||||
): IrModuleFragment {
|
||||
val psi2Ir = Psi2IrTranslator(languageVersionSettings, configuration)
|
||||
|
||||
val extensions = IrGenerationExtension.getInstances(project)
|
||||
|
||||
if (extensions.isNotEmpty()) {
|
||||
// plugin context should be instantiated before postprocessing steps
|
||||
val pluginContext = IrPluginContextImpl(
|
||||
moduleDescriptor,
|
||||
bindingContext,
|
||||
languageVersionSettings,
|
||||
symbolTable,
|
||||
typeTranslator,
|
||||
irBuiltIns,
|
||||
linker = irLinker,
|
||||
messageLogger
|
||||
)
|
||||
|
||||
for (extension in extensions) {
|
||||
psi2Ir.addPostprocessingStep { module ->
|
||||
extension.generate(module, pluginContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return psi2Ir.generateModuleFragment(this, files, listOf(irLinker), extensions, expectDescriptorToSymbol)
|
||||
}
|
||||
|
||||
fun compileIntoPirCache() {
|
||||
TODO("Compile into Cache")
|
||||
}
|
||||
|
||||
sealed class MainModule {
|
||||
class SourceFiles(val files: List<KtFile>) : MainModule()
|
||||
class Klib(val lib: String) : MainModule()
|
||||
}
|
||||
|
||||
private fun doJsBackend(
|
||||
allModules: List<IrModuleFragment>,
|
||||
irLinker: JsIrLinker,
|
||||
phaseConfig: PhaseConfig,
|
||||
mainArguments: List<String>?,
|
||||
exportedDeclarations: Set<FqName>
|
||||
): CompilerResult {
|
||||
val mainModule = allModules.last()
|
||||
val symbolTable = irLinker.symbolTable
|
||||
val factory = symbolTable.irFactory
|
||||
|
||||
val context = JsIrBackendContext(
|
||||
mainModule.descriptor,
|
||||
irLinker.builtIns,
|
||||
symbolTable,
|
||||
allModules.first(),
|
||||
exportedDeclarations,
|
||||
configuration,
|
||||
es6mode = options.es6mode,
|
||||
propertyLazyInitialization = options.propertyLazyInitialization,
|
||||
irFactory = factory
|
||||
)
|
||||
|
||||
// Load declarations referenced during `context` initialization
|
||||
val irProviders = listOf(irLinker)
|
||||
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
|
||||
|
||||
irLinker.postProcess()
|
||||
symbolTable.noUnboundLeft("Unbound symbols at the end of linker")
|
||||
|
||||
allModules.forEach { module ->
|
||||
moveBodilessDeclarationsToSeparatePlace(context, module)
|
||||
}
|
||||
|
||||
// TODO should be done incrementally
|
||||
generateTests(context, mainModule)
|
||||
|
||||
if (options.dceDriven) {
|
||||
val controller = MutableController(context, pirLowerings)
|
||||
|
||||
check(factory is PersistentIrFactory)
|
||||
|
||||
factory.stageController = controller
|
||||
|
||||
controller.currentStage = controller.lowerings.size + 1
|
||||
|
||||
eliminateDeadDeclarations(allModules, context)
|
||||
|
||||
factory.stageController = StageController(controller.currentStage)
|
||||
} else {
|
||||
jsPhases.invokeToplevel(phaseConfig, context, allModules)
|
||||
}
|
||||
|
||||
val transformer = IrModuleToJsTransformer(
|
||||
context,
|
||||
mainArguments,
|
||||
fullJs = options.dceDriven || options.generateFullJs,
|
||||
dceJs = !options.dceDriven && options.generateDceJs,
|
||||
multiModule = options.multiModule,
|
||||
relativeRequirePath = options.relativeRequirePath
|
||||
)
|
||||
return transformer.generateModule(allModules)
|
||||
|
||||
}
|
||||
|
||||
private fun doWasmBackend(
|
||||
allModules: List<IrModuleFragment>,
|
||||
irLinker: JsIrLinker,
|
||||
phaseConfig: PhaseConfig,
|
||||
@Suppress("UNUSED_PARAMETER") mainArguments: List<String>?,
|
||||
exportedDeclarations: Set<FqName>
|
||||
): WasmCompilerResult {
|
||||
|
||||
val moduleFragment = allModules.last()
|
||||
val symbolTable = irLinker.symbolTable
|
||||
val moduleDescriptor = moduleFragment.descriptor
|
||||
val context =
|
||||
WasmBackendContext(moduleDescriptor, irLinker.builtIns, symbolTable, moduleFragment, exportedDeclarations, configuration)
|
||||
|
||||
// Load declarations referenced during `context` initialization
|
||||
allModules.forEach {
|
||||
val irProviders = generateTypicalIrProviderList(it.descriptor, irLinker.builtIns, symbolTable, irLinker)
|
||||
ExternalDependenciesGenerator(symbolTable, irProviders)
|
||||
.generateUnboundSymbolsAsDependencies()
|
||||
}
|
||||
|
||||
val irFiles = allModules.flatMap { it.files }
|
||||
|
||||
moduleFragment.files.clear()
|
||||
moduleFragment.files += irFiles
|
||||
|
||||
// Create stubs
|
||||
val irProviders = generateTypicalIrProviderList(moduleDescriptor, irLinker.builtIns, symbolTable, irLinker)
|
||||
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
|
||||
moduleFragment.patchDeclarationParents()
|
||||
|
||||
wasmPhases.invokeToplevel(phaseConfig, context, moduleFragment)
|
||||
|
||||
val compiledWasmModule = WasmCompiledModuleFragment()
|
||||
val codeGenerator = WasmModuleFragmentGenerator(context, compiledWasmModule)
|
||||
codeGenerator.generateModule(moduleFragment)
|
||||
|
||||
val linkedModule = compiledWasmModule.linkWasmCompiledFragments()
|
||||
val watGenerator = WasmIrToText()
|
||||
watGenerator.appendWasmModule(linkedModule)
|
||||
val wat = watGenerator.toString()
|
||||
|
||||
val js = compiledWasmModule.generateJs()
|
||||
|
||||
val os = ByteArrayOutputStream()
|
||||
WasmIrToBinary(os, linkedModule).appendWasmModule()
|
||||
val byteArray = os.toByteArray()
|
||||
|
||||
return WasmCompilerResult(
|
||||
wat = wat,
|
||||
js = js,
|
||||
wasm = byteArray
|
||||
)
|
||||
}
|
||||
|
||||
fun compileBinaryWasm(
|
||||
mainModule: MainModule,
|
||||
phaseConfig: PhaseConfig,
|
||||
mainArguments: List<String>?,
|
||||
exportedDeclarations: Set<FqName>
|
||||
): WasmCompilerResult {
|
||||
return compileBinary(mainModule) { modules, linker ->
|
||||
doWasmBackend(modules, linker, phaseConfig, mainArguments, exportedDeclarations)
|
||||
}
|
||||
}
|
||||
|
||||
fun compileBinaryJs(
|
||||
mainModule: MainModule,
|
||||
phaseConfig: PhaseConfig,
|
||||
mainArguments: List<String>?,
|
||||
exportedDeclarations: Set<FqName> = emptySet()
|
||||
): CompilerResult {
|
||||
return compileBinary(mainModule) { modules, linker ->
|
||||
doJsBackend(modules, linker, phaseConfig, mainArguments, exportedDeclarations)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> compileBinary(mainModule: MainModule, backend: (List<IrModuleFragment>, JsIrLinker) -> T): T {
|
||||
val irLinker: JsIrLinker
|
||||
val allModuleFragments = when (mainModule) {
|
||||
is MainModule.SourceFiles -> {
|
||||
val files = mainModule.files
|
||||
val frontEndResult = doAnalysis(mainModule.files)
|
||||
val psi2IrContext = createPsi2IrContext(frontEndResult, options.dceDriven)
|
||||
irLinker = psi2IrContext.run {
|
||||
val feContext = JsIrLinker.JsFePluginContext(moduleDescriptor, bindingContext, symbolTable, typeTranslator, irBuiltIns)
|
||||
createIrLinker(moduleDescriptor, irBuiltIns, symbolTable, feContext, null, onlyHeaders = false)
|
||||
}
|
||||
val moduleFragment = psi2IrContext.generateModuleFragmentWithPlugins(files, irLinker)
|
||||
mutableListOf<IrModuleFragment>().apply {
|
||||
addAll(irLinker.modules)
|
||||
add(moduleFragment)
|
||||
}
|
||||
}
|
||||
is MainModule.Klib -> {
|
||||
val mainKlib = moduleLoader.resolveModuleByPath(mainModule.lib) ?: error("No module with path ${mainModule.lib} found")
|
||||
irLinker = createRawLinker(mainKlib, options.dceDriven)
|
||||
irLinker.run {
|
||||
init(null, emptyList())
|
||||
ExternalDependenciesGenerator(symbolTable, listOf(this)).generateUnboundSymbolsAsDependencies()
|
||||
postProcess()
|
||||
modules
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return backend(allModuleFragments, irLinker)
|
||||
}
|
||||
|
||||
// Klibs
|
||||
|
||||
private class ICCacheData(
|
||||
val icData: List<KotlinFileSerializedData>,
|
||||
val serializedIrFiles: List<SerializedIrFile>?)
|
||||
|
||||
private fun loadICdataIfExists(files: Collection<KtFile>): ICCacheData {
|
||||
val incrementalDataProvider = configuration.get(JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER)
|
||||
return if (incrementalDataProvider != null) {
|
||||
val nonCompiledSources = files.map { VfsUtilCore.virtualToIoFile(it.virtualFile) to it }.toMap()
|
||||
val compiledIrFiles = incrementalDataProvider.serializedIrFiles
|
||||
val compiledMetaFiles = incrementalDataProvider.compiledPackageParts
|
||||
|
||||
assert(compiledIrFiles.size == compiledMetaFiles.size)
|
||||
|
||||
val storage = mutableListOf<KotlinFileSerializedData>()
|
||||
|
||||
for (f in compiledIrFiles.keys) {
|
||||
if (f in nonCompiledSources) continue
|
||||
|
||||
val irData = compiledIrFiles[f] ?: error("No Ir Data found for file $f")
|
||||
val metaFile = compiledMetaFiles[f] ?: error("No Meta Data found for file $f")
|
||||
val irFile = with(irData) {
|
||||
SerializedIrFile(fileData, String(fqn), f.path.replace('\\', '/'), types, signatures, strings, bodies, declarations)
|
||||
}
|
||||
storage.add(KotlinFileSerializedData(metaFile.metadata, irFile))
|
||||
}
|
||||
|
||||
ICCacheData(storage, storage.map { it.irData })
|
||||
} else {
|
||||
ICCacheData(emptyList(), null)
|
||||
}
|
||||
}
|
||||
|
||||
fun compileKlib(files: Collection<KtFile>, outputKlibPath: String) {
|
||||
|
||||
val icCacheData = loadICdataIfExists(files)
|
||||
|
||||
val frontEndResult = doAnalysis(files)
|
||||
val psi2IrContext = createPsi2IrContext(frontEndResult, isPersistent = false)
|
||||
|
||||
val irLinker = psi2IrContext.run {
|
||||
val feContext = JsIrLinker.JsFePluginContext(moduleDescriptor, bindingContext, symbolTable, typeTranslator, irBuiltIns)
|
||||
createIrLinker(moduleDescriptor, irBuiltIns, symbolTable, feContext, icCacheData.serializedIrFiles, onlyHeaders = true)
|
||||
}
|
||||
|
||||
val expectDescriptorToSymbol = mutableMapOf<DeclarationDescriptor, IrSymbol>()
|
||||
val moduleFragment = psi2IrContext.generateModuleFragmentWithPlugins(files, irLinker, expectDescriptorToSymbol)
|
||||
|
||||
moduleFragment.acceptVoid(ManglerChecker(JsManglerIr, Ir2DescriptorManglerAdapter(JsManglerDesc)))
|
||||
if (configuration.getBoolean(JSConfigurationKeys.FAKE_OVERRIDE_VALIDATOR)) {
|
||||
val fakeOverrideChecker = FakeOverrideChecker(JsManglerIr, JsManglerDesc)
|
||||
irLinker.modules.forEach { fakeOverrideChecker.check(it) }
|
||||
}
|
||||
|
||||
val moduleName = configuration[CommonConfigurationKeys.MODULE_NAME]!!
|
||||
|
||||
if (!expectActualLinker) {
|
||||
moduleFragment.acceptVoid(ExpectDeclarationRemover(psi2IrContext.symbolTable, false))
|
||||
}
|
||||
|
||||
serializeModuleIntoKlib(
|
||||
moduleName,
|
||||
project,
|
||||
configuration,
|
||||
messageLogger,
|
||||
psi2IrContext.bindingContext,
|
||||
files,
|
||||
outputKlibPath,
|
||||
dependenciesRpo,
|
||||
moduleFragment,
|
||||
expectDescriptorToSymbol,
|
||||
icCacheData.icData,
|
||||
configuration.get(JSConfigurationKeys.INCREMENTAL_RESULTS_CONSUMER),
|
||||
options.nopack,
|
||||
options.perFile,
|
||||
frontEndResult.hasErrors
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.compiler.wjs
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.DynamicTypeDeserializer
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataModuleDescriptorFactory
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
|
||||
import org.jetbrains.kotlin.library.resolver.KotlinResolvedLibrary
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import java.io.File
|
||||
|
||||
class ModuleLoader(
|
||||
private val resolvedLibraries: KotlinLibraryResolveResult,
|
||||
private val descriptorFactory: KlibMetadataModuleDescriptorFactory,
|
||||
private val configuration: CompilerConfiguration,
|
||||
private val storageManager: LockBasedStorageManager
|
||||
) {
|
||||
|
||||
private val lookupTracker: LookupTracker =
|
||||
configuration[CommonConfigurationKeys.LOOKUP_TRACKER] ?: LookupTracker.DO_NOTHING
|
||||
|
||||
var builtInsModule: ModuleDescriptorImpl? = null
|
||||
private set
|
||||
|
||||
private val resolvedDependenciesRpo: List<KotlinResolvedLibrary> = computeDependenciesRpo()
|
||||
|
||||
val dependenciesRpo: List<KotlinLibrary> = resolvedDependenciesRpo.map { it.library }
|
||||
|
||||
private fun computeDependenciesRpo(): List<KotlinResolvedLibrary> {
|
||||
val transitives = resolvedLibraries.getFullResolvedList()
|
||||
return DFS.topologicalOrder(transitives) { it.resolvedDependencies }.reversed()
|
||||
}
|
||||
|
||||
val dependencyDescriptors: Map<String, ModuleDescriptorImpl> = loadDependencies()
|
||||
|
||||
private fun loadDependencies(): Map<String, ModuleDescriptorImpl> {
|
||||
val depsMap: MutableMap<String, ModuleDescriptorImpl> = mutableMapOf()
|
||||
|
||||
fun loadSingleModule(current: KotlinResolvedLibrary): ModuleDescriptorImpl {
|
||||
val library = current.library
|
||||
return depsMap.getOrPut(library.libraryName) {
|
||||
descriptorFactory.createDescriptorOptionalBuiltIns(
|
||||
library,
|
||||
configuration.languageVersionSettings,
|
||||
storageManager,
|
||||
builtInsModule?.builtIns,
|
||||
packageAccessHandler = null, // TODO: This is a speed optimization used by Native. Don't bother for now.
|
||||
lookupTracker = lookupTracker
|
||||
).apply {
|
||||
val klibDependencies = current.resolvedDependencies
|
||||
if (klibDependencies.isEmpty()) builtInsModule = this
|
||||
val dependencies = ArrayList<ModuleDescriptorImpl>(klibDependencies.size + 1)
|
||||
dependencies.add(this)
|
||||
klibDependencies.mapTo(dependencies) { loadSingleModule(it) }
|
||||
setDependencies(dependencies)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolvedDependenciesRpo.forEach { loadSingleModule(it) }
|
||||
|
||||
return depsMap
|
||||
}
|
||||
|
||||
fun resolveModuleByPath(path: String): KotlinLibrary? {
|
||||
val canonicalPath = File(path).canonicalPath
|
||||
return dependenciesRpo.singleOrNull { it.libraryFile.canonicalPath == canonicalPath }
|
||||
}
|
||||
|
||||
companion object {
|
||||
val jsMetadataFactories = KlibMetadataFactories({ object : KotlinBuiltIns(it) {} }, DynamicTypeDeserializer)
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js
|
||||
package org.jetbrains.kotlin.ir.compiler.wjs
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.context.ModuleContext
|
||||
@@ -11,17 +11,17 @@ import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider
|
||||
import org.jetbrains.kotlin.js.analyze.AbstractTopDownAnalyzerFacadeForJS
|
||||
import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
|
||||
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
|
||||
|
||||
// TODO: put it in separated module `frontend.js`
|
||||
object TopDownAnalyzerFacadeForJSIR : AbstractTopDownAnalyzerFacadeForJS() {
|
||||
class TopDownAnalyzerFacadeForJSIR(private val jsFactories: KlibMetadataFactories) : AbstractTopDownAnalyzerFacadeForJS() {
|
||||
override fun loadIncrementalCacheMetadata(
|
||||
incrementalData: IncrementalDataProvider,
|
||||
moduleContext: ModuleContext,
|
||||
lookupTracker: LookupTracker,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): PackageFragmentProvider {
|
||||
return JsFactories.DefaultDeserializedDescriptorFactory.createCachedPackageFragmentProvider(
|
||||
return jsFactories.DefaultDeserializedDescriptorFactory.createCachedPackageFragmentProvider(
|
||||
incrementalData.compiledPackageParts.values.map { it.metadata },
|
||||
moduleContext.storageManager,
|
||||
moduleContext.module,
|
||||
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator) {
|
||||
@@ -206,6 +207,8 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
|
||||
createVariableValue(ktExpr, descriptor, origin)
|
||||
is PropertyDescriptor ->
|
||||
generateAssignmentReceiverForProperty(descriptor, origin, ktExpr, resolvedCall, isAssignmentStatement)
|
||||
is FakeCallableDescriptorForObject ->
|
||||
OnceExpressionValue(ktExpr.genExpr())
|
||||
is ValueDescriptor ->
|
||||
createVariableValue(ktExpr, descriptor, origin)
|
||||
else ->
|
||||
|
||||
@@ -269,6 +269,11 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
|
||||
|
||||
override fun TypeConstructorMarker.isIntegerLiteralTypeConstructor() = false
|
||||
|
||||
override fun TypeConstructorMarker.isLocalType(): Boolean {
|
||||
if (this !is IrClassSymbol) return false
|
||||
return this.owner.classId?.isLocal == true
|
||||
}
|
||||
|
||||
override fun createFlexibleType(lowerBound: SimpleTypeMarker, upperBound: SimpleTypeMarker): KotlinTypeMarker {
|
||||
require(lowerBound.isNothing())
|
||||
require(upperBound is IrType && upperBound.isNullableAny())
|
||||
@@ -516,4 +521,4 @@ fun extractTypeParameters(parent: IrDeclarationParent): List<IrTypeParameter> {
|
||||
}
|
||||
|
||||
|
||||
class IrTypeSystemContextImpl(override val irBuiltIns: IrBuiltIns) : IrTypeSystemContext
|
||||
class IrTypeSystemContextImpl(override val irBuiltIns: IrBuiltIns) : IrTypeSystemContext
|
||||
|
||||
@@ -109,17 +109,25 @@ fun IrType.isMarkedNullable() = (this as? IrSimpleType)?.hasQuestionMark ?: fals
|
||||
fun IrType.isUnit() = isNotNullClassType(IdSignatureValues.unit)
|
||||
|
||||
fun IrType.isBoolean(): Boolean = isNotNullClassType(IdSignatureValues._boolean)
|
||||
fun IrType.isBooleanOrNullable(): Boolean = isClassType(IdSignatureValues._boolean)
|
||||
fun IrType.isChar(): Boolean = isNotNullClassType(IdSignatureValues._char)
|
||||
fun IrType.isCharOrNullable(): Boolean = isClassType(IdSignatureValues._char)
|
||||
fun IrType.isByte(): Boolean = isNotNullClassType(IdSignatureValues._byte)
|
||||
fun IrType.isByteOrNullable(): Boolean = isClassType(IdSignatureValues._byte)
|
||||
fun IrType.isShort(): Boolean = isNotNullClassType(IdSignatureValues._short)
|
||||
fun IrType.isShortOrNullable(): Boolean = isClassType(IdSignatureValues._short)
|
||||
fun IrType.isInt(): Boolean = isNotNullClassType(IdSignatureValues._int)
|
||||
fun IrType.isIntOrNullable(): Boolean = isClassType(IdSignatureValues._int)
|
||||
fun IrType.isLong(): Boolean = isNotNullClassType(IdSignatureValues._long)
|
||||
fun IrType.isLongOrNullable(): Boolean = isClassType(IdSignatureValues._long)
|
||||
fun IrType.isUByte(): Boolean = isNotNullClassType(IdSignatureValues.uByte)
|
||||
fun IrType.isUShort(): Boolean = isNotNullClassType(IdSignatureValues.uShort)
|
||||
fun IrType.isUInt(): Boolean = isNotNullClassType(IdSignatureValues.uInt)
|
||||
fun IrType.isULong(): Boolean = isNotNullClassType(IdSignatureValues.uLong)
|
||||
fun IrType.isFloat(): Boolean = isNotNullClassType(IdSignatureValues._float)
|
||||
fun IrType.isFloatOrNullable(): Boolean = isClassType(IdSignatureValues._float)
|
||||
fun IrType.isDouble(): Boolean = isNotNullClassType(IdSignatureValues._double)
|
||||
fun IrType.isDoubleOrNullable(): Boolean = isClassType(IdSignatureValues._double)
|
||||
fun IrType.isNumber(): Boolean = isNotNullClassType(IdSignatureValues.number)
|
||||
|
||||
fun IrType.isComparable(): Boolean = isNotNullClassType(IdSignatureValues.comparable)
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.serialization
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
import org.jetbrains.kotlin.library.IrLibrary
|
||||
import org.jetbrains.kotlin.protobuf.CodedInputStream
|
||||
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFile as ProtoFile
|
||||
|
||||
abstract class BasicIrModuleDeserializer(
|
||||
val linker: KotlinIrLinker,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
override val klib: IrLibrary,
|
||||
override val strategy: DeserializationStrategy,
|
||||
private val containsErrorCode: Boolean = false
|
||||
) :
|
||||
IrModuleDeserializer(moduleDescriptor) {
|
||||
|
||||
private val fileToDeserializerMap = mutableMapOf<IrFile, IrFileDeserializer>()
|
||||
|
||||
private val moduleDeserializationState = ModuleDeserializationState(linker, this)
|
||||
|
||||
internal val moduleReversedFileIndex = mutableMapOf<IdSignature, FileDeserializationState>()
|
||||
|
||||
override val moduleDependencies by lazy {
|
||||
moduleDescriptor.allDependencyModules.filter { it != moduleDescriptor }.map { linker.resolveModuleDeserializer(it, null) }
|
||||
}
|
||||
|
||||
override fun init(delegate: IrModuleDeserializer) {
|
||||
val fileCount = klib.fileCount()
|
||||
|
||||
val files = ArrayList<IrFile>(fileCount)
|
||||
|
||||
for (i in 0 until fileCount) {
|
||||
val fileStream = klib.file(i).codedInputStream
|
||||
val fileProto = ProtoFile.parseFrom(fileStream, ExtensionRegistryLite.newInstance())
|
||||
files.add(deserializeIrFile(fileProto, i, delegate, containsErrorCode))
|
||||
}
|
||||
|
||||
moduleFragment.files.addAll(files)
|
||||
|
||||
fileToDeserializerMap.values.forEach { it.symbolDeserializer.deserializeExpectActualMapping() }
|
||||
}
|
||||
|
||||
private fun IrSymbolDeserializer.deserializeExpectActualMapping() {
|
||||
actuals.forEach {
|
||||
val expectSymbol = parseSymbolData(it.expectSymbol)
|
||||
val actualSymbol = parseSymbolData(it.actualSymbol)
|
||||
|
||||
val expect = deserializeIdSignature(expectSymbol.signatureId)
|
||||
val actual = deserializeIdSignature(actualSymbol.signatureId)
|
||||
|
||||
assert(linker.expectUniqIdToActualUniqId[expect] == null) {
|
||||
"Expect signature $expect is already actualized by ${linker.expectUniqIdToActualUniqId[expect]}, while we try to record $actual"
|
||||
}
|
||||
linker.expectUniqIdToActualUniqId[expect] = actual
|
||||
// Non-null only for topLevel declarations.
|
||||
findModuleDeserializerForTopLevelId(actual)?.let { md -> linker.topLevelActualUniqItToDeserializer[actual] = md }
|
||||
}
|
||||
}
|
||||
|
||||
override fun referenceSimpleFunctionByLocalSignature(file: IrFile, idSignature: IdSignature) : IrSimpleFunctionSymbol =
|
||||
fileToDeserializerMap[file]?.symbolDeserializer?.referenceSimpleFunctionByLocalSignature(idSignature)
|
||||
?: error("No deserializer for file $file in module ${moduleDescriptor.name}")
|
||||
|
||||
override fun referencePropertyByLocalSignature(file: IrFile, idSignature: IdSignature): IrPropertySymbol =
|
||||
fileToDeserializerMap[file]?.symbolDeserializer?.referencePropertyByLocalSignature(idSignature)
|
||||
?: error("No deserializer for file $file in module ${moduleDescriptor.name}")
|
||||
|
||||
// TODO: fix to topLevel checker
|
||||
override fun contains(idSig: IdSignature): Boolean = idSig in moduleReversedFileIndex
|
||||
|
||||
override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
||||
assert(idSig.isPublic)
|
||||
|
||||
val topLevelSignature = idSig.topLevelSignature()
|
||||
val fileLocalDeserializationState = moduleReversedFileIndex[topLevelSignature]
|
||||
?: error("No file for $topLevelSignature (@ $idSig) in module $moduleDescriptor")
|
||||
|
||||
fileLocalDeserializationState.addIdSignature(topLevelSignature)
|
||||
moduleDeserializationState.enqueueFile(fileLocalDeserializationState)
|
||||
|
||||
return fileLocalDeserializationState.fileDeserializer.symbolDeserializer.deserializeIrSymbol(idSig, symbolKind).also {
|
||||
linker.deserializedSymbols.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
override val moduleFragment: IrModuleFragment = IrModuleFragmentImpl(moduleDescriptor, linker.builtIns, emptyList())
|
||||
|
||||
private fun deserializeIrFile(fileProto: ProtoFile, fileIndex: Int, moduleDeserializer: IrModuleDeserializer, allowErrorNodes: Boolean): IrFile {
|
||||
|
||||
val fileReader = IrLibraryFileFromKlib(moduleDeserializer.klib, fileIndex)
|
||||
val file = fileReader.createFile(moduleDescriptor, fileProto)
|
||||
|
||||
val fileDeserializationState = FileDeserializationState(
|
||||
linker,
|
||||
file,
|
||||
fileReader,
|
||||
fileProto,
|
||||
strategy.needBodies,
|
||||
allowErrorNodes,
|
||||
strategy.inlineBodies,
|
||||
moduleDeserializer,
|
||||
linker::handleNoModuleDeserializerFound,
|
||||
)
|
||||
|
||||
fileToDeserializerMap[file] = fileDeserializationState.fileDeserializer
|
||||
|
||||
val topLevelDeclarations = fileDeserializationState.fileDeserializer.reversedSignatureIndex.keys
|
||||
topLevelDeclarations.forEach {
|
||||
moduleReversedFileIndex.putIfAbsent(it, fileDeserializationState) // TODO Why not simple put?
|
||||
}
|
||||
|
||||
if (strategy.theWholeWorld) {
|
||||
fileDeserializationState.enqueueAllDeclarations()
|
||||
}
|
||||
if (strategy.theWholeWorld || strategy.explicitlyExported) {
|
||||
moduleDeserializationState.enqueueFile(fileDeserializationState)
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
// TODO useless
|
||||
override fun addModuleReachableTopLevel(idSig: IdSignature) {
|
||||
moduleDeserializationState.addIdSignature(idSig)
|
||||
}
|
||||
}
|
||||
|
||||
internal class ModuleDeserializationState(val linker: KotlinIrLinker, val moduleDeserializer: BasicIrModuleDeserializer) {
|
||||
private val filesWithPendingTopLevels = mutableSetOf<FileDeserializationState>()
|
||||
|
||||
fun enqueueFile(fileDeserializationState: FileDeserializationState) {
|
||||
filesWithPendingTopLevels.add(fileDeserializationState)
|
||||
linker.modulesWithReachableTopLevels.add(this)
|
||||
}
|
||||
|
||||
fun addIdSignature(key: IdSignature) {
|
||||
val fileLocalDeserializationState = moduleDeserializer.moduleReversedFileIndex[key] ?: error("No file found for key $key")
|
||||
fileLocalDeserializationState.addIdSignature(key)
|
||||
|
||||
enqueueFile(fileLocalDeserializationState)
|
||||
}
|
||||
|
||||
fun deserializeReachableDeclarations() {
|
||||
while (filesWithPendingTopLevels.isNotEmpty()) {
|
||||
val pendingFileDeserializationState = filesWithPendingTopLevels.first()
|
||||
|
||||
pendingFileDeserializationState.fileDeserializer.deserializeFileImplicitDataIfFirstUse()
|
||||
pendingFileDeserializationState.deserializeAllFileReachableTopLevel()
|
||||
|
||||
filesWithPendingTopLevels.remove(pendingFileDeserializationState)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String = moduleDeserializer.klib.toString()
|
||||
}
|
||||
|
||||
fun IrModuleDeserializer.findModuleDeserializerForTopLevelId(idSignature: IdSignature): IrModuleDeserializer? {
|
||||
if (idSignature in this) return this
|
||||
return moduleDependencies.firstOrNull { idSignature in it }
|
||||
}
|
||||
|
||||
internal val ByteArray.codedInputStream: CodedInputStream
|
||||
get() {
|
||||
val codedInputStream = CodedInputStream.newInstance(this)
|
||||
codedInputStream.setRecursionLimit(65535) // The default 64 is blatantly not enough for IR.
|
||||
return codedInputStream
|
||||
}
|
||||
@@ -100,10 +100,6 @@ class CurrentModuleWithICDeserializer(
|
||||
icDeserializer.addModuleReachableTopLevel(idSig)
|
||||
}
|
||||
|
||||
override fun deserializeReachableDeclarations() {
|
||||
icDeserializer.deserializeReachableDeclarations()
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.isDirtyDescriptor(): Boolean {
|
||||
if (this is PropertyAccessorDescriptor) return correspondingProperty.isDirtyDescriptor()
|
||||
// Since descriptors for FO methods of `kotlin.Any` (toString, equals, hashCode) are Deserialized even in
|
||||
|
||||
@@ -0,0 +1,787 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.serialization
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.serialization.encodings.*
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrConst.ValueCase.*
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrOperation.OperationCase.*
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrStatement.StatementCase
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrVarargElement.VarargElementCase
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrBlock as ProtoBlock
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrBlockBody as ProtoBlockBody
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrBranch as ProtoBranch
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrBreak as ProtoBreak
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrCall as ProtoCall
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrCatch as ProtoCatch
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrClassReference as ProtoClassReference
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrComposite as ProtoComposite
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrConst as ProtoConst
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrConstructorCall as ProtoConstructorCall
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrContinue as ProtoContinue
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDelegatingConstructorCall as ProtoDelegatingConstructorCall
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDoWhile as ProtoDoWhile
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDynamicMemberExpression as ProtoDynamicMemberExpression
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDynamicOperatorExpression as ProtoDynamicOperatorExpression
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrEnumConstructorCall as ProtoEnumConstructorCall
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrExpression as ProtoExpression
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFunctionExpression as ProtoFunctionExpression
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrErrorExpression as ProtoErrorExpression
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrErrorCallExpression as ProtoErrorCallExpression
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFunctionReference as ProtoFunctionReference
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrGetClass as ProtoGetClass
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrGetEnumValue as ProtoGetEnumValue
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrGetField as ProtoGetField
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrGetObject as ProtoGetObject
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrGetValue as ProtoGetValue
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrInstanceInitializerCall as ProtoInstanceInitializerCall
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrLocalDelegatedPropertyReference as ProtoLocalDelegatedPropertyReference
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrOperation as ProtoOperation
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrPropertyReference as ProtoPropertyReference
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrReturn as ProtoReturn
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSetField as ProtoSetField
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSetValue as ProtoSetValue
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSpreadElement as ProtoSpreadElement
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrStatement as ProtoStatement
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrStringConcat as ProtoStringConcat
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSyntheticBody as ProtoSyntheticBody
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSyntheticBodyKind as ProtoSyntheticBodyKind
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrThrow as ProtoThrow
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrTry as ProtoTry
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrTypeOp as ProtoTypeOp
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrTypeOperator as ProtoTypeOperator
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrVararg as ProtoVararg
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrVarargElement as ProtoVarargElement
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrWhen as ProtoWhen
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrWhile as ProtoWhile
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.Loop as ProtoLoop
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.MemberAccessCommon as ProtoMemberAccessCommon
|
||||
|
||||
class IrBodyDeserializer(
|
||||
private val builtIns: IrBuiltIns,
|
||||
private val allowErrorNodes: Boolean,
|
||||
private val irFactory: IrFactory,
|
||||
private val fileReader: IrLibraryFile,
|
||||
private val declarationDeserializer: IrDeclarationDeserializer,
|
||||
) {
|
||||
|
||||
private val fileLoops = mutableMapOf<Int, IrLoop>()
|
||||
|
||||
private fun deserializeLoopHeader(loopIndex: Int, loopBuilder: () -> IrLoop): IrLoop =
|
||||
fileLoops.getOrPut(loopIndex, loopBuilder)
|
||||
|
||||
private fun deserializeBlockBody(
|
||||
proto: ProtoBlockBody,
|
||||
start: Int, end: Int
|
||||
): IrBlockBody {
|
||||
|
||||
val statements = mutableListOf<IrStatement>()
|
||||
|
||||
val statementProtos = proto.statementList
|
||||
statementProtos.forEach {
|
||||
statements.add(deserializeStatement(it) as IrStatement)
|
||||
}
|
||||
|
||||
return irFactory.createBlockBody(start, end, statements)
|
||||
}
|
||||
|
||||
private fun deserializeBranch(proto: ProtoBranch, start: Int, end: Int): IrBranch {
|
||||
|
||||
val condition = deserializeExpression(proto.condition)
|
||||
val result = deserializeExpression(proto.result)
|
||||
|
||||
return IrBranchImpl(start, end, condition, result)
|
||||
}
|
||||
|
||||
private fun deserializeCatch(proto: ProtoCatch, start: Int, end: Int): IrCatch {
|
||||
val catchParameter = declarationDeserializer.deserializeIrVariable(proto.catchParameter)
|
||||
val result = deserializeExpression(proto.result)
|
||||
|
||||
return IrCatchImpl(start, end, catchParameter, result)
|
||||
}
|
||||
|
||||
private fun deserializeSyntheticBody(proto: ProtoSyntheticBody, start: Int, end: Int): IrSyntheticBody {
|
||||
val kind = when (proto.kind!!) {
|
||||
ProtoSyntheticBodyKind.ENUM_VALUES -> IrSyntheticBodyKind.ENUM_VALUES
|
||||
ProtoSyntheticBodyKind.ENUM_VALUEOF -> IrSyntheticBodyKind.ENUM_VALUEOF
|
||||
}
|
||||
return IrSyntheticBodyImpl(start, end, kind)
|
||||
}
|
||||
|
||||
internal fun deserializeStatement(proto: ProtoStatement): IrElement {
|
||||
val coordinates = BinaryCoordinates.decode(proto.coordinates)
|
||||
val start = coordinates.startOffset
|
||||
val end = coordinates.endOffset
|
||||
val element = when (proto.statementCase) {
|
||||
StatementCase.BLOCK_BODY //proto.hasBlockBody()
|
||||
-> deserializeBlockBody(proto.blockBody, start, end)
|
||||
StatementCase.BRANCH //proto.hasBranch()
|
||||
-> deserializeBranch(proto.branch, start, end)
|
||||
StatementCase.CATCH //proto.hasCatch()
|
||||
-> deserializeCatch(proto.catch, start, end)
|
||||
StatementCase.DECLARATION // proto.hasDeclaration()
|
||||
-> declarationDeserializer.deserializeDeclaration(proto.declaration)
|
||||
StatementCase.EXPRESSION // proto.hasExpression()
|
||||
-> deserializeExpression(proto.expression)
|
||||
StatementCase.SYNTHETIC_BODY // proto.hasSyntheticBody()
|
||||
-> deserializeSyntheticBody(proto.syntheticBody, start, end)
|
||||
else
|
||||
-> TODO("Statement deserialization not implemented: ${proto.statementCase}")
|
||||
}
|
||||
|
||||
return element
|
||||
}
|
||||
|
||||
private fun deserializeBlock(proto: ProtoBlock, start: Int, end: Int, type: IrType): IrBlock {
|
||||
val statements = mutableListOf<IrStatement>()
|
||||
val statementProtos = proto.statementList
|
||||
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
|
||||
|
||||
statementProtos.forEach {
|
||||
statements.add(deserializeStatement(it) as IrStatement)
|
||||
}
|
||||
|
||||
return IrBlockImpl(start, end, type, origin, statements)
|
||||
}
|
||||
|
||||
private fun deserializeMemberAccessCommon(access: IrMemberAccessExpression<*>, proto: ProtoMemberAccessCommon) {
|
||||
|
||||
proto.valueArgumentList.mapIndexed { i, arg ->
|
||||
if (arg.hasExpression()) {
|
||||
val expr = deserializeExpression(arg.expression)
|
||||
access.putValueArgument(i, expr)
|
||||
}
|
||||
}
|
||||
|
||||
proto.typeArgumentList.mapIndexed { i, arg ->
|
||||
access.putTypeArgument(i, declarationDeserializer.deserializeIrType(arg))
|
||||
}
|
||||
|
||||
if (proto.hasDispatchReceiver()) {
|
||||
access.dispatchReceiver = deserializeExpression(proto.dispatchReceiver)
|
||||
}
|
||||
if (proto.hasExtensionReceiver()) {
|
||||
access.extensionReceiver = deserializeExpression(proto.extensionReceiver)
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeClassReference(
|
||||
proto: ProtoClassReference,
|
||||
start: Int,
|
||||
end: Int,
|
||||
type: IrType
|
||||
): IrClassReference {
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.classSymbol) as IrClassifierSymbol
|
||||
val classType = declarationDeserializer.deserializeIrType(proto.classType)
|
||||
/** TODO: [createClassifierSymbolForClassReference] is internal function */
|
||||
return IrClassReferenceImpl(start, end, type, symbol, classType)
|
||||
}
|
||||
|
||||
fun deserializeAnnotation(proto: ProtoConstructorCall): IrConstructorCall {
|
||||
return deserializeConstructorCall(proto, 0, 0, builtIns.unitType) // TODO: need a proper deserialization here
|
||||
}
|
||||
|
||||
fun deserializeConstructorCall(proto: ProtoConstructorCall, start: Int, end: Int, type: IrType): IrConstructorCall {
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrConstructorSymbol
|
||||
return IrConstructorCallImpl(
|
||||
start, end, type,
|
||||
symbol, typeArgumentsCount = proto.memberAccess.typeArgumentCount,
|
||||
constructorTypeArgumentsCount = proto.constructorTypeArgumentsCount,
|
||||
valueArgumentsCount = proto.memberAccess.valueArgumentCount
|
||||
).also {
|
||||
deserializeMemberAccessCommon(it, proto.memberAccess)
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeCall(proto: ProtoCall, start: Int, end: Int, type: IrType): IrCall {
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrSimpleFunctionSymbol
|
||||
|
||||
val superSymbol = if (proto.hasSuper()) {
|
||||
declarationDeserializer.deserializeIrSymbolAndRemap(proto.`super`) as IrClassSymbol
|
||||
} else null
|
||||
|
||||
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
|
||||
|
||||
val call: IrCall =
|
||||
// TODO: implement the last three args here.
|
||||
IrCallImpl(
|
||||
start, end, type,
|
||||
symbol, proto.memberAccess.typeArgumentCount,
|
||||
proto.memberAccess.valueArgumentList.size,
|
||||
origin,
|
||||
superSymbol
|
||||
)
|
||||
deserializeMemberAccessCommon(call, proto.memberAccess)
|
||||
return call
|
||||
}
|
||||
|
||||
private fun deserializeComposite(proto: ProtoComposite, start: Int, end: Int, type: IrType): IrComposite {
|
||||
val statements = mutableListOf<IrStatement>()
|
||||
val statementProtos = proto.statementList
|
||||
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
|
||||
|
||||
statementProtos.forEach {
|
||||
statements.add(deserializeStatement(it) as IrStatement)
|
||||
}
|
||||
return IrCompositeImpl(start, end, type, origin, statements)
|
||||
}
|
||||
|
||||
private fun deserializeDelegatingConstructorCall(
|
||||
proto: ProtoDelegatingConstructorCall,
|
||||
start: Int,
|
||||
end: Int
|
||||
): IrDelegatingConstructorCall {
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrConstructorSymbol
|
||||
val call = IrDelegatingConstructorCallImpl(
|
||||
start,
|
||||
end,
|
||||
builtIns.unitType,
|
||||
symbol,
|
||||
proto.memberAccess.typeArgumentCount,
|
||||
proto.memberAccess.valueArgumentCount
|
||||
)
|
||||
|
||||
deserializeMemberAccessCommon(call, proto.memberAccess)
|
||||
return call
|
||||
}
|
||||
|
||||
|
||||
private fun deserializeEnumConstructorCall(
|
||||
proto: ProtoEnumConstructorCall,
|
||||
start: Int,
|
||||
end: Int,
|
||||
): IrEnumConstructorCall {
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrConstructorSymbol
|
||||
val call = IrEnumConstructorCallImpl(
|
||||
start,
|
||||
end,
|
||||
builtIns.unitType,
|
||||
symbol,
|
||||
proto.memberAccess.typeArgumentCount,
|
||||
proto.memberAccess.valueArgumentCount
|
||||
)
|
||||
deserializeMemberAccessCommon(call, proto.memberAccess)
|
||||
return call
|
||||
}
|
||||
|
||||
private fun deserializeFunctionExpression(
|
||||
functionExpression: ProtoFunctionExpression,
|
||||
start: Int,
|
||||
end: Int,
|
||||
type: IrType
|
||||
) =
|
||||
IrFunctionExpressionImpl(
|
||||
start, end, type,
|
||||
declarationDeserializer.deserializeIrFunction(functionExpression.function),
|
||||
deserializeIrStatementOrigin(functionExpression.originName)
|
||||
)
|
||||
|
||||
private fun deserializeErrorExpression(
|
||||
proto: ProtoErrorExpression,
|
||||
start: Int, end: Int, type: IrType
|
||||
): IrErrorExpression {
|
||||
require(allowErrorNodes) {
|
||||
"IrErrorExpression($start, $end, \"${fileReader.deserializeString(proto.description)}\") found but error code is not allowed"
|
||||
}
|
||||
return IrErrorExpressionImpl(start, end, type, fileReader.deserializeString(proto.description))
|
||||
}
|
||||
|
||||
private fun deserializeErrorCallExpression(
|
||||
proto: ProtoErrorCallExpression,
|
||||
start: Int, end: Int, type: IrType
|
||||
): IrErrorCallExpression {
|
||||
require(allowErrorNodes) {
|
||||
"IrErrorCallExpressionImpl($start, $end, \"${fileReader.deserializeString(proto.description)}\") found but error code is not allowed"
|
||||
}
|
||||
return IrErrorCallExpressionImpl(start, end, type, fileReader.deserializeString(proto.description)).apply {
|
||||
if (proto.hasReceiver()) {
|
||||
explicitReceiver = deserializeExpression(proto.receiver)
|
||||
}
|
||||
proto.valueArgumentList.forEach {
|
||||
addArgument(deserializeExpression(it))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun deserializeFunctionReference(
|
||||
proto: ProtoFunctionReference,
|
||||
start: Int, end: Int, type: IrType
|
||||
): IrFunctionReference {
|
||||
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrFunctionSymbol
|
||||
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
|
||||
val reflectionTarget =
|
||||
if (proto.hasReflectionTargetSymbol()) declarationDeserializer.deserializeIrSymbolAndRemap(proto.reflectionTargetSymbol) as IrFunctionSymbol else null
|
||||
val callable = IrFunctionReferenceImpl(
|
||||
start,
|
||||
end,
|
||||
type,
|
||||
symbol,
|
||||
proto.memberAccess.typeArgumentCount,
|
||||
proto.memberAccess.valueArgumentCount,
|
||||
reflectionTarget,
|
||||
origin
|
||||
)
|
||||
deserializeMemberAccessCommon(callable, proto.memberAccess)
|
||||
|
||||
return callable
|
||||
}
|
||||
|
||||
private fun deserializeGetClass(proto: ProtoGetClass, start: Int, end: Int, type: IrType): IrGetClass {
|
||||
val argument = deserializeExpression(proto.argument)
|
||||
return IrGetClassImpl(start, end, type, argument)
|
||||
}
|
||||
|
||||
private fun deserializeGetField(proto: ProtoGetField, start: Int, end: Int, type: IrType): IrGetField {
|
||||
val access = proto.fieldAccess
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(access.symbol) as IrFieldSymbol
|
||||
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
|
||||
|
||||
val superQualifier = if (access.hasSuper()) {
|
||||
declarationDeserializer.deserializeIrSymbolAndRemap(access.symbol) as IrClassSymbol
|
||||
} else null
|
||||
val receiver = if (access.hasReceiver()) {
|
||||
deserializeExpression(access.receiver)
|
||||
} else null
|
||||
|
||||
return IrGetFieldImpl(start, end, symbol, type, receiver, origin, superQualifier)
|
||||
}
|
||||
|
||||
private fun deserializeGetValue(proto: ProtoGetValue, start: Int, end: Int, type: IrType): IrGetValue {
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrValueSymbol
|
||||
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
|
||||
// TODO: origin!
|
||||
return IrGetValueImpl(start, end, type, symbol, origin)
|
||||
}
|
||||
|
||||
private fun deserializeGetEnumValue(
|
||||
proto: ProtoGetEnumValue,
|
||||
start: Int,
|
||||
end: Int,
|
||||
type: IrType
|
||||
): IrGetEnumValue {
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrEnumEntrySymbol
|
||||
return IrGetEnumValueImpl(start, end, type, symbol)
|
||||
}
|
||||
|
||||
private fun deserializeGetObject(
|
||||
proto: ProtoGetObject,
|
||||
start: Int,
|
||||
end: Int,
|
||||
type: IrType
|
||||
): IrGetObjectValue {
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrClassSymbol
|
||||
return IrGetObjectValueImpl(start, end, type, symbol)
|
||||
}
|
||||
|
||||
private fun deserializeInstanceInitializerCall(
|
||||
proto: ProtoInstanceInitializerCall,
|
||||
start: Int,
|
||||
end: Int
|
||||
): IrInstanceInitializerCall {
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrClassSymbol
|
||||
return IrInstanceInitializerCallImpl(start, end, symbol, builtIns.unitType)
|
||||
}
|
||||
|
||||
private fun deserializeIrLocalDelegatedPropertyReference(
|
||||
proto: ProtoLocalDelegatedPropertyReference,
|
||||
start: Int,
|
||||
end: Int,
|
||||
type: IrType
|
||||
): IrLocalDelegatedPropertyReference {
|
||||
|
||||
val delegate = declarationDeserializer.deserializeIrSymbolAndRemap(proto.delegate) as IrVariableSymbol
|
||||
val getter = declarationDeserializer.deserializeIrSymbolAndRemap(proto.getter) as IrSimpleFunctionSymbol
|
||||
val setter = if (proto.hasSetter()) declarationDeserializer.deserializeIrSymbolAndRemap(proto.setter) as IrSimpleFunctionSymbol else null
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrLocalDelegatedPropertySymbol
|
||||
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
|
||||
|
||||
return IrLocalDelegatedPropertyReferenceImpl(
|
||||
start, end, type,
|
||||
symbol,
|
||||
delegate,
|
||||
getter,
|
||||
setter,
|
||||
origin
|
||||
)
|
||||
}
|
||||
|
||||
private fun deserializePropertyReference(proto: ProtoPropertyReference, start: Int, end: Int, type: IrType): IrPropertyReference {
|
||||
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrPropertySymbol
|
||||
|
||||
val field = if (proto.hasField()) declarationDeserializer.deserializeIrSymbolAndRemap(proto.field) as IrFieldSymbol else null
|
||||
val getter = if (proto.hasGetter()) declarationDeserializer.deserializeIrSymbolAndRemap(proto.getter) as IrSimpleFunctionSymbol else null
|
||||
val setter = if (proto.hasSetter()) declarationDeserializer.deserializeIrSymbolAndRemap(proto.setter) as IrSimpleFunctionSymbol else null
|
||||
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
|
||||
|
||||
val callable = IrPropertyReferenceImpl(
|
||||
start, end, type,
|
||||
symbol,
|
||||
proto.memberAccess.typeArgumentCount,
|
||||
field,
|
||||
getter,
|
||||
setter,
|
||||
origin
|
||||
)
|
||||
deserializeMemberAccessCommon(callable, proto.memberAccess)
|
||||
return callable
|
||||
}
|
||||
|
||||
private fun deserializeReturn(proto: ProtoReturn, start: Int, end: Int): IrReturn {
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.returnTarget) as IrReturnTargetSymbol
|
||||
val value = deserializeExpression(proto.value)
|
||||
return IrReturnImpl(start, end, builtIns.nothingType, symbol, value)
|
||||
}
|
||||
|
||||
private fun deserializeSetField(proto: ProtoSetField, start: Int, end: Int): IrSetField {
|
||||
val access = proto.fieldAccess
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(access.symbol) as IrFieldSymbol
|
||||
val superQualifier = if (access.hasSuper()) {
|
||||
declarationDeserializer.deserializeIrSymbolAndRemap(access.symbol) as IrClassSymbol
|
||||
} else null
|
||||
val receiver = if (access.hasReceiver()) {
|
||||
deserializeExpression(access.receiver)
|
||||
} else null
|
||||
val value = deserializeExpression(proto.value)
|
||||
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
|
||||
|
||||
return IrSetFieldImpl(start, end, symbol, receiver, value, builtIns.unitType, origin, superQualifier)
|
||||
}
|
||||
|
||||
private fun deserializeSetValue(proto: ProtoSetValue, start: Int, end: Int): IrSetValue {
|
||||
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrVariableSymbol
|
||||
val value = deserializeExpression(proto.value)
|
||||
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
|
||||
return IrSetValueImpl(start, end, builtIns.unitType, symbol, value, origin)
|
||||
}
|
||||
|
||||
private fun deserializeSpreadElement(proto: ProtoSpreadElement): IrSpreadElement {
|
||||
val expression = deserializeExpression(proto.expression)
|
||||
val coordinates = BinaryCoordinates.decode(proto.coordinates)
|
||||
return IrSpreadElementImpl(coordinates.startOffset, coordinates.endOffset, expression)
|
||||
}
|
||||
|
||||
private fun deserializeStringConcat(proto: ProtoStringConcat, start: Int, end: Int, type: IrType): IrStringConcatenation {
|
||||
val argumentProtos = proto.argumentList
|
||||
val arguments = mutableListOf<IrExpression>()
|
||||
|
||||
argumentProtos.forEach {
|
||||
arguments.add(deserializeExpression(it))
|
||||
}
|
||||
return IrStringConcatenationImpl(start, end, type, arguments)
|
||||
}
|
||||
|
||||
private fun deserializeThrow(proto: ProtoThrow, start: Int, end: Int): IrThrowImpl {
|
||||
return IrThrowImpl(start, end, builtIns.nothingType, deserializeExpression(proto.value))
|
||||
}
|
||||
|
||||
private fun deserializeTry(proto: ProtoTry, start: Int, end: Int, type: IrType): IrTryImpl {
|
||||
val result = deserializeExpression(proto.result)
|
||||
val catches = mutableListOf<IrCatch>()
|
||||
proto.catchList.forEach {
|
||||
catches.add(deserializeStatement(it) as IrCatch)
|
||||
}
|
||||
val finallyExpression =
|
||||
if (proto.hasFinally()) deserializeExpression(proto.getFinally()) else null
|
||||
return IrTryImpl(start, end, type, result, catches, finallyExpression)
|
||||
}
|
||||
|
||||
private fun deserializeTypeOperator(operator: ProtoTypeOperator) = when (operator) {
|
||||
ProtoTypeOperator.CAST ->
|
||||
IrTypeOperator.CAST
|
||||
ProtoTypeOperator.IMPLICIT_CAST ->
|
||||
IrTypeOperator.IMPLICIT_CAST
|
||||
ProtoTypeOperator.IMPLICIT_NOTNULL ->
|
||||
IrTypeOperator.IMPLICIT_NOTNULL
|
||||
ProtoTypeOperator.IMPLICIT_COERCION_TO_UNIT ->
|
||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT
|
||||
ProtoTypeOperator.IMPLICIT_INTEGER_COERCION ->
|
||||
IrTypeOperator.IMPLICIT_INTEGER_COERCION
|
||||
ProtoTypeOperator.SAFE_CAST ->
|
||||
IrTypeOperator.SAFE_CAST
|
||||
ProtoTypeOperator.INSTANCEOF ->
|
||||
IrTypeOperator.INSTANCEOF
|
||||
ProtoTypeOperator.NOT_INSTANCEOF ->
|
||||
IrTypeOperator.NOT_INSTANCEOF
|
||||
ProtoTypeOperator.SAM_CONVERSION ->
|
||||
IrTypeOperator.SAM_CONVERSION
|
||||
ProtoTypeOperator.IMPLICIT_DYNAMIC_CAST ->
|
||||
IrTypeOperator.IMPLICIT_DYNAMIC_CAST
|
||||
}
|
||||
|
||||
private fun deserializeTypeOp(proto: ProtoTypeOp, start: Int, end: Int, type: IrType): IrTypeOperatorCall {
|
||||
val operator = deserializeTypeOperator(proto.operator)
|
||||
val operand = declarationDeserializer.deserializeIrType(proto.operand)//.brokenIr
|
||||
val argument = deserializeExpression(proto.argument)
|
||||
return IrTypeOperatorCallImpl(start, end, type, operator, operand, argument)
|
||||
}
|
||||
|
||||
private fun deserializeVararg(proto: ProtoVararg, start: Int, end: Int, type: IrType): IrVararg {
|
||||
val elementType = declarationDeserializer.deserializeIrType(proto.elementType)
|
||||
|
||||
val elements = mutableListOf<IrVarargElement>()
|
||||
proto.elementList.forEach {
|
||||
elements.add(deserializeVarargElement(it))
|
||||
}
|
||||
return IrVarargImpl(start, end, type, elementType, elements)
|
||||
}
|
||||
|
||||
private fun deserializeVarargElement(element: ProtoVarargElement): IrVarargElement {
|
||||
return when (element.varargElementCase) {
|
||||
VarargElementCase.EXPRESSION
|
||||
-> deserializeExpression(element.expression)
|
||||
VarargElementCase.SPREAD_ELEMENT
|
||||
-> deserializeSpreadElement(element.spreadElement)
|
||||
else
|
||||
-> TODO("Unexpected vararg element")
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeWhen(proto: ProtoWhen, start: Int, end: Int, type: IrType): IrWhen {
|
||||
val branches = mutableListOf<IrBranch>()
|
||||
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
|
||||
|
||||
proto.branchList.forEach {
|
||||
branches.add(deserializeStatement(it) as IrBranch)
|
||||
}
|
||||
|
||||
// TODO: provide some origin!
|
||||
return IrWhenImpl(start, end, type, origin, branches)
|
||||
}
|
||||
|
||||
private fun deserializeLoop(proto: ProtoLoop, loop: IrLoop): IrLoop {
|
||||
val label = if (proto.hasLabel()) fileReader.deserializeString(proto.label) else null
|
||||
val body = if (proto.hasBody()) deserializeExpression(proto.body) else null
|
||||
val condition = deserializeExpression(proto.condition)
|
||||
|
||||
loop.label = label
|
||||
loop.condition = condition
|
||||
loop.body = body
|
||||
|
||||
return loop
|
||||
}
|
||||
|
||||
// we create the loop before deserializing the body, so that
|
||||
// IrBreak statements have something to put into 'loop' field.
|
||||
private fun deserializeDoWhile(proto: ProtoDoWhile, start: Int, end: Int, type: IrType) =
|
||||
deserializeLoop(
|
||||
proto.loop,
|
||||
deserializeLoopHeader(proto.loop.loopId) {
|
||||
val origin = if (proto.loop.hasOriginName()) deserializeIrStatementOrigin(proto.loop.originName) else null
|
||||
IrDoWhileLoopImpl(start, end, type, origin)
|
||||
}
|
||||
)
|
||||
|
||||
private fun deserializeWhile(proto: ProtoWhile, start: Int, end: Int, type: IrType) =
|
||||
deserializeLoop(
|
||||
proto.loop,
|
||||
deserializeLoopHeader(proto.loop.loopId) {
|
||||
val origin = if (proto.loop.hasOriginName()) deserializeIrStatementOrigin(proto.loop.originName) else null
|
||||
IrWhileLoopImpl(start, end, type, origin)
|
||||
}
|
||||
)
|
||||
|
||||
private fun deserializeDynamicMemberExpression(
|
||||
proto: ProtoDynamicMemberExpression,
|
||||
start: Int,
|
||||
end: Int,
|
||||
type: IrType
|
||||
) =
|
||||
IrDynamicMemberExpressionImpl(
|
||||
start,
|
||||
end,
|
||||
type,
|
||||
fileReader.deserializeString(proto.memberName),
|
||||
deserializeExpression(proto.receiver)
|
||||
)
|
||||
|
||||
private fun deserializeDynamicOperatorExpression(
|
||||
proto: ProtoDynamicOperatorExpression,
|
||||
start: Int,
|
||||
end: Int,
|
||||
type: IrType
|
||||
) =
|
||||
IrDynamicOperatorExpressionImpl(start, end, type, deserializeDynamicOperator(proto.operator)).apply {
|
||||
receiver = deserializeExpression(proto.receiver)
|
||||
proto.argumentList.mapTo(arguments) { deserializeExpression(it) }
|
||||
}
|
||||
|
||||
private fun deserializeDynamicOperator(operator: ProtoDynamicOperatorExpression.IrDynamicOperator) =
|
||||
when (operator) {
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.UNARY_PLUS -> IrDynamicOperator.UNARY_PLUS
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.UNARY_MINUS -> IrDynamicOperator.UNARY_MINUS
|
||||
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.EXCL -> IrDynamicOperator.EXCL
|
||||
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.PREFIX_INCREMENT -> IrDynamicOperator.PREFIX_INCREMENT
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.PREFIX_DECREMENT -> IrDynamicOperator.PREFIX_DECREMENT
|
||||
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.POSTFIX_INCREMENT -> IrDynamicOperator.POSTFIX_INCREMENT
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.POSTFIX_DECREMENT -> IrDynamicOperator.POSTFIX_DECREMENT
|
||||
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.BINARY_PLUS -> IrDynamicOperator.BINARY_PLUS
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.BINARY_MINUS -> IrDynamicOperator.BINARY_MINUS
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.MUL -> IrDynamicOperator.MUL
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.DIV -> IrDynamicOperator.DIV
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.MOD -> IrDynamicOperator.MOD
|
||||
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.GT -> IrDynamicOperator.GT
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.LT -> IrDynamicOperator.LT
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.GE -> IrDynamicOperator.GE
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.LE -> IrDynamicOperator.LE
|
||||
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.EQEQ -> IrDynamicOperator.EQEQ
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.EXCLEQ -> IrDynamicOperator.EXCLEQ
|
||||
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.EQEQEQ -> IrDynamicOperator.EQEQEQ
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.EXCLEQEQ -> IrDynamicOperator.EXCLEQEQ
|
||||
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.ANDAND -> IrDynamicOperator.ANDAND
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.OROR -> IrDynamicOperator.OROR
|
||||
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.EQ -> IrDynamicOperator.EQ
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.PLUSEQ -> IrDynamicOperator.PLUSEQ
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.MINUSEQ -> IrDynamicOperator.MINUSEQ
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.MULEQ -> IrDynamicOperator.MULEQ
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.DIVEQ -> IrDynamicOperator.DIVEQ
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.MODEQ -> IrDynamicOperator.MODEQ
|
||||
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.ARRAY_ACCESS -> IrDynamicOperator.ARRAY_ACCESS
|
||||
|
||||
ProtoDynamicOperatorExpression.IrDynamicOperator.INVOKE -> IrDynamicOperator.INVOKE
|
||||
}
|
||||
|
||||
private fun deserializeBreak(proto: ProtoBreak, start: Int, end: Int, type: IrType): IrBreak {
|
||||
val label = if (proto.hasLabel()) fileReader.deserializeString(proto.label) else null
|
||||
val loopId = proto.loopId
|
||||
val loop = deserializeLoopHeader(loopId) { error("break clause before loop header") }
|
||||
val irBreak = IrBreakImpl(start, end, type, loop)
|
||||
irBreak.label = label
|
||||
|
||||
return irBreak
|
||||
}
|
||||
|
||||
private fun deserializeContinue(proto: ProtoContinue, start: Int, end: Int, type: IrType): IrContinue {
|
||||
val label = if (proto.hasLabel()) fileReader.deserializeString(proto.label) else null
|
||||
val loopId = proto.loopId
|
||||
val loop = deserializeLoopHeader(loopId) { error("continue clause before loop header") }
|
||||
val irContinue = IrContinueImpl(start, end, type, loop)
|
||||
irContinue.label = label
|
||||
|
||||
return irContinue
|
||||
}
|
||||
|
||||
private fun deserializeConst(proto: ProtoConst, start: Int, end: Int, type: IrType): IrExpression =
|
||||
when (proto.valueCase!!) {
|
||||
NULL
|
||||
-> IrConstImpl.constNull(start, end, type)
|
||||
BOOLEAN
|
||||
-> IrConstImpl.boolean(start, end, type, proto.boolean)
|
||||
BYTE
|
||||
-> IrConstImpl.byte(start, end, type, proto.byte.toByte())
|
||||
CHAR
|
||||
-> IrConstImpl.char(start, end, type, proto.char.toChar())
|
||||
SHORT
|
||||
-> IrConstImpl.short(start, end, type, proto.short.toShort())
|
||||
INT
|
||||
-> IrConstImpl.int(start, end, type, proto.int)
|
||||
LONG
|
||||
-> IrConstImpl.long(start, end, type, proto.long)
|
||||
STRING
|
||||
-> IrConstImpl.string(start, end, type, fileReader.deserializeString(proto.string))
|
||||
FLOAT_BITS
|
||||
-> IrConstImpl.float(start, end, type, Float.fromBits(proto.floatBits))
|
||||
DOUBLE_BITS
|
||||
-> IrConstImpl.double(start, end, type, Double.fromBits(proto.doubleBits))
|
||||
VALUE_NOT_SET
|
||||
-> error("Const deserialization error: ${proto.valueCase} ")
|
||||
}
|
||||
|
||||
private fun deserializeOperation(proto: ProtoOperation, start: Int, end: Int, type: IrType): IrExpression =
|
||||
when (proto.operationCase!!) {
|
||||
BLOCK -> deserializeBlock(proto.block, start, end, type)
|
||||
BREAK -> deserializeBreak(proto.`break`, start, end, type)
|
||||
CLASS_REFERENCE -> deserializeClassReference(proto.classReference, start, end, type)
|
||||
CALL -> deserializeCall(proto.call, start, end, type)
|
||||
COMPOSITE -> deserializeComposite(proto.composite, start, end, type)
|
||||
CONST -> deserializeConst(proto.const, start, end, type)
|
||||
CONTINUE -> deserializeContinue(proto.`continue`, start, end, type)
|
||||
DELEGATING_CONSTRUCTOR_CALL -> deserializeDelegatingConstructorCall(proto.delegatingConstructorCall, start, end)
|
||||
DO_WHILE -> deserializeDoWhile(proto.doWhile, start, end, type)
|
||||
ENUM_CONSTRUCTOR_CALL -> deserializeEnumConstructorCall(proto.enumConstructorCall, start, end)
|
||||
FUNCTION_REFERENCE -> deserializeFunctionReference(proto.functionReference, start, end, type)
|
||||
GET_ENUM_VALUE -> deserializeGetEnumValue(proto.getEnumValue, start, end, type)
|
||||
GET_CLASS -> deserializeGetClass(proto.getClass, start, end, type)
|
||||
GET_FIELD -> deserializeGetField(proto.getField, start, end, type)
|
||||
GET_OBJECT -> deserializeGetObject(proto.getObject, start, end, type)
|
||||
GET_VALUE -> deserializeGetValue(proto.getValue, start, end, type)
|
||||
LOCAL_DELEGATED_PROPERTY_REFERENCE -> deserializeIrLocalDelegatedPropertyReference(
|
||||
proto.localDelegatedPropertyReference,
|
||||
start,
|
||||
end,
|
||||
type
|
||||
)
|
||||
INSTANCE_INITIALIZER_CALL -> deserializeInstanceInitializerCall(proto.instanceInitializerCall, start, end)
|
||||
PROPERTY_REFERENCE -> deserializePropertyReference(proto.propertyReference, start, end, type)
|
||||
RETURN -> deserializeReturn(proto.`return`, start, end)
|
||||
SET_FIELD -> deserializeSetField(proto.setField, start, end)
|
||||
SET_VALUE -> deserializeSetValue(proto.setValue, start, end)
|
||||
STRING_CONCAT -> deserializeStringConcat(proto.stringConcat, start, end, type)
|
||||
THROW -> deserializeThrow(proto.`throw`, start, end)
|
||||
TRY -> deserializeTry(proto.`try`, start, end, type)
|
||||
TYPE_OP -> deserializeTypeOp(proto.typeOp, start, end, type)
|
||||
VARARG -> deserializeVararg(proto.vararg, start, end, type)
|
||||
WHEN -> deserializeWhen(proto.`when`, start, end, type)
|
||||
WHILE -> deserializeWhile(proto.`while`, start, end, type)
|
||||
DYNAMIC_MEMBER -> deserializeDynamicMemberExpression(proto.dynamicMember, start, end, type)
|
||||
DYNAMIC_OPERATOR -> deserializeDynamicOperatorExpression(proto.dynamicOperator, start, end, type)
|
||||
CONSTRUCTOR_CALL -> deserializeConstructorCall(proto.constructorCall, start, end, type)
|
||||
FUNCTION_EXPRESSION -> deserializeFunctionExpression(proto.functionExpression, start, end, type)
|
||||
ERROR_EXPRESSION -> deserializeErrorExpression(proto.errorExpression, start, end, type)
|
||||
ERROR_CALL_EXPRESSION -> deserializeErrorCallExpression(proto.errorCallExpression, start, end, type)
|
||||
OPERATION_NOT_SET -> error("Expression deserialization not implemented: ${proto.operationCase}")
|
||||
}
|
||||
|
||||
fun deserializeExpression(proto: ProtoExpression): IrExpression {
|
||||
val coordinates = BinaryCoordinates.decode(proto.coordinates)
|
||||
val start = coordinates.startOffset
|
||||
val end = coordinates.endOffset
|
||||
val type = declarationDeserializer.deserializeIrType(proto.type)
|
||||
val operation = proto.operation
|
||||
val expression = deserializeOperation(operation, start, end, type)
|
||||
|
||||
return expression
|
||||
}
|
||||
|
||||
fun deserializeIrStatementOrigin(protoName: Int): IrStatementOrigin {
|
||||
return fileReader.deserializeString(protoName).let {
|
||||
val componentPrefix = "COMPONENT_"
|
||||
when {
|
||||
it.startsWith(componentPrefix) -> {
|
||||
IrStatementOrigin.COMPONENT_N.withIndex(it.removePrefix(componentPrefix).toInt())
|
||||
}
|
||||
else -> statementOriginIndex[it] ?: error("Unexpected statement origin: $it")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val allKnownStatementOrigins = IrStatementOrigin::class.nestedClasses.toList()
|
||||
|
||||
private val statementOriginIndex =
|
||||
allKnownStatementOrigins.mapNotNull { it.objectInstance as? IrStatementOriginImpl }.associateBy { it.debugName }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,695 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.serialization
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.lower.InnerClassesSupport
|
||||
import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder
|
||||
import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideClassFilter
|
||||
import org.jetbrains.kotlin.backend.common.serialization.encodings.*
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclaration.DeclaratorCase.*
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrType.KindCase.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.protobuf.CodedInputStream
|
||||
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrAnonymousInit as ProtoAnonymousInit
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrClass as ProtoClass
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrConstructor as ProtoConstructor
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrConstructorCall as ProtoConstructorCall
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclaration as ProtoDeclaration
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclarationBase as ProtoDeclarationBase
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDynamicType as ProtoDynamicType
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrEnumEntry as ProtoEnumEntry
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrErrorType as ProtoErrorType
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrField as ProtoField
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFunction as ProtoFunction
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFunctionBase as ProtoFunctionBase
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrErrorDeclaration as ProtoErrorDeclaration
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrExpression as ProtoExpression
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrStatement as ProtoStatement
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrLocalDelegatedProperty as ProtoLocalDelegatedProperty
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrProperty as ProtoProperty
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSimpleType as ProtoSimpleType
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrType as ProtoType
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrTypeAbbreviation as ProtoTypeAbbreviation
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrTypeAlias as ProtoTypeAlias
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrTypeParameter as ProtoTypeParameter
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrValueParameter as ProtoValueParameter
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrVariable as ProtoVariable
|
||||
|
||||
|
||||
class IrDeclarationDeserializer(
|
||||
builtIns: IrBuiltIns,
|
||||
private val symbolTable: SymbolTable,
|
||||
private val irFactory: IrFactory,
|
||||
private val fileReader: IrLibraryFile,
|
||||
file: IrFile,
|
||||
private val allowErrorNodes: Boolean,
|
||||
private val deserializeInlineFunctions: Boolean,
|
||||
private var deserializeBodies: Boolean,
|
||||
private val symbolDeserializer: IrSymbolDeserializer,
|
||||
private val platformFakeOverrideClassFilter: FakeOverrideClassFilter,
|
||||
private val fakeOverrideBuilder: FakeOverrideBuilder,
|
||||
) {
|
||||
|
||||
private val bodyDeserializer = IrBodyDeserializer(builtIns, allowErrorNodes, irFactory, fileReader, this)
|
||||
|
||||
private fun deserializeName(index: Int): Name {
|
||||
val name = fileReader.deserializeString(index)
|
||||
return Name.guessByFirstCharacter(name)
|
||||
}
|
||||
|
||||
private val irTypeCache = mutableMapOf<Int, IrType>()
|
||||
|
||||
private fun readType(index: Int): CodedInputStream =
|
||||
fileReader.type(index).codedInputStream
|
||||
|
||||
private fun loadTypeProto(index: Int): ProtoType {
|
||||
return ProtoType.parseFrom(readType(index), ExtensionRegistryLite.newInstance())
|
||||
}
|
||||
|
||||
internal fun deserializeIrType(index: Int): IrType {
|
||||
return irTypeCache.getOrPut(index) {
|
||||
val typeData = loadTypeProto(index)
|
||||
deserializeIrTypeData(typeData)
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeIrTypeArgument(proto: Long): IrTypeArgument {
|
||||
val encoding = BinaryTypeProjection.decode(proto)
|
||||
|
||||
if (encoding.isStarProjection) return IrStarProjectionImpl
|
||||
|
||||
return makeTypeProjection(deserializeIrType(encoding.typeIndex), encoding.variance)
|
||||
}
|
||||
|
||||
internal fun deserializeAnnotations(annotations: List<ProtoConstructorCall>): List<IrConstructorCall> {
|
||||
return annotations.map {
|
||||
bodyDeserializer.deserializeAnnotation(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeSimpleType(proto: ProtoSimpleType): IrSimpleType {
|
||||
val symbol = deserializeIrSymbolAndRemap(proto.classifier) as? IrClassifierSymbol
|
||||
?: error("could not convert sym to ClassifierSymbol")
|
||||
|
||||
val arguments = proto.argumentList.map { deserializeIrTypeArgument(it) }
|
||||
val annotations = deserializeAnnotations(proto.annotationList)
|
||||
|
||||
val result: IrSimpleType = IrSimpleTypeImpl(
|
||||
null,
|
||||
symbol,
|
||||
proto.hasQuestionMark,
|
||||
arguments,
|
||||
annotations,
|
||||
if (proto.hasAbbreviation()) deserializeTypeAbbreviation(proto.abbreviation) else null
|
||||
)
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
private fun deserializeTypeAbbreviation(proto: ProtoTypeAbbreviation): IrTypeAbbreviation =
|
||||
IrTypeAbbreviationImpl(
|
||||
deserializeIrSymbolAndRemap(proto.typeAlias).let {
|
||||
it as? IrTypeAliasSymbol
|
||||
?: error("IrTypeAliasSymbol expected: $it")
|
||||
},
|
||||
proto.hasQuestionMark,
|
||||
proto.argumentList.map { deserializeIrTypeArgument(it) },
|
||||
deserializeAnnotations(proto.annotationList)
|
||||
)
|
||||
|
||||
private fun deserializeDynamicType(proto: ProtoDynamicType): IrDynamicType {
|
||||
val annotations = deserializeAnnotations(proto.annotationList)
|
||||
return IrDynamicTypeImpl(null, annotations, Variance.INVARIANT)
|
||||
}
|
||||
|
||||
private fun deserializeErrorType(proto: ProtoErrorType): IrErrorType {
|
||||
require(allowErrorNodes) { "IrErrorType found but error code is not allowed" }
|
||||
val annotations = deserializeAnnotations(proto.annotationList)
|
||||
return IrErrorTypeImpl(null, annotations, Variance.INVARIANT)
|
||||
}
|
||||
|
||||
private fun deserializeIrTypeData(proto: ProtoType): IrType {
|
||||
return when (proto.kindCase) {
|
||||
SIMPLE -> deserializeSimpleType(proto.simple)
|
||||
DYNAMIC -> deserializeDynamicType(proto.dynamic)
|
||||
ERROR -> deserializeErrorType(proto.error)
|
||||
else -> error("Unexpected IrType kind: ${proto.kindCase}")
|
||||
}
|
||||
}
|
||||
|
||||
private var currentParent: IrDeclarationParent = file
|
||||
|
||||
private inline fun <T : IrDeclarationParent> T.usingParent(block: T.() -> Unit): T =
|
||||
this.apply {
|
||||
val oldParent = currentParent
|
||||
currentParent = this
|
||||
try {
|
||||
block(this)
|
||||
} finally {
|
||||
currentParent = oldParent
|
||||
}
|
||||
}
|
||||
|
||||
// Delegating symbol maps to it's delegate only inside the declaration the symbol belongs to.
|
||||
private val delegatedSymbolMap = mutableMapOf<IrSymbol, IrSymbol>()
|
||||
|
||||
internal fun deserializeIrSymbolAndRemap(code: Long): IrSymbol {
|
||||
// TODO: could be simplified
|
||||
return symbolDeserializer.deserializeIrSymbol(code).let {
|
||||
delegatedSymbolMap[it] ?: it
|
||||
}
|
||||
}
|
||||
|
||||
private fun recordDelegatedSymbol(symbol: IrSymbol) {
|
||||
if (symbol is IrDelegatingSymbol<*, *, *>) {
|
||||
delegatedSymbolMap[symbol] = symbol.delegate
|
||||
}
|
||||
}
|
||||
|
||||
private fun eraseDelegatedSymbol(symbol: IrSymbol) {
|
||||
if (symbol is IrDelegatingSymbol<*, *, *>) {
|
||||
delegatedSymbolMap.remove(symbol)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T> withDeserializedIrDeclarationBase(
|
||||
proto: ProtoDeclarationBase,
|
||||
block: (IrSymbol, IdSignature, Int, Int, IrDeclarationOrigin, Long) -> T
|
||||
): T where T : IrDeclaration, T : IrSymbolOwner {
|
||||
val (s, uid) = symbolDeserializer.deserializeIrSymbolToDeclare(proto.symbol)
|
||||
val coordinates = BinaryCoordinates.decode(proto.coordinates)
|
||||
try {
|
||||
recordDelegatedSymbol(s)
|
||||
val result = block(
|
||||
s,
|
||||
uid,
|
||||
coordinates.startOffset, coordinates.endOffset,
|
||||
deserializeIrDeclarationOrigin(proto.originName), proto.flags
|
||||
)
|
||||
result.annotations += deserializeAnnotations(proto.annotationList)
|
||||
result.parent = currentParent
|
||||
return result
|
||||
} finally {
|
||||
eraseDelegatedSymbol(s)
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeIrTypeParameter(proto: ProtoTypeParameter, index: Int, isGlobal: Boolean): IrTypeParameter {
|
||||
val name = deserializeName(proto.name)
|
||||
val coordinates = BinaryCoordinates.decode(proto.base.coordinates)
|
||||
val flags = TypeParameterFlags.decode(proto.base.flags)
|
||||
|
||||
val factory = { symbol: IrTypeParameterSymbol ->
|
||||
irFactory.createTypeParameter(
|
||||
coordinates.startOffset,
|
||||
coordinates.endOffset,
|
||||
deserializeIrDeclarationOrigin(proto.base.originName),
|
||||
symbol,
|
||||
name,
|
||||
index,
|
||||
flags.isReified,
|
||||
flags.variance
|
||||
)
|
||||
}
|
||||
|
||||
val sig: IdSignature
|
||||
val result = symbolTable.run {
|
||||
if (isGlobal) {
|
||||
val p = symbolDeserializer.deserializeIrSymbolToDeclare(proto.base.symbol)
|
||||
val symbol = p.first as IrTypeParameterSymbol
|
||||
sig = p.second
|
||||
declareGlobalTypeParameter(sig, { symbol }, factory)
|
||||
} else {
|
||||
val symbolData = BinarySymbolData
|
||||
.decode(proto.base.symbol)
|
||||
sig = symbolDeserializer.deserializeIdSignature(symbolData.signatureId)
|
||||
declareScopedTypeParameter(sig, { IrTypeParameterSymbolImpl() }, factory)
|
||||
}
|
||||
}
|
||||
|
||||
// make sure this symbol is known to linker
|
||||
symbolDeserializer.referenceLocalIrSymbol(result.symbol, sig)
|
||||
result.annotations += deserializeAnnotations(proto.base.annotationList)
|
||||
result.parent = currentParent
|
||||
return result
|
||||
}
|
||||
|
||||
private fun deserializeIrValueParameter(proto: ProtoValueParameter, index: Int): IrValueParameter =
|
||||
withDeserializedIrDeclarationBase(proto.base) { symbol, _, startOffset, endOffset, origin, fcode ->
|
||||
val flags = ValueParameterFlags.decode(fcode)
|
||||
val nameAndType = BinaryNameAndType.decode(proto.nameType)
|
||||
irFactory.createValueParameter(
|
||||
startOffset, endOffset, origin,
|
||||
symbol as IrValueParameterSymbol,
|
||||
deserializeName(nameAndType.nameIndex),
|
||||
index,
|
||||
deserializeIrType(nameAndType.typeIndex),
|
||||
if (proto.hasVarargElementType()) deserializeIrType(proto.varargElementType) else null,
|
||||
flags.isCrossInline,
|
||||
flags.isNoInline,
|
||||
flags.isHidden,
|
||||
flags.isAssignable
|
||||
).apply {
|
||||
if (proto.hasDefaultValue())
|
||||
defaultValue = deserializeExpressionBody(proto.defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeIrClass(proto: ProtoClass): IrClass =
|
||||
withDeserializedIrDeclarationBase(proto.base) { symbol, signature, startOffset, endOffset, origin, fcode ->
|
||||
val flags = ClassFlags.decode(fcode)
|
||||
|
||||
symbolTable.declareClass(signature, { symbol as IrClassSymbol }) {
|
||||
irFactory.createClass(
|
||||
startOffset, endOffset, origin,
|
||||
it,
|
||||
deserializeName(proto.name),
|
||||
flags.kind,
|
||||
flags.visibility,
|
||||
flags.modality,
|
||||
flags.isCompanion,
|
||||
flags.isInner,
|
||||
flags.isData,
|
||||
flags.isExternal,
|
||||
flags.isInline,
|
||||
flags.isExpect,
|
||||
flags.isFun,
|
||||
)
|
||||
}.usingParent {
|
||||
typeParameters = deserializeTypeParameters(proto.typeParameterList, true)
|
||||
|
||||
superTypes = proto.superTypeList.map { deserializeIrType(it) }
|
||||
|
||||
proto.declarationList
|
||||
.filterNot { isSkippableFakeOverride(it, this) }
|
||||
.mapTo(declarations) { deserializeDeclaration(it) }
|
||||
|
||||
thisReceiver = deserializeIrValueParameter(proto.thisReceiver, -1)
|
||||
|
||||
fakeOverrideBuilder.enqueueClass(this, signature)
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeIrTypeAlias(proto: ProtoTypeAlias): IrTypeAlias =
|
||||
withDeserializedIrDeclarationBase(proto.base) { symbol, uniqId, startOffset, endOffset, origin, fcode ->
|
||||
require(symbol is IrTypeAliasSymbol)
|
||||
symbolTable.declareTypeAlias(uniqId, { symbol }) {
|
||||
val flags = TypeAliasFlags.decode(fcode)
|
||||
val nameType = BinaryNameAndType.decode(proto.nameType)
|
||||
irFactory.createTypeAlias(
|
||||
startOffset, endOffset,
|
||||
it,
|
||||
deserializeName(nameType.nameIndex),
|
||||
flags.visibility,
|
||||
deserializeIrType(nameType.typeIndex),
|
||||
flags.isActual,
|
||||
origin
|
||||
)
|
||||
}.usingParent {
|
||||
typeParameters = deserializeTypeParameters(proto.typeParameterList, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeErrorDeclaration(proto: ProtoErrorDeclaration): IrErrorDeclaration {
|
||||
require(allowErrorNodes) { "IrErrorDeclaration found but error code is not allowed" }
|
||||
val coordinates = BinaryCoordinates.decode(proto.coordinates)
|
||||
return irFactory.createErrorDeclaration(coordinates.startOffset, coordinates.endOffset).also {
|
||||
it.parent = currentParent
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeTypeParameters(protos: List<ProtoTypeParameter>, isGlobal: Boolean): List<IrTypeParameter> {
|
||||
// NOTE: fun <C : MutableCollection<in T>, T : Any> Array<out T?>.filterNotNullTo(destination: C): C
|
||||
val result = ArrayList<IrTypeParameter>(protos.size)
|
||||
for (index in protos.indices) {
|
||||
val proto = protos[index]
|
||||
result.add(deserializeIrTypeParameter(proto, index, isGlobal))
|
||||
}
|
||||
|
||||
for (i in protos.indices) {
|
||||
result[i].superTypes = protos[i].superTypeList.map { deserializeIrType(it) }
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun deserializeValueParameters(protos: List<ProtoValueParameter>): List<IrValueParameter> {
|
||||
val result = ArrayList<IrValueParameter>(protos.size)
|
||||
|
||||
for (i in protos.indices) {
|
||||
result.add(deserializeIrValueParameter(protos[i], i))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* In `declarations-only` mode in case of private property/function with inferred anonymous private type like this
|
||||
* class C {
|
||||
* private val p = object {
|
||||
* fun foo() = 42
|
||||
* }
|
||||
*
|
||||
* private fun f() = object {
|
||||
* fun bar() = "42"
|
||||
* }
|
||||
*
|
||||
* private val pp = p.foo()
|
||||
* private fun ff() = f().bar()
|
||||
* }
|
||||
* object's classifier is leaked outside p/f scopes and accessible on C's level so
|
||||
* if their initializer/body weren't read we have unbound `foo/bar` symbol and unbound `object` symbols.
|
||||
* To fix this make sure that such declaration forced to be deserialized completely.
|
||||
*
|
||||
* For more information see `anonymousClassLeak.kt` test and issue KT-40216
|
||||
*/
|
||||
private fun IrType.checkObjectLeak(): Boolean {
|
||||
return if (this is IrSimpleType) {
|
||||
classifier.let { !it.isPublicApi && it !is IrTypeParameterSymbol } || arguments.any { it.typeOrNull?.checkObjectLeak() == true }
|
||||
} else false
|
||||
}
|
||||
|
||||
private fun <T : IrFunction> T.withBodyGuard(block: T.() -> Unit) {
|
||||
val oldBodiesPolicy = deserializeBodies
|
||||
|
||||
fun checkInlineBody(): Boolean = deserializeInlineFunctions && this is IrSimpleFunction && isInline
|
||||
|
||||
try {
|
||||
deserializeBodies = oldBodiesPolicy || checkInlineBody() || returnType.checkObjectLeak()
|
||||
block()
|
||||
} finally {
|
||||
deserializeBodies = oldBodiesPolicy
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun IrField.withInitializerGuard(f: IrField.() -> Unit) {
|
||||
val oldBodiesPolicy = deserializeBodies
|
||||
|
||||
try {
|
||||
deserializeBodies = oldBodiesPolicy || type.checkObjectLeak()
|
||||
f()
|
||||
} finally {
|
||||
deserializeBodies = oldBodiesPolicy
|
||||
}
|
||||
}
|
||||
|
||||
private fun readBody(index: Int): CodedInputStream =
|
||||
fileReader.body(index).codedInputStream
|
||||
|
||||
private fun loadStatementBodyProto(index: Int): ProtoStatement {
|
||||
return ProtoStatement.parseFrom(readBody(index), ExtensionRegistryLite.newInstance())
|
||||
}
|
||||
|
||||
private fun loadExpressionBodyProto(index: Int): ProtoExpression {
|
||||
return ProtoExpression.parseFrom(readBody(index), ExtensionRegistryLite.newInstance())
|
||||
}
|
||||
|
||||
private fun deserializeExpressionBody(index: Int): IrExpressionBody {
|
||||
return irFactory.createExpressionBody(
|
||||
if (deserializeBodies) {
|
||||
val bodyData = loadExpressionBodyProto(index)
|
||||
bodyDeserializer.deserializeExpression(bodyData)
|
||||
} else {
|
||||
val errorType = IrErrorTypeImpl(null, emptyList(), Variance.INVARIANT)
|
||||
IrErrorExpressionImpl(-1, -1, errorType, "Expression body is not deserialized yet")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun deserializeStatementBody(index: Int): IrElement {
|
||||
return if (deserializeBodies) {
|
||||
val bodyData = loadStatementBodyProto(index)
|
||||
bodyDeserializer.deserializeStatement(bodyData)
|
||||
} else {
|
||||
val errorType = IrErrorTypeImpl(null, emptyList(), Variance.INVARIANT)
|
||||
irFactory.createBlockBody(
|
||||
-1, -1, listOf(IrErrorExpressionImpl(-1, -1, errorType, "Statement body is not deserialized yet"))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T : IrFunction> withDeserializedIrFunctionBase(
|
||||
proto: ProtoFunctionBase,
|
||||
block: (IrFunctionSymbol, IdSignature, Int, Int, IrDeclarationOrigin, Long) -> T
|
||||
): T = withDeserializedIrDeclarationBase(proto.base) { symbol, idSig, startOffset, endOffset, origin, fcode ->
|
||||
symbolTable.withScope(symbol) {
|
||||
block(symbol as IrFunctionSymbol, idSig, startOffset, endOffset, origin, fcode).usingParent {
|
||||
typeParameters = deserializeTypeParameters(proto.typeParameterList, false)
|
||||
val nameType = BinaryNameAndType.decode(proto.nameType)
|
||||
returnType = deserializeIrType(nameType.typeIndex)
|
||||
|
||||
withBodyGuard {
|
||||
valueParameters = deserializeValueParameters(proto.valueParameterList)
|
||||
if (proto.hasDispatchReceiver())
|
||||
dispatchReceiverParameter = deserializeIrValueParameter(proto.dispatchReceiver, -1)
|
||||
if (proto.hasExtensionReceiver())
|
||||
extensionReceiverParameter = deserializeIrValueParameter(proto.extensionReceiver, -1)
|
||||
if (proto.hasBody()) {
|
||||
body = deserializeStatementBody(proto.body) as IrBody
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun deserializeIrFunction(proto: ProtoFunction): IrSimpleFunction {
|
||||
return withDeserializedIrFunctionBase(proto.base) { symbol, idSig, startOffset, endOffset, origin, fcode ->
|
||||
val flags = FunctionFlags.decode(fcode)
|
||||
symbolTable.declareSimpleFunction(idSig, { symbol as IrSimpleFunctionSymbol }) {
|
||||
val nameType = BinaryNameAndType.decode(proto.base.nameType)
|
||||
irFactory.createFunction(
|
||||
startOffset, endOffset, origin,
|
||||
it,
|
||||
deserializeName(nameType.nameIndex),
|
||||
flags.visibility,
|
||||
flags.modality,
|
||||
IrUninitializedType,
|
||||
flags.isInline,
|
||||
flags.isExternal,
|
||||
flags.isTailrec,
|
||||
flags.isSuspend,
|
||||
flags.isOperator,
|
||||
flags.isInfix,
|
||||
flags.isExpect,
|
||||
flags.isFakeOverride
|
||||
)
|
||||
}.apply {
|
||||
overriddenSymbols = proto.overriddenList.map { deserializeIrSymbolAndRemap(it) as IrSimpleFunctionSymbol }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun deserializeIrVariable(proto: ProtoVariable): IrVariable =
|
||||
withDeserializedIrDeclarationBase(proto.base) { symbol, _, startOffset, endOffset, origin, fcode ->
|
||||
val flags = LocalVariableFlags.decode(fcode)
|
||||
val nameType = BinaryNameAndType.decode(proto.nameType)
|
||||
IrVariableImpl(
|
||||
startOffset, endOffset, origin,
|
||||
symbol as IrVariableSymbol,
|
||||
deserializeName(nameType.nameIndex),
|
||||
deserializeIrType(nameType.typeIndex),
|
||||
flags.isVar,
|
||||
flags.isConst,
|
||||
flags.isLateinit
|
||||
).apply {
|
||||
if (proto.hasInitializer())
|
||||
initializer = bodyDeserializer.deserializeExpression(proto.initializer)
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeIrEnumEntry(proto: ProtoEnumEntry): IrEnumEntry =
|
||||
withDeserializedIrDeclarationBase(proto.base) { symbol, uniqId, startOffset, endOffset, origin, _ ->
|
||||
symbolTable.declareEnumEntry(uniqId, { symbol as IrEnumEntrySymbol }) {
|
||||
irFactory.createEnumEntry(startOffset, endOffset, origin, it, deserializeName(proto.name))
|
||||
}.apply {
|
||||
if (proto.hasCorrespondingClass())
|
||||
correspondingClass = deserializeIrClass(proto.correspondingClass)
|
||||
if (proto.hasInitializer())
|
||||
initializerExpression = deserializeExpressionBody(proto.initializer)
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeIrAnonymousInit(proto: ProtoAnonymousInit): IrAnonymousInitializer =
|
||||
withDeserializedIrDeclarationBase(proto.base) { symbol, _, startOffset, endOffset, origin, _ ->
|
||||
irFactory.createAnonymousInitializer(startOffset, endOffset, origin, symbol as IrAnonymousInitializerSymbol).apply {
|
||||
body = deserializeStatementBody(proto.body) as IrBlockBody
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeIrConstructor(proto: ProtoConstructor): IrConstructor =
|
||||
withDeserializedIrFunctionBase(proto.base) { symbol, idSig, startOffset, endOffset, origin, fcode ->
|
||||
require(symbol is IrConstructorSymbol)
|
||||
val flags = FunctionFlags.decode(fcode)
|
||||
val nameType = BinaryNameAndType.decode(proto.base.nameType)
|
||||
symbolTable.declareConstructor(idSig, { symbol }) {
|
||||
irFactory.createConstructor(
|
||||
startOffset, endOffset, origin,
|
||||
it,
|
||||
deserializeName(nameType.nameIndex),
|
||||
flags.visibility,
|
||||
IrUninitializedType,
|
||||
flags.isInline,
|
||||
flags.isExternal,
|
||||
flags.isPrimary,
|
||||
flags.isExpect
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun deserializeIrField(proto: ProtoField): IrField =
|
||||
withDeserializedIrDeclarationBase(proto.base) { symbol, uniqId, startOffset, endOffset, origin, fcode ->
|
||||
require(symbol is IrFieldSymbol)
|
||||
val nameType = BinaryNameAndType.decode(proto.nameType)
|
||||
val type = deserializeIrType(nameType.typeIndex)
|
||||
val flags = FieldFlags.decode(fcode)
|
||||
symbolTable.declareField(uniqId, { symbol }) {
|
||||
irFactory.createField(
|
||||
startOffset, endOffset, origin,
|
||||
it,
|
||||
deserializeName(nameType.nameIndex),
|
||||
type,
|
||||
flags.visibility,
|
||||
flags.isFinal,
|
||||
flags.isExternal,
|
||||
flags.isStatic,
|
||||
)
|
||||
}.usingParent {
|
||||
if (proto.hasInitializer()) {
|
||||
withInitializerGuard {
|
||||
initializer = deserializeExpressionBody(proto.initializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeIrLocalDelegatedProperty(proto: ProtoLocalDelegatedProperty): IrLocalDelegatedProperty =
|
||||
withDeserializedIrDeclarationBase(proto.base) { symbol, _, startOffset, endOffset, origin, fcode ->
|
||||
val flags = LocalVariableFlags.decode(fcode)
|
||||
val nameAndType = BinaryNameAndType.decode(proto.nameType)
|
||||
irFactory.createLocalDelegatedProperty(
|
||||
startOffset, endOffset, origin,
|
||||
symbol as IrLocalDelegatedPropertySymbol,
|
||||
deserializeName(nameAndType.nameIndex),
|
||||
deserializeIrType(nameAndType.typeIndex),
|
||||
flags.isVar
|
||||
).apply {
|
||||
delegate = deserializeIrVariable(proto.delegate)
|
||||
getter = deserializeIrFunction(proto.getter)
|
||||
if (proto.hasSetter())
|
||||
setter = deserializeIrFunction(proto.setter)
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeIrProperty(proto: ProtoProperty): IrProperty =
|
||||
withDeserializedIrDeclarationBase(proto.base) { symbol, uniqId, startOffset, endOffset, origin, fcode ->
|
||||
require(symbol is IrPropertySymbol)
|
||||
val flags = PropertyFlags.decode(fcode)
|
||||
symbolTable.declareProperty(uniqId, { symbol }) {
|
||||
irFactory.createProperty(
|
||||
startOffset, endOffset, origin,
|
||||
it,
|
||||
deserializeName(proto.name),
|
||||
flags.visibility,
|
||||
flags.modality,
|
||||
flags.isVar,
|
||||
flags.isConst,
|
||||
flags.isLateinit,
|
||||
flags.isDelegated,
|
||||
flags.isExternal,
|
||||
flags.isExpect,
|
||||
flags.isFakeOverride
|
||||
)
|
||||
}.apply {
|
||||
if (proto.hasGetter()) {
|
||||
getter = deserializeIrFunction(proto.getter).also {
|
||||
it.correspondingPropertySymbol = symbol
|
||||
}
|
||||
}
|
||||
if (proto.hasSetter()) {
|
||||
setter = deserializeIrFunction(proto.setter).also {
|
||||
it.correspondingPropertySymbol = symbol
|
||||
}
|
||||
}
|
||||
if (proto.hasBackingField()) {
|
||||
backingField = deserializeIrField(proto.backingField).also {
|
||||
it.correspondingPropertySymbol = symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val allKnownDeclarationOrigins =
|
||||
IrDeclarationOrigin::class.nestedClasses.toList() + InnerClassesSupport.FIELD_FOR_OUTER_THIS::class
|
||||
private val declarationOriginIndex =
|
||||
allKnownDeclarationOrigins.map { it.objectInstance as IrDeclarationOriginImpl }.associateBy { it.name }
|
||||
}
|
||||
|
||||
private fun deserializeIrDeclarationOrigin(protoName: Int): IrDeclarationOriginImpl {
|
||||
val originName = fileReader.deserializeString(protoName)
|
||||
return declarationOriginIndex[originName] ?: object : IrDeclarationOriginImpl(originName) {}
|
||||
}
|
||||
|
||||
fun deserializeDeclaration(proto: ProtoDeclaration): IrDeclaration {
|
||||
val declaration: IrDeclaration = when (proto.declaratorCase!!) {
|
||||
IR_ANONYMOUS_INIT -> deserializeIrAnonymousInit(proto.irAnonymousInit)
|
||||
IR_CONSTRUCTOR -> deserializeIrConstructor(proto.irConstructor)
|
||||
IR_FIELD -> deserializeIrField(proto.irField)
|
||||
IR_CLASS -> deserializeIrClass(proto.irClass)
|
||||
IR_FUNCTION -> deserializeIrFunction(proto.irFunction)
|
||||
IR_PROPERTY -> deserializeIrProperty(proto.irProperty)
|
||||
IR_TYPE_PARAMETER -> error("Unreachable execution Type Parameter") // deserializeIrTypeParameter(proto.irTypeParameter)
|
||||
IR_VARIABLE -> deserializeIrVariable(proto.irVariable)
|
||||
IR_VALUE_PARAMETER -> error("Unreachable execution Value Parameter") // deserializeIrValueParameter(proto.irValueParameter)
|
||||
IR_ENUM_ENTRY -> deserializeIrEnumEntry(proto.irEnumEntry)
|
||||
IR_LOCAL_DELEGATED_PROPERTY -> deserializeIrLocalDelegatedProperty(proto.irLocalDelegatedProperty)
|
||||
IR_TYPE_ALIAS -> deserializeIrTypeAlias(proto.irTypeAlias)
|
||||
IR_ERROR_DECLARATION -> deserializeErrorDeclaration(proto.irErrorDeclaration)
|
||||
DECLARATOR_NOT_SET -> error("Declaration deserialization not implemented: ${proto.declaratorCase}")
|
||||
}
|
||||
|
||||
return declaration
|
||||
}
|
||||
|
||||
// Depending on deserialization strategy we either deserialize public api fake overrides
|
||||
// or reconstruct them after IR linker completes.
|
||||
private fun isSkippableFakeOverride(proto: ProtoDeclaration, parent: IrClass): Boolean {
|
||||
if (!platformFakeOverrideClassFilter.needToConstructFakeOverrides(parent)) return false
|
||||
|
||||
val symbol = when (proto.declaratorCase!!) {
|
||||
IR_FUNCTION -> symbolDeserializer.deserializeIrSymbol(proto.irFunction.base.base.symbol)
|
||||
IR_PROPERTY -> symbolDeserializer.deserializeIrSymbol(proto.irProperty.base.symbol)
|
||||
// Don't consider IR_FIELDS here.
|
||||
else -> return false
|
||||
}
|
||||
if (symbol !is IrPublicSymbolBase<*>) return false
|
||||
if (!symbol.signature.isPublic) return false
|
||||
|
||||
return when (proto.declaratorCase!!) {
|
||||
IR_FUNCTION -> FunctionFlags.decode(proto.irFunction.base.base.flags).isFakeOverride
|
||||
IR_PROPERTY -> PropertyFlags.decode(proto.irProperty.base.flags).isFakeOverride
|
||||
// Don't consider IR_FIELDS here.
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -55,8 +55,6 @@ abstract class IrModuleDeserializer(val moduleDescriptor: ModuleDescriptor) {
|
||||
|
||||
open fun addModuleReachableTopLevel(idSig: IdSignature) { error("Unsupported Operation (sig: $idSig") }
|
||||
|
||||
open fun deserializeReachableDeclarations() { error("Unsupported Operation") }
|
||||
|
||||
abstract val moduleFragment: IrModuleFragment
|
||||
|
||||
abstract val moduleDependencies: Collection<IrModuleDeserializer>
|
||||
@@ -103,10 +101,6 @@ class IrModuleDeserializerWithBuiltIns(
|
||||
override fun referencePropertyByLocalSignature(file: IrFile, idSignature: IdSignature): IrPropertySymbol =
|
||||
delegate.referencePropertyByLocalSignature(file, idSignature)
|
||||
|
||||
override fun deserializeReachableDeclarations() {
|
||||
delegate.deserializeReachableDeclarations()
|
||||
}
|
||||
|
||||
private fun computeFunctionDescriptor(className: String): FunctionClassDescriptor {
|
||||
val isK = className[0] == 'K'
|
||||
val isSuspend = (if (isK) className[1] else className[0]) == 'S'
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.serialization
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.serialization.encodings.*
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.Actual
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IdSignature.IdsigCase.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrLocalDelegatedPropertySymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.protobuf.CodedInputStream
|
||||
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.AccessorIdSignature as ProtoAccessorIdSignature
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.FileLocalIdSignature as ProtoFileLocalIdSignature
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IdSignature as ProtoIdSignature
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.PublicIdSignature as ProtoPublicIdSignature
|
||||
|
||||
class IrSymbolDeserializer(
|
||||
val symbolTable: ReferenceSymbolTable,
|
||||
val fileReader: IrLibraryFile,
|
||||
val actuals: List<Actual>,
|
||||
val enqueueLocalTopLevelDeclaration: (IdSignature) -> Unit,
|
||||
val handleExpectActualMapping: (IdSignature, IrSymbol) -> IrSymbol,
|
||||
val deserializePublicSymbol: (IdSignature, BinarySymbolData.SymbolKind) -> IrSymbol,
|
||||
) {
|
||||
|
||||
val deserializedSymbols = mutableMapOf<IdSignature, IrSymbol>()
|
||||
|
||||
fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
||||
return deserializedSymbols.getOrPut(idSig) {
|
||||
val symbol = referenceDeserializedSymbol(symbolKind, idSig)
|
||||
|
||||
handleExpectActualMapping(idSig, symbol)
|
||||
}
|
||||
}
|
||||
|
||||
private fun referenceDeserializedSymbol(symbolKind: BinarySymbolData.SymbolKind, idSig: IdSignature): IrSymbol = symbolTable.run {
|
||||
when (symbolKind) {
|
||||
BinarySymbolData.SymbolKind.ANONYMOUS_INIT_SYMBOL -> IrAnonymousInitializerSymbolImpl()
|
||||
BinarySymbolData.SymbolKind.CLASS_SYMBOL -> referenceClassFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.CONSTRUCTOR_SYMBOL -> referenceConstructorFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.TYPE_PARAMETER_SYMBOL -> referenceTypeParameterFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL -> referenceEnumEntryFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.STANDALONE_FIELD_SYMBOL -> referenceFieldFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.FIELD_SYMBOL -> referenceFieldFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.FUNCTION_SYMBOL -> referenceSimpleFunctionFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.TYPEALIAS_SYMBOL -> referenceTypeAliasFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.PROPERTY_SYMBOL -> referencePropertyFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.VARIABLE_SYMBOL -> IrVariableSymbolImpl()
|
||||
BinarySymbolData.SymbolKind.VALUE_PARAMETER_SYMBOL -> IrValueParameterSymbolImpl()
|
||||
BinarySymbolData.SymbolKind.RECEIVER_PARAMETER_SYMBOL -> IrValueParameterSymbolImpl()
|
||||
BinarySymbolData.SymbolKind.LOCAL_DELEGATED_PROPERTY_SYMBOL ->
|
||||
IrLocalDelegatedPropertySymbolImpl()
|
||||
else -> error("Unexpected classifier symbol kind: $symbolKind for signature $idSig")
|
||||
}
|
||||
}
|
||||
|
||||
fun referenceLocalIrSymbol(symbol: IrSymbol, signature: IdSignature) {
|
||||
assert(signature.isLocal)
|
||||
deserializedSymbols.putIfAbsent(signature, symbol)
|
||||
}
|
||||
|
||||
fun referenceSimpleFunctionByLocalSignature(idSignature: IdSignature) : IrSimpleFunctionSymbol =
|
||||
deserializeIrSymbolData(idSignature, BinarySymbolData.SymbolKind.FUNCTION_SYMBOL) as IrSimpleFunctionSymbol
|
||||
|
||||
fun referencePropertyByLocalSignature(idSignature: IdSignature): IrPropertySymbol =
|
||||
deserializeIrSymbolData(idSignature, BinarySymbolData.SymbolKind.PROPERTY_SYMBOL) as IrPropertySymbol
|
||||
|
||||
private fun deserializeIrSymbolData(idSignature: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
||||
if (idSignature.isLocal) {
|
||||
if (idSignature.hasTopLevel) {
|
||||
enqueueLocalTopLevelDeclaration(idSignature.topLevelSignature())
|
||||
}
|
||||
return deserializedSymbols.getOrPut(idSignature) {
|
||||
referenceDeserializedSymbol(symbolKind, idSignature)
|
||||
}
|
||||
}
|
||||
|
||||
return deserializePublicSymbol(idSignature, symbolKind)
|
||||
}
|
||||
|
||||
fun deserializeIrSymbolToDeclare(code: Long): Pair<IrSymbol, IdSignature> {
|
||||
val symbolData = parseSymbolData(code)
|
||||
val signature = deserializeIdSignature(symbolData.signatureId)
|
||||
return Pair(deserializeIrSymbolData(signature, symbolData.kind), signature)
|
||||
}
|
||||
|
||||
fun parseSymbolData(code: Long): BinarySymbolData = BinarySymbolData.decode(code)
|
||||
|
||||
fun deserializeIrSymbol(code: Long): IrSymbol {
|
||||
val symbolData = parseSymbolData(code)
|
||||
val signature = deserializeIdSignature(symbolData.signatureId)
|
||||
return deserializeIrSymbolData(signature, symbolData.kind)
|
||||
}
|
||||
|
||||
private fun readSignature(index: Int): CodedInputStream =
|
||||
fileReader.signature(index).codedInputStream
|
||||
|
||||
private fun loadSignatureProto(index: Int): ProtoIdSignature {
|
||||
return ProtoIdSignature.parseFrom(readSignature(index), ExtensionRegistryLite.newInstance())
|
||||
}
|
||||
|
||||
fun deserializeIdSignature(index: Int): IdSignature {
|
||||
val sigData = loadSignatureProto(index)
|
||||
return deserializeSignatureData(sigData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
// TODO: Think about isolating id signature related logic behind corresponding interface
|
||||
|
||||
private fun deserializePublicIdSignature(proto: ProtoPublicIdSignature): IdSignature.PublicSignature {
|
||||
val pkg = fileReader.deserializeFqName(proto.packageFqNameList)
|
||||
val cls = fileReader.deserializeFqName(proto.declarationFqNameList)
|
||||
val memberId = if (proto.hasMemberUniqId()) proto.memberUniqId else null
|
||||
|
||||
return IdSignature.PublicSignature(pkg, cls, memberId, proto.flags)
|
||||
}
|
||||
|
||||
private fun deserializeAccessorIdSignature(proto: ProtoAccessorIdSignature): IdSignature.AccessorSignature {
|
||||
val propertySignature = deserializeIdSignature(proto.propertySignature)
|
||||
require(propertySignature is IdSignature.PublicSignature) { "For public accessor corresponding property supposed to be public as well" }
|
||||
val name = fileReader.deserializeString(proto.name)
|
||||
val hash = proto.accessorHashId
|
||||
val mask = proto.flags
|
||||
|
||||
val accessorSignature =
|
||||
IdSignature.PublicSignature(propertySignature.packageFqName, "${propertySignature.declarationFqName}.$name", hash, mask)
|
||||
|
||||
return IdSignature.AccessorSignature(propertySignature, accessorSignature)
|
||||
}
|
||||
|
||||
private fun deserializeFileLocalIdSignature(proto: ProtoFileLocalIdSignature): IdSignature.FileLocalSignature {
|
||||
return IdSignature.FileLocalSignature(deserializeIdSignature(proto.container), proto.localId)
|
||||
}
|
||||
|
||||
private fun deserializeScopeLocalIdSignature(proto: Int): IdSignature.ScopeLocalDeclaration {
|
||||
return IdSignature.ScopeLocalDeclaration(proto)
|
||||
}
|
||||
|
||||
fun deserializeSignatureData(proto: ProtoIdSignature): IdSignature {
|
||||
return when (proto.idsigCase) {
|
||||
PUBLIC_SIG -> deserializePublicIdSignature(proto.publicSig)
|
||||
ACCESSOR_SIG -> deserializeAccessorIdSignature(proto.accessorSig)
|
||||
PRIVATE_SIG -> deserializeFileLocalIdSignature(proto.privateSig)
|
||||
SCOPED_LOCAL_SIG -> deserializeScopeLocalIdSignature(proto.scopedLocalSig)
|
||||
else -> error("Unexpected IdSignature kind: ${proto.idsigCase}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,59 +11,39 @@ import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolD
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrAbstractFunctionFactory
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
|
||||
import org.jetbrains.kotlin.ir.linkage.IrDeserializer
|
||||
import org.jetbrains.kotlin.ir.linkage.KotlinIrLinkerInternalException
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrErrorTypeImpl
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.ir.util.file
|
||||
import org.jetbrains.kotlin.library.IrLibrary
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.protobuf.CodedInputStream
|
||||
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite.newInstance
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.Actual as ProtoActual
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IdSignature as ProtoIdSignature
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrConstructorCall as ProtoConstructorCall
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclaration as ProtoDeclaration
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrExpression as ProtoExpression
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFile as ProtoFile
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrStatement as ProtoStatement
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrType as ProtoType
|
||||
|
||||
abstract class KotlinIrLinker(
|
||||
private val currentModule: ModuleDescriptor?,
|
||||
val messageLogger: IrMessageLogger,
|
||||
val builtIns: IrBuiltIns,
|
||||
val symbolTable: SymbolTable,
|
||||
private val exportedDependencies: List<ModuleDescriptor>
|
||||
private val exportedDependencies: List<ModuleDescriptor>,
|
||||
) : IrDeserializer, FileLocalAwareLinker {
|
||||
|
||||
// Kotlin-MPP related data. Consider some refactoring
|
||||
private val expectUniqIdToActualUniqId = mutableMapOf<IdSignature, IdSignature>()
|
||||
private val topLevelActualUniqItToDeserializer = mutableMapOf<IdSignature, IrModuleDeserializer>()
|
||||
private val expectSymbols = mutableMapOf<IdSignature, IrSymbol>()
|
||||
private val actualSymbols = mutableMapOf<IdSignature, IrSymbol>()
|
||||
internal val expectUniqIdToActualUniqId = mutableMapOf<IdSignature, IdSignature>()
|
||||
internal val topLevelActualUniqItToDeserializer = mutableMapOf<IdSignature, IrModuleDeserializer>()
|
||||
internal val expectSymbols = mutableMapOf<IdSignature, IrSymbol>()
|
||||
internal val actualSymbols = mutableMapOf<IdSignature, IrSymbol>()
|
||||
|
||||
private val modulesWithReachableTopLevels = mutableSetOf<IrModuleDeserializer>()
|
||||
internal val modulesWithReachableTopLevels = mutableSetOf<ModuleDeserializationState>()
|
||||
|
||||
// TODO: replace with Map<Name, IrModuleDeserializer>
|
||||
protected val deserializersForModules = mutableMapOf<ModuleDescriptor, IrModuleDeserializer>()
|
||||
@@ -72,411 +52,12 @@ abstract class KotlinIrLinker(
|
||||
|
||||
abstract val translationPluginContext: TranslationPluginContext?
|
||||
|
||||
private val haveSeen = mutableSetOf<IrSymbol>()
|
||||
internal val triedToDeserializeDeclarationForSymbol = mutableSetOf<IrSymbol>()
|
||||
internal val deserializedSymbols = mutableSetOf<IrSymbol>()
|
||||
|
||||
private lateinit var linkerExtensions: Collection<IrDeserializer.IrLinkerExtension>
|
||||
|
||||
abstract inner class BasicIrModuleDeserializer(moduleDescriptor: ModuleDescriptor, override val klib: IrLibrary, override val strategy: DeserializationStrategy, private val containsErrorCode: Boolean = false) :
|
||||
IrModuleDeserializer(moduleDescriptor) {
|
||||
|
||||
private val fileToDeserializerMap = mutableMapOf<IrFile, IrDeserializerForFile>()
|
||||
|
||||
private inner class ModuleDeserializationState {
|
||||
private val filesWithPendingTopLevels = mutableSetOf<IrDeserializerForFile>()
|
||||
|
||||
fun enqueueFile(fileDeserializer: IrDeserializerForFile) {
|
||||
filesWithPendingTopLevels.add(fileDeserializer)
|
||||
enqueueModule()
|
||||
}
|
||||
|
||||
fun addIdSignature(key: IdSignature) {
|
||||
val fileDeserializer = moduleReversedFileIndex[key] ?: error("No file found for key $key")
|
||||
fileDeserializer.fileLocalDeserializationState.addIdSignature(key)
|
||||
|
||||
enqueueFile(fileDeserializer)
|
||||
}
|
||||
|
||||
fun processPendingDeclarations() {
|
||||
while (filesWithPendingTopLevels.isNotEmpty()) {
|
||||
val pendingDeserializer = filesWithPendingTopLevels.first()
|
||||
|
||||
pendingDeserializer.deserializeFileImplicitDataIfFirstUse()
|
||||
pendingDeserializer.deserializeAllFileReachableTopLevel()
|
||||
|
||||
filesWithPendingTopLevels.remove(pendingDeserializer)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String = klib.toString()
|
||||
}
|
||||
|
||||
private val moduleDeserializationState = ModuleDeserializationState()
|
||||
private val moduleReversedFileIndex = mutableMapOf<IdSignature, IrDeserializerForFile>()
|
||||
override val moduleDependencies by lazy {
|
||||
moduleDescriptor.allDependencyModules.filter { it != moduleDescriptor }.map { resolveModuleDeserializer(it, null) }
|
||||
}
|
||||
|
||||
override fun init(delegate: IrModuleDeserializer) {
|
||||
val fileCount = klib.fileCount()
|
||||
|
||||
val files = ArrayList<IrFile>(fileCount)
|
||||
|
||||
for (i in 0 until fileCount) {
|
||||
val fileStream = klib.file(i).codedInputStream
|
||||
files.add(deserializeIrFile(ProtoFile.parseFrom(fileStream, newInstance()), i, delegate, containsErrorCode))
|
||||
}
|
||||
|
||||
moduleFragment.files.addAll(files)
|
||||
|
||||
fileToDeserializerMap.values.forEach { it.deserializeExpectActualMapping() }
|
||||
}
|
||||
|
||||
override fun referenceSimpleFunctionByLocalSignature(file: IrFile, idSignature: IdSignature): IrSimpleFunctionSymbol =
|
||||
fileToDeserializerMap[file]?.referenceSimpleFunctionByLocalSignature(idSignature)
|
||||
?: error("No deserializer for file $file in module ${moduleDescriptor.name}")
|
||||
|
||||
override fun referencePropertyByLocalSignature(file: IrFile, idSignature: IdSignature): IrPropertySymbol =
|
||||
fileToDeserializerMap[file]?.referencePropertyByLocalSignature(idSignature)
|
||||
?: error("No deserializer for file $file in module ${moduleDescriptor.name}")
|
||||
|
||||
// TODO: fix to topLevel checker
|
||||
override fun contains(idSig: IdSignature): Boolean = idSig in moduleReversedFileIndex
|
||||
|
||||
override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
||||
assert(idSig.isPublic)
|
||||
|
||||
val topLevelSignature = idSig.topLevelSignature()
|
||||
val fileDeserializer = moduleReversedFileIndex[topLevelSignature]
|
||||
?: error("No file for $topLevelSignature (@ $idSig) in module $moduleDescriptor")
|
||||
|
||||
val fileDeserializationState = fileDeserializer.fileLocalDeserializationState
|
||||
|
||||
fileDeserializationState.addIdSignature(topLevelSignature)
|
||||
moduleDeserializationState.enqueueFile(fileDeserializer)
|
||||
|
||||
return fileDeserializationState.deserializedSymbols.getOrPut(idSig) {
|
||||
// val descriptor = resolveSpecialSignature(idSig)
|
||||
val symbol = referenceDeserializedSymbol(symbolKind, idSig)
|
||||
|
||||
handleExpectActualMapping(idSig, symbol)
|
||||
}
|
||||
}
|
||||
|
||||
override val moduleFragment: IrModuleFragment = IrModuleFragmentImpl(moduleDescriptor, builtIns, emptyList())
|
||||
|
||||
private fun deserializeIrFile(fileProto: ProtoFile, fileIndex: Int, moduleDeserializer: IrModuleDeserializer, allowErrorNodes: Boolean): IrFile {
|
||||
|
||||
val fileName = fileProto.fileEntry.name
|
||||
|
||||
val fileEntry = NaiveSourceBasedFileEntryImpl(fileName, fileProto.fileEntry.lineStartOffsetsList.toIntArray())
|
||||
|
||||
val fileDeserializer =
|
||||
IrDeserializerForFile(
|
||||
fileProto.annotationList,
|
||||
fileProto.actualsList,
|
||||
fileIndex,
|
||||
!strategy.needBodies,
|
||||
strategy.inlineBodies,
|
||||
moduleDeserializer, allowErrorNodes
|
||||
).apply {
|
||||
|
||||
// Explicitly exported declarations (e.g. top-level initializers) must be deserialized before all other declarations.
|
||||
// Thus we schedule their deserialization in deserializer's constructor.
|
||||
fileProto.explicitlyExportedToCompilerList.forEach {
|
||||
val symbolData = parseSymbolData(it)
|
||||
val sig = deserializeIdSignature(symbolData.signatureId)
|
||||
assert(!sig.isPackageSignature())
|
||||
fileLocalDeserializationState.addIdSignature(sig.topLevelSignature())
|
||||
}
|
||||
}
|
||||
|
||||
val fqName = FqName(fileDeserializer.deserializeFqName(fileProto.fqNameList))
|
||||
|
||||
val packageFragmentDescriptor = EmptyPackageFragmentDescriptor(moduleDescriptor, fqName)
|
||||
|
||||
val symbol = IrFileSymbolImpl(packageFragmentDescriptor)
|
||||
val file = IrFileImpl(fileEntry, symbol, fqName)
|
||||
|
||||
fileDeserializer.file = file
|
||||
fileToDeserializerMap[file] = fileDeserializer
|
||||
|
||||
val fileSignatureIndex = fileProto.declarationIdList.map { fileDeserializer.deserializeIdSignature(it) to it }
|
||||
|
||||
fileSignatureIndex.forEach {
|
||||
moduleReversedFileIndex.getOrPut(it.first) { fileDeserializer }
|
||||
}
|
||||
|
||||
fileDeserializer.reversedSignatureIndex = fileSignatureIndex.toMap()
|
||||
|
||||
if (strategy.theWholeWorld) {
|
||||
for (id in fileSignatureIndex) {
|
||||
moduleDeserializationState.addIdSignature(id.first)
|
||||
}
|
||||
moduleDeserializationState.enqueueFile(fileDeserializer)
|
||||
} else if (strategy.explicitlyExported) {
|
||||
moduleDeserializationState.enqueueFile(fileDeserializer)
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
override fun deserializeReachableDeclarations() {
|
||||
moduleDeserializationState.processPendingDeclarations()
|
||||
}
|
||||
|
||||
private fun enqueueModule() {
|
||||
modulesWithReachableTopLevels.add(this)
|
||||
}
|
||||
|
||||
override fun addModuleReachableTopLevel(idSig: IdSignature) {
|
||||
moduleDeserializationState.addIdSignature(idSig)
|
||||
}
|
||||
}
|
||||
|
||||
inner class IrDeserializerForFile(
|
||||
private var annotations: List<ProtoConstructorCall>?,
|
||||
private val actuals: List<ProtoActual>,
|
||||
private val fileIndex: Int,
|
||||
onlyHeaders: Boolean,
|
||||
inlineBodies: Boolean,
|
||||
private val moduleDeserializer: IrModuleDeserializer,
|
||||
allowErrorNodes: Boolean
|
||||
) :
|
||||
IrFileDeserializer(
|
||||
messageLogger,
|
||||
builtIns,
|
||||
symbolTable,
|
||||
!onlyHeaders,
|
||||
fakeOverrideBuilder,
|
||||
allowErrorNodes
|
||||
)
|
||||
{
|
||||
|
||||
private var fileLoops = mutableMapOf<Int, IrLoop>()
|
||||
|
||||
lateinit var file: IrFile
|
||||
|
||||
private val irTypeCache = mutableMapOf<Int, IrType>()
|
||||
|
||||
override val deserializeInlineFunctions: Boolean = inlineBodies
|
||||
|
||||
override val platformFakeOverrideClassFilter = fakeOverrideBuilder.platformSpecificClassFilter
|
||||
|
||||
var reversedSignatureIndex = emptyMap<IdSignature, Int>()
|
||||
|
||||
inner class FileDeserializationState {
|
||||
private val reachableTopLevels = LinkedHashSet<IdSignature>()
|
||||
val deserializedSymbols = mutableMapOf<IdSignature, IrSymbol>()
|
||||
|
||||
fun addIdSignature(key: IdSignature) {
|
||||
reachableTopLevels.add(key)
|
||||
}
|
||||
|
||||
fun processPendingDeclarations() {
|
||||
while (reachableTopLevels.isNotEmpty()) {
|
||||
val reachableKey = reachableTopLevels.first()
|
||||
|
||||
val existedSymbol = deserializedSymbols[reachableKey]
|
||||
if (existedSymbol == null || !existedSymbol.isBound) {
|
||||
val declaration = deserializeDeclaration(reachableKey)
|
||||
file.declarations.add(declaration)
|
||||
}
|
||||
|
||||
reachableTopLevels.remove(reachableKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val fileLocalDeserializationState = FileDeserializationState()
|
||||
|
||||
fun deserializeDeclaration(idSig: IdSignature): IrDeclaration {
|
||||
return deserializeDeclaration(loadTopLevelDeclarationProto(idSig), file)
|
||||
}
|
||||
|
||||
fun deserializeExpectActualMapping() {
|
||||
actuals.forEach {
|
||||
val expectSymbol = parseSymbolData(it.expectSymbol)
|
||||
val actualSymbol = parseSymbolData(it.actualSymbol)
|
||||
|
||||
val expect = deserializeIdSignature(expectSymbol.signatureId)
|
||||
val actual = deserializeIdSignature(actualSymbol.signatureId)
|
||||
|
||||
assert(expectUniqIdToActualUniqId[expect] == null) {
|
||||
"Expect signature $expect is already actualized by ${expectUniqIdToActualUniqId[expect]}, while we try to record $actual"
|
||||
}
|
||||
expectUniqIdToActualUniqId[expect] = actual
|
||||
// Non-null only for topLevel declarations.
|
||||
getModuleForTopLevelId(actual)?.let { md -> topLevelActualUniqItToDeserializer[actual] = md }
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveSignatureIndex(idSig: IdSignature): Int {
|
||||
return reversedSignatureIndex[idSig] ?: error("Not found Idx for $idSig")
|
||||
}
|
||||
|
||||
private fun readDeclaration(index: Int): CodedInputStream =
|
||||
moduleDeserializer.klib.irDeclaration(index, fileIndex).codedInputStream
|
||||
|
||||
private fun loadTopLevelDeclarationProto(idSig: IdSignature): ProtoDeclaration {
|
||||
val idSigIndex = resolveSignatureIndex(idSig)
|
||||
return ProtoDeclaration.parseFrom(readDeclaration(idSigIndex), newInstance())
|
||||
}
|
||||
|
||||
private fun readType(index: Int): CodedInputStream =
|
||||
moduleDeserializer.klib.type(index, fileIndex).codedInputStream
|
||||
|
||||
private fun loadTypeProto(index: Int): ProtoType {
|
||||
return ProtoType.parseFrom(readType(index), newInstance())
|
||||
}
|
||||
|
||||
private fun readSignature(index: Int): CodedInputStream =
|
||||
moduleDeserializer.klib.signature(index, fileIndex).codedInputStream
|
||||
|
||||
private fun loadSignatureProto(index: Int): ProtoIdSignature {
|
||||
return ProtoIdSignature.parseFrom(readSignature(index), newInstance())
|
||||
}
|
||||
|
||||
private fun readBody(index: Int): CodedInputStream =
|
||||
moduleDeserializer.klib.body(index, fileIndex).codedInputStream
|
||||
|
||||
private fun loadStatementBodyProto(index: Int): ProtoStatement {
|
||||
return ProtoStatement.parseFrom(readBody(index), newInstance())
|
||||
}
|
||||
|
||||
private fun loadExpressionBodyProto(index: Int): ProtoExpression {
|
||||
return ProtoExpression.parseFrom(readBody(index), newInstance())
|
||||
}
|
||||
|
||||
private fun loadStringProto(index: Int): String {
|
||||
return String(moduleDeserializer.klib.string(index, fileIndex))
|
||||
}
|
||||
|
||||
private fun getModuleForTopLevelId(idSignature: IdSignature): IrModuleDeserializer? {
|
||||
if (idSignature in moduleDeserializer) return moduleDeserializer
|
||||
return moduleDeserializer.moduleDependencies.firstOrNull { idSignature in it }
|
||||
}
|
||||
|
||||
private fun findModuleDeserializer(idSig: IdSignature): IrModuleDeserializer {
|
||||
assert(idSig.isPublic)
|
||||
|
||||
val topLevelSig = idSig.topLevelSignature()
|
||||
if (topLevelSig in moduleDeserializer) return moduleDeserializer
|
||||
return moduleDeserializer.moduleDependencies.firstOrNull { topLevelSig in it } ?: handleNoModuleDeserializerFound(
|
||||
idSig,
|
||||
moduleDeserializer.moduleDescriptor,
|
||||
moduleDeserializer.moduleDependencies
|
||||
)
|
||||
}
|
||||
|
||||
private fun referenceIrSymbolData(symbol: IrSymbol, signature: IdSignature) {
|
||||
assert(signature.isLocal)
|
||||
fileLocalDeserializationState.deserializedSymbols.putIfAbsent(signature, symbol)
|
||||
}
|
||||
|
||||
private fun deserializeIrLocalSymbolData(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
||||
assert(idSig.isLocal)
|
||||
|
||||
if (idSig.hasTopLevel) {
|
||||
fileLocalDeserializationState.addIdSignature(idSig.topLevelSignature())
|
||||
}
|
||||
|
||||
return fileLocalDeserializationState.deserializedSymbols.getOrPut(idSig) {
|
||||
referenceDeserializedSymbol(symbolKind, idSig)
|
||||
}
|
||||
}
|
||||
|
||||
fun referenceSimpleFunctionByLocalSignature(idSignature: IdSignature) : IrSimpleFunctionSymbol =
|
||||
deserializeIrSymbolData(idSignature, BinarySymbolData.SymbolKind.FUNCTION_SYMBOL) as IrSimpleFunctionSymbol
|
||||
|
||||
fun referencePropertyByLocalSignature(idSignature: IdSignature): IrPropertySymbol =
|
||||
deserializeIrSymbolData(idSignature, BinarySymbolData.SymbolKind.PROPERTY_SYMBOL) as IrPropertySymbol
|
||||
|
||||
private fun deserializeIrSymbolData(idSignature: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
||||
if (idSignature.isLocal) return deserializeIrLocalSymbolData(idSignature, symbolKind)
|
||||
|
||||
return findModuleDeserializer(idSignature).deserializeIrSymbol(idSignature, symbolKind).also {
|
||||
haveSeen.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun deserializeIrSymbolToDeclare(code: Long): Pair<IrSymbol, IdSignature> {
|
||||
val symbolData = parseSymbolData(code)
|
||||
val signature = deserializeIdSignature(symbolData.signatureId)
|
||||
return Pair(deserializeIrSymbolData(signature, symbolData.kind), signature)
|
||||
}
|
||||
|
||||
fun parseSymbolData(code: Long): BinarySymbolData = BinarySymbolData.decode(code)
|
||||
|
||||
override fun deserializeIrSymbol(code: Long): IrSymbol {
|
||||
val symbolData = parseSymbolData(code)
|
||||
val signature = deserializeIdSignature(symbolData.signatureId)
|
||||
return deserializeIrSymbolData(signature, symbolData.kind)
|
||||
}
|
||||
|
||||
override fun deserializeIrType(index: Int): IrType {
|
||||
return irTypeCache.getOrPut(index) {
|
||||
val typeData = loadTypeProto(index)
|
||||
deserializeIrTypeData(typeData)
|
||||
}
|
||||
}
|
||||
|
||||
override fun deserializeIdSignature(index: Int): IdSignature {
|
||||
val sigData = loadSignatureProto(index)
|
||||
return deserializeSignatureData(sigData)
|
||||
}
|
||||
|
||||
override fun deserializeString(index: Int): String =
|
||||
loadStringProto(index)
|
||||
|
||||
override fun deserializeLoopHeader(loopIndex: Int, loopBuilder: () -> IrLoop) =
|
||||
fileLoops.getOrPut(loopIndex, loopBuilder)
|
||||
|
||||
override fun deserializeExpressionBody(index: Int): IrExpression {
|
||||
return if (deserializeBodies) {
|
||||
val bodyData = loadExpressionBodyProto(index)
|
||||
deserializeExpression(bodyData)
|
||||
} else {
|
||||
val errorType = IrErrorTypeImpl(null, emptyList(), Variance.INVARIANT)
|
||||
IrErrorExpressionImpl(-1, -1, errorType, "Expression body is not deserialized yet")
|
||||
}
|
||||
}
|
||||
|
||||
override fun deserializeStatementBody(index: Int): IrElement {
|
||||
return if (deserializeBodies) {
|
||||
val bodyData = loadStatementBodyProto(index)
|
||||
deserializeStatement(bodyData)
|
||||
} else {
|
||||
val errorType = IrErrorTypeImpl(null, emptyList(), Variance.INVARIANT)
|
||||
irFactory.createBlockBody(
|
||||
-1, -1, listOf(IrErrorExpressionImpl(-1, -1, errorType, "Statement body is not deserialized yet"))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun referenceIrSymbol(symbol: IrSymbol, signature: IdSignature) {
|
||||
referenceIrSymbolData(symbol, signature)
|
||||
}
|
||||
|
||||
fun deserializeFileImplicitDataIfFirstUse() {
|
||||
annotations?.let {
|
||||
file.annotations += deserializeAnnotations(it)
|
||||
annotations = null
|
||||
}
|
||||
}
|
||||
|
||||
fun deserializeAllFileReachableTopLevel() {
|
||||
fileLocalDeserializationState.processPendingDeclarations()
|
||||
}
|
||||
}
|
||||
|
||||
private val ByteArray.codedInputStream: CodedInputStream
|
||||
get() {
|
||||
val codedInputStream = CodedInputStream.newInstance(this)
|
||||
codedInputStream.setRecursionLimit(65535) // The default 64 is blatantly not enough for IR.
|
||||
return codedInputStream
|
||||
}
|
||||
|
||||
protected open fun handleNoModuleDeserializerFound(idSignature: IdSignature, currentModule: ModuleDescriptor, dependencies: Collection<IrModuleDeserializer>): IrModuleDeserializer {
|
||||
public open fun handleNoModuleDeserializerFound(idSignature: IdSignature, currentModule: ModuleDescriptor, dependencies: Collection<IrModuleDeserializer>): IrModuleDeserializer {
|
||||
val message = buildString {
|
||||
append("Module $currentModule has reference $idSignature, unfortunately neither itself nor its dependencies ")
|
||||
dependencies.joinTo(this, "\n\t", "[\n\t", "\n]")
|
||||
@@ -489,7 +70,7 @@ abstract class KotlinIrLinker(
|
||||
throw KotlinIrLinkerInternalException
|
||||
}
|
||||
|
||||
protected open fun resolveModuleDeserializer(module: ModuleDescriptor, signature: IdSignature?): IrModuleDeserializer {
|
||||
public open fun resolveModuleDeserializer(module: ModuleDescriptor, signature: IdSignature?): IrModuleDeserializer {
|
||||
return deserializersForModules[module] ?: run {
|
||||
val message = buildString {
|
||||
append("Could not load module ")
|
||||
@@ -515,58 +96,22 @@ abstract class KotlinIrLinker(
|
||||
|
||||
protected abstract fun isBuiltInModule(moduleDescriptor: ModuleDescriptor): Boolean
|
||||
|
||||
// TODO: the following code worth some refactoring in the nearest future
|
||||
|
||||
private fun handleExpectActualMapping(idSig: IdSignature, rawSymbol: IrSymbol): IrSymbol {
|
||||
val referencingSymbol = if (idSig in expectUniqIdToActualUniqId.keys) {
|
||||
assert(idSig.run { IdSignature.Flags.IS_EXPECT.test() })
|
||||
wrapInDelegatedSymbol(rawSymbol).also { expectSymbols[idSig] = it }
|
||||
} else rawSymbol
|
||||
|
||||
if (idSig in expectUniqIdToActualUniqId.values) {
|
||||
actualSymbols[idSig] = rawSymbol
|
||||
}
|
||||
|
||||
return referencingSymbol
|
||||
}
|
||||
|
||||
private fun referenceDeserializedSymbol(symbolKind: BinarySymbolData.SymbolKind, idSig: IdSignature): IrSymbol = symbolTable.run {
|
||||
when (symbolKind) {
|
||||
BinarySymbolData.SymbolKind.ANONYMOUS_INIT_SYMBOL -> IrAnonymousInitializerSymbolImpl()
|
||||
BinarySymbolData.SymbolKind.CLASS_SYMBOL -> referenceClassFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.CONSTRUCTOR_SYMBOL -> referenceConstructorFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.TYPE_PARAMETER_SYMBOL -> referenceTypeParameterFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL -> referenceEnumEntryFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.STANDALONE_FIELD_SYMBOL -> referenceFieldFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.FIELD_SYMBOL -> referenceFieldFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.FUNCTION_SYMBOL -> referenceSimpleFunctionFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.TYPEALIAS_SYMBOL -> referenceTypeAliasFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.PROPERTY_SYMBOL -> referencePropertyFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.VARIABLE_SYMBOL -> IrVariableSymbolImpl()
|
||||
BinarySymbolData.SymbolKind.VALUE_PARAMETER_SYMBOL -> IrValueParameterSymbolImpl()
|
||||
BinarySymbolData.SymbolKind.RECEIVER_PARAMETER_SYMBOL -> IrValueParameterSymbolImpl()
|
||||
BinarySymbolData.SymbolKind.LOCAL_DELEGATED_PROPERTY_SYMBOL ->
|
||||
IrLocalDelegatedPropertySymbolImpl()
|
||||
else -> error("Unexpected classifier symbol kind: $symbolKind for signature $idSig")
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeAllReachableTopLevels() {
|
||||
while (modulesWithReachableTopLevels.isNotEmpty()) {
|
||||
val moduleDeserializer = modulesWithReachableTopLevels.first()
|
||||
modulesWithReachableTopLevels.remove(moduleDeserializer)
|
||||
val moduleDeserializationState = modulesWithReachableTopLevels.first()
|
||||
modulesWithReachableTopLevels.remove(moduleDeserializationState)
|
||||
|
||||
moduleDeserializer.deserializeReachableDeclarations()
|
||||
moduleDeserializationState.deserializeReachableDeclarations()
|
||||
}
|
||||
}
|
||||
|
||||
private fun findDeserializedDeclarationForSymbol(symbol: IrSymbol): DeclarationDescriptor? {
|
||||
assert(symbol.isPublicApi || symbol.descriptor.module === currentModule || platformSpecificSymbol(symbol))
|
||||
|
||||
if (haveSeen.contains(symbol)) {
|
||||
if (symbol in triedToDeserializeDeclarationForSymbol || symbol in deserializedSymbols) {
|
||||
return null
|
||||
}
|
||||
haveSeen.add(symbol)
|
||||
triedToDeserializeDeclarationForSymbol.add(symbol)
|
||||
|
||||
val descriptor = symbol.descriptor
|
||||
|
||||
@@ -586,6 +131,7 @@ abstract class KotlinIrLinker(
|
||||
if (!symbol.hasDescriptor) return null
|
||||
|
||||
val descriptor = symbol.descriptor
|
||||
|
||||
if (descriptor is CallableMemberDescriptor) {
|
||||
if (descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||
// skip fake overrides
|
||||
@@ -661,12 +207,43 @@ abstract class KotlinIrLinker(
|
||||
override fun postProcess() {
|
||||
finalizeExpectActualLinker()
|
||||
fakeOverrideBuilder.provideFakeOverrides()
|
||||
haveSeen.clear()
|
||||
triedToDeserializeDeclarationForSymbol.clear()
|
||||
deserializedSymbols.clear()
|
||||
|
||||
// TODO: fix IrPluginContext to make it not produce additional external reference
|
||||
// symbolTable.noUnboundLeft("unbound after fake overrides:")
|
||||
}
|
||||
|
||||
fun handleExpectActualMapping(idSig: IdSignature, rawSymbol: IrSymbol): IrSymbol {
|
||||
|
||||
// Actual signature
|
||||
if (idSig in expectUniqIdToActualUniqId.values) {
|
||||
actualSymbols[idSig] = rawSymbol
|
||||
}
|
||||
|
||||
// Expect signature
|
||||
expectUniqIdToActualUniqId[idSig]?.let { actualSig ->
|
||||
assert(idSig.run { IdSignature.Flags.IS_EXPECT.test() })
|
||||
|
||||
val referencingSymbol = wrapInDelegatedSymbol(rawSymbol)
|
||||
|
||||
expectSymbols[idSig] = referencingSymbol
|
||||
|
||||
// Trigger actual symbol deserialization
|
||||
topLevelActualUniqItToDeserializer[actualSig]?.let { moduleDeserializer -> // Not null if top-level
|
||||
val actualSymbol = actualSymbols[actualSig]
|
||||
// Check if
|
||||
if (actualSymbol == null || !actualSymbol.isBound) {
|
||||
moduleDeserializer.addModuleReachableTopLevel(actualSig)
|
||||
}
|
||||
}
|
||||
|
||||
return referencingSymbol
|
||||
}
|
||||
|
||||
return rawSymbol
|
||||
}
|
||||
|
||||
private fun topLevelKindToSymbolKind(kind: IrDeserializer.TopLevelSymbolKind): BinarySymbolData.SymbolKind {
|
||||
return when (kind) {
|
||||
IrDeserializer.TopLevelSymbolKind.CLASS_SYMBOL -> BinarySymbolData.SymbolKind.CLASS_SYMBOL
|
||||
@@ -690,16 +267,7 @@ abstract class KotlinIrLinker(
|
||||
// because the expect can not see the actual higher in the module dependency dag.
|
||||
// So we force deserialization of actuals for all deserialized expect symbols here.
|
||||
private fun finalizeExpectActualLinker() {
|
||||
expectUniqIdToActualUniqId.filter { topLevelActualUniqItToDeserializer[it.value] != null }.forEach {
|
||||
val expectSymbol = expectSymbols[it.key]
|
||||
val actualSymbol = actualSymbols[it.value]
|
||||
if (expectSymbol != null && (actualSymbol == null || !actualSymbol.isBound)) {
|
||||
topLevelActualUniqItToDeserializer[it.value]!!.addModuleReachableTopLevel(it.value)
|
||||
deserializeAllReachableTopLevels()
|
||||
}
|
||||
}
|
||||
|
||||
// Now after all actuals have been deserialized, retarget delegating symbols from expects to actuals.
|
||||
// All actuals have been deserialized, retarget delegating symbols from expects to actuals.
|
||||
expectUniqIdToActualUniqId.forEach {
|
||||
val expectSymbol = expectSymbols[it.key]
|
||||
val actualSymbol = actualSymbols[it.value]
|
||||
@@ -760,6 +328,11 @@ abstract class KotlinIrLinker(
|
||||
|
||||
fun deserializeHeadersWithInlineBodies(moduleDescriptor: ModuleDescriptor, kotlinLibrary: KotlinLibrary?): IrModuleFragment =
|
||||
deserializeIrModuleHeader(moduleDescriptor, kotlinLibrary, DeserializationStrategy.WITH_INLINE_BODIES)
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun deserializeDirtyFiles(moduleDescriptor: ModuleDescriptor, kotlinLibrary: KotlinLibrary, dirtyFiles: Set<String>): IrModuleFragment {
|
||||
TODO("...")
|
||||
}
|
||||
}
|
||||
|
||||
enum class DeserializationStrategy(
|
||||
@@ -773,4 +346,4 @@ enum class DeserializationStrategy(
|
||||
EXPLICITLY_EXPORTED(true, true, false, true),
|
||||
ONLY_DECLARATION_HEADERS(false, false, false, false),
|
||||
WITH_INLINE_BODIES(false, false, false, true)
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ plugins {
|
||||
dependencies {
|
||||
compile(project(":compiler:ir.psi2ir"))
|
||||
compile(project(":compiler:ir.serialization.common"))
|
||||
compile(project(":js:js.frontend"))
|
||||
compile(project(":js:js.config"))
|
||||
|
||||
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
//class InlineFunctionReporter(private val incrementalResultsConsumer: IncrementalResultsConsumer) : IrElementVisitorVoid {
|
||||
// override fun visitElement(element: IrElement) {
|
||||
// element.acceptChildren(this, null)
|
||||
// }
|
||||
//
|
||||
// override fun visitSimpleFunction(declaration: IrSimpleFunction) {
|
||||
// super.visitSimpleFunction(declaration)
|
||||
// if (declaration.isInline) {
|
||||
//
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//// private fun reportInlineFunction(function: IrSimpleFunction) {
|
||||
//// val signature = function.symbol.signature ?: return
|
||||
////
|
||||
//// val file = function.file
|
||||
//// file.fileEntry.name
|
||||
//// }
|
||||
//
|
||||
//}
|
||||
@@ -8,61 +8,32 @@ package org.jetbrains.kotlin.ir.backend.js
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.analyzer.AbstractAnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContextImpl
|
||||
import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideChecker
|
||||
import org.jetbrains.kotlin.backend.common.serialization.DeserializationStrategy
|
||||
import org.jetbrains.kotlin.backend.common.serialization.ICData
|
||||
import org.jetbrains.kotlin.backend.common.serialization.KlibIrVersion
|
||||
import org.jetbrains.kotlin.backend.common.serialization.knownBuiltins
|
||||
import org.jetbrains.kotlin.backend.common.serialization.mangle.ManglerChecker
|
||||
import org.jetbrains.kotlin.backend.common.serialization.mangle.descriptor.Ir2DescriptorManglerAdapter
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.DynamicTypeDeserializer
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataIncrementalSerializer
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
|
||||
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.KotlinCompilerVersion
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrModuleSerializer
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFactory
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrFunctionFactory
|
||||
import org.jetbrains.kotlin.ir.linkage.IrDeserializer
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
|
||||
import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.konan.properties.Properties
|
||||
import org.jetbrains.kotlin.konan.properties.propertyList
|
||||
import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
|
||||
import org.jetbrains.kotlin.library.*
|
||||
import org.jetbrains.kotlin.library.impl.BuiltInsPlatform
|
||||
import org.jetbrains.kotlin.library.impl.buildKotlinLibrary
|
||||
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.progress.IncrementalNextRoundException
|
||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
|
||||
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
|
||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import java.io.File
|
||||
import org.jetbrains.kotlin.konan.file.File as KFile
|
||||
|
||||
@@ -89,109 +60,6 @@ private val CompilerConfiguration.expectActualLinker: Boolean
|
||||
|
||||
class KotlinFileSerializedData(val metadata: ByteArray, val irData: SerializedIrFile)
|
||||
|
||||
fun generateKLib(
|
||||
project: Project,
|
||||
files: List<KtFile>,
|
||||
analyzer: AbstractAnalyzerWithCompilerReport,
|
||||
configuration: CompilerConfiguration,
|
||||
allDependencies: KotlinLibraryResolveResult,
|
||||
friendDependencies: List<KotlinLibrary>,
|
||||
irFactory: IrFactory,
|
||||
outputKlibPath: String,
|
||||
nopack: Boolean
|
||||
) {
|
||||
val incrementalDataProvider = configuration.get(JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER)
|
||||
val errorPolicy = configuration.get(JSConfigurationKeys.ERROR_TOLERANCE_POLICY) ?: ErrorTolerancePolicy.DEFAULT
|
||||
val messageLogger = configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None
|
||||
|
||||
val icData: List<KotlinFileSerializedData>
|
||||
val serializedIrFiles: List<SerializedIrFile>?
|
||||
|
||||
if (incrementalDataProvider != null) {
|
||||
val nonCompiledSources = files.map { VfsUtilCore.virtualToIoFile(it.virtualFile) to it }.toMap()
|
||||
val compiledIrFiles = incrementalDataProvider.serializedIrFiles
|
||||
val compiledMetaFiles = incrementalDataProvider.compiledPackageParts
|
||||
|
||||
assert(compiledIrFiles.size == compiledMetaFiles.size)
|
||||
|
||||
val storage = mutableListOf<KotlinFileSerializedData>()
|
||||
|
||||
for (f in compiledIrFiles.keys) {
|
||||
if (f in nonCompiledSources) continue
|
||||
|
||||
val irData = compiledIrFiles[f] ?: error("No Ir Data found for file $f")
|
||||
val metaFile = compiledMetaFiles[f] ?: error("No Meta Data found for file $f")
|
||||
val irFile = with(irData) {
|
||||
SerializedIrFile(fileData, String(fqn), f.path.replace('\\', '/'), types, signatures, strings, bodies, declarations)
|
||||
}
|
||||
storage.add(KotlinFileSerializedData(metaFile.metadata, irFile))
|
||||
}
|
||||
|
||||
icData = storage
|
||||
serializedIrFiles = storage.map { it.irData }
|
||||
} else {
|
||||
icData = emptyList()
|
||||
serializedIrFiles = null
|
||||
}
|
||||
|
||||
val depsDescriptors =
|
||||
ModulesStructure(project, MainModule.SourceFiles(files), analyzer, configuration, allDependencies, friendDependencies)
|
||||
|
||||
val (psi2IrContext, hasErrors) = runAnalysisAndPreparePsi2Ir(depsDescriptors, irFactory, errorPolicy)
|
||||
val irBuiltIns = psi2IrContext.irBuiltIns
|
||||
val functionFactory = IrFunctionFactory(irBuiltIns, psi2IrContext.symbolTable)
|
||||
irBuiltIns.functionFactory = functionFactory
|
||||
|
||||
val expectDescriptorToSymbol = mutableMapOf<DeclarationDescriptor, IrSymbol>()
|
||||
val feContext = psi2IrContext.run {
|
||||
JsIrLinker.JsFePluginContext(moduleDescriptor, bindingContext, symbolTable, typeTranslator, irBuiltIns)
|
||||
}
|
||||
val irLinker = JsIrLinker(
|
||||
psi2IrContext.moduleDescriptor,
|
||||
messageLogger,
|
||||
psi2IrContext.irBuiltIns,
|
||||
psi2IrContext.symbolTable,
|
||||
functionFactory,
|
||||
feContext,
|
||||
serializedIrFiles?.let { ICData(it, errorPolicy.allowErrors) }
|
||||
)
|
||||
|
||||
sortDependencies(allDependencies.getFullList(), depsDescriptors.descriptors).map {
|
||||
irLinker.deserializeOnlyHeaderModule(depsDescriptors.getModuleDescriptor(it), it)
|
||||
}
|
||||
|
||||
val moduleFragment = psi2IrContext.generateModuleFragmentWithPlugins(project, files, irLinker, messageLogger, expectDescriptorToSymbol)
|
||||
|
||||
moduleFragment.acceptVoid(ManglerChecker(JsManglerIr, Ir2DescriptorManglerAdapter(JsManglerDesc)))
|
||||
if (configuration.getBoolean(JSConfigurationKeys.FAKE_OVERRIDE_VALIDATOR)) {
|
||||
val fakeOverrideChecker = FakeOverrideChecker(JsManglerIr, JsManglerDesc)
|
||||
irLinker.modules.forEach { fakeOverrideChecker.check(it) }
|
||||
}
|
||||
|
||||
val moduleName = configuration[CommonConfigurationKeys.MODULE_NAME]!!
|
||||
|
||||
if (!configuration.expectActualLinker) {
|
||||
moduleFragment.acceptVoid(ExpectDeclarationRemover(psi2IrContext.symbolTable, false))
|
||||
}
|
||||
|
||||
serializeModuleIntoKlib(
|
||||
moduleName,
|
||||
project,
|
||||
configuration,
|
||||
messageLogger,
|
||||
psi2IrContext.bindingContext,
|
||||
files,
|
||||
outputKlibPath,
|
||||
allDependencies.getFullList(),
|
||||
moduleFragment,
|
||||
expectDescriptorToSymbol,
|
||||
icData,
|
||||
nopack,
|
||||
perFile = false,
|
||||
hasErrors
|
||||
)
|
||||
}
|
||||
|
||||
data class IrModuleInfo(
|
||||
val module: IrModuleFragment,
|
||||
val allDependencies: List<IrModuleFragment>,
|
||||
@@ -200,260 +68,11 @@ data class IrModuleInfo(
|
||||
val deserializer: JsIrLinker
|
||||
)
|
||||
|
||||
private fun sortDependencies(dependencies: List<KotlinLibrary>, mapping: Map<KotlinLibrary, ModuleDescriptor>): Collection<KotlinLibrary> {
|
||||
val m2l = mapping.map { it.value to it.key }.toMap()
|
||||
|
||||
return DFS.topologicalOrder(dependencies) { m ->
|
||||
val descriptor = mapping[m] ?: error("No descriptor found for library ${m.libraryName}")
|
||||
descriptor.allDependencyModules.filter { it != descriptor }.map { m2l[it] }
|
||||
}.reversed()
|
||||
}
|
||||
|
||||
fun loadIr(
|
||||
project: Project,
|
||||
mainModule: MainModule,
|
||||
analyzer: AbstractAnalyzerWithCompilerReport,
|
||||
configuration: CompilerConfiguration,
|
||||
allDependencies: KotlinLibraryResolveResult,
|
||||
friendDependencies: List<KotlinLibrary>,
|
||||
irFactory: IrFactory,
|
||||
): IrModuleInfo {
|
||||
val depsDescriptors = ModulesStructure(project, mainModule, analyzer, configuration, allDependencies, friendDependencies)
|
||||
val errorPolicy = configuration.get(JSConfigurationKeys.ERROR_TOLERANCE_POLICY) ?: ErrorTolerancePolicy.DEFAULT
|
||||
val messageLogger = configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None
|
||||
|
||||
when (mainModule) {
|
||||
is MainModule.SourceFiles -> {
|
||||
val (psi2IrContext, _) = runAnalysisAndPreparePsi2Ir(depsDescriptors, irFactory, errorPolicy)
|
||||
val irBuiltIns = psi2IrContext.irBuiltIns
|
||||
val symbolTable = psi2IrContext.symbolTable
|
||||
val functionFactory = IrFunctionFactory(irBuiltIns, symbolTable)
|
||||
irBuiltIns.functionFactory = functionFactory
|
||||
val feContext = psi2IrContext.run {
|
||||
JsIrLinker.JsFePluginContext(moduleDescriptor, bindingContext, symbolTable, typeTranslator, irBuiltIns)
|
||||
}
|
||||
val irLinker = JsIrLinker(psi2IrContext.moduleDescriptor, messageLogger, irBuiltIns, symbolTable, functionFactory, feContext, null)
|
||||
val deserializedModuleFragments = sortDependencies(allDependencies.getFullList(), depsDescriptors.descriptors).map {
|
||||
irLinker.deserializeIrModuleHeader(depsDescriptors.getModuleDescriptor(it), it)
|
||||
}
|
||||
|
||||
val moduleFragment = psi2IrContext.generateModuleFragmentWithPlugins(project, mainModule.files, irLinker, messageLogger)
|
||||
symbolTable.noUnboundLeft("Unbound symbols left after linker")
|
||||
|
||||
// TODO: not sure whether this check should be enabled by default. Add configuration key for it.
|
||||
val mangleChecker = ManglerChecker(JsManglerIr, Ir2DescriptorManglerAdapter(JsManglerDesc))
|
||||
moduleFragment.acceptVoid(mangleChecker)
|
||||
|
||||
if (configuration.getBoolean(JSConfigurationKeys.FAKE_OVERRIDE_VALIDATOR)) {
|
||||
val fakeOverrideChecker = FakeOverrideChecker(JsManglerIr, JsManglerDesc)
|
||||
irLinker.modules.forEach { fakeOverrideChecker.check(it) }
|
||||
}
|
||||
|
||||
irBuiltIns.knownBuiltins.forEach { it.acceptVoid(mangleChecker) }
|
||||
|
||||
return IrModuleInfo(moduleFragment, deserializedModuleFragments, irBuiltIns, symbolTable, irLinker)
|
||||
}
|
||||
is MainModule.Klib -> {
|
||||
val moduleDescriptor = depsDescriptors.getModuleDescriptor(mainModule.lib)
|
||||
val mangler = JsManglerDesc
|
||||
val signaturer = IdSignatureDescriptor(mangler)
|
||||
val symbolTable = SymbolTable(signaturer, irFactory)
|
||||
val constantValueGenerator = ConstantValueGenerator(moduleDescriptor, symbolTable)
|
||||
val typeTranslator = TypeTranslator(
|
||||
symbolTable,
|
||||
depsDescriptors.compilerConfiguration.languageVersionSettings,
|
||||
builtIns = moduleDescriptor.builtIns
|
||||
)
|
||||
typeTranslator.constantValueGenerator = constantValueGenerator
|
||||
constantValueGenerator.typeTranslator = typeTranslator
|
||||
val irBuiltIns = IrBuiltIns(moduleDescriptor.builtIns, typeTranslator, symbolTable)
|
||||
val functionFactory = IrFunctionFactory(irBuiltIns, symbolTable)
|
||||
val irLinker =
|
||||
JsIrLinker(null, messageLogger, irBuiltIns, symbolTable, functionFactory, null, null)
|
||||
|
||||
val deserializedModuleFragments = sortDependencies(allDependencies.getFullList(), depsDescriptors.descriptors).map {
|
||||
val strategy =
|
||||
if (it == mainModule.lib)
|
||||
DeserializationStrategy.ALL
|
||||
else
|
||||
DeserializationStrategy.EXPLICITLY_EXPORTED
|
||||
|
||||
irLinker.deserializeIrModuleHeader(depsDescriptors.getModuleDescriptor(it), it, strategy)
|
||||
}
|
||||
irBuiltIns.functionFactory = functionFactory
|
||||
|
||||
val moduleFragment = deserializedModuleFragments.last()
|
||||
|
||||
irLinker.init(null, emptyList())
|
||||
ExternalDependenciesGenerator(symbolTable, listOf(irLinker)).generateUnboundSymbolsAsDependencies()
|
||||
irLinker.postProcess()
|
||||
|
||||
return IrModuleInfo(moduleFragment, deserializedModuleFragments, irBuiltIns, symbolTable, irLinker)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun runAnalysisAndPreparePsi2Ir(
|
||||
depsDescriptors: ModulesStructure,
|
||||
irFactory: IrFactory,
|
||||
errorIgnorancePolicy: ErrorTolerancePolicy
|
||||
): Pair<GeneratorContext, Boolean> {
|
||||
val analysisResult = depsDescriptors.runAnalysis(errorIgnorancePolicy)
|
||||
val psi2Ir = Psi2IrTranslator(
|
||||
depsDescriptors.compilerConfiguration.languageVersionSettings,
|
||||
Psi2IrConfiguration(errorIgnorancePolicy.allowErrors)
|
||||
)
|
||||
val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), irFactory)
|
||||
return psi2Ir.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext, symbolTable) to analysisResult.hasErrors
|
||||
}
|
||||
|
||||
fun GeneratorContext.generateModuleFragmentWithPlugins(
|
||||
project: Project,
|
||||
files: List<KtFile>,
|
||||
irLinker: IrDeserializer,
|
||||
messageLogger: IrMessageLogger,
|
||||
expectDescriptorToSymbol: MutableMap<DeclarationDescriptor, IrSymbol>? = null
|
||||
): IrModuleFragment {
|
||||
val psi2Ir = Psi2IrTranslator(languageVersionSettings, configuration)
|
||||
|
||||
val extensions = IrGenerationExtension.getInstances(project)
|
||||
|
||||
if (extensions.isNotEmpty()) {
|
||||
// plugin context should be instantiated before postprocessing steps
|
||||
val pluginContext = IrPluginContextImpl(
|
||||
moduleDescriptor,
|
||||
bindingContext,
|
||||
languageVersionSettings,
|
||||
symbolTable,
|
||||
typeTranslator,
|
||||
irBuiltIns,
|
||||
linker = irLinker,
|
||||
messageLogger
|
||||
)
|
||||
|
||||
for (extension in extensions) {
|
||||
psi2Ir.addPostprocessingStep { module ->
|
||||
extension.generate(module, pluginContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return psi2Ir.generateModuleFragment(this, files, listOf(irLinker), extensions, expectDescriptorToSymbol)
|
||||
}
|
||||
|
||||
private fun createBuiltIns(storageManager: StorageManager) = object : KotlinBuiltIns(storageManager) {}
|
||||
internal val JsFactories = KlibMetadataFactories(::createBuiltIns, DynamicTypeDeserializer)
|
||||
|
||||
fun getModuleDescriptorByLibrary(current: KotlinLibrary, mapping: Map<String, ModuleDescriptorImpl>): ModuleDescriptorImpl {
|
||||
val md = JsFactories.DefaultDeserializedDescriptorFactory.createDescriptorOptionalBuiltIns(
|
||||
current,
|
||||
LanguageVersionSettingsImpl.DEFAULT,
|
||||
LockBasedStorageManager.NO_LOCKS,
|
||||
null,
|
||||
packageAccessHandler = null, // TODO: This is a speed optimization used by Native. Don't bother for now.
|
||||
lookupTracker = LookupTracker.DO_NOTHING
|
||||
)
|
||||
// if (isBuiltIns) runtimeModule = md
|
||||
|
||||
val dependencies = current.manifestProperties.propertyList(KLIB_PROPERTY_DEPENDS, escapeInQuotes = true).map { mapping.getValue(it) }
|
||||
|
||||
md.setDependencies(listOf(md) + dependencies)
|
||||
return md
|
||||
}
|
||||
|
||||
sealed class MainModule {
|
||||
class SourceFiles(val files: List<KtFile>) : MainModule()
|
||||
class Klib(val lib: KotlinLibrary) : MainModule()
|
||||
}
|
||||
|
||||
private class ModulesStructure(
|
||||
private val project: Project,
|
||||
private val mainModule: MainModule,
|
||||
private val analyzer: AbstractAnalyzerWithCompilerReport,
|
||||
val compilerConfiguration: CompilerConfiguration,
|
||||
val allDependencies: KotlinLibraryResolveResult,
|
||||
private val friendDependencies: List<KotlinLibrary>
|
||||
) {
|
||||
val moduleDependencies: Map<KotlinLibrary, List<KotlinLibrary>> = run {
|
||||
val transitives = allDependencies.getFullResolvedList()
|
||||
transitives.associate { klib ->
|
||||
klib.library to klib.resolvedDependencies.map { d -> d.library }
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
val builtInsDep = allDependencies.getFullList().find { it.isBuiltIns }
|
||||
|
||||
class JsFrontEndResult(val moduleDescriptor: ModuleDescriptor, val bindingContext: BindingContext, val hasErrors: Boolean)
|
||||
|
||||
fun runAnalysis(errorPolicy: ErrorTolerancePolicy): JsFrontEndResult {
|
||||
require(mainModule is MainModule.SourceFiles)
|
||||
val files = mainModule.files
|
||||
|
||||
analyzer.analyzeAndReport(files) {
|
||||
TopDownAnalyzerFacadeForJSIR.analyzeFiles(
|
||||
files,
|
||||
project,
|
||||
compilerConfiguration,
|
||||
allDependencies.getFullList().map { getModuleDescriptor(it) },
|
||||
friendModuleDescriptors = friendDependencies.map { getModuleDescriptor(it) },
|
||||
thisIsBuiltInsModule = builtInModuleDescriptor == null,
|
||||
customBuiltInsModule = builtInModuleDescriptor
|
||||
)
|
||||
}
|
||||
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
|
||||
val analysisResult = analyzer.analysisResult
|
||||
if (IncrementalCompilation.isEnabledForJs()) {
|
||||
/** can throw [IncrementalNextRoundException] */
|
||||
compareMetadataAndGoToNextICRoundIfNeeded(analysisResult, compilerConfiguration, project, files, errorPolicy.allowErrors)
|
||||
}
|
||||
|
||||
var hasErrors = false
|
||||
if (analyzer.hasErrors() || analysisResult !is JsAnalysisResult) {
|
||||
if (!errorPolicy.allowErrors)
|
||||
throw AnalysisResult.CompilationErrorException()
|
||||
else hasErrors = true
|
||||
}
|
||||
|
||||
hasErrors = TopDownAnalyzerFacadeForJSIR.checkForErrors(files, analysisResult.bindingContext, errorPolicy) || hasErrors
|
||||
|
||||
return JsFrontEndResult(analysisResult.moduleDescriptor, analysisResult.bindingContext, hasErrors)
|
||||
}
|
||||
|
||||
private val languageVersionSettings: LanguageVersionSettings = compilerConfiguration.languageVersionSettings
|
||||
|
||||
private val storageManager: LockBasedStorageManager = LockBasedStorageManager("ModulesStructure")
|
||||
private var runtimeModule: ModuleDescriptorImpl? = null
|
||||
|
||||
// TODO: these are roughly equivalent to KlibResolvedModuleDescriptorsFactoryImpl. Refactor me.
|
||||
val descriptors = mutableMapOf<KotlinLibrary, ModuleDescriptorImpl>()
|
||||
|
||||
fun getModuleDescriptor(current: KotlinLibrary): ModuleDescriptorImpl = descriptors.getOrPut(current) {
|
||||
val isBuiltIns = current.unresolvedDependencies.isEmpty()
|
||||
|
||||
val lookupTracker = compilerConfiguration[CommonConfigurationKeys.LOOKUP_TRACKER] ?: LookupTracker.DO_NOTHING
|
||||
val md = JsFactories.DefaultDeserializedDescriptorFactory.createDescriptorOptionalBuiltIns(
|
||||
current,
|
||||
languageVersionSettings,
|
||||
storageManager,
|
||||
runtimeModule?.builtIns,
|
||||
packageAccessHandler = null, // TODO: This is a speed optimization used by Native. Don't bother for now.
|
||||
lookupTracker = lookupTracker
|
||||
)
|
||||
if (isBuiltIns) runtimeModule = md
|
||||
|
||||
val dependencies = moduleDependencies.getValue(current).map { getModuleDescriptor(it) }
|
||||
md.setDependencies(listOf(md) + dependencies)
|
||||
md
|
||||
}
|
||||
|
||||
val builtInModuleDescriptor =
|
||||
if (builtInsDep != null)
|
||||
getModuleDescriptor(builtInsDep)
|
||||
else
|
||||
null // null in case compiling builtInModule itself
|
||||
}
|
||||
|
||||
private fun getDescriptorForElement(
|
||||
context: BindingContext,
|
||||
@@ -466,12 +85,13 @@ fun serializeModuleIntoKlib(
|
||||
configuration: CompilerConfiguration,
|
||||
messageLogger: IrMessageLogger,
|
||||
bindingContext: BindingContext,
|
||||
files: List<KtFile>,
|
||||
files: Collection<KtFile>,
|
||||
klibPath: String,
|
||||
dependencies: List<KotlinLibrary>,
|
||||
moduleFragment: IrModuleFragment,
|
||||
expectDescriptorToSymbol: MutableMap<DeclarationDescriptor, IrSymbol>,
|
||||
cleanFiles: List<KotlinFileSerializedData>,
|
||||
incrementalResultsConsumer: IncrementalResultsConsumer?,
|
||||
nopack: Boolean,
|
||||
perFile: Boolean,
|
||||
containsErrorCode: Boolean = false
|
||||
@@ -489,7 +109,6 @@ fun serializeModuleIntoKlib(
|
||||
val moduleDescriptor = moduleFragment.descriptor
|
||||
val metadataSerializer = KlibMetadataIncrementalSerializer(configuration, project, containsErrorCode)
|
||||
|
||||
val incrementalResultsConsumer = configuration.get(JSConfigurationKeys.INCREMENTAL_RESULTS_CONSUMER)
|
||||
val empty = ByteArray(0)
|
||||
|
||||
fun processCompiledFileData(ioFile: File, compiledFile: KotlinFileSerializedData) {
|
||||
@@ -565,7 +184,7 @@ fun serializeModuleIntoKlib(
|
||||
)
|
||||
}
|
||||
|
||||
private fun KlibMetadataIncrementalSerializer.serializeScope(
|
||||
fun KlibMetadataIncrementalSerializer.serializeScope(
|
||||
ktFile: KtFile,
|
||||
bindingContext: BindingContext,
|
||||
moduleDescriptor: ModuleDescriptor
|
||||
@@ -574,27 +193,9 @@ private fun KlibMetadataIncrementalSerializer.serializeScope(
|
||||
return serializePackageFragment(moduleDescriptor, memberScope, ktFile.packageFqName)
|
||||
}
|
||||
|
||||
private fun compareMetadataAndGoToNextICRoundIfNeeded(
|
||||
analysisResult: AnalysisResult,
|
||||
config: CompilerConfiguration,
|
||||
project: Project,
|
||||
files: List<KtFile>,
|
||||
allowErrors: Boolean
|
||||
) {
|
||||
val nextRoundChecker = config.get(JSConfigurationKeys.INCREMENTAL_NEXT_ROUND_CHECKER) ?: return
|
||||
val bindingContext = analysisResult.bindingContext
|
||||
val serializer = KlibMetadataIncrementalSerializer(config, project, allowErrors)
|
||||
for (ktFile in files) {
|
||||
val packageFragment = serializer.serializeScope(ktFile, bindingContext, analysisResult.moduleDescriptor)
|
||||
// to minimize a number of IC rounds, we should inspect all proto for changes first,
|
||||
// then go to a next round if needed, with all new dirty files
|
||||
nextRoundChecker.checkProtoChanges(VfsUtilCore.virtualToIoFile(ktFile.virtualFile), packageFragment.toByteArray())
|
||||
}
|
||||
|
||||
if (nextRoundChecker.shouldGoToNextRound()) throw IncrementalNextRoundException()
|
||||
}
|
||||
|
||||
private fun KlibMetadataIncrementalSerializer(configuration: CompilerConfiguration, project: Project, allowErrors: Boolean) = KlibMetadataIncrementalSerializer(
|
||||
fun KlibMetadataIncrementalSerializer(configuration: CompilerConfiguration, project: Project, allowErrors: Boolean) = KlibMetadataIncrementalSerializer(
|
||||
languageVersionSettings = configuration.languageVersionSettings,
|
||||
metadataVersion = configuration.metadataVersion,
|
||||
project = project,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user