Compare commits

...

67 Commits

Author SHA1 Message Date
Roman Artemev
5fd956041a ~~ disable ts export check in PIR mode 2021-03-01 17:09:38 +03:00
Roman Artemev
83cd5dcc45 ~~ refactored compile entry points 2021-02-26 18:29:43 +03:00
Roman Artemev
e9731131ea ~~wip cache invalidator main loop 2021-02-24 15:20:02 +03:00
Roman Artemev
5224ff9ae2 ~~wip cache invalidator 2021-02-19 17:01:12 +03:00
Dmitriy Novozhilov
d40777c28f [FIR] Fix calculating arguments of bare type with intersection type as base 2021-02-19 16:23:24 +03:00
Alexander Udalov
56f9e3360f JVM IR: do not generate invokeinterface hashCode if smart cast is present
#KT-45008 Fixed
2021-02-19 14:21:54 +01:00
Tianyu Geng
56854a8b1a FIR IDE: register quickfix for the following
1. NON_ABSTRACT_FUNCTION_WITH_NO_BODY
  2. ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS
  3. ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS
2021-02-19 13:16:42 +01:00
Dmitriy Novozhilov
88c43e7f7b [FE] Assume that effective visibility of sealed class constructor is internal
#KT-45033 Fixed
#KT-45043
2021-02-19 14:06:49 +03:00
Ilya Kirillov
b08eb6cf4c FIR IDE: specify behaviour of HL API getOverriddenSymbols
- Split it into two functions getAllOverriddenSymbols and getDirectlyOverriddenSymbols
- Implement tests for getOverriddenSymbols
- temporary mute inheritance.kt light classes test
2021-02-19 11:49:57 +01:00
Ilya Kirillov
804df1aec2 FIR IDE: introduce base class for multifile tests 2021-02-19 11:49:56 +01:00
Dmitriy Novozhilov
3626008ed2 [Inference] Add ability to approximate local types in AbstractTypeApproximator 2021-02-19 12:47:27 +03:00
Mikhail Glukhikh
73616107b4 Unmute passing FIR BB test 2021-02-19 12:19:42 +03:00
Dmitry Petrov
c629ba5a3c JVM_IR indy-SAM: function reference to Java interface 2021-02-19 12:04:30 +03:00
Mikhail Glukhikh
357a7907a3 FIR: fix type approximation by visibility 2021-02-19 10:39:57 +03:00
Roman Golyshev
74bdb2398e FIR: Get rid of PSI dependency in the :fir:resolve module 2021-02-19 07:20:06 +00:00
Tianyu Geng
6b453d9b23 FIR: implement checker for open members
Specifically,

1. NON_FINAL_MEMBER_IN_FINAL_CLASS
2. NON_FINAL_MEMBER_IN_OBJECT
2021-02-19 10:17:18 +03:00
Mikhail Glukhikh
3e9ff3ecda FIR: report SUPERTYPE_NOT_A_CLASS_OR_INTERFACE on type parameters 2021-02-19 10:17:17 +03:00
Jinseong Jeon
e67eb0c123 FIR checker: typed declaration's return type should be resolved
except for those in function contracts
2021-02-19 10:17:17 +03:00
Jinseong Jeon
5f9357eb41 FIR: transform implicit type ref in anonymous function arguments & body
^KT-45010 Fixed
2021-02-19 10:17:16 +03:00
Jinseong Jeon
a841a0bbca FIR: transform other parts of function call even though callee is an error 2021-02-19 10:17:16 +03:00
Jinseong Jeon
27c942a0ff FIR: enforce the return type of function literals without body
Its return type should be Unit, so do not use the expected type from,
e.g., parameter type.
2021-02-19 10:17:16 +03:00
Jinseong Jeon
9aaa952b39 FIR: regard implicit type for value parameter after body resolve as an error type 2021-02-19 10:17:16 +03:00
Jinseong Jeon
fbb19e3b50 FIR: ensure type ref transformed by type resolve transformer is resolved 2021-02-19 10:17:15 +03:00
Jinseong Jeon
52ea7fdb72 FIR: ensure type ref after supertype resolve transformer is resolved 2021-02-19 10:17:15 +03:00
Vladimir Dolzhenko
8783ebc352 Report highlight errors to WolfTheProblemSolver
Relates to #KT-37702
#KTIJ-1246 Fixed

Original commit: bd222a5255c2fd6f4abfce3115f81733ef9a39f3
2021-02-19 05:46:04 +00:00
tgeng
afe71f5d59 FIR: Add runConfig to generate FIR boilerplate (#4130)
* FIR: Add runConfig to generate FIR boilerplate

* FIR: Add runConfig to generate FIR boilerplate
2021-02-18 23:26:10 +01:00
Tianyu Geng
51da54ce66 FIR IDE: Simplify registerPsiQuickFixes
This change makes it possible to register multiple fixes for a
diagnostic. Also, the previous registerPsiQuickFix that relies compiler
to infer the KtFirDiagnostic type parameter is dangerous since it
can silently register fixes on interface `KtDiagnosticWithPsi` if caller
doesn't specify it explicitly.
2021-02-18 19:37:37 +01:00
Ilmir Usmanov
cacd84390e Use erased upper bound instead of checking for inline type 2021-02-18 18:31:50 +01:00
Ilmir Usmanov
741c1a864f JVM_IR: IC: Unbox inline class argument of callable reference
if it is unbound and the underlying type is reference type.
If the underlying type is primitive, it is boxed and unboxed
correctly, otherwise, it is simply casted and not unboxed.
Additionally, generate functions for inliner with inline classes
in signature, so unboxing works.
The unboxing is removed after inlining.
 #KT-44722 Fixed
2021-02-18 18:31:48 +01:00
Dmitry Petrov
744a0fcd25 PSI2IR KT-45022 object in LHS of compound assignment 2021-02-18 20:24:16 +03:00
Dmitriy Dolovov
05447ce0c8 [Commonizer] Print true time for resolving of libraries to be commonized 2021-02-18 18:47:38 +03:00
Dmitriy Dolovov
0b26a281de [Commonizer] Print pretty target name in console output 2021-02-18 18:47:33 +03:00
Dmitriy Dolovov
fb51105a5d [Commonizer] Log time in commonizer result consumers 2021-02-18 18:47:28 +03:00
Dmitriy Dolovov
496aad3c4a [Commonizer] Log commonization only for really present targets 2021-02-18 18:47:19 +03:00
Dmitriy Dolovov
3ad7b60747 [Commonizer] Prefer using CommonizerTarget instead of KonanTarget 2021-02-18 18:47:14 +03:00
Dmitriy Dolovov
1895c230ef [Commonizer] K/N dist: Process targets in alphabetical order 2021-02-18 18:47:10 +03:00
Dmitriy Dolovov
f473b88e47 [Commonizer] Nicer API for CirProvidedClassifiers 2021-02-18 18:47:05 +03:00
Dmitriy Dolovov
84ce9c612c [Commonizer] Keep only "common" dependencies in CirKnownClassifiers 2021-02-18 18:47:00 +03:00
Dmitriy Dolovov
2581b67cda [Commonizer] Rename: CirCommonizedClassifiers -> CirCommonizedClassifierNodes 2021-02-18 18:46:55 +03:00
Dmitriy Dolovov
43ad0ed907 [Commonizer] Optimized implementation of CirProvidedClassifiers
Read classifiers directly from metadata, don't use descriptors.
2021-02-18 18:46:49 +03:00
Dmitriy Dolovov
79e3ce022f [Commonizer] Fix: Keep fwd declarations under real names in CirForwardDeclarations cache 2021-02-18 18:46:45 +03:00
Anton Bannykh
bc9a791809 Refactor klib serializer/deserializer 2021-02-18 18:03:41 +03:00
Victor Petukhov
ad9fd7ecf3 KotlinBinaryClassCache: clean-up request caches for all threads
^KT-44550 Fixed
2021-02-18 17:05:59 +03:00
Alexander Dudinsky
5cbbbc3b83 Fix artifacts needed for the kotlin-gradle-plugin 2021-02-18 16:50:52 +03:00
Alexander Dudinsky
33313ae4b4 Fix artifacts needed for the kotlin-gradle-plugin 2021-02-18 16:47:22 +03:00
Sergey Shanshin
8c20c655fe Updated bytecode of serialization for IR
`shouldEncodeElementDefault` now checked before evaluating default value
2021-02-18 15:03:35 +03:00
Dmitriy Novozhilov
7b7b8fbea7 [Test] Filter dependent modules by source kind in creating FirModuleInfo 2021-02-18 14:44:44 +03:00
Alexander Udalov
8c95b78346 Update JVM metadata version to 1.5.0
Improve the test which checks that we use correct metadata version if
`-language-version` is passed by checking all supported language
versions.

The change in libraries/reflect/build.gradle.kts is needed because
kotlinx-metadata-jvm of version 0.1.0 is based on pre-1.4 Kotlin, which
doesn't support the new module file metadata generated with metadata
version 1.4 and later, and module files need to be readable there to be
able to transform them for the shadow plugin.

Similarly override dependency on kotlinx-metadata-jvm in the
binary-compatibility-validator module.
2021-02-18 12:42:23 +01:00
Alexander Udalov
dbadd5846a Add test for script flag in kotlin.Metadata
It passes at the moment because the test uses old backend, but the
required behavior is not yet supported in JVM IR, and it'll need to be
fixed.
2021-02-18 12:36:54 +01:00
Alexander Udalov
1d6b198915 Build: suppress version and JVM target warnings
To further reduce the output on each build.
2021-02-18 12:17:17 +01:00
Alexander Udalov
49fc1b9e3e Build: enable -Werror for several modules 2021-02-18 12:14:09 +01:00
Hyojae Kim
82ac482143 Fix typo (#4051)
Fix typo
2021-02-18 12:28:19 +03:00
Alexander Dudinsky
a3fa6c6d13 Publish artifacts needed for the kotlin-gradle-plugin in kotlin-ide repository 2021-02-18 11:51:32 +03:00
Dmitriy Novozhilov
9b4949a3c5 [FIR] Fix taking symbol of expression with smartcast inside DFA 2021-02-18 10:10:38 +03:00
Alexander Udalov
adb05ab076 JVM IR: write inherited multifile parts flag to kotlin.Metadata
This flag is unused at the moment, but might be used one day to support
proper incremental compilation for multifile classes.
2021-02-17 21:56:18 +01:00
sebastian.sellmair
35008df969 [Commonizer] Rename NativeDistributionCommonizer to LibraryCommonizer 2021-02-17 19:24:54 +00:00
sebastian.sellmair
4500b6ce74 [Commonizer] Implement :native:kotlin-klib-commonizer:api with support for library commonization
- Implement new Gradle module ':native:kotlin-klib-commonizer'
- Implement new NativeKlibCommonize task
- Implement CommonizerTarget.identityString
2021-02-17 19:24:54 +00:00
Dmitry Petrov
6d019d9544 JVM_IR indy-SAM on functional expression 2021-02-17 22:18:06 +03:00
Mikhael Bogdanov
134fda8bad Support Unit/V types in string-concat indy calls
unitComponent.kt test fails with JVM target 9+
2021-02-17 18:43:24 +01:00
Mikhael Bogdanov
e3e7e6b740 Make indy-with-constants default for -jvm-target 9+
#KT-42522 Fixed
2021-02-17 18:43:23 +01:00
Mikhael Bogdanov
3d8e8dd3ba Fail on compilation errors in AbstractBytecodeTextTest 2021-02-17 18:43:23 +01:00
Mikhael Bogdanov
61fce74b76 Support new targets in KotlinBytecodeToolWindow
#KT-30222 Fixed
2021-02-17 18:43:23 +01:00
Sergey Shanshin
91f1cb88c1 Support serialization of java enum classes in IR
Fixes Kotlin/kotlinx.serialization#1334
2021-02-17 20:24:31 +03:00
Tianyu Geng
652207dcac FIR IDE: add AddModifierFix 2021-02-17 18:19:27 +01:00
Tianyu Geng
5793f77ece FIR IDE: AddModifierFix -> AddModifierFixMpp 2021-02-17 18:19:27 +01:00
Sergey Shanshin
de06a69b12 Added external serializers in serialization plugin for IR backend
- added fallback support of external serializers in IR
- implemented calculations of properties default values in IR
- swapped check of shouldEncodeElementDefault and comparing the property with default value in IR. Now default value calculated only of shouldEncodeElementDefault returns false
2021-02-17 20:16:34 +03:00
Tianyu Geng
66f00a2eb5 FIR IDE: move AddFunctionBodyFix to fe-independent 2021-02-17 18:14:10 +01:00
469 changed files with 11420 additions and 4544 deletions

View 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>

View File

@@ -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(

View File

@@ -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")

View File

@@ -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(

View File

@@ -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)

View File

@@ -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"
)
}
}

View File

@@ -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)

View File

@@ -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()) {

View File

@@ -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
)
}

View File

@@ -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"))

View File

@@ -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)

View File

@@ -50,6 +50,7 @@ dependencies {
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
kotlinOptions {
apiVersion = "1.3"
freeCompilerArgs += "-Xsuppress-version-warnings"
}
}

View File

@@ -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"
}
}

View File

@@ -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")

View File

@@ -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|

View File

@@ -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>| {

View File

@@ -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| {

View File

@@ -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| {

View File

@@ -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'))
}
)
}

View File

@@ -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'<!>)<!>
}
}
}

View File

@@ -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|
}

View File

@@ -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!
}

View File

@@ -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() {

View File

@@ -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| {

View 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|()
}
}
}

View File

@@ -0,0 +1,12 @@
interface A {
fun foo()
}
fun Any.test() {
if (this is A) {
val a = this
a.foo()
}
}

View File

@@ -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|>()
}

View File

@@ -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<!>

View 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|)
}

View 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)
}

View File

@@ -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| {

View File

@@ -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

View File

@@ -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

View File

@@ -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 {

View File

@@ -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") {

View File

@@ -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>()

View File

@@ -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>()

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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"

View File

@@ -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}")
}

View File

@@ -39,6 +39,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
override val classCheckers: Set<FirClassChecker> = setOf(
FirOverrideChecker,
FirThrowableSubclassChecker,
FirOpenMemberChecker,
)
override val regularClassCheckers: Set<FirRegularClassChecker> = setOf(

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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()
}
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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(

View File

@@ -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?

View File

@@ -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
}

View File

@@ -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>

View File

@@ -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)
}

View File

@@ -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()
}

View File

@@ -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))

View File

@@ -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(

View File

@@ -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()
}

View File

@@ -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
}
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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)
// }
//}

View File

@@ -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"))

View File

@@ -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())

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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())
}

View File

@@ -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()

View File

@@ -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)

View File

@@ -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()}")
}
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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()}"
}
)

View File

@@ -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)
}
}
}
}

View File

@@ -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
)
}
}

View File

@@ -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()

View File

@@ -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"))

View File

@@ -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;
},

View 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" {}
}

View File

@@ -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
)
}
}

View File

@@ -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)
}
}

View File

@@ -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,

View File

@@ -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 ->

View File

@@ -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

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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

View File

@@ -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 }
}
}

View File

@@ -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
}
}
}

View File

@@ -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'

View File

@@ -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}")
}
}
}

View File

@@ -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)
}
}

View File

@@ -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") }
}

View File

@@ -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
//// }
//
//}

View File

@@ -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