mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-22 15:51:33 +00:00
Compare commits
6 Commits
entry_poin
...
java6-Xint
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d48a7a55c6 | ||
|
|
30639af5a3 | ||
|
|
3add3f091d | ||
|
|
4583e31991 | ||
|
|
f49fe26632 | ||
|
|
73ec5d27a6 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -58,7 +58,7 @@ build/
|
||||
.idea/artifacts/kotlin_stdlib_wasm_*
|
||||
.idea/jarRepositories.xml
|
||||
.idea/csv-plugin.xml
|
||||
.idea/libraries-with-intellij-classes.xml
|
||||
kotlin-ultimate/
|
||||
node_modules/
|
||||
.rpt2_cache/
|
||||
libraries/tools/kotlin-test-js-runner/lib/
|
||||
|
||||
12
.idea/vcs.xml
generated
12
.idea/vcs.xml
generated
@@ -8,18 +8,6 @@
|
||||
<inspection_tool class="SubjectLimit" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
<component name="GithubSharedProjectSettings">
|
||||
<option name="branchProtectionPatterns">
|
||||
<list>
|
||||
<option value="master" />
|
||||
<option value="1\.5\.0-M2" />
|
||||
<option value="1\.5\.0" />
|
||||
<option value="1\.5\.20" />
|
||||
<option value="1\.5\.20-M1-release" />
|
||||
<option value="1\.5\.20-RC-release" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="IssueNavigationConfiguration">
|
||||
<option name="links">
|
||||
<list>
|
||||
|
||||
@@ -23,6 +23,9 @@ dependencies {
|
||||
testCompile(commonDep("junit:junit"))
|
||||
testCompile(protobufFull())
|
||||
testCompile(kotlinStdlib())
|
||||
Platform[193].orLower {
|
||||
testCompileOnly(intellijDep()) { includeJars("openapi", rootProject = rootProject) }
|
||||
}
|
||||
testRuntime(project(":kotlin-reflect"))
|
||||
}
|
||||
|
||||
|
||||
@@ -30,10 +30,11 @@ buildscript {
|
||||
dependencies {
|
||||
bootstrapCompilerClasspath(kotlin("compiler-embeddable", bootstrapKotlinVersion))
|
||||
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.30")
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.29")
|
||||
classpath(kotlin("gradle-plugin", bootstrapKotlinVersion))
|
||||
classpath(kotlin("serialization", bootstrapKotlinVersion))
|
||||
classpath("org.jetbrains.dokka:dokka-gradle-plugin:0.9.17")
|
||||
classpath("org.jfrog.buildinfo:build-info-extractor-gradle:4.17.2")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,8 +89,10 @@ val distKotlinHomeDir by extra("$distDir/kotlinc")
|
||||
val distLibDir = "$distKotlinHomeDir/lib"
|
||||
val commonLocalDataDir = "$rootDir/local"
|
||||
val ideaSandboxDir = "$commonLocalDataDir/ideaSandbox"
|
||||
val ideaUltimateSandboxDir = "$commonLocalDataDir/ideaUltimateSandbox"
|
||||
val artifactsDir = "$distDir/artifacts"
|
||||
val ideaPluginDir = "$artifactsDir/ideaPlugin/Kotlin"
|
||||
val ideaUltimatePluginDir = "$artifactsDir/ideaUltimatePlugin/Kotlin"
|
||||
|
||||
extra["ktorExcludesForDaemon"] = listOf(
|
||||
"org.jetbrains.kotlin" to "kotlin-reflect",
|
||||
@@ -107,7 +110,9 @@ extra["distLibDir"] = project.file(distLibDir)
|
||||
extra["libsDir"] = project.file(distLibDir)
|
||||
extra["commonLocalDataDir"] = project.file(commonLocalDataDir)
|
||||
extra["ideaSandboxDir"] = project.file(ideaSandboxDir)
|
||||
extra["ideaUltimateSandboxDir"] = project.file(ideaUltimateSandboxDir)
|
||||
extra["ideaPluginDir"] = project.file(ideaPluginDir)
|
||||
extra["ideaUltimatePluginDir"] = project.file(ideaUltimatePluginDir)
|
||||
extra["isSonatypeRelease"] = false
|
||||
val kotlinNativeVersionObject = project.kotlinNativeVersionValue()
|
||||
subprojects {
|
||||
@@ -186,9 +191,10 @@ extra["versions.kotlinx-collections-immutable-jvm"] = immutablesVersion
|
||||
extra["versions.ktor-network"] = "1.0.1"
|
||||
|
||||
if (!project.hasProperty("versions.kotlin-native")) {
|
||||
extra["versions.kotlin-native"] = "1.5.30-dev-1916"
|
||||
extra["versions.kotlin-native"] = "1.5.20-dev-5613"
|
||||
}
|
||||
|
||||
val intellijUltimateEnabled by extra(project.kotlinBuildProperties.intellijUltimateEnabled)
|
||||
val effectSystemEnabled by extra(project.getBooleanProperty("kotlin.compiler.effectSystemEnabled") ?: false)
|
||||
val newInferenceEnabled by extra(project.getBooleanProperty("kotlin.compiler.newInferenceEnabled") ?: false)
|
||||
val useJvmIrBackend by extra(project.kotlinBuildProperties.useIR)
|
||||
@@ -200,11 +206,15 @@ extra["intellijSeparateSdks"] = intellijSeparateSdks
|
||||
|
||||
extra["IntellijCoreDependencies"] =
|
||||
listOf(
|
||||
"asm-all-8.0.1",
|
||||
when {
|
||||
Platform[202].orHigher() -> "asm-all-8.0.1"
|
||||
else -> "asm-all-7.0.1"
|
||||
},
|
||||
"guava",
|
||||
"jdom",
|
||||
"jna",
|
||||
"log4j",
|
||||
if (Platform[201].orHigher()) null else "picocontainer",
|
||||
"snappy-in-java",
|
||||
"streamex",
|
||||
"trove4j"
|
||||
@@ -332,7 +342,6 @@ extra["compilerArtifactsForIde"] = listOf(
|
||||
":prepare:ide-plugin-dependencies:parcelize-compiler-plugin-for-ide",
|
||||
":prepare:ide-plugin-dependencies:lombok-compiler-plugin-for-ide",
|
||||
":prepare:ide-plugin-dependencies:kotlin-compiler-tests-for-ide",
|
||||
":prepare:ide-plugin-dependencies:kotlin-compiler-testdata-for-ide",
|
||||
":kotlin-script-runtime",
|
||||
":kotlin-script-util",
|
||||
":kotlin-scripting-common",
|
||||
@@ -354,7 +363,6 @@ extra["tasksWithWarnings"] = listOf(
|
||||
":kotlin-stdlib-jdk7:compileTestKotlin",
|
||||
":kotlin-stdlib-jdk8:compileTestKotlin",
|
||||
":plugins:uast-kotlin-base:compileKotlin",
|
||||
":plugins:uast-kotlin-base:compileTestKotlin",
|
||||
":plugins:uast-kotlin:compileKotlin",
|
||||
":plugins:uast-kotlin:compileTestKotlin",
|
||||
":plugins:uast-kotlin-fir:compileKotlin",
|
||||
@@ -572,8 +580,6 @@ allprojects {
|
||||
register("checkBuild")
|
||||
}
|
||||
|
||||
apply(from = "$rootDir/gradle/cacheRedirector.gradle.kts")
|
||||
|
||||
afterEvaluate {
|
||||
if (javaHome != defaultJavaHome || jvmTarget != defaultJvmTarget) {
|
||||
logger.info("configuring project $name to compile to the target jvm version $jvmTarget using jdk: $javaHome")
|
||||
@@ -608,6 +614,7 @@ allprojects {
|
||||
?.exclude("org.jetbrains.kotlin", "kotlin-scripting-compiler-embeddable")
|
||||
}
|
||||
|
||||
apply(from = "$rootDir/gradle/cacheRedirector.gradle.kts")
|
||||
apply(from = "$rootDir/gradle/testRetry.gradle.kts")
|
||||
}
|
||||
}
|
||||
@@ -942,6 +949,22 @@ tasks {
|
||||
)
|
||||
}
|
||||
|
||||
register("kmmTest", AggregateTest::class) {
|
||||
dependsOn(
|
||||
":idea:idea-gradle:test",
|
||||
":idea:test",
|
||||
":compiler:test",
|
||||
":compiler:container:test",
|
||||
":js:js.tests:test"
|
||||
)
|
||||
|
||||
dependsOn(":kotlin-gradle-plugin-integration-tests:test")
|
||||
if (Ide.AS40.orHigher())
|
||||
dependsOn(":kotlin-ultimate:ide:android-studio-native:test")
|
||||
|
||||
testPatternFile = file("tests/mpp/kmm-patterns.csv")
|
||||
}
|
||||
|
||||
register("test") {
|
||||
doLast {
|
||||
throw GradleException("Don't use directly, use aggregate tasks *-check instead")
|
||||
@@ -1026,7 +1049,8 @@ val zipTestData by task<Zip> {
|
||||
val zipPlugin by task<Zip> {
|
||||
val src = when (project.findProperty("pluginArtifactDir") as String?) {
|
||||
"Kotlin" -> ideaPluginDir
|
||||
null -> ideaPluginDir
|
||||
"KotlinUltimate" -> ideaUltimatePluginDir
|
||||
null -> if (project.hasProperty("ultimate")) ideaUltimatePluginDir else ideaPluginDir
|
||||
else -> error("Unsupported plugin artifact dir")
|
||||
}
|
||||
val destPath = project.findProperty("pluginZipPath") as String?
|
||||
|
||||
@@ -22,7 +22,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.30")
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.29")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${project.bootstrapKotlinVersion}")
|
||||
classpath("org.jetbrains.kotlin:kotlin-sam-with-receiver:${project.bootstrapKotlinVersion}")
|
||||
}
|
||||
@@ -69,6 +69,7 @@ rootProject.apply {
|
||||
}
|
||||
|
||||
val isTeamcityBuild = kotlinBuildProperties.isTeamcityBuild
|
||||
val intellijUltimateEnabled by extra(kotlinBuildProperties.intellijUltimateEnabled)
|
||||
val intellijSeparateSdks by extra(project.getBooleanProperty("intellijSeparateSdks") ?: false)
|
||||
|
||||
extra["intellijReleaseType"] = when {
|
||||
@@ -143,7 +144,7 @@ java {
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib", embeddedKotlinVersion))
|
||||
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${project.bootstrapKotlinVersion}")
|
||||
implementation("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.30")
|
||||
implementation("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.29")
|
||||
implementation("com.gradle.publish:plugin-publish-plugin:0.14.0")
|
||||
|
||||
implementation("net.rubygrapefruit:native-platform:${property("versions.native-platform")}")
|
||||
|
||||
@@ -15,6 +15,7 @@ plugins {
|
||||
base
|
||||
}
|
||||
|
||||
val intellijUltimateEnabled: Boolean by rootProject.extra
|
||||
val intellijReleaseType: String by rootProject.extra
|
||||
val intellijVersion = rootProject.extra["versions.intellijSdk"] as String
|
||||
val intellijVersionForIde = rootProject.intellijSdkVersionForIde()
|
||||
@@ -22,6 +23,8 @@ val asmVersion = rootProject.findProperty("versions.jar.asm-all") as String?
|
||||
val androidStudioRelease = rootProject.findProperty("versions.androidStudioRelease") as String?
|
||||
val androidStudioBuild = rootProject.findProperty("versions.androidStudioBuild") as String?
|
||||
val intellijSeparateSdks: Boolean by rootProject.extra
|
||||
val installIntellijCommunity = !intellijUltimateEnabled || intellijSeparateSdks
|
||||
val installIntellijUltimate = intellijUltimateEnabled && androidStudioRelease == null
|
||||
|
||||
fun checkIntellijVersion(intellijVersion: String) {
|
||||
val intellijVersionDelimiterIndex = intellijVersion.indexOfAny(charArrayOf('.', '-'))
|
||||
@@ -32,11 +35,14 @@ fun checkIntellijVersion(intellijVersion: String) {
|
||||
checkIntellijVersion(intellijVersion)
|
||||
intellijVersionForIde?.let { checkIntellijVersion(it) }
|
||||
|
||||
logger.info("intellijUltimateEnabled: $intellijUltimateEnabled")
|
||||
logger.info("intellijVersion: $intellijVersion")
|
||||
logger.info("intellijVersionForIde: $intellijVersionForIde")
|
||||
logger.info("androidStudioRelease: $androidStudioRelease")
|
||||
logger.info("androidStudioBuild: $androidStudioBuild")
|
||||
logger.info("intellijSeparateSdks: $intellijSeparateSdks")
|
||||
logger.info("installIntellijCommunity: $installIntellijCommunity")
|
||||
logger.info("installIntellijUltimate: $installIntellijUltimate")
|
||||
|
||||
val androidStudioOs by lazy {
|
||||
when {
|
||||
@@ -72,6 +78,8 @@ repositories {
|
||||
|
||||
val intellij by configurations.creating
|
||||
val intellijForIde by configurations.creating
|
||||
val intellijUltimate by configurations.creating
|
||||
val intellijUltimateForIde by configurations.creating
|
||||
val androidStudio by configurations.creating
|
||||
val sources by configurations.creating
|
||||
val sourcesForIde by configurations.creating
|
||||
@@ -105,8 +113,14 @@ dependencies {
|
||||
|
||||
androidStudio("google:android-studio-ide:$androidStudioBuild@$extension")
|
||||
} else {
|
||||
intellij("com.jetbrains.intellij.idea:ideaIC:$intellijVersion")
|
||||
intellijVersionForIde?.let { intellijForIde("com.jetbrains.intellij.idea:ideaIC:$it") }
|
||||
if (installIntellijCommunity) {
|
||||
intellij("com.jetbrains.intellij.idea:ideaIC:$intellijVersion")
|
||||
intellijVersionForIde?.let { intellijForIde("com.jetbrains.intellij.idea:ideaIC:$it") }
|
||||
}
|
||||
if (installIntellijUltimate) {
|
||||
intellijUltimate("com.jetbrains.intellij.idea:ideaIU:$intellijVersion")
|
||||
intellijVersionForIde.let { intellijUltimateForIde("com.jetbrains.intellij.idea:ideaIU:$it") }
|
||||
}
|
||||
}
|
||||
|
||||
if (asmVersion != null) {
|
||||
@@ -119,15 +133,12 @@ dependencies {
|
||||
intellijVersionForIde?.let { jpsStandaloneForIde("com.jetbrains.intellij.idea:jps-standalone:$it") }
|
||||
intellijCore("com.jetbrains.intellij.idea:intellij-core:$intellijVersion")
|
||||
intellijVersionForIde?.let { intellijCoreForIde("com.jetbrains.intellij.idea:intellij-core:$it") }
|
||||
if (intellijUltimateEnabled) {
|
||||
nodeJSPlugin("com.jetbrains.plugins:NodeJS:${rootProject.extra["versions.idea.NodeJS"]}@zip")
|
||||
}
|
||||
}
|
||||
|
||||
fun prepareDeps(
|
||||
intellij: Configuration,
|
||||
intellijCore: Configuration,
|
||||
sources: Configuration,
|
||||
jpsStandalone: Configuration,
|
||||
intellijVersion: String
|
||||
) {
|
||||
fun prepareDeps(intellij: Configuration, intellijCore: Configuration, sources: Configuration, intellijUltimate: Configuration, jpsStandalone: Configuration, intellijVersion: String) {
|
||||
val makeIntellijCore = buildIvyRepositoryTask(intellijCore, customDepsOrg, customDepsRepoDir)
|
||||
|
||||
val makeIntellijAnnotations = tasks.register("makeIntellijAnnotations${intellij.name.capitalize()}", Copy::class) {
|
||||
@@ -188,7 +199,11 @@ fun prepareDeps(
|
||||
::skipToplevelDirectory
|
||||
)
|
||||
} else {
|
||||
val task = buildIvyRepositoryTask(intellij, customDepsOrg, customDepsRepoDir, null, sourcesFile)
|
||||
val task = if (installIntellijUltimate) {
|
||||
buildIvyRepositoryTask(intellijUltimate, customDepsOrg, customDepsRepoDir, null, sourcesFile)
|
||||
} else {
|
||||
buildIvyRepositoryTask(intellij, customDepsOrg, customDepsRepoDir, null, sourcesFile)
|
||||
}
|
||||
|
||||
task.configure {
|
||||
dependsOn(mergeSources)
|
||||
@@ -207,11 +222,17 @@ fun prepareDeps(
|
||||
makeIntellijAnnotations
|
||||
)
|
||||
}
|
||||
|
||||
if (installIntellijUltimate) {
|
||||
val buildNodeJsPlugin =
|
||||
buildIvyRepositoryTask(nodeJSPlugin, customDepsOrg, customDepsRepoDir, ::skipToplevelDirectory, sourcesFile)
|
||||
tasks.named("build") { dependsOn(buildNodeJsPlugin) }
|
||||
}
|
||||
}
|
||||
|
||||
prepareDeps(intellij, intellijCore, sources, jpsStandalone, intellijVersion)
|
||||
prepareDeps(intellij, intellijCore, sources, intellijUltimate, jpsStandalone, intellijVersion)
|
||||
if (intellijVersionForIde != null) {
|
||||
prepareDeps(intellijForIde, intellijCoreForIde, sourcesForIde, jpsStandaloneForIde, intellijVersionForIde)
|
||||
prepareDeps(intellijForIde, intellijCoreForIde, sourcesForIde, intellijUltimateForIde, jpsStandaloneForIde, intellijVersionForIde)
|
||||
}
|
||||
|
||||
tasks.named<Delete>("clean") {
|
||||
|
||||
@@ -21,8 +21,53 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.30")
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.29")
|
||||
}
|
||||
}
|
||||
|
||||
include "prepare-deps"
|
||||
def buildProperties = BuildPropertiesKt.getKotlinBuildPropertiesForSettings(settings)
|
||||
def projectVersions = file("../gradle/versions.properties").text
|
||||
|
||||
include "prepare-deps"
|
||||
|
||||
def target_AppCode_Clion = buildProperties.includeCidrPlugins && !projectVersions.contains("versions.androidStudioRelease")
|
||||
def target_AndroidStudio = buildProperties.includeCidrPlugins && projectVersions.contains("versions.androidStudioRelease")
|
||||
def target_IdeaUltimate = buildProperties.includeUltimate
|
||||
|
||||
if (target_AppCode_Clion) {
|
||||
logger.info("Including modules for AC and CL in buildSrc/settings.gradle")
|
||||
|
||||
include ":prepare-deps:kotlin-native-platform-deps"
|
||||
include ":prepare-deps:native-debug-plugin"
|
||||
|
||||
project(":prepare-deps:kotlin-native-platform-deps").projectDir =
|
||||
file("${buildProperties.propertiesProvider.rootProjectDir}/kotlin-ultimate/buildSrc/prepare-deps/kotlin-native-platform-deps")
|
||||
project(":prepare-deps:native-debug-plugin").projectDir =
|
||||
file("${buildProperties.propertiesProvider.rootProjectDir}/kotlin-ultimate/buildSrc/prepare-deps/native-debug-plugin")
|
||||
} else if (target_AndroidStudio) {
|
||||
logger.info("Including modules for AS (mobile plugin) in buildSrc/settings.gradle")
|
||||
|
||||
include ":prepare-deps:appcode-binaries"
|
||||
include ":prepare-deps:lldb-framework"
|
||||
include ":prepare-deps:lldb-frontend"
|
||||
|
||||
project(":prepare-deps:appcode-binaries").projectDir =
|
||||
file("${buildProperties.propertiesProvider.rootProjectDir}/kotlin-ultimate/buildSrc/prepare-deps/appcode-binaries")
|
||||
project(":prepare-deps:lldb-framework").projectDir =
|
||||
file("${buildProperties.propertiesProvider.rootProjectDir}/kotlin-ultimate/buildSrc/prepare-deps/lldb-framework")
|
||||
project(":prepare-deps:lldb-frontend").projectDir =
|
||||
file("${buildProperties.propertiesProvider.rootProjectDir}/kotlin-ultimate/buildSrc/prepare-deps/lldb-frontend")
|
||||
} else if (target_IdeaUltimate) {
|
||||
logger.info("Including modules for IU in buildSrc/settings.gradle")
|
||||
|
||||
include ":prepare-deps:lldb-frontend"
|
||||
include ":prepare-deps:native-debug-plugin"
|
||||
|
||||
project(":prepare-deps:lldb-frontend").projectDir =
|
||||
file("${buildProperties.propertiesProvider.rootProjectDir}/kotlin-ultimate/buildSrc/prepare-deps/lldb-frontend")
|
||||
project(":prepare-deps:native-debug-plugin").projectDir =
|
||||
file("${buildProperties.propertiesProvider.rootProjectDir}/kotlin-ultimate/buildSrc/prepare-deps/native-debug-plugin")
|
||||
|
||||
} else {
|
||||
logger.info("Not including extra modules in buildSrc/settings.gradle")
|
||||
}
|
||||
|
||||
@@ -86,7 +86,4 @@ val Project.isConfigurationCacheDisabled
|
||||
get() = (gradle.startParameter as? org.gradle.api.internal.StartParameterInternal)?.isConfigurationCache != true
|
||||
|
||||
val Project.isIdeaActive
|
||||
get() = providers.systemProperty("idea.active").forUseAtConfigurationTime().isPresent
|
||||
|
||||
val Project.intellijCommunityDir: File
|
||||
get() = rootDir.resolve("kotlin-ide/intellij/community").takeIf { it.isDirectory } ?: rootDir.resolve("kotlin-ide/intellij")
|
||||
get() = providers.systemProperty("idea.active").forUseAtConfigurationTime().isPresent
|
||||
@@ -26,7 +26,7 @@ fun CompatibilityPredicate.or(other: CompatibilityPredicate): CompatibilityPredi
|
||||
}
|
||||
|
||||
enum class Platform : CompatibilityPredicate {
|
||||
P202, P203;
|
||||
P183, P191, P192, P193, P201, P202, P203;
|
||||
|
||||
val version: Int = name.drop(1).toInt()
|
||||
|
||||
@@ -43,9 +43,17 @@ enum class Platform : CompatibilityPredicate {
|
||||
}
|
||||
|
||||
enum class Ide(val platform: Platform) : CompatibilityPredicate {
|
||||
IJ191(Platform.P191),
|
||||
IJ192(Platform.P192),
|
||||
IJ193(Platform.P193),
|
||||
IJ201(Platform.P201),
|
||||
IJ202(Platform.P202),
|
||||
IJ203(Platform.P203),
|
||||
|
||||
AS35(Platform.P183),
|
||||
AS36(Platform.P192),
|
||||
AS40(Platform.P193),
|
||||
AS41(Platform.P201),
|
||||
AS42(Platform.P202);
|
||||
|
||||
val kind = Kind.values().first { it.shortName == name.take(2) }
|
||||
|
||||
@@ -240,11 +240,6 @@ fun Project.publishJarsForIde(projects: List<String>, libraryDependencies: List<
|
||||
idePluginDependency {
|
||||
publishProjectJars(projects, libraryDependencies)
|
||||
}
|
||||
configurations.all {
|
||||
// Don't allow `ideaIC` from compiler to leak into Kotlin plugin modules. Compiler and
|
||||
// plugin may depend on different versions of IDEA and it will lead to version conflict
|
||||
exclude(module = ideModuleName())
|
||||
}
|
||||
dependencies {
|
||||
projects.forEach {
|
||||
jpsLikeJarDependency(project(it), JpsDepScope.COMPILE, { isTransitive = false }, exported = true)
|
||||
@@ -259,11 +254,6 @@ fun Project.publishTestJarsForIde(projectNames: List<String>) {
|
||||
idePluginDependency {
|
||||
publishTestJar(projectNames)
|
||||
}
|
||||
configurations.all {
|
||||
// Don't allow `ideaIC` from compiler to leak into Kotlin plugin modules. Compiler and
|
||||
// plugin may depend on different versions of IDEA and it will lead to version conflict
|
||||
exclude(module = ideModuleName())
|
||||
}
|
||||
dependencies {
|
||||
for (projectName in projectNames) {
|
||||
jpsLikeJarDependency(projectTests(projectName), JpsDepScope.COMPILE, exported = true)
|
||||
|
||||
@@ -36,7 +36,7 @@ val Project.internalBootstrapRepo: String? get() =
|
||||
when {
|
||||
bootstrapKotlinRepo?.startsWith("https://buildserver.labs.intellij.net") == true ->
|
||||
bootstrapKotlinRepo!!.replace("artifacts/content/maven", "artifacts/content/internal/repo")
|
||||
else -> "https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_KotlinPublic_Aggregate),number:$bootstrapKotlinVersion," +
|
||||
else -> "https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_KotlinPublic_Compiler),number:$bootstrapKotlinVersion," +
|
||||
"branch:default:any/artifacts/content/internal/repo/"
|
||||
}
|
||||
|
||||
@@ -91,6 +91,12 @@ fun Project.preloadedDeps(
|
||||
return files(*matchingFiles.map { it.canonicalPath }.toTypedArray())
|
||||
}
|
||||
|
||||
fun Project.ideaUltimatePreloadedDeps(vararg artifactBaseNames: String, subdir: String? = null): ConfigurableFileCollection {
|
||||
val ultimateDepsDir = fileFrom(rootDir, "ultimate", "dependencies")
|
||||
return if (ultimateDepsDir.isDirectory) preloadedDeps(*artifactBaseNames, baseDir = ultimateDepsDir, subdir = subdir)
|
||||
else files()
|
||||
}
|
||||
|
||||
fun Project.kotlinDep(artifactBaseName: String, version: String, classifier: String? = null): String =
|
||||
listOfNotNull("org.jetbrains.kotlin:kotlin-$artifactBaseName:$version", classifier).joinToString(":")
|
||||
|
||||
|
||||
@@ -93,6 +93,7 @@ fun Project.compilerDummyForDependenciesRewriting(
|
||||
exclude(packagesToExcludeFromDummy)
|
||||
body()
|
||||
}
|
||||
|
||||
const val COMPILER_DUMMY_JAR_CONFIGURATION_NAME = "compilerDummyJar"
|
||||
|
||||
fun Project.compilerDummyJar(task: TaskProvider<out Jar>, body: Jar.() -> Unit = {}) {
|
||||
|
||||
@@ -117,13 +117,8 @@ fun MutableCollection<JdkId>.discoverJdksOnMacOS(project: Project) {
|
||||
for (rex in macOsJavaHomeOutRegexes) {
|
||||
val matchResult = rex.matchEntire(line)
|
||||
if (matchResult != null) {
|
||||
val jdkHomeDir = File(matchResult.groupValues[3])
|
||||
// Filter out JRE installed at /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/
|
||||
// and shown by the java_home tool
|
||||
if (!jdkHomeDir.path.contains("JavaAppletPlugin.plugin")) {
|
||||
addIfBetter(project, matchResult.groupValues[1], matchResult.groupValues[0], jdkHomeDir)
|
||||
break
|
||||
}
|
||||
addIfBetter(project, matchResult.groupValues[1], matchResult.groupValues[0], File(matchResult.groupValues[3]))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,9 +35,11 @@ private fun Project.kotlinBuildLocalDependenciesDir(): File =
|
||||
|
||||
private fun Project.kotlinBuildLocalRepoDir(): File = kotlinBuildLocalDependenciesDir().resolve("repo")
|
||||
|
||||
fun Project.ideModuleName() = when (IdeVersionConfigurator.currentIde.kind) {
|
||||
private fun Project.ideModuleName() = when (IdeVersionConfigurator.currentIde.kind) {
|
||||
Ide.Kind.AndroidStudio -> "android-studio-ide"
|
||||
Ide.Kind.IntelliJ -> "ideaIC"
|
||||
Ide.Kind.IntelliJ -> {
|
||||
if (kotlinBuildProperties.intellijUltimateEnabled) "ideaIU" else "ideaIC"
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.ideModuleVersion(forIde: Boolean) = when (IdeVersionConfigurator.currentIde.kind) {
|
||||
@@ -108,6 +110,10 @@ fun Project.intellijRuntimeAnnotations() = "kotlin.build:intellij-runtime-annota
|
||||
|
||||
fun Project.intellijPluginDep(plugin: String, forIde: Boolean = false) = intellijDep(plugin, forIde)
|
||||
|
||||
fun Project.intellijUltimateDep() = intellijDep("ideaIU")
|
||||
|
||||
fun Project.intellijUltimatePluginDep(plugin: String) = intellijDep(plugin)
|
||||
|
||||
fun ModuleDependency.includeJars(vararg names: String, rootProject: Project? = null) {
|
||||
names.forEach {
|
||||
var baseName = it.removeSuffix(".jar")
|
||||
@@ -146,8 +152,19 @@ fun ModuleDependency.includeIntellijCoreJarDependencies(project: Project, jarsFi
|
||||
rootProject = project.rootProject
|
||||
)
|
||||
|
||||
fun Project.isIntellijCommunityAvailable() =
|
||||
!(rootProject.extra["intellijUltimateEnabled"] as Boolean) || rootProject.extra["intellijSeparateSdks"] as Boolean
|
||||
|
||||
fun Project.isIntellijUltimateSdkAvailable() = (rootProject.extra["intellijUltimateEnabled"] as Boolean)
|
||||
|
||||
fun Project.intellijRootDir() = IntellijRootUtils.getIntellijRootDir(project)
|
||||
|
||||
fun Project.intellijUltimateRootDir() =
|
||||
if (isIntellijUltimateSdkAvailable())
|
||||
File(kotlinBuildLocalRepoDir(), "kotlin.build/ideaIU/${rootProject.extra["versions.intellijSdk"]}/artifacts")
|
||||
else
|
||||
throw GradleException("intellij ultimate SDK is not available")
|
||||
|
||||
fun DependencyHandlerScope.excludeInAndroidStudio(rootProject: Project, block: DependencyHandlerScope.() -> Unit) {
|
||||
if (!rootProject.extra.has("versions.androidStudioRelease")) {
|
||||
block()
|
||||
@@ -181,7 +198,9 @@ fun Project.runIdeTask(name: String, ideaPluginDir: File, ideaSandboxDir: File,
|
||||
"-Dplugin.path=${ideaPluginDir.absolutePath}"
|
||||
)
|
||||
|
||||
jvmArgs("-Didea.platform.prefix=Idea")
|
||||
if (Platform[201].orHigher() && !isIntellijUltimateSdkAvailable()) {
|
||||
jvmArgs("-Didea.platform.prefix=Idea")
|
||||
}
|
||||
|
||||
if (rootProject.findProperty("versions.androidStudioRelease") != null) {
|
||||
jvmArgs("-Didea.platform.prefix=AndroidStudio")
|
||||
|
||||
@@ -194,7 +194,9 @@ fun Project.projectTest(
|
||||
systemProperty("kotlin.ni", if (project.rootProject.hasProperty("newInferenceTests")) "true" else "false")
|
||||
systemProperty("org.jetbrains.kotlin.skip.muted.tests", if (project.rootProject.hasProperty("skipMutedTests")) "true" else "false")
|
||||
|
||||
systemProperty("idea.ignore.disabled.plugins", "true")
|
||||
if (Platform[202].orHigher()) {
|
||||
systemProperty("idea.ignore.disabled.plugins", "true")
|
||||
}
|
||||
|
||||
var subProjectTempRoot: Path? = null
|
||||
val projectName = project.name
|
||||
|
||||
@@ -27,9 +27,17 @@ dependencies {
|
||||
testCompile(projectTests(":jps-plugin"))
|
||||
testCompile(commonDep("junit:junit"))
|
||||
|
||||
testCompile(intellijDep()) { includeJars("util", "idea", "idea_rt", rootProject = rootProject) }
|
||||
testCompile(intellijDep()) { includeJars("groovy", rootProject = rootProject) }
|
||||
Platform[193].orLower {
|
||||
testCompile(intellijDep()) { includeJars("openapi", rootProject = rootProject) }
|
||||
}
|
||||
|
||||
testCompile(intellijDep()) { includeJars("util", "idea", "idea_rt", rootProject = rootProject) }
|
||||
Platform[202].orHigher {
|
||||
testCompile(intellijDep()) { includeJars("groovy", rootProject = rootProject) }
|
||||
}
|
||||
Platform[201].orLower {
|
||||
testCompile(intellijDep()) { includeJars("groovy-all", rootProject = rootProject) }
|
||||
}
|
||||
testCompile(intellijPluginDep("java")) { includeJars("jps-builders") }
|
||||
testCompile(jpsStandalone()) { includeJars("jps-model") }
|
||||
testCompile(jpsBuildTest())
|
||||
|
||||
@@ -20,12 +20,14 @@ import org.jetbrains.kotlin.codegen.inline.NameGenerator
|
||||
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.Companion.putReifiedOperationMarker
|
||||
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.OperationKind
|
||||
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeParameterMarker
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
interface BaseExpressionCodegen {
|
||||
|
||||
val frameMap: FrameMapBase<*>
|
||||
|
||||
val visitor: InstructionAdapter
|
||||
@@ -38,14 +40,24 @@ interface BaseExpressionCodegen {
|
||||
|
||||
fun propagateChildReifiedTypeParametersUsages(reifiedTypeParametersUsages: ReifiedTypeParametersUsages)
|
||||
|
||||
fun pushClosureOnStack(
|
||||
classDescriptor: ClassDescriptor,
|
||||
putThis: Boolean,
|
||||
callGenerator: CallGenerator,
|
||||
functionReferenceReceiver: StackValue?
|
||||
)
|
||||
|
||||
fun markLineNumberAfterInlineIfNeeded(registerLineNumberAfterwards: Boolean)
|
||||
|
||||
fun consumeReifiedOperationMarker(typeParameter: TypeParameterMarker)
|
||||
}
|
||||
|
||||
fun BaseExpressionCodegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type: KotlinTypeMarker, operationKind: OperationKind): Boolean {
|
||||
val (typeParameter, second) = typeSystem.extractReificationArgument(type) ?: return false
|
||||
consumeReifiedOperationMarker(typeParameter)
|
||||
putReifiedOperationMarker(operationKind, second, visitor)
|
||||
return true
|
||||
fun putReifiedOperationMarkerIfTypeIsReifiedParameter(type: KotlinTypeMarker, operationKind: OperationKind) {
|
||||
with(typeSystem) {
|
||||
val (typeParameter, second) = extractReificationArgument(type) ?: return
|
||||
if (typeParameter.isReified()) {
|
||||
consumeReifiedOperationMarker(typeParameter)
|
||||
putReifiedOperationMarker(operationKind, second, visitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ enum class ValueKind {
|
||||
DEFAULT_MASK,
|
||||
METHOD_HANDLE_IN_DEFAULT,
|
||||
CAPTURED,
|
||||
DEFAULT_LAMBDA_CAPTURED_PARAMETER,
|
||||
NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND,
|
||||
NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER
|
||||
}
|
||||
@@ -39,9 +40,13 @@ interface CallGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
override fun processHiddenParameters() {}
|
||||
override fun processAndPutHiddenParameters(justProcess: Boolean) {
|
||||
|
||||
override fun putHiddenParamsIntoLocals() {}
|
||||
}
|
||||
|
||||
override fun putHiddenParamsIntoLocals() {
|
||||
|
||||
}
|
||||
|
||||
override fun genValueAndPut(
|
||||
valueParameterDescriptor: ValueParameterDescriptor?,
|
||||
@@ -136,8 +141,9 @@ interface CallGenerator {
|
||||
paramIndex: Int
|
||||
)
|
||||
|
||||
fun processHiddenParameters()
|
||||
fun processAndPutHiddenParameters(justProcess: Boolean)
|
||||
|
||||
/*should be called if justProcess = true in processAndPutHiddenParameters*/
|
||||
fun putHiddenParamsIntoLocals()
|
||||
|
||||
fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: List<ArgumentAndDeclIndex>, valueParameterTypes: List<Type>)
|
||||
|
||||
@@ -6,16 +6,14 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.inline.loadCompiledInlineFunction
|
||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegen
|
||||
import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.FunctionImportedFromObject
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
@@ -67,14 +65,13 @@ class DelegatedPropertiesCodegenHelper(private val state: GenerationState) {
|
||||
this
|
||||
|
||||
private fun isDelegatedPropertyMetadataRequiredForFunctionFromBinaries(calleeDescriptor: FunctionDescriptor): Boolean {
|
||||
require(calleeDescriptor is DescriptorWithContainerSource) {
|
||||
assert(calleeDescriptor is DescriptorWithContainerSource) {
|
||||
"Function descriptor from binaries expected: $calleeDescriptor"
|
||||
}
|
||||
|
||||
val metadataParameterIndex = getMetadataParameterIndex(calleeDescriptor)
|
||||
val containerId = KotlinTypeMapper.getContainingClassesForDeserializedCallable(calleeDescriptor).implClassId
|
||||
val asmMethod = state.typeMapper.mapAsmMethod(calleeDescriptor)
|
||||
val isMangled = requiresFunctionNameManglingForReturnType(calleeDescriptor)
|
||||
val methodNode = loadCompiledInlineFunction(containerId, asmMethod, calleeDescriptor.isSuspend, isMangled, state).node
|
||||
val methodNode = InlineCodegen.createSpecialInlineMethodNodeFromBinaries(calleeDescriptor, state)
|
||||
|
||||
return isMetadataParameterUsedInCompiledMethodBody(metadataParameterIndex, methodNode)
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,6 @@ import java.util.stream.Collectors;
|
||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isInt;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.boxType;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.BaseExpressionCodegenKt.putReifiedOperationMarkerIfTypeIsReifiedParameter;
|
||||
import static org.jetbrains.kotlin.codegen.CodegenUtilKt.*;
|
||||
import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.boxType;
|
||||
import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.*;
|
||||
@@ -1262,8 +1261,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
if (closure.isSuspendLambda()) {
|
||||
// When inlining crossinline lambda, the ACONST_NULL is never popped.
|
||||
// Thus, do not generate it. Otherwise, it leads to VerifyError on run-time.
|
||||
boolean isCrossinlineLambda = (callGenerator instanceof PsiInlineCodegen) &&
|
||||
Objects.requireNonNull(((PsiInlineCodegen) callGenerator).getActiveLambda(),
|
||||
boolean isCrossinlineLambda = (callGenerator instanceof InlineCodegen<?>) &&
|
||||
Objects.requireNonNull(((InlineCodegen) callGenerator).getActiveLambda(),
|
||||
"no active lambda found").isCrossInline;
|
||||
if (!isCrossinlineLambda) {
|
||||
v.aconst(null);
|
||||
@@ -2781,8 +2780,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
putReceiverAndInlineMarkerIfNeeded(callableMethod, resolvedCall, receiver, maybeSuspensionPoint, isConstructor);
|
||||
}
|
||||
|
||||
callGenerator.processHiddenParameters();
|
||||
callGenerator.putHiddenParamsIntoLocals();
|
||||
callGenerator.processAndPutHiddenParameters(false);
|
||||
|
||||
List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
|
||||
assert valueArguments != null : "Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor();
|
||||
@@ -2951,12 +2949,13 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
bindingContext, state
|
||||
);
|
||||
|
||||
PsiSourceCompilerForInline sourceCompiler = new PsiSourceCompilerForInline(this, callElement);
|
||||
FunctionDescriptor functionDescriptor =
|
||||
InlineUtil.isArrayConstructorWithLambda(original)
|
||||
? FictitiousArrayConstructor.create((ConstructorDescriptor) original) : original.getOriginal();
|
||||
PsiSourceCompilerForInline sourceCompiler = new PsiSourceCompilerForInline(this, callElement, functionDescriptor);
|
||||
|
||||
JvmMethodSignature signature = typeMapper.mapSignatureWithGeneric(functionDescriptor, sourceCompiler.getContext().getContextKind());
|
||||
sourceCompiler.initializeInlineFunctionContext(functionDescriptor);
|
||||
JvmMethodSignature signature = typeMapper.mapSignatureWithGeneric(functionDescriptor, sourceCompiler.getContextKind());
|
||||
if (signature.getAsmMethod().getName().contains("-") &&
|
||||
!state.getConfiguration().getBoolean(JVMConfigurationKeys.USE_OLD_INLINE_CLASSES_MANGLING_SCHEME)
|
||||
) {
|
||||
@@ -2964,15 +2963,17 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
InlineClassesCodegenUtilKt.classFileContainsMethod(functionDescriptor, state, signature.getAsmMethod());
|
||||
if (classFileContainsMethod != null && !classFileContainsMethod) {
|
||||
typeMapper.setUseOldManglingRulesForFunctionAcceptingInlineClass(true);
|
||||
signature = typeMapper.mapSignatureWithGeneric(functionDescriptor, sourceCompiler.getContext().getContextKind());
|
||||
signature = typeMapper.mapSignatureWithGeneric(functionDescriptor, sourceCompiler.getContextKind());
|
||||
typeMapper.setUseOldManglingRulesForFunctionAcceptingInlineClass(false);
|
||||
}
|
||||
}
|
||||
Type methodOwner = typeMapper.mapImplementationOwner(functionDescriptor);
|
||||
if (isDefaultCompilation) {
|
||||
return new InlineCodegenForDefaultBody(functionDescriptor, this, state, signature, sourceCompiler);
|
||||
} else {
|
||||
return new PsiInlineCodegen(this, state, functionDescriptor, signature, typeParameterMappings, sourceCompiler,
|
||||
typeMapper.mapImplementationOwner(functionDescriptor), typeMapper.mapOwner(descriptor));
|
||||
return new InlineCodegenForDefaultBody(functionDescriptor, this, state, methodOwner, signature, sourceCompiler);
|
||||
}
|
||||
else {
|
||||
return new PsiInlineCodegen(this, state, functionDescriptor, methodOwner, signature, typeParameterMappings, sourceCompiler,
|
||||
typeMapper.mapOwner(descriptor));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3556,7 +3557,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
if (TypeUtils.isTypeParameter(type)) {
|
||||
assert TypeUtils.isReifiedTypeParameter(type) :
|
||||
"Non-reified type parameter under ::class should be rejected by type checker: " + type;
|
||||
putReifiedOperationMarkerIfTypeIsReifiedParameter(this, type, ReifiedTypeInliner.OperationKind.JAVA_CLASS);
|
||||
putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.JAVA_CLASS);
|
||||
}
|
||||
|
||||
putJavaLangClassInstance(v, typeMapper.mapType(type), type, typeMapper);
|
||||
@@ -4929,7 +4930,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
public void newArrayInstruction(@NotNull KotlinType arrayType) {
|
||||
if (KotlinBuiltIns.isArray(arrayType)) {
|
||||
KotlinType elementJetType = arrayType.getArguments().get(0).getType();
|
||||
putReifiedOperationMarkerIfTypeIsReifiedParameter(this, elementJetType, ReifiedTypeInliner.OperationKind.NEW_ARRAY);
|
||||
putReifiedOperationMarkerIfTypeIsReifiedParameter(
|
||||
elementJetType,
|
||||
ReifiedTypeInliner.OperationKind.NEW_ARRAY
|
||||
);
|
||||
v.newarray(boxType(typeMapper.mapTypeAsDeclaration(elementJetType)));
|
||||
}
|
||||
else {
|
||||
@@ -5233,7 +5237,7 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
|
||||
boolean safeAs = opToken == KtTokens.AS_SAFE;
|
||||
if (TypeUtils.isReifiedTypeParameter(rightKotlinType)) {
|
||||
putReifiedOperationMarkerIfTypeIsReifiedParameter(this, rightKotlinType,
|
||||
putReifiedOperationMarkerIfTypeIsReifiedParameter(rightKotlinType,
|
||||
safeAs ? ReifiedTypeInliner.OperationKind.SAFE_AS
|
||||
: ReifiedTypeInliner.OperationKind.AS);
|
||||
v.checkcast(boxedRightType);
|
||||
@@ -5290,7 +5294,7 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
|
||||
Type type = boxType(typeMapper.mapTypeAsDeclaration(rhsKotlinType));
|
||||
if (TypeUtils.isReifiedTypeParameter(rhsKotlinType)) {
|
||||
putReifiedOperationMarkerIfTypeIsReifiedParameter(this, rhsKotlinType, ReifiedTypeInliner.OperationKind.IS);
|
||||
putReifiedOperationMarkerIfTypeIsReifiedParameter(rhsKotlinType, ReifiedTypeInliner.OperationKind.IS);
|
||||
v.instanceOf(type);
|
||||
return null;
|
||||
}
|
||||
@@ -5542,4 +5546,11 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
parentCodegen.getReifiedTypeParametersUsages().addUsedReifiedParameter(typeParameterDescriptor.getName().asString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putReifiedOperationMarkerIfTypeIsReifiedParameter(
|
||||
@NotNull KotlinTypeMarker type, @NotNull ReifiedTypeInliner.OperationKind operationKind
|
||||
) {
|
||||
BaseExpressionCodegen.DefaultImpls.putReifiedOperationMarkerIfTypeIsReifiedParameter(this, type, operationKind);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,13 +68,6 @@ open class FrameMapBase<T : Any> {
|
||||
return Mark(currentSize)
|
||||
}
|
||||
|
||||
fun skipTo(target: Int): Mark {
|
||||
return mark().also {
|
||||
if (currentSize < target)
|
||||
currentSize = target
|
||||
}
|
||||
}
|
||||
|
||||
inner class Mark(private val myIndex: Int) {
|
||||
|
||||
fun dropTo() {
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.SimpleType;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
@@ -1328,8 +1329,8 @@ public abstract class StackValue {
|
||||
StackValue newReceiver = StackValue.receiver(call, receiver, codegen, callable);
|
||||
ArgumentGenerator generator = createArgumentGenerator();
|
||||
newReceiver.put(newReceiver.type, newReceiver.kotlinType, v);
|
||||
callGenerator.processHiddenParameters();
|
||||
callGenerator.putHiddenParamsIntoLocals();
|
||||
callGenerator.processAndPutHiddenParameters(false);
|
||||
|
||||
defaultArgs = generator.generate(valueArguments, valueArguments, call.getResultingDescriptor());
|
||||
}
|
||||
|
||||
@@ -1747,8 +1748,7 @@ public abstract class StackValue {
|
||||
assert getterDescriptor != null : "Getter descriptor should be not null for " + descriptor;
|
||||
if (resolvedCall != null && getterDescriptor.isInline()) {
|
||||
CallGenerator callGenerator = codegen.getOrCreateCallGenerator(resolvedCall, ((PropertyDescriptor)resolvedCall.getResultingDescriptor()).getGetter());
|
||||
callGenerator.processHiddenParameters();
|
||||
callGenerator.putHiddenParamsIntoLocals();
|
||||
callGenerator.processAndPutHiddenParameters(false);
|
||||
callGenerator.genCall(getter, resolvedCall, false, codegen);
|
||||
}
|
||||
else {
|
||||
@@ -1832,7 +1832,7 @@ public abstract class StackValue {
|
||||
if (!skipReceiver) {
|
||||
putReceiver(v, false);
|
||||
}
|
||||
callGenerator.processHiddenParameters();
|
||||
callGenerator.processAndPutHiddenParameters(true);
|
||||
callGenerator.putValueIfNeeded(new JvmKotlinType(
|
||||
CollectionsKt.last(setter.getValueParameters()).getAsmType(),
|
||||
CollectionsKt.last(setterDescriptor.getValueParameters()).getType()),
|
||||
|
||||
@@ -393,12 +393,13 @@ fun TypeSystemCommonBackendContext.extractReificationArgument(initialType: Kotli
|
||||
while (type.isArrayOrNullableArray()) {
|
||||
arrayDepth++
|
||||
val argument = type.getArgument(0)
|
||||
if (argument.isStarProjection()) return null
|
||||
type = argument.getType()
|
||||
type =
|
||||
if (argument.isStarProjection()) nullableAnyType()
|
||||
else argument.getType()
|
||||
}
|
||||
|
||||
val typeParameter = type.typeConstructor().getTypeParameterClassifier() ?: return null
|
||||
if (!typeParameter.isReified()) return null
|
||||
|
||||
return Pair(typeParameter, ReificationArgument(typeParameter.getName().asString(), isNullable, arrayDepth))
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.intellij.util.ArrayUtil
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.coroutines.DEBUG_METADATA_ANNOTATION_ASM_TYPE
|
||||
import org.jetbrains.kotlin.codegen.coroutines.isCoroutineSuperClass
|
||||
import org.jetbrains.kotlin.codegen.coroutines.isResumeImplMethodName
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.CoroutineTransformer
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
|
||||
import org.jetbrains.kotlin.codegen.serialization.JvmCodegenStringTable
|
||||
@@ -26,7 +27,6 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import java.util.*
|
||||
|
||||
@@ -272,7 +272,7 @@ class AnonymousObjectTransformer(
|
||||
// Since $$forInline functions are not generated if retransformation is the last one (i.e. call site is not inline)
|
||||
// link to the function in OUTERCLASS field becomes invalid. However, since $$forInline function always has no-inline
|
||||
// companion without the suffix, use it.
|
||||
visitor.visitOuterClass(info.ownerClassName, info.method.name.removeSuffix(FOR_INLINE_SUFFIX), info.method.descriptor)
|
||||
visitor.visitOuterClass(info.ownerClassName, info.functionName?.removeSuffix(FOR_INLINE_SUFFIX), info.functionDesc)
|
||||
}
|
||||
|
||||
private fun inlineMethodAndUpdateGlobalResult(
|
||||
@@ -314,10 +314,11 @@ class AnonymousObjectTransformer(
|
||||
SourceMapCopier(sourceMapper, sourceMap),
|
||||
InlineCallSiteInfo(
|
||||
transformationInfo.oldClassName,
|
||||
Method(sourceNode.name, if (isConstructor) transformationInfo.newConstructorDescriptor else sourceNode.desc),
|
||||
sourceNode.name,
|
||||
if (isConstructor) transformationInfo.newConstructorDescriptor else sourceNode.desc,
|
||||
inliningContext.callSiteInfo.isInlineOrInsideInline,
|
||||
inliningContext.callSiteInfo.file,
|
||||
inliningContext.callSiteInfo.lineNumber
|
||||
isSuspendFunctionOrLambda(sourceNode),
|
||||
inliningContext.root.sourceCompilerForInline.inlineCallSiteInfo.lineNumber
|
||||
), null
|
||||
)
|
||||
|
||||
@@ -327,6 +328,12 @@ class AnonymousObjectTransformer(
|
||||
return result
|
||||
}
|
||||
|
||||
private fun isSuspendFunctionOrLambda(sourceNode: MethodNode): Boolean =
|
||||
(sourceNode.desc.endsWith(";Lkotlin/coroutines/Continuation;)Ljava/lang/Object;") ||
|
||||
sourceNode.desc.endsWith(";Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object;")) &&
|
||||
(CoroutineTransformer.findFakeContinuationConstructorClassName(sourceNode) != null ||
|
||||
languageVersionSettings.isResumeImplMethodName(sourceNode.name.removeSuffix(FOR_INLINE_SUFFIX)))
|
||||
|
||||
private fun generateConstructorAndFields(
|
||||
classBuilder: ClassBuilder,
|
||||
allCapturedBuilder: ParametersBuilder,
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
data class MethodId(val ownerInternalName: String, val method: Method)
|
||||
|
||||
class InlineCache {
|
||||
val classBytes: SLRUMap<String, ByteArray> = SLRUMap(30, 20)
|
||||
val classBytes: SLRUMap<ClassId, ByteArray> = SLRUMap(30, 20)
|
||||
val methodNodeById: SLRUMap<MethodId, SMAPAndMethodNode> = SLRUMap(60, 50)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.codegen.inline
|
||||
|
||||
class InlineCallSiteInfo(
|
||||
val ownerClassName: String,
|
||||
val functionName: String?,
|
||||
val functionDesc: String?,
|
||||
val isInlineOrInsideInline: Boolean,
|
||||
val isSuspend: Boolean,
|
||||
val lineNumber: Int
|
||||
)
|
||||
@@ -6,83 +6,213 @@
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive
|
||||
import org.jetbrains.kotlin.codegen.context.ClosureContext
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructors
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.Position
|
||||
import org.jetbrains.kotlin.incremental.components.ScopeKind
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
import org.jetbrains.kotlin.resolve.inline.isInlineOnly
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral
|
||||
import org.jetbrains.kotlin.types.expressions.LabelResolver
|
||||
import org.jetbrains.kotlin.types.model.TypeParameterMarker
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import kotlin.math.max
|
||||
|
||||
abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
protected val codegen: T,
|
||||
protected val state: GenerationState,
|
||||
protected val functionDescriptor: FunctionDescriptor,
|
||||
protected val methodOwner: Type,
|
||||
protected val jvmSignature: JvmMethodSignature,
|
||||
private val typeParameterMappings: TypeParameterMappings<*>,
|
||||
protected val sourceCompiler: SourceCompilerForInline,
|
||||
private val reifiedTypeInliner: ReifiedTypeInliner<*>
|
||||
) {
|
||||
init {
|
||||
assert(InlineUtil.isInline(functionDescriptor)) {
|
||||
"InlineCodegen can inline only inline functions: $functionDescriptor"
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: implement AS_FUNCTION inline strategy
|
||||
private val asFunctionInline = false
|
||||
|
||||
private val initialFrameSize = codegen.frameMap.currentSize
|
||||
|
||||
private val isSameModule: Boolean
|
||||
|
||||
protected val invocationParamBuilder = ParametersBuilder.newBuilder()
|
||||
|
||||
protected val expressionMap = linkedMapOf<Int, FunctionalArgument>()
|
||||
|
||||
var activeLambda: LambdaInfo? = null
|
||||
protected set
|
||||
|
||||
private val sourceMapper = sourceCompiler.lazySourceMapper
|
||||
|
||||
protected var delayedHiddenWriting: Function0<Unit>? = null
|
||||
|
||||
protected val maskValues = ArrayList<Int>()
|
||||
protected var maskStartIndex = -1
|
||||
protected var methodHandleInDefaultMethodIndex = -1
|
||||
|
||||
protected fun generateStub(text: String, codegen: BaseExpressionCodegen) {
|
||||
leaveTemps()
|
||||
AsmUtil.genThrow(codegen.visitor, "java/lang/UnsupportedOperationException", "Call is part of inline cycle: $text")
|
||||
}
|
||||
init {
|
||||
isSameModule = sourceCompiler.isCallInsideSameModuleAsDeclared(functionDescriptor)
|
||||
|
||||
fun performInline(registerLineNumberAfterwards: Boolean, isInlineOnly: Boolean) {
|
||||
var nodeAndSmap: SMAPAndMethodNode? = null
|
||||
try {
|
||||
nodeAndSmap = sourceCompiler.compileInlineFunction(jvmSignature).apply {
|
||||
node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false)
|
||||
if (functionDescriptor !is FictitiousArrayConstructor) {
|
||||
//track changes for property accessor and @JvmName inline functions/property accessors
|
||||
if (jvmSignature.asmMethod.name != functionDescriptor.name.asString()) {
|
||||
trackLookup(functionDescriptor)
|
||||
}
|
||||
val result = inlineCall(nodeAndSmap, isInlineOnly)
|
||||
leaveTemps()
|
||||
codegen.propagateChildReifiedTypeParametersUsages(result.reifiedTypeParametersUsages)
|
||||
codegen.markLineNumberAfterInlineIfNeeded(registerLineNumberAfterwards)
|
||||
state.factory.removeClasses(result.calcClassesToRemove())
|
||||
} catch (e: CompilationException) {
|
||||
throw e
|
||||
} catch (e: InlineException) {
|
||||
throw CompilationException(
|
||||
"Couldn't inline method call: ${sourceCompiler.callElementText}",
|
||||
e, sourceCompiler.callElement as? PsiElement
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
throw CompilationException(
|
||||
"Couldn't inline method call: ${sourceCompiler.callElementText}\nMethod: ${nodeAndSmap?.node?.nodeText}",
|
||||
e, sourceCompiler.callElement as? PsiElement
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun inlineCall(nodeAndSmap: SMAPAndMethodNode, isInlineOnly: Boolean): InlineResult {
|
||||
|
||||
protected fun throwCompilationException(
|
||||
nodeAndSmap: SMAPAndMethodNode?, e: Exception, generateNodeText: Boolean
|
||||
): CompilationException {
|
||||
val contextDescriptor = sourceCompiler.compilationContextDescriptor
|
||||
val element = DescriptorToSourceUtils.descriptorToDeclaration(contextDescriptor)
|
||||
val node = nodeAndSmap?.node
|
||||
throw CompilationException(
|
||||
"Couldn't inline method call '" + functionDescriptor.name + "' into\n" +
|
||||
DescriptorRenderer.DEBUG_TEXT.render(contextDescriptor) + "\n" +
|
||||
(element?.text ?: "<no source>") +
|
||||
if (generateNodeText) "\nCause: " + node.nodeText else "",
|
||||
e, sourceCompiler.callElement as? PsiElement
|
||||
)
|
||||
}
|
||||
|
||||
protected fun generateStub(text: String, codegen: BaseExpressionCodegen) {
|
||||
leaveTemps()
|
||||
AsmUtil.genThrow(codegen.v, "java/lang/UnsupportedOperationException", "Call is part of inline cycle: $text")
|
||||
}
|
||||
|
||||
protected fun endCall(result: InlineResult, registerLineNumberAfterwards: Boolean) {
|
||||
leaveTemps()
|
||||
|
||||
codegen.propagateChildReifiedTypeParametersUsages(result.reifiedTypeParametersUsages)
|
||||
|
||||
state.factory.removeClasses(result.calcClassesToRemove())
|
||||
|
||||
codegen.markLineNumberAfterInlineIfNeeded(registerLineNumberAfterwards)
|
||||
}
|
||||
|
||||
fun performInline(
|
||||
typeArguments: List<TypeParameterMarker>?,
|
||||
inlineDefaultLambdas: Boolean,
|
||||
mapDefaultSignature: Boolean,
|
||||
typeSystem: TypeSystemCommonBackendContext,
|
||||
registerLineNumberAfterwards: Boolean,
|
||||
) {
|
||||
var nodeAndSmap: SMAPAndMethodNode? = null
|
||||
try {
|
||||
nodeAndSmap = createInlineMethodNode(mapDefaultSignature, typeArguments, typeSystem)
|
||||
endCall(inlineCall(nodeAndSmap, inlineDefaultLambdas), registerLineNumberAfterwards)
|
||||
} catch (e: CompilationException) {
|
||||
throw e
|
||||
} catch (e: InlineException) {
|
||||
throw throwCompilationException(nodeAndSmap, e, false)
|
||||
} catch (e: Exception) {
|
||||
throw throwCompilationException(nodeAndSmap, e, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun canSkipStackSpillingOnInline(methodNode: MethodNode): Boolean {
|
||||
// Stack spilling before inline function 'f' call is required if:
|
||||
// - 'f' is a suspend function
|
||||
// - 'f' has try-catch blocks
|
||||
// - 'f' has loops
|
||||
//
|
||||
// Instead of checking for loops precisely, we just check if there are any backward jumps -
|
||||
// that is, a jump from instruction #i to instruction #j where j < i
|
||||
|
||||
if (functionDescriptor.isSuspend) return false
|
||||
if (methodNode.tryCatchBlocks.isNotEmpty()) return false
|
||||
|
||||
fun isBackwardJump(fromIndex: Int, toLabel: LabelNode) =
|
||||
methodNode.instructions.indexOf(toLabel) < fromIndex
|
||||
|
||||
val insns = methodNode.instructions.toArray()
|
||||
for (i in insns.indices) {
|
||||
val insn = insns[i]
|
||||
when (insn) {
|
||||
is JumpInsnNode ->
|
||||
if (isBackwardJump(i, insn.label)) return false
|
||||
|
||||
is LookupSwitchInsnNode -> {
|
||||
insn.dflt?.let {
|
||||
if (isBackwardJump(i, it)) return false
|
||||
}
|
||||
if (insn.labels.any { isBackwardJump(i, it) }) return false
|
||||
}
|
||||
|
||||
is TableSwitchInsnNode -> {
|
||||
insn.dflt?.let {
|
||||
if (isBackwardJump(i, it)) return false
|
||||
}
|
||||
if (insn.labels.any { isBackwardJump(i, it) }) return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun continuationValue(): StackValue {
|
||||
assert(codegen is ExpressionCodegen) { "Expected ExpressionCodegen in coroutineContext inlining" }
|
||||
codegen as ExpressionCodegen
|
||||
|
||||
val parentContext = codegen.context.parentContext
|
||||
return if (parentContext is ClosureContext) {
|
||||
val originalSuspendLambdaDescriptor =
|
||||
parentContext.originalSuspendLambdaDescriptor ?: error("No original lambda descriptor found")
|
||||
codegen.genCoroutineInstanceForSuspendLambda(originalSuspendLambdaDescriptor)
|
||||
?: error("No stack value for coroutine instance of lambda found")
|
||||
} else
|
||||
codegen.getContinuationParameterFromEnclosingSuspendFunctionDescriptor(codegen.context.functionDescriptor)
|
||||
?: error("No stack value for continuation parameter of suspend function")
|
||||
}
|
||||
|
||||
private fun inlineCall(nodeAndSmap: SMAPAndMethodNode, inlineDefaultLambda: Boolean): InlineResult {
|
||||
assert(delayedHiddenWriting == null) { "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'" }
|
||||
val node = nodeAndSmap.node
|
||||
if (maskStartIndex != -1) {
|
||||
if (inlineDefaultLambda) {
|
||||
for (lambda in extractDefaultLambdas(node)) {
|
||||
invocationParamBuilder.buildParameters().getParameterByDeclarationSlot(lambda.offset).functionalArgument = lambda
|
||||
val prev = expressionMap.put(lambda.offset, lambda)
|
||||
assert(prev == null) { "Lambda with offset ${lambda.offset} already exists: $prev" }
|
||||
if (lambda.needReification) {
|
||||
lambda.reifiedTypeParametersUsages.mergeAll(reifiedTypeInliner.reifyInstructions(lambda.node.node))
|
||||
}
|
||||
rememberCapturedForDefaultLambda(lambda)
|
||||
}
|
||||
}
|
||||
|
||||
val reificationResult = reifiedTypeInliner.reifyInstructions(node)
|
||||
generateClosuresBodies()
|
||||
|
||||
//through generation captured parameters will be added to invocationParamBuilder
|
||||
putClosureParametersOnStack()
|
||||
|
||||
val parameters = invocationParamBuilder.buildParameters()
|
||||
|
||||
@@ -91,14 +221,13 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
sourceCompiler, sourceCompiler.inlineCallSiteInfo, reifiedTypeInliner, typeParameterMappings
|
||||
)
|
||||
|
||||
val sourceMapper = sourceCompiler.sourceMapper
|
||||
val sourceInfo = sourceMapper.sourceInfo!!
|
||||
val callSite = SourcePosition(codegen.lastLineNumber, sourceInfo.sourceFileName!!, sourceInfo.pathOrCleanFQN)
|
||||
val inliner = MethodInliner(
|
||||
node, parameters, info, FieldRemapper(null, null, parameters), sourceCompiler.isCallInsideSameModuleAsCallee,
|
||||
node, parameters, info, FieldRemapper(null, null, parameters), isSameModule,
|
||||
"Method inlining " + sourceCompiler.callElementText,
|
||||
SourceMapCopier(sourceMapper, nodeAndSmap.classSMAP, callSite),
|
||||
info.callSiteInfo, if (isInlineOnly) InlineOnlySmapSkipper(codegen) else null,
|
||||
info.callSiteInfo, if (functionDescriptor.isInlineOnly()) InlineOnlySmapSkipper(codegen) else null,
|
||||
!isInlinedToInlineFunInKotlinRuntime()
|
||||
) //with captured
|
||||
|
||||
@@ -113,45 +242,43 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
|
||||
val infos = MethodInliner.processReturns(adapter, sourceCompiler.getContextLabels(), null)
|
||||
generateAndInsertFinallyBlocks(
|
||||
adapter, infos, (remapper.remap(parameters.argsSizeOnStack).value as StackValue.Local).index
|
||||
adapter, infos, (remapper.remap(parameters.argsSizeOnStack + 1).value as StackValue.Local).index
|
||||
)
|
||||
if (!sourceCompiler.isFinallyMarkerRequired) {
|
||||
if (!sourceCompiler.isFinallyMarkerRequired()) {
|
||||
removeFinallyMarkers(adapter)
|
||||
}
|
||||
|
||||
// In case `codegen.visitor` is `<clinit>`, initializer for the `$assertionsDisabled` field
|
||||
// In case `codegen.v` is `<clinit>`, initializer for the `$assertionsDisabled` field
|
||||
// needs to be inserted before the code that actually uses it.
|
||||
generateAssertFieldIfNeeded(info)
|
||||
|
||||
val shouldSpillStack = node.requiresEmptyStackOnEntry()
|
||||
val shouldSpillStack = !canSkipStackSpillingOnInline(node)
|
||||
if (shouldSpillStack) {
|
||||
addInlineMarker(codegen.visitor, true)
|
||||
addInlineMarker(codegen.v, true)
|
||||
}
|
||||
adapter.accept(MethodBodyVisitor(codegen.visitor))
|
||||
adapter.accept(MethodBodyVisitor(codegen.v))
|
||||
if (shouldSpillStack) {
|
||||
addInlineMarker(codegen.visitor, false)
|
||||
addInlineMarker(codegen.v, false)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
abstract fun extractDefaultLambdas(node: MethodNode): List<DefaultLambda>
|
||||
|
||||
protected inline fun <T> extractDefaultLambdas(
|
||||
node: MethodNode, parameters: Map<Int, T>, block: ExtractedDefaultLambda.(T) -> DefaultLambda
|
||||
): List<DefaultLambda> = expandMaskConditionsAndUpdateVariableNodes(
|
||||
node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex, parameters.keys
|
||||
).map {
|
||||
it.block(parameters[it.offset]!!)
|
||||
}
|
||||
abstract fun descriptorIsDeserialized(memberDescriptor: CallableMemberDescriptor): Boolean
|
||||
|
||||
private fun generateAndInsertFinallyBlocks(
|
||||
fun generateAndInsertFinallyBlocks(
|
||||
intoNode: MethodNode,
|
||||
insertPoints: List<MethodInliner.PointForExternalFinallyBlocks>,
|
||||
offsetForFinallyLocalVar: Int
|
||||
) {
|
||||
if (!sourceCompiler.hasFinallyBlocks()) return
|
||||
|
||||
val extensionPoints = insertPoints.associateBy { it.beforeIns }
|
||||
val extensionPoints = HashMap<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks>()
|
||||
for (insertPoint in insertPoints) {
|
||||
extensionPoints.put(insertPoint.beforeIns, insertPoint)
|
||||
}
|
||||
|
||||
val processor = DefaultProcessor(intoNode, offsetForFinallyLocalVar)
|
||||
|
||||
var curFinallyDepth = 0
|
||||
@@ -165,32 +292,44 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
|
||||
val extension = extensionPoints[curInstr]
|
||||
if (extension != null) {
|
||||
var nextFreeLocalIndex = processor.nextFreeLocalIndex
|
||||
for (local in processor.localVarsMetaInfo.currentIntervals) {
|
||||
val size = Type.getType(local.node.desc).size
|
||||
nextFreeLocalIndex = max(offsetForFinallyLocalVar + local.node.index + size, nextFreeLocalIndex)
|
||||
}
|
||||
|
||||
val start = Label()
|
||||
|
||||
val finallyNode = createEmptyMethodNode()
|
||||
finallyNode.visitLabel(start)
|
||||
val mark = codegen.frameMap.skipTo(nextFreeLocalIndex)
|
||||
sourceCompiler.generateFinallyBlocks(
|
||||
finallyNode, curFinallyDepth, extension.returnType, extension.finallyIntervalEnd.label, extension.jumpTarget
|
||||
|
||||
val finallyCodegen =
|
||||
sourceCompiler.createCodegenForExternalFinallyBlockGenerationOnNonLocalReturn(finallyNode, curFinallyDepth)
|
||||
|
||||
val frameMap = finallyCodegen.frameMap
|
||||
val mark = frameMap.mark()
|
||||
var marker = -1
|
||||
val intervals = processor.localVarsMetaInfo.currentIntervals
|
||||
for (interval in intervals) {
|
||||
marker = max(interval.node.index + 1, marker)
|
||||
}
|
||||
while (frameMap.currentSize < max(processor.nextFreeLocalIndex, offsetForFinallyLocalVar + marker)) {
|
||||
frameMap.enterTemp(Type.INT_TYPE)
|
||||
}
|
||||
|
||||
sourceCompiler.generateFinallyBlocksIfNeeded(
|
||||
finallyCodegen, extension.returnType, extension.finallyIntervalEnd.label, extension.jumpTarget
|
||||
)
|
||||
mark.dropTo()
|
||||
|
||||
//Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method
|
||||
insertNodeBefore(finallyNode, intoNode, curInstr)
|
||||
|
||||
val splitBy = SimpleInterval(start.info as LabelNode, extension.finallyIntervalEnd)
|
||||
processor.tryBlocksMetaInfo.splitAndRemoveCurrentIntervals(splitBy, true)
|
||||
processor.localVarsMetaInfo.splitAndRemoveCurrentIntervals(splitBy, true)
|
||||
processor.localVarsMetaInfo.splitAndRemoveCurrentIntervals(splitBy, true);
|
||||
|
||||
mark.dropTo()
|
||||
}
|
||||
|
||||
curInstr = curInstr.next
|
||||
}
|
||||
|
||||
processor.substituteTryBlockNodes(intoNode)
|
||||
processor.substituteLocalVarTable(intoNode)
|
||||
processor.substituteLocalVarTable(intoNode);
|
||||
}
|
||||
|
||||
protected abstract fun generateAssertFieldIfNeeded(info: RootInliningContext)
|
||||
@@ -206,50 +345,90 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
}
|
||||
}
|
||||
|
||||
protected fun rememberClosure(parameterType: Type, index: Int, lambdaInfo: LambdaInfo) {
|
||||
val closureInfo = invocationParamBuilder.addNextValueParameter(parameterType, true, null, index)
|
||||
closureInfo.functionalArgument = lambdaInfo
|
||||
expressionMap[closureInfo.index] = lambdaInfo
|
||||
}
|
||||
|
||||
protected fun putCapturedToLocalVal(stackValue: StackValue, capturedParam: CapturedParamDesc, kotlinType: KotlinType?) {
|
||||
val info = invocationParamBuilder.addCapturedParam(capturedParam, capturedParam.fieldName, false)
|
||||
if (stackValue.isLocalWithNoBoxing(JvmKotlinType(info.type, kotlinType))) {
|
||||
info.remapValue = stackValue
|
||||
} else {
|
||||
stackValue.put(info.type, kotlinType, codegen.visitor)
|
||||
val local = StackValue.local(codegen.frameMap.enterTemp(info.type), info.type)
|
||||
local.store(StackValue.onStack(info.type), codegen.visitor)
|
||||
info.remapValue = local
|
||||
info.isSynthetic = true
|
||||
}
|
||||
}
|
||||
|
||||
protected fun putArgumentToLocalVal(jvmKotlinType: JvmKotlinType, stackValue: StackValue, parameterIndex: Int, kind: ValueKind) {
|
||||
if (kind === ValueKind.DEFAULT_MASK || kind === ValueKind.METHOD_HANDLE_IN_DEFAULT) {
|
||||
return processDefaultMaskOrMethodHandler(stackValue, kind)
|
||||
}
|
||||
|
||||
val info = invocationParamBuilder.addNextValueParameter(jvmKotlinType.type, false, null, parameterIndex)
|
||||
info.functionalArgument = when (kind) {
|
||||
ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND ->
|
||||
NonInlineableArgumentForInlineableParameterCalledInSuspend
|
||||
ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER ->
|
||||
NonInlineableArgumentForInlineableSuspendParameter
|
||||
else -> null
|
||||
}
|
||||
when {
|
||||
kind === ValueKind.DEFAULT_PARAMETER ->
|
||||
codegen.frameMap.enterTemp(info.type) // the inline function will put the value into this slot
|
||||
stackValue.isLocalWithNoBoxing(jvmKotlinType) ->
|
||||
info.remapValue = stackValue
|
||||
else -> {
|
||||
stackValue.put(info.type, jvmKotlinType.kotlinType, codegen.visitor)
|
||||
codegen.visitor.store(codegen.frameMap.enterTemp(info.type), info.type)
|
||||
private fun generateClosuresBodies() {
|
||||
for (info in expressionMap.values) {
|
||||
if (info is LambdaInfo) {
|
||||
info.generateLambdaBody(sourceCompiler, reifiedTypeInliner)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected fun putArgumentOrCapturedToLocalVal(
|
||||
jvmKotlinType: JvmKotlinType,
|
||||
stackValue: StackValue,
|
||||
capturedParamIndex: Int,
|
||||
parameterIndex: Int,
|
||||
kind: ValueKind
|
||||
) {
|
||||
val isDefaultParameter = kind === ValueKind.DEFAULT_PARAMETER
|
||||
val jvmType = jvmKotlinType.type
|
||||
val kotlinType = jvmKotlinType.kotlinType
|
||||
if (!isDefaultParameter && shouldPutGeneralValue(jvmType, kotlinType, stackValue)) {
|
||||
stackValue.put(jvmType, kotlinType, codegen.v)
|
||||
}
|
||||
|
||||
if (!asFunctionInline && Type.VOID_TYPE !== jvmType) {
|
||||
//TODO remap only inlinable closure => otherwise we could get a lot of problem
|
||||
val couldBeRemapped = !shouldPutGeneralValue(jvmType, kotlinType, stackValue) && kind !== ValueKind.DEFAULT_PARAMETER
|
||||
val remappedValue = if (couldBeRemapped) stackValue else null
|
||||
|
||||
val info: ParameterInfo
|
||||
if (capturedParamIndex >= 0) {
|
||||
val capturedParamInfoInLambda = activeLambda!!.capturedVars[capturedParamIndex]
|
||||
info = invocationParamBuilder.addCapturedParam(capturedParamInfoInLambda, capturedParamInfoInLambda.fieldName, false)
|
||||
info.remapValue = remappedValue
|
||||
} else {
|
||||
info = invocationParamBuilder.addNextValueParameter(jvmType, false, remappedValue, parameterIndex)
|
||||
info.functionalArgument = when (kind) {
|
||||
ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND ->
|
||||
NonInlineableArgumentForInlineableParameterCalledInSuspend
|
||||
ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER -> NonInlineableArgumentForInlineableSuspendParameter
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
recordParameterValueInLocalVal(
|
||||
false,
|
||||
isDefaultParameter || kind === ValueKind.DEFAULT_LAMBDA_CAPTURED_PARAMETER,
|
||||
info
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun recordParameterValueInLocalVal(
|
||||
delayedWritingToLocals: Boolean,
|
||||
skipStore: Boolean,
|
||||
vararg infos: ParameterInfo
|
||||
): Function0<Unit>? {
|
||||
val index = IntArray(infos.size) { i ->
|
||||
if (!infos[i].isSkippedOrRemapped) {
|
||||
codegen.frameMap.enterTemp(infos[i].type)
|
||||
} else -1
|
||||
}
|
||||
|
||||
val possibleLazyTask = {
|
||||
for (i in infos.indices.reversed()) {
|
||||
val info = infos[i]
|
||||
if (!info.isSkippedOrRemapped) {
|
||||
val type = info.type
|
||||
val local = StackValue.local(index[i], type)
|
||||
if (!skipStore) {
|
||||
local.store(StackValue.onStack(info.typeOnStack), codegen.v)
|
||||
}
|
||||
if (info is CapturedParamInfo) {
|
||||
info.remapValue = local
|
||||
info.isSynthetic = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (delayedWritingToLocals) return possibleLazyTask
|
||||
possibleLazyTask()
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
private fun leaveTemps() {
|
||||
invocationParamBuilder.listAllParams().asReversed().forEach { param ->
|
||||
if (!param.isSkippedOrRemapped || CapturedParamInfo.isSynthetic(param)) {
|
||||
@@ -258,19 +437,45 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
}
|
||||
}
|
||||
|
||||
private fun rememberCapturedForDefaultLambda(defaultLambda: DefaultLambda) {
|
||||
for (captured in defaultLambda.capturedVars) {
|
||||
val info = invocationParamBuilder.addCapturedParam(captured, captured.fieldName, false)
|
||||
info.remapValue = StackValue.local(codegen.frameMap.enterTemp(info.type), info.type)
|
||||
info.isSynthetic = true
|
||||
private fun putClosureParametersOnStack() {
|
||||
for (next in expressionMap.values) {
|
||||
//closure parameters for bounded callable references are generated inplace
|
||||
if (next is LambdaInfo) {
|
||||
if (next is ExpressionLambda && next.isBoundCallableReference) continue
|
||||
putClosureParametersOnStack(next, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processDefaultMaskOrMethodHandler(value: StackValue, kind: ValueKind) {
|
||||
assert(value is StackValue.Constant) { "Additional default method argument should be constant, but $value" }
|
||||
abstract protected fun putClosureParametersOnStack(next: LambdaInfo, functionReferenceReceiver: StackValue?)
|
||||
|
||||
protected fun rememberCapturedForDefaultLambda(defaultLambda: DefaultLambda) {
|
||||
for ((paramIndex, captured) in defaultLambda.capturedVars.withIndex()) {
|
||||
putArgumentOrCapturedToLocalVal(
|
||||
JvmKotlinType(captured.type),
|
||||
//HACK: actually parameter would be placed on stack in default function
|
||||
// also see ValueKind.DEFAULT_LAMBDA_CAPTURED_PARAMETER check
|
||||
StackValue.onStack(captured.type),
|
||||
paramIndex,
|
||||
paramIndex,
|
||||
ValueKind.DEFAULT_LAMBDA_CAPTURED_PARAMETER
|
||||
)
|
||||
|
||||
defaultLambda.parameterOffsetsInDefault.add(invocationParamBuilder.nextParameterOffset)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected fun processDefaultMaskOrMethodHandler(value: StackValue, kind: ValueKind): Boolean {
|
||||
if (kind !== ValueKind.DEFAULT_MASK && kind !== ValueKind.METHOD_HANDLE_IN_DEFAULT) {
|
||||
return false
|
||||
}
|
||||
assert(value is StackValue.Constant) {
|
||||
"Additional default method argument should be constant, but " + value
|
||||
}
|
||||
val constantValue = (value as StackValue.Constant).value
|
||||
if (kind === ValueKind.DEFAULT_MASK) {
|
||||
assert(constantValue is Int) { "Mask should be of Integer type, but $constantValue" }
|
||||
assert(constantValue is Int) { "Mask should be of Integer type, but " + constantValue }
|
||||
maskValues.add(constantValue as Int)
|
||||
if (maskStartIndex == -1) {
|
||||
maskStartIndex = invocationParamBuilder.listAllParams().sumOf {
|
||||
@@ -281,40 +486,228 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
assert(constantValue == null) { "Additional method handle for default argument should be null, but " + constantValue!! }
|
||||
methodHandleInDefaultMethodIndex = maskStartIndex + maskValues.size
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun trackLookup(functionOrAccessor: FunctionDescriptor) {
|
||||
val functionOrAccessorName = jvmSignature.asmMethod.name
|
||||
val lookupTracker = state.configuration.get(CommonConfigurationKeys.LOOKUP_TRACKER) ?: return
|
||||
val location = sourceCompiler.lookupLocation.location ?: return
|
||||
val position = if (lookupTracker.requiresPosition) location.position else Position.NO_POSITION
|
||||
val classOrPackageFragment = functionOrAccessor.containingDeclaration
|
||||
lookupTracker.record(
|
||||
location.filePath,
|
||||
position,
|
||||
DescriptorUtils.getFqName(classOrPackageFragment).asString(),
|
||||
ScopeKind.CLASSIFIER,
|
||||
functionOrAccessorName
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
internal fun createInlineMethodNode(
|
||||
callDefault: Boolean,
|
||||
typeArguments: List<TypeParameterMarker>?,
|
||||
typeSystem: TypeSystemCommonBackendContext
|
||||
): SMAPAndMethodNode {
|
||||
val intrinsic = generateInlineIntrinsic(state, functionDescriptor, typeArguments, typeSystem)
|
||||
if (intrinsic != null) {
|
||||
return SMAPAndMethodNode(intrinsic, createDefaultFakeSMAP())
|
||||
}
|
||||
|
||||
var asmMethod = mapMethod(callDefault)
|
||||
if (asmMethod.name.contains("-") &&
|
||||
!state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_INLINE_CLASSES_MANGLING_SCHEME) &&
|
||||
classFileContainsMethod(functionDescriptor, state, asmMethod) == false
|
||||
) {
|
||||
state.typeMapper.useOldManglingRulesForFunctionAcceptingInlineClass = true
|
||||
asmMethod = mapMethod(callDefault)
|
||||
state.typeMapper.useOldManglingRulesForFunctionAcceptingInlineClass = false
|
||||
}
|
||||
|
||||
val directMember = getDirectMemberAndCallableFromObject(functionDescriptor)
|
||||
if (!isBuiltInArrayIntrinsic(functionDescriptor) && !descriptorIsDeserialized(directMember)) {
|
||||
val node = sourceCompiler.doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, callDefault, asmMethod)
|
||||
node.node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false)
|
||||
return node
|
||||
}
|
||||
|
||||
return getCompiledMethodNodeInner(functionDescriptor, directMember, asmMethod, methodOwner, state, jvmSignature)
|
||||
}
|
||||
|
||||
private fun mapMethod(callDefault: Boolean): Method =
|
||||
if (callDefault) state.typeMapper.mapDefaultMethod(functionDescriptor, sourceCompiler.contextKind)
|
||||
else mangleSuspendInlineFunctionAsmMethodIfNeeded(functionDescriptor, jvmSignature.asmMethod)
|
||||
|
||||
companion object {
|
||||
private fun StackValue.isLocalWithNoBoxing(expected: JvmKotlinType): Boolean =
|
||||
isPrimitive(expected.type) == isPrimitive(type) &&
|
||||
!StackValue.requiresInlineClassBoxingOrUnboxing(type, kotlinType, expected.type, expected.kotlinType) &&
|
||||
(this is StackValue.Local || isCapturedInlineParameter())
|
||||
|
||||
private fun StackValue.isCapturedInlineParameter(): Boolean {
|
||||
val field = if (this is StackValue.FieldForSharedVar) receiver else this
|
||||
return field is StackValue.Field && field.descriptor is ParameterDescriptor &&
|
||||
InlineUtil.isInlineParameter(field.descriptor) &&
|
||||
InlineUtil.isInline(field.descriptor.containingDeclaration)
|
||||
internal fun createSpecialInlineMethodNodeFromBinaries(functionDescriptor: FunctionDescriptor, state: GenerationState): MethodNode {
|
||||
val directMember = getDirectMemberAndCallableFromObject(functionDescriptor)
|
||||
assert(directMember is DescriptorWithContainerSource) {
|
||||
"Function is not in binaries: $functionDescriptor"
|
||||
}
|
||||
assert(directMember is FunctionDescriptor && directMember.isOperator) {
|
||||
"Operator function expected: $directMember"
|
||||
}
|
||||
|
||||
val methodOwner = state.typeMapper.mapImplementationOwner(functionDescriptor)
|
||||
val jvmSignature = state.typeMapper.mapSignatureWithGeneric(functionDescriptor, OwnerKind.IMPLEMENTATION)
|
||||
|
||||
val asmMethod = mangleSuspendInlineFunctionAsmMethodIfNeeded(functionDescriptor, jvmSignature.asmMethod)
|
||||
|
||||
return getCompiledMethodNodeInner(functionDescriptor, directMember, asmMethod, methodOwner, state, jvmSignature).node
|
||||
}
|
||||
|
||||
// Stack spilling before inline function call is required if the inlined bytecode has:
|
||||
// 1. try-catch blocks - otherwise the stack spilling before and after them will not be correct;
|
||||
// 2. suspension points - again, the stack spilling around them is otherwise wrong;
|
||||
// 3. loops - OpenJDK cannot JIT-optimize between loop iterations if the stack is not empty.
|
||||
// Instead of checking for loops precisely, we just check if there are any backward jumps -
|
||||
// that is, a jump from instruction #i to instruction #j where j < i.
|
||||
private fun MethodNode.requiresEmptyStackOnEntry(): Boolean = tryCatchBlocks.isNotEmpty() ||
|
||||
instructions.toArray().any { isBeforeSuspendMarker(it) || isBeforeInlineSuspendMarker(it) || isBackwardsJump(it) }
|
||||
private fun getCompiledMethodNodeInner(
|
||||
functionDescriptor: FunctionDescriptor,
|
||||
directMember: CallableMemberDescriptor,
|
||||
asmMethod: Method,
|
||||
methodOwner: Type,
|
||||
state: GenerationState,
|
||||
jvmSignature: JvmMethodSignature
|
||||
): SMAPAndMethodNode {
|
||||
val methodId = MethodId(methodOwner.internalName, asmMethod)
|
||||
|
||||
private fun MethodNode.isBackwardsJump(insn: AbstractInsnNode): Boolean = when (insn) {
|
||||
is JumpInsnNode -> isBackwardsJump(insn, insn.label)
|
||||
is LookupSwitchInsnNode ->
|
||||
insn.dflt?.let { to -> isBackwardsJump(insn, to) } == true || insn.labels.any { to -> isBackwardsJump(insn, to) }
|
||||
is TableSwitchInsnNode ->
|
||||
insn.dflt?.let { to -> isBackwardsJump(insn, to) } == true || insn.labels.any { to -> isBackwardsJump(insn, to) }
|
||||
else -> false
|
||||
val resultInCache = state.inlineCache.methodNodeById.getOrPut(methodId) {
|
||||
val result = doCreateMethodNodeFromCompiled(directMember, state, asmMethod)
|
||||
?: if (functionDescriptor.isSuspend)
|
||||
doCreateMethodNodeFromCompiled(directMember, state, jvmSignature.asmMethod)
|
||||
else
|
||||
null
|
||||
result ?:
|
||||
throw IllegalStateException("Couldn't obtain compiled function body for $functionDescriptor")
|
||||
}
|
||||
|
||||
return SMAPAndMethodNode(cloneMethodNode(resultInCache.node), resultInCache.classSMAP)
|
||||
}
|
||||
|
||||
private fun MethodNode.isBackwardsJump(from: AbstractInsnNode, to: LabelNode): Boolean =
|
||||
instructions.indexOf(to) < instructions.indexOf(from)
|
||||
private fun createDefaultFakeSMAP() = SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)
|
||||
|
||||
// For suspend inline functions we generate two methods:
|
||||
// 1) normal one: with state machine to call directly
|
||||
// 2) for inliner: with mangled name and without state machine
|
||||
private fun mangleSuspendInlineFunctionAsmMethodIfNeeded(functionDescriptor: FunctionDescriptor, asmMethod: Method): Method {
|
||||
if (!functionDescriptor.isSuspend) return asmMethod
|
||||
return Method("${asmMethod.name}$FOR_INLINE_SUFFIX", asmMethod.descriptor)
|
||||
}
|
||||
|
||||
private fun getDirectMemberAndCallableFromObject(functionDescriptor: FunctionDescriptor): CallableMemberDescriptor {
|
||||
val directMember = JvmCodegenUtil.getDirectMember(functionDescriptor)
|
||||
return (directMember as? ImportedFromObjectCallableDescriptor<*>)?.callableFromObject ?: directMember
|
||||
}
|
||||
|
||||
private fun doCreateMethodNodeFromCompiled(
|
||||
callableDescriptor: CallableMemberDescriptor,
|
||||
state: GenerationState,
|
||||
asmMethod: Method
|
||||
): SMAPAndMethodNode? {
|
||||
if (isBuiltInArrayIntrinsic(callableDescriptor)) {
|
||||
val body = when {
|
||||
callableDescriptor is FictitiousArrayConstructor -> IntrinsicArrayConstructors.generateArrayConstructorBody(asmMethod)
|
||||
callableDescriptor.name.asString() == "emptyArray" -> IntrinsicArrayConstructors.generateEmptyArrayBody(asmMethod)
|
||||
callableDescriptor.name.asString() == "arrayOf" -> IntrinsicArrayConstructors.generateArrayOfBody(asmMethod)
|
||||
else -> throw UnsupportedOperationException("Not an array intrinsic: $callableDescriptor")
|
||||
}
|
||||
return SMAPAndMethodNode(body, SMAP(listOf()))
|
||||
}
|
||||
|
||||
assert(callableDescriptor is DescriptorWithContainerSource) { "Not a deserialized function or proper: $callableDescriptor" }
|
||||
|
||||
val containingClasses =
|
||||
KotlinTypeMapper.getContainingClassesForDeserializedCallable(callableDescriptor as DescriptorWithContainerSource)
|
||||
|
||||
val containerId = containingClasses.implClassId
|
||||
|
||||
val bytes = state.inlineCache.classBytes.getOrPut(containerId) {
|
||||
findVirtualFile(state, containerId)?.contentsToByteArray()
|
||||
?: throw IllegalStateException("Couldn't find declaration file for $containerId")
|
||||
}
|
||||
|
||||
val classType = AsmUtil.asmTypeByClassId(containerId)
|
||||
val methodNode = getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, classType)
|
||||
if (methodNode == null && requiresFunctionNameManglingForReturnType(callableDescriptor)) {
|
||||
val nameWithoutManglingSuffix = asmMethod.name.stripManglingSuffixOrNull()
|
||||
if (nameWithoutManglingSuffix != null) {
|
||||
val methodWithoutMangling = getMethodNode(bytes, nameWithoutManglingSuffix, asmMethod.descriptor, classType)
|
||||
if (methodWithoutMangling != null) return methodWithoutMangling
|
||||
}
|
||||
return getMethodNode(bytes, "$nameWithoutManglingSuffix-impl", asmMethod.descriptor, classType)
|
||||
}
|
||||
|
||||
return methodNode
|
||||
}
|
||||
|
||||
private fun String.stripManglingSuffixOrNull(): String? {
|
||||
val dashIndex = indexOf('-')
|
||||
return if (dashIndex < 0) null else substring(0, dashIndex)
|
||||
}
|
||||
|
||||
private fun isBuiltInArrayIntrinsic(callableDescriptor: CallableMemberDescriptor): Boolean {
|
||||
if (callableDescriptor is FictitiousArrayConstructor) return true
|
||||
val name = callableDescriptor.name.asString()
|
||||
return (name == "arrayOf" || name == "emptyArray") && callableDescriptor.containingDeclaration.let { container ->
|
||||
container is PackageFragmentDescriptor && container.fqName == StandardNames.BUILT_INS_PACKAGE_FQ_NAME
|
||||
}
|
||||
}
|
||||
|
||||
/*descriptor is null for captured vars*/
|
||||
private fun shouldPutGeneralValue(type: Type, kotlinType: KotlinType?, stackValue: StackValue): Boolean {
|
||||
//remap only inline functions (and maybe non primitives)
|
||||
//TODO - clean assertion and remapping logic
|
||||
|
||||
// don't remap boxing/unboxing primitives
|
||||
if (isPrimitive(type) != isPrimitive(stackValue.type)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// don't remap boxing/unboxing inline classes
|
||||
if (StackValue.requiresInlineClassBoxingOrUnboxing(stackValue.type, stackValue.kotlinType, type, kotlinType)) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (stackValue is StackValue.Local) {
|
||||
return false
|
||||
}
|
||||
|
||||
var field = stackValue
|
||||
if (stackValue is StackValue.FieldForSharedVar) {
|
||||
field = stackValue.receiver
|
||||
}
|
||||
|
||||
//check that value corresponds to captured inlining parameter
|
||||
if (field is StackValue.Field) {
|
||||
val varDescriptor = field.descriptor
|
||||
//check that variable is inline function parameter
|
||||
return !(varDescriptor is ParameterDescriptor &&
|
||||
InlineUtil.isInlineParameter(varDescriptor) &&
|
||||
InlineUtil.isInline(varDescriptor.containingDeclaration))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
fun getDeclarationLabels(lambdaOrFun: PsiElement?, descriptor: DeclarationDescriptor): Set<String> {
|
||||
val result = HashSet<String>()
|
||||
|
||||
if (lambdaOrFun != null) {
|
||||
val label = LabelResolver.getLabelNameIfAny(lambdaOrFun)
|
||||
if (label != null) {
|
||||
result.add(label.asString())
|
||||
}
|
||||
}
|
||||
|
||||
if (!isFunctionLiteral(descriptor)) {
|
||||
if (!descriptor.name.isSpecial) {
|
||||
result.add(descriptor.name.asString())
|
||||
}
|
||||
result.add(FIRST_FUN_LABEL)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val BaseExpressionCodegen.v: InstructionAdapter
|
||||
get() = visitor
|
||||
|
||||
@@ -15,13 +15,15 @@ import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
class InlineCodegenForDefaultBody(
|
||||
private val function: FunctionDescriptor,
|
||||
codegen: ExpressionCodegen,
|
||||
val state: GenerationState,
|
||||
private val methodOwner: Type,
|
||||
private val jvmSignature: JvmMethodSignature,
|
||||
private val sourceCompilerForInline: PsiSourceCompilerForInline
|
||||
private val sourceCompilerForInline: SourceCompilerForInline
|
||||
) : CallGenerator {
|
||||
private val sourceMapper: SourceMapper = codegen.parentCodegen.orCreateSourceMapper
|
||||
|
||||
@@ -37,22 +39,32 @@ class InlineCodegenForDefaultBody(
|
||||
}
|
||||
|
||||
override fun genCallInner(callableMethod: Callable, resolvedCall: ResolvedCall<*>?, callDefault: Boolean, codegen: ExpressionCodegen) {
|
||||
assert(!callDefault) { "inlining default stub into another default stub" }
|
||||
val (node, smap) = sourceCompilerForInline.compileInlineFunction(jvmSignature)
|
||||
val childSourceMapper = SourceMapCopier(sourceMapper, smap)
|
||||
val nodeAndSmap = PsiInlineCodegen(
|
||||
codegen, state, function, methodOwner, jvmSignature, TypeParameterMappings(), sourceCompilerForInline
|
||||
).createInlineMethodNode(
|
||||
callDefault, null, codegen.typeSystem
|
||||
)
|
||||
val childSourceMapper = SourceMapCopier(sourceMapper, nodeAndSmap.classSMAP)
|
||||
|
||||
val node = nodeAndSmap.node
|
||||
val transformedMethod = MethodNode(
|
||||
node.access,
|
||||
node.name,
|
||||
node.desc,
|
||||
node.signature,
|
||||
node.exceptions.toTypedArray()
|
||||
)
|
||||
|
||||
val argsSize =
|
||||
(Type.getArgumentsAndReturnSizes(jvmSignature.asmMethod.descriptor) ushr 2) - if (callableMethod.isStaticCall()) 1 else 0
|
||||
// `$default` is only for Kotlin use so it has no `$$forInline` version - this *is* what the inliner will use.
|
||||
node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false)
|
||||
node.accept(object : MethodBodyVisitor(codegen.visitor) {
|
||||
// The LVT was not generated at all, so move the start of parameters to the start of the method.
|
||||
override fun visitLocalVariable(name: String, desc: String, signature: String?, start: Label, end: Label, index: Int) =
|
||||
super.visitLocalVariable(name, desc, signature, if (index < argsSize) methodStartLabel else start, end, index)
|
||||
|
||||
override fun visitLineNumber(line: Int, start: Label) =
|
||||
super.visitLineNumber(childSourceMapper.mapLineNumber(line), start)
|
||||
node.accept(object : InlineAdapter(transformedMethod, 0, childSourceMapper) {
|
||||
override fun visitLocalVariable(name: String, desc: String, signature: String?, start: Label, end: Label, index: Int) {
|
||||
val startLabel = if (index < argsSize) methodStartLabel else start
|
||||
super.visitLocalVariable(name, desc, signature, startLabel, end, index)
|
||||
}
|
||||
})
|
||||
|
||||
transformedMethod.accept(MethodBodyVisitor(codegen.visitor))
|
||||
}
|
||||
|
||||
override fun genValueAndPut(
|
||||
@@ -73,7 +85,7 @@ class InlineCodegenForDefaultBody(
|
||||
throw UnsupportedOperationException("Shouldn't be called")
|
||||
}
|
||||
|
||||
override fun processHiddenParameters() {
|
||||
override fun processAndPutHiddenParameters(justProcess: Boolean) {
|
||||
throw UnsupportedOperationException("Shouldn't be called")
|
||||
}
|
||||
|
||||
|
||||
@@ -8,11 +8,13 @@ package org.jetbrains.kotlin.codegen.inline
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.org.objectweb.asm.ClassReader
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
interface FunctionalArgument
|
||||
|
||||
@@ -39,6 +41,8 @@ abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgu
|
||||
|
||||
val reifiedTypeParametersUsages = ReifiedTypeParametersUsages()
|
||||
|
||||
abstract fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner<*>)
|
||||
|
||||
open val hasDispatchReceiver = true
|
||||
|
||||
fun addAllParameters(remapper: FieldRemapper): Parameters {
|
||||
@@ -67,52 +71,50 @@ object NonInlineableArgumentForInlineableParameterCalledInSuspend : FunctionalAr
|
||||
object NonInlineableArgumentForInlineableSuspendParameter : FunctionalArgument
|
||||
|
||||
abstract class ExpressionLambda(isCrossInline: Boolean) : LambdaInfo(isCrossInline) {
|
||||
fun generateLambdaBody(sourceCompiler: SourceCompilerForInline) {
|
||||
override fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner<*>) {
|
||||
node = sourceCompiler.generateLambdaBody(this, reifiedTypeParametersUsages)
|
||||
node.node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DefaultLambda(
|
||||
final override val lambdaClassType: Type,
|
||||
capturedArgs: Array<Type>,
|
||||
private val capturedArgs: Array<Type>,
|
||||
isCrossinline: Boolean,
|
||||
val offset: Int,
|
||||
val needReification: Boolean,
|
||||
sourceCompiler: SourceCompilerForInline
|
||||
val needReification: Boolean
|
||||
) : LambdaInfo(isCrossinline) {
|
||||
final override val isSuspend
|
||||
get() = false // TODO: it should probably be true sometimes, but it never was
|
||||
final override val isBoundCallableReference: Boolean
|
||||
final override val capturedVars: List<CapturedParamDesc>
|
||||
|
||||
final override val invokeMethod: Method
|
||||
get() = Method(node.node.name, node.node.desc)
|
||||
final override var isBoundCallableReference by Delegates.notNull<Boolean>()
|
||||
private set
|
||||
|
||||
val originalBoundReceiverType: Type?
|
||||
val parameterOffsetsInDefault: MutableList<Int> = arrayListOf()
|
||||
|
||||
protected val isPropertyReference: Boolean
|
||||
protected val isFunctionReference: Boolean
|
||||
final override lateinit var invokeMethod: Method
|
||||
private set
|
||||
|
||||
init {
|
||||
val classBytes = loadClass(sourceCompiler)
|
||||
final override lateinit var capturedVars: List<CapturedParamDesc>
|
||||
private set
|
||||
|
||||
var originalBoundReceiverType: Type? = null
|
||||
private set
|
||||
|
||||
override val isSuspend = false // TODO: it should probably be true sometimes, but it never was
|
||||
|
||||
override fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner<*>) {
|
||||
val classBytes = loadClassBytesByInternalName(sourceCompiler.state, lambdaClassType.internalName)
|
||||
val superName = ClassReader(classBytes).superName
|
||||
isPropertyReference = superName in PROPERTY_REFERENCE_SUPER_CLASSES
|
||||
isFunctionReference = superName == FUNCTION_REFERENCE.internalName || superName == FUNCTION_REFERENCE_IMPL.internalName
|
||||
val isPropertyReference = superName in PROPERTY_REFERENCE_SUPER_CLASSES
|
||||
val isFunctionReference = superName == FUNCTION_REFERENCE.internalName || superName == FUNCTION_REFERENCE_IMPL.internalName
|
||||
|
||||
val constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, *capturedArgs)
|
||||
val constructor = getMethodNode(classBytes, "<init>", constructorDescriptor, lambdaClassType)?.node
|
||||
assert(constructor != null || capturedArgs.isEmpty()) {
|
||||
"Can't find non-default constructor <init>$constructorDescriptor for default lambda $lambdaClassType"
|
||||
}
|
||||
// This only works for primitives but not inline classes, since information about the Kotlin type of the bound
|
||||
// receiver is not present anywhere. This is why with JVM_IR the constructor argument of bound references
|
||||
// is already `Object`, and this field is never used.
|
||||
originalBoundReceiverType =
|
||||
capturedArgs.singleOrNull()?.takeIf { (isFunctionReference || isPropertyReference) && AsmUtil.isPrimitive(it) }
|
||||
capturedVars =
|
||||
if (isFunctionReference || isPropertyReference)
|
||||
capturedArgs.singleOrNull()?.let {
|
||||
constructor?.desc?.let { Type.getArgumentTypes(it) }?.singleOrNull()?.let {
|
||||
originalBoundReceiverType = it
|
||||
listOf(capturedParamDesc(AsmUtil.RECEIVER_PARAMETER_NAME, AsmUtil.boxType(it), isSuspend = false))
|
||||
} ?: emptyList()
|
||||
else
|
||||
@@ -120,23 +122,23 @@ abstract class DefaultLambda(
|
||||
capturedParamDesc(fieldNode.name, Type.getType(fieldNode.desc), isSuspend = false)
|
||||
}?.toList() ?: emptyList()
|
||||
isBoundCallableReference = (isFunctionReference || isPropertyReference) && capturedVars.isNotEmpty()
|
||||
}
|
||||
|
||||
private fun loadClass(sourceCompiler: SourceCompilerForInline): ByteArray =
|
||||
sourceCompiler.state.inlineCache.classBytes.getOrPut(lambdaClassType.internalName) {
|
||||
loadClassBytesByInternalName(sourceCompiler.state, lambdaClassType.internalName)
|
||||
val invokeNameFallback = (if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString()
|
||||
val invokeMethod = mapAsmMethod(sourceCompiler, isPropertyReference)
|
||||
// TODO: `signatureAmbiguity = true` ignores the argument types from `invokeDescriptor` and only looks at the count.
|
||||
// This effectively masks incorrect results from `mapAsmDescriptor`, which hopefully won't manifest in another way.
|
||||
node = getMethodNode(classBytes, invokeMethod.name, invokeMethod.descriptor, lambdaClassType, signatureAmbiguity = true)
|
||||
?: getMethodNode(classBytes, invokeNameFallback, invokeMethod.descriptor, lambdaClassType, signatureAmbiguity = true)
|
||||
?: error("Can't find method '$invokeMethod' in '${lambdaClassType.internalName}'")
|
||||
this.invokeMethod = Method(node.node.name, node.node.desc)
|
||||
if (needReification) {
|
||||
//nested classes could also require reification
|
||||
reifiedTypeParametersUsages.mergeAll(reifiedTypeInliner.reifyInstructions(node.node))
|
||||
}
|
||||
|
||||
// Returns whether the loaded invoke is erased, i.e. the name equals the fallback and all types are `Object`.
|
||||
protected fun loadInvoke(sourceCompiler: SourceCompilerForInline, erasedName: String, actualMethod: Method): Boolean {
|
||||
val classBytes = loadClass(sourceCompiler)
|
||||
// TODO: `signatureAmbiguity = true` ignores the argument types from `invokeMethod` and only looks at the count.
|
||||
node = getMethodNode(classBytes, actualMethod.name, actualMethod.descriptor, lambdaClassType, signatureAmbiguity = true)
|
||||
?: getMethodNode(classBytes, erasedName, actualMethod.descriptor, lambdaClassType, signatureAmbiguity = true)
|
||||
?: error("Can't find method '$actualMethod' in '${lambdaClassType.internalName}'")
|
||||
return invokeMethod.run { name == erasedName && returnType == OBJECT_TYPE && argumentTypes.all { it == OBJECT_TYPE } }
|
||||
}
|
||||
|
||||
protected abstract fun mapAsmMethod(sourceCompiler: SourceCompilerForInline, isPropertyReference: Boolean): Method
|
||||
|
||||
private companion object {
|
||||
val PROPERTY_REFERENCE_SUPER_CLASSES =
|
||||
listOf(
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType
|
||||
import org.jetbrains.kotlin.codegen.inline.FieldRemapper.Companion.foldName
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.CoroutineTransformer
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.isSuspendLambdaCapturedByOuterObjectOrLambda
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.markNoinlineLambdaIfSuspend
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.surroundInvokesWithSuspendMarkersIfNeeded
|
||||
import org.jetbrains.kotlin.codegen.optimization.ApiVersionCallsPreprocessingMethodTransformer
|
||||
@@ -23,6 +24,7 @@ import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNot
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
@@ -228,7 +230,7 @@ class MethodInliner(
|
||||
return
|
||||
}
|
||||
|
||||
val nullableAnyType = inliningContext.state.module.builtIns.nullableAnyType
|
||||
val nullableAnyType = inliningContext.root.sourceCompilerForInline.compilationContextDescriptor.builtIns.nullableAnyType
|
||||
val expectedParameters = info.invokeMethod.argumentTypes
|
||||
val expectedKotlinParameters = info.invokeMethodParameters
|
||||
val argumentCount = Type.getArgumentTypes(desc).size.let {
|
||||
@@ -423,10 +425,10 @@ class MethodInliner(
|
||||
if (DEFAULT_LAMBDA_FAKE_CALL == owner) {
|
||||
val index = name.substringAfter(DEFAULT_LAMBDA_FAKE_CALL).toInt()
|
||||
val lambda = getFunctionalArgumentIfExists(index) as DefaultLambda
|
||||
for (captured in lambda.capturedVars.asReversed()) {
|
||||
lambda.originalBoundReceiverType?.let {
|
||||
// The receiver is the only captured value; it needs to be boxed.
|
||||
StackValue.onStack(it).put(captured.type, InstructionAdapter(this))
|
||||
lambda.parameterOffsetsInDefault.zip(lambda.capturedVars).asReversed().forEach { (_, captured) ->
|
||||
val originalBoundReceiverType = lambda.originalBoundReceiverType
|
||||
if (lambda.isBoundCallableReference && AsmUtil.isPrimitive(originalBoundReceiverType)) {
|
||||
StackValue.onStack(originalBoundReceiverType!!).put(captured.type, InstructionAdapter(this))
|
||||
}
|
||||
super.visitFieldInsn(
|
||||
Opcodes.PUTSTATIC,
|
||||
@@ -823,7 +825,7 @@ class MethodInliner(
|
||||
getFunctionalArgumentIfExists((insnNode as VarInsnNode).`var`)
|
||||
insnNode is FieldInsnNode && insnNode.name.startsWith(CAPTURED_FIELD_FOLD_PREFIX) ->
|
||||
findCapturedField(insnNode, nodeRemapper).functionalArgument
|
||||
insnNode is FieldInsnNode && inliningContext.root.sourceCompilerForInline.isSuspendLambdaCapturedByOuterObjectOrLambda(insnNode.name) ->
|
||||
insnNode is FieldInsnNode && insnNode.isSuspendLambdaCapturedByOuterObjectOrLambda(inliningContext) ->
|
||||
NonInlineableArgumentForInlineableParameterCalledInSuspend
|
||||
else ->
|
||||
null
|
||||
|
||||
@@ -37,7 +37,7 @@ abstract class ObjectTransformer<out T : TransformationInfo>(@JvmField val trans
|
||||
val classBuilder = state.factory.newVisitor(
|
||||
JvmDeclarationOrigin.NO_ORIGIN,
|
||||
Type.getObjectType(transformationInfo.newClassName),
|
||||
inliningContext.callSiteInfo.file!!
|
||||
inliningContext.root.sourceCompilerForInline.callsiteFile!!
|
||||
)
|
||||
|
||||
return RemappingClassBuilder(
|
||||
|
||||
@@ -13,9 +13,11 @@ import org.jetbrains.kotlin.codegen.binding.CalculatedClosure
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||
@@ -24,9 +26,10 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlinableParameterExpression
|
||||
import org.jetbrains.kotlin.resolve.inline.isInlineOnly
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
@@ -38,14 +41,14 @@ import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
class PsiInlineCodegen(
|
||||
codegen: ExpressionCodegen,
|
||||
state: GenerationState,
|
||||
private val functionDescriptor: FunctionDescriptor,
|
||||
function: FunctionDescriptor,
|
||||
methodOwner: Type,
|
||||
signature: JvmMethodSignature,
|
||||
typeParameterMappings: TypeParameterMappings<KotlinType>,
|
||||
sourceCompiler: SourceCompilerForInline,
|
||||
private val methodOwner: Type,
|
||||
private val actualDispatchReceiver: Type
|
||||
private val actualDispatchReceiver: Type = methodOwner
|
||||
) : InlineCodegen<ExpressionCodegen>(
|
||||
codegen, state, signature, typeParameterMappings, sourceCompiler,
|
||||
codegen, state, function, methodOwner, signature, typeParameterMappings, sourceCompiler,
|
||||
ReifiedTypeInliner(
|
||||
typeParameterMappings, PsiInlineIntrinsicsSupport(state), codegen.typeSystem,
|
||||
state.languageVersionSettings, state.unifiedNullChecks
|
||||
@@ -63,26 +66,13 @@ class PsiInlineCodegen(
|
||||
callDefault: Boolean,
|
||||
codegen: ExpressionCodegen
|
||||
) {
|
||||
(sourceCompiler as PsiSourceCompilerForInline).callDefault = callDefault
|
||||
assert(hiddenParameters.isEmpty()) { "putHiddenParamsIntoLocals() should be called after processHiddenParameters()" }
|
||||
if (!state.globalInlineContext.enterIntoInlining(functionDescriptor, resolvedCall?.call?.callElement)) {
|
||||
generateStub(resolvedCall?.call?.callElement?.text ?: "<no source>", codegen)
|
||||
return
|
||||
}
|
||||
try {
|
||||
val registerLineNumber = registerLineNumberAfterwards(resolvedCall)
|
||||
for (info in expressionMap.values) {
|
||||
if (info is PsiExpressionLambda) {
|
||||
// Can't be done immediately in `rememberClosure` for some reason:
|
||||
info.generateLambdaBody(sourceCompiler)
|
||||
// Requires `generateLambdaBody` first if the closure is non-empty (for bound callable references,
|
||||
// or indeed any callable references, it *is* empty, so this was done in `rememberClosure`):
|
||||
if (!info.isBoundCallableReference) {
|
||||
putClosureParametersOnStack(info, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
performInline(registerLineNumber, functionDescriptor.isInlineOnly())
|
||||
performInline(resolvedCall?.typeArguments?.keys?.toList(), callDefault, callDefault, codegen.typeSystem, registerLineNumber)
|
||||
} finally {
|
||||
state.globalInlineContext.exitFromInlining()
|
||||
}
|
||||
@@ -94,30 +84,38 @@ class PsiInlineCodegen(
|
||||
return parentIfCondition.isAncestor(callElement, false)
|
||||
}
|
||||
|
||||
private val hiddenParameters = mutableListOf<Pair<ParameterInfo, Int>>()
|
||||
|
||||
override fun processHiddenParameters() {
|
||||
val contextKind = (sourceCompiler as PsiSourceCompilerForInline).context.contextKind
|
||||
if (getMethodAsmFlags(functionDescriptor, contextKind, state) and Opcodes.ACC_STATIC == 0) {
|
||||
hiddenParameters += invocationParamBuilder.addNextParameter(methodOwner, false, actualDispatchReceiver) to
|
||||
codegen.frameMap.enterTemp(methodOwner)
|
||||
override fun processAndPutHiddenParameters(justProcess: Boolean) {
|
||||
if (getMethodAsmFlags(functionDescriptor, sourceCompiler.contextKind, state) and Opcodes.ACC_STATIC == 0) {
|
||||
invocationParamBuilder.addNextParameter(methodOwner, false, actualDispatchReceiver)
|
||||
}
|
||||
|
||||
for (param in jvmSignature.valueParameters) {
|
||||
if (param.kind == JvmMethodParameterKind.VALUE) {
|
||||
break
|
||||
}
|
||||
hiddenParameters += invocationParamBuilder.addNextParameter(param.asmType, false) to
|
||||
codegen.frameMap.enterTemp(param.asmType)
|
||||
invocationParamBuilder.addNextParameter(param.asmType, false)
|
||||
}
|
||||
|
||||
invocationParamBuilder.markValueParametersStart()
|
||||
val hiddenParameters = invocationParamBuilder.buildParameters().parameters
|
||||
|
||||
delayedHiddenWriting = recordParameterValueInLocalVal(justProcess, false, *hiddenParameters.toTypedArray())
|
||||
}
|
||||
|
||||
override fun putHiddenParamsIntoLocals() {
|
||||
for (i in hiddenParameters.indices.reversed()) {
|
||||
val (param, offset) = hiddenParameters[i]
|
||||
StackValue.local(offset, param.type).store(StackValue.onStack(param.typeOnStack), codegen.visitor)
|
||||
override fun putClosureParametersOnStack(next: LambdaInfo, functionReferenceReceiver: StackValue?) {
|
||||
activeLambda = next
|
||||
when (next) {
|
||||
is PsiExpressionLambda -> codegen.pushClosureOnStack(next.classDescriptor, true, this, functionReferenceReceiver)
|
||||
is DefaultLambda -> rememberCapturedForDefaultLambda(next)
|
||||
else -> throw RuntimeException("Unknown lambda: $next")
|
||||
}
|
||||
hiddenParameters.clear()
|
||||
activeLambda = null
|
||||
}
|
||||
|
||||
private fun getBoundCallableReferenceReceiver(argumentExpression: KtExpression): ReceiverValue? {
|
||||
val deparenthesized = KtPsiUtil.deparenthesize(argumentExpression) as? KtCallableReferenceExpression ?: return null
|
||||
val resolvedCall = deparenthesized.callableReference.getResolvedCallWithAssert(state.bindingContext)
|
||||
return JvmCodegenUtil.getBoundCallableReferenceReceiver(resolvedCall)
|
||||
}
|
||||
|
||||
/*lambda or callable reference*/
|
||||
@@ -140,7 +138,23 @@ class PsiInlineCodegen(
|
||||
}
|
||||
|
||||
if (isInliningParameter(argumentExpression, valueParameterDescriptor)) {
|
||||
rememberClosure(argumentExpression, parameterType.type, valueParameterDescriptor)
|
||||
val lambdaInfo = rememberClosure(argumentExpression, parameterType.type, valueParameterDescriptor)
|
||||
|
||||
val receiverValue = getBoundCallableReferenceReceiver(argumentExpression)
|
||||
if (receiverValue != null) {
|
||||
val receiver = codegen.generateReceiverValue(receiverValue, false)
|
||||
val receiverKotlinType = receiver.kotlinType
|
||||
val boxedReceiver =
|
||||
if (receiverKotlinType != null)
|
||||
DescriptorAsmUtil.boxType(receiver.type, receiverKotlinType, state.typeMapper)
|
||||
else
|
||||
AsmUtil.boxType(receiver.type)
|
||||
|
||||
putClosureParametersOnStack(
|
||||
lambdaInfo,
|
||||
StackValue.coercion(receiver, boxedReceiver, receiverKotlinType)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val value = codegen.gen(argumentExpression)
|
||||
val kind = when {
|
||||
@@ -159,52 +173,52 @@ class PsiInlineCodegen(
|
||||
private fun isCallSiteIsSuspend(descriptor: ValueParameterDescriptor): Boolean =
|
||||
state.bindingContext[CodegenBinding.CALL_SITE_IS_SUSPEND_FOR_CROSSINLINE_LAMBDA, descriptor] == true
|
||||
|
||||
private fun rememberClosure(expression: KtExpression, type: Type, parameter: ValueParameterDescriptor) {
|
||||
private fun rememberClosure(expression: KtExpression, type: Type, parameter: ValueParameterDescriptor): LambdaInfo {
|
||||
val ktLambda = KtPsiUtil.deparenthesize(expression)
|
||||
assert(isInlinableParameterExpression(ktLambda)) { "Couldn't find inline expression in ${expression.text}" }
|
||||
|
||||
val boundReceiver = if (ktLambda is KtCallableReferenceExpression) {
|
||||
val resolvedCall = ktLambda.callableReference.getResolvedCallWithAssert(state.bindingContext)
|
||||
JvmCodegenUtil.getBoundCallableReferenceReceiver(resolvedCall)
|
||||
} else null
|
||||
|
||||
val lambda = PsiExpressionLambda(ktLambda!!, state, parameter.isCrossinline, boundReceiver != null)
|
||||
rememberClosure(type, parameter.index, lambda)
|
||||
if (boundReceiver != null) {
|
||||
// Has to be done immediately to preserve evaluation order.
|
||||
val receiver = codegen.generateReceiverValue(boundReceiver, false)
|
||||
val receiverKotlinType = receiver.kotlinType
|
||||
val boxedReceiver =
|
||||
if (receiverKotlinType != null)
|
||||
DescriptorAsmUtil.boxType(receiver.type, receiverKotlinType, state.typeMapper)
|
||||
else
|
||||
AsmUtil.boxType(receiver.type)
|
||||
val receiverValue = StackValue.coercion(receiver, boxedReceiver, receiverKotlinType)
|
||||
putClosureParametersOnStack(lambda, receiverValue)
|
||||
return PsiExpressionLambda(
|
||||
ktLambda!!, state.typeMapper, state.languageVersionSettings,
|
||||
parameter.isCrossinline, getBoundCallableReferenceReceiver(expression) != null
|
||||
).also { lambda ->
|
||||
val closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameter.index)
|
||||
closureInfo.functionalArgument = lambda
|
||||
expressionMap[closureInfo.index] = lambda
|
||||
}
|
||||
}
|
||||
|
||||
var activeLambda: LambdaInfo? = null
|
||||
private set
|
||||
override fun putValueIfNeeded(parameterType: JvmKotlinType, value: StackValue, kind: ValueKind, parameterIndex: Int) {
|
||||
if (processDefaultMaskOrMethodHandler(value, kind)) return
|
||||
|
||||
private fun putClosureParametersOnStack(next: PsiExpressionLambda, receiverValue: StackValue?) {
|
||||
activeLambda = next
|
||||
codegen.pushClosureOnStack(next.classDescriptor, true, this, receiverValue)
|
||||
activeLambda = null
|
||||
assert(maskValues.isEmpty()) { "Additional default call arguments should be last ones, but $value" }
|
||||
|
||||
putArgumentOrCapturedToLocalVal(parameterType, value, -1, parameterIndex, kind)
|
||||
}
|
||||
|
||||
override fun putValueIfNeeded(parameterType: JvmKotlinType, value: StackValue, kind: ValueKind, parameterIndex: Int) =
|
||||
putArgumentToLocalVal(parameterType, value, parameterIndex, kind)
|
||||
|
||||
override fun putCapturedValueOnStack(stackValue: StackValue, valueType: Type, paramIndex: Int) =
|
||||
putCapturedToLocalVal(stackValue, activeLambda!!.capturedVars[paramIndex], stackValue.kotlinType)
|
||||
override fun putCapturedValueOnStack(stackValue: StackValue, valueType: Type, paramIndex: Int) {
|
||||
putArgumentOrCapturedToLocalVal(
|
||||
JvmKotlinType(stackValue.type, stackValue.kotlinType), stackValue, paramIndex, paramIndex, ValueKind.CAPTURED
|
||||
)
|
||||
}
|
||||
|
||||
override fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: List<ArgumentAndDeclIndex>, valueParameterTypes: List<Type>) = Unit
|
||||
|
||||
override fun extractDefaultLambdas(node: MethodNode): List<DefaultLambda> =
|
||||
extractDefaultLambdas(node, extractDefaultLambdaOffsetAndDescriptor(jvmSignature, functionDescriptor)) { parameter ->
|
||||
PsiDefaultLambda(type, capturedArgs, parameter, offset, needReification, sourceCompiler)
|
||||
}
|
||||
override fun putHiddenParamsIntoLocals() {
|
||||
assert(delayedHiddenWriting != null) { "processAndPutHiddenParameters(true) should be called before putHiddenParamsIntoLocals" }
|
||||
delayedHiddenWriting!!.invoke()
|
||||
delayedHiddenWriting = null
|
||||
}
|
||||
|
||||
override fun extractDefaultLambdas(node: MethodNode): List<DefaultLambda> {
|
||||
return expandMaskConditionsAndUpdateVariableNodes(
|
||||
node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex,
|
||||
extractDefaultLambdaOffsetAndDescriptor(jvmSignature, functionDescriptor),
|
||||
::PsiDefaultLambda
|
||||
)
|
||||
}
|
||||
|
||||
override fun descriptorIsDeserialized(memberDescriptor: CallableMemberDescriptor): Boolean =
|
||||
memberDescriptor is DescriptorWithContainerSource
|
||||
}
|
||||
|
||||
private val FunctionDescriptor.explicitParameters
|
||||
@@ -212,10 +226,12 @@ private val FunctionDescriptor.explicitParameters
|
||||
|
||||
class PsiExpressionLambda(
|
||||
expression: KtExpression,
|
||||
private val state: GenerationState,
|
||||
private val typeMapper: KotlinTypeMapper,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
isCrossInline: Boolean,
|
||||
override val isBoundCallableReference: Boolean
|
||||
) : ExpressionLambda(isCrossInline) {
|
||||
|
||||
override val lambdaClassType: Type
|
||||
|
||||
override val invokeMethod: Method
|
||||
@@ -225,7 +241,9 @@ class PsiExpressionLambda(
|
||||
override val invokeMethodParameters: List<KotlinType?>
|
||||
get() {
|
||||
val actualInvokeDescriptor = if (isSuspend)
|
||||
getOrCreateJvmSuspendFunctionView(invokeMethodDescriptor, state)
|
||||
getOrCreateJvmSuspendFunctionView(
|
||||
invokeMethodDescriptor, languageVersionSettings.isReleaseCoroutines(), typeMapper.bindingContext
|
||||
)
|
||||
else
|
||||
invokeMethodDescriptor
|
||||
return actualInvokeDescriptor.explicitParameters.map { it.returnType }
|
||||
@@ -247,7 +265,7 @@ class PsiExpressionLambda(
|
||||
val closure: CalculatedClosure
|
||||
|
||||
init {
|
||||
val bindingContext = state.bindingContext
|
||||
val bindingContext = typeMapper.bindingContext
|
||||
val function = bindingContext.get(BindingContext.FUNCTION, functionWithBodyOrCallableReference)
|
||||
if (function == null && expression is KtCallableReferenceExpression) {
|
||||
val variableDescriptor =
|
||||
@@ -255,7 +273,7 @@ class PsiExpressionLambda(
|
||||
?: throw AssertionError("Reference expression not resolved to variable descriptor with accessors: ${expression.getText()}")
|
||||
classDescriptor = bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, variableDescriptor)
|
||||
?: throw IllegalStateException("Class for callable not found: $variableDescriptor\n${expression.text}")
|
||||
lambdaClassType = state.typeMapper.mapClass(classDescriptor)
|
||||
lambdaClassType = typeMapper.mapClass(classDescriptor)
|
||||
val getFunction = PropertyReferenceCodegen.findGetFunction(variableDescriptor)
|
||||
invokeMethodDescriptor = PropertyReferenceCodegen.createFakeOpenDescriptor(getFunction, classDescriptor)
|
||||
val resolvedCall = expression.callableReference.getResolvedCallWithAssert(bindingContext)
|
||||
@@ -270,26 +288,24 @@ class PsiExpressionLambda(
|
||||
|
||||
closure = bindingContext.get(CodegenBinding.CLOSURE, classDescriptor)
|
||||
?: throw AssertionError("null closure for lambda ${expression.text}")
|
||||
returnLabels = getDeclarationLabels(expression, invokeMethodDescriptor).associateWith { null }
|
||||
invokeMethod = state.typeMapper.mapAsmMethod(invokeMethodDescriptor)
|
||||
returnLabels = InlineCodegen.getDeclarationLabels(expression, invokeMethodDescriptor).associateWith { null }
|
||||
invokeMethod = typeMapper.mapAsmMethod(invokeMethodDescriptor)
|
||||
isSuspend = invokeMethodDescriptor.isSuspend
|
||||
}
|
||||
|
||||
// This can only be computed after generating the body, hence `lazy`.
|
||||
override val capturedVars: List<CapturedParamDesc> by lazy {
|
||||
arrayListOf<CapturedParamDesc>().apply {
|
||||
val captureThis = closure.capturedOuterClassDescriptor
|
||||
if (captureThis != null) {
|
||||
add(capturedParamDesc(AsmUtil.CAPTURED_THIS_FIELD, state.typeMapper.mapType(captureThis.defaultType), isSuspend = false))
|
||||
add(capturedParamDesc(AsmUtil.CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis.defaultType), isSuspend = false))
|
||||
}
|
||||
|
||||
val capturedReceiver = closure.capturedReceiverFromOuterContext
|
||||
if (capturedReceiver != null) {
|
||||
val fieldName = closure.getCapturedReceiverFieldName(state.typeMapper.bindingContext, state.languageVersionSettings)
|
||||
val type = if (isBoundCallableReference)
|
||||
state.typeMapper.mapType(capturedReceiver, null, TypeMappingMode.GENERIC_ARGUMENT)
|
||||
else
|
||||
state.typeMapper.mapType(capturedReceiver)
|
||||
val fieldName = closure.getCapturedReceiverFieldName(typeMapper.bindingContext, languageVersionSettings)
|
||||
val type = typeMapper.mapType(capturedReceiver).let {
|
||||
if (isBoundCallableReference) AsmUtil.boxType(it) else it
|
||||
}
|
||||
add(capturedParamDesc(fieldName, type, isSuspend = false))
|
||||
}
|
||||
|
||||
@@ -305,14 +321,13 @@ class PsiExpressionLambda(
|
||||
}
|
||||
|
||||
class PsiDefaultLambda(
|
||||
lambdaClassType: Type,
|
||||
override val lambdaClassType: Type,
|
||||
capturedArgs: Array<Type>,
|
||||
parameterDescriptor: ValueParameterDescriptor,
|
||||
private val parameterDescriptor: ValueParameterDescriptor,
|
||||
offset: Int,
|
||||
needReification: Boolean,
|
||||
sourceCompiler: SourceCompilerForInline
|
||||
) : DefaultLambda(lambdaClassType, capturedArgs, parameterDescriptor.isCrossinline, offset, needReification, sourceCompiler) {
|
||||
private val invokeMethodDescriptor: FunctionDescriptor
|
||||
needReification: Boolean
|
||||
) : DefaultLambda(capturedArgs, parameterDescriptor.isCrossinline, offset, needReification) {
|
||||
private lateinit var invokeMethodDescriptor: FunctionDescriptor
|
||||
|
||||
override val invokeMethodParameters: List<KotlinType?>
|
||||
get() = invokeMethodDescriptor.explicitParameters.map { it.returnType }
|
||||
@@ -320,15 +335,24 @@ class PsiDefaultLambda(
|
||||
override val invokeMethodReturnType: KotlinType?
|
||||
get() = invokeMethodDescriptor.returnType
|
||||
|
||||
init {
|
||||
val name = if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE
|
||||
val descriptor = parameterDescriptor.type.memberScope
|
||||
override fun mapAsmMethod(sourceCompiler: SourceCompilerForInline, isPropertyReference: Boolean): Method {
|
||||
val substitutedDescriptor = parameterDescriptor.type.memberScope
|
||||
.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND)
|
||||
.single()
|
||||
.let { if (parameterDescriptor.type.isSuspendFunctionType) getOrCreateJvmSuspendFunctionView(it, sourceCompiler.state) else it }
|
||||
// This is technically wrong as it always uses `invoke`, but `loadInvoke` will fall back to `get` which is never mangled...
|
||||
val asmMethod = sourceCompiler.state.typeMapper.mapAsmMethod(descriptor)
|
||||
val invokeIsErased = loadInvoke(sourceCompiler, name.asString(), asmMethod)
|
||||
invokeMethodDescriptor = if (invokeIsErased) descriptor.original else descriptor
|
||||
invokeMethodDescriptor = when {
|
||||
// Property references: `(A) -> B` => `get(Any?): Any?`
|
||||
isPropertyReference -> substitutedDescriptor.original
|
||||
// Suspend function references: `suspend (A) -> B` => `invoke(A, Continuation<B>): Any?`
|
||||
// TODO: default suspend lambdas are currently uninlinable
|
||||
parameterDescriptor.type.isSuspendFunctionType ->
|
||||
getOrCreateJvmSuspendFunctionView(
|
||||
substitutedDescriptor,
|
||||
sourceCompiler.state.languageVersionSettings.isReleaseCoroutines(),
|
||||
sourceCompiler.state.bindingContext
|
||||
)
|
||||
// Non-suspend function references and lambdas: `(A) -> B` => `invoke(A): B`
|
||||
else -> substitutedDescriptor
|
||||
}
|
||||
return sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,443 +0,0 @@
|
||||
/*
|
||||
* 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.codegen.inline
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.context.*
|
||||
import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.isInlineClass
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.isCallableMemberCompiledToJvmDefault
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||
import org.jetbrains.kotlin.types.expressions.LabelResolver
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
class PsiSourceCompilerForInline(
|
||||
private val codegen: ExpressionCodegen,
|
||||
override val callElement: KtElement,
|
||||
private val functionDescriptor: FunctionDescriptor
|
||||
) : SourceCompilerForInline {
|
||||
override val state
|
||||
get() = codegen.state
|
||||
|
||||
private val additionalInnerClasses = mutableListOf<ClassDescriptor>()
|
||||
|
||||
val context = getContext(
|
||||
functionDescriptor,
|
||||
functionDescriptor,
|
||||
codegen.state,
|
||||
DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor)?.containingFile as? KtFile,
|
||||
additionalInnerClasses
|
||||
) as MethodContext
|
||||
|
||||
override val callElementText: String by lazy { callElement.text }
|
||||
|
||||
override val inlineCallSiteInfo: InlineCallSiteInfo
|
||||
get() {
|
||||
var context = codegen.getContext()
|
||||
var parentCodegen = codegen.parentCodegen
|
||||
while (context is InlineLambdaContext) {
|
||||
val closureContext = context.getParentContext()
|
||||
assert(closureContext is ClosureContext) { "Parent context of inline lambda should be closure context" }
|
||||
assert(closureContext.parentContext is MethodContext) { "Closure context should appear in method context" }
|
||||
context = closureContext.parentContext as MethodContext
|
||||
assert(parentCodegen is FakeMemberCodegen) { "Parent codegen of inlined lambda should be FakeMemberCodegen" }
|
||||
parentCodegen = (parentCodegen as FakeMemberCodegen).delegate
|
||||
}
|
||||
|
||||
val signature = codegen.state.typeMapper.mapSignatureSkipGeneric(context.functionDescriptor, context.contextKind)
|
||||
return InlineCallSiteInfo(
|
||||
parentCodegen.className,
|
||||
signature.asmMethod,
|
||||
context.functionDescriptor.isInlineOrInsideInline(),
|
||||
callElement.containingFile,
|
||||
CodegenUtil.getLineNumberForElement(callElement, false) ?: 0
|
||||
)
|
||||
}
|
||||
|
||||
override val sourceMapper
|
||||
get() = codegen.parentCodegen.orCreateSourceMapper
|
||||
|
||||
override fun generateLambdaBody(lambdaInfo: ExpressionLambda, reifiedTypeParameters: ReifiedTypeParametersUsages): SMAPAndMethodNode {
|
||||
require(lambdaInfo is PsiExpressionLambda)
|
||||
val invokeMethodDescriptor = lambdaInfo.invokeMethodDescriptor
|
||||
val jvmMethodSignature = state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor)
|
||||
val asmMethod = jvmMethodSignature.asmMethod
|
||||
val methodNode = MethodNode(
|
||||
Opcodes.API_VERSION, DescriptorAsmUtil.getMethodAsmFlags(invokeMethodDescriptor, OwnerKind.IMPLEMENTATION, state),
|
||||
asmMethod.name, asmMethod.descriptor, null, null
|
||||
)
|
||||
val adapter = wrapWithMaxLocalCalc(methodNode)
|
||||
val closureContext = when {
|
||||
lambdaInfo.isPropertyReference ->
|
||||
codegen.getContext().intoAnonymousClass(lambdaInfo.classDescriptor, codegen, OwnerKind.IMPLEMENTATION)
|
||||
invokeMethodDescriptor.isSuspend ->
|
||||
codegen.getContext().intoCoroutineClosure(
|
||||
getOrCreateJvmSuspendFunctionView(invokeMethodDescriptor, state), invokeMethodDescriptor, codegen, state.typeMapper
|
||||
)
|
||||
else -> codegen.getContext().intoClosure(invokeMethodDescriptor, codegen, state.typeMapper)
|
||||
}
|
||||
val context = closureContext.intoInlinedLambda(invokeMethodDescriptor, lambdaInfo.isCrossInline, lambdaInfo.isPropertyReference)
|
||||
val smap = generateMethodBody(
|
||||
adapter, invokeMethodDescriptor, context,
|
||||
lambdaInfo.functionWithBodyOrCallableReference,
|
||||
jvmMethodSignature, lambdaInfo
|
||||
)
|
||||
adapter.visitMaxs(-1, -1)
|
||||
return SMAPAndMethodNode(methodNode, smap)
|
||||
}
|
||||
|
||||
private fun generateMethodBody(
|
||||
adapter: MethodVisitor,
|
||||
descriptor: FunctionDescriptor,
|
||||
context: MethodContext,
|
||||
expression: KtExpression,
|
||||
jvmMethodSignature: JvmMethodSignature,
|
||||
lambdaInfo: PsiExpressionLambda?
|
||||
): SMAP {
|
||||
val isLambda = lambdaInfo != null
|
||||
|
||||
// Wrapping for preventing marking actual parent codegen as containing reified markers
|
||||
val parentCodegen = FakeMemberCodegen(
|
||||
codegen.parentCodegen, expression, context.parentContext as FieldOwnerContext<*>,
|
||||
if (isLambda)
|
||||
codegen.parentCodegen.className
|
||||
else
|
||||
state.typeMapper.mapImplementationOwner(descriptor).internalName,
|
||||
if (isLambda) emptyList() else additionalInnerClasses,
|
||||
isLambda
|
||||
)
|
||||
|
||||
val strategy = when (expression) {
|
||||
is KtCallableReferenceExpression -> {
|
||||
val resolvedCall = expression.callableReference.getResolvedCallWithAssert(state.bindingContext)
|
||||
val receiverKotlinType = JvmCodegenUtil.getBoundCallableReferenceReceiver(resolvedCall)?.type
|
||||
val receiverType = receiverKotlinType?.let(state.typeMapper::mapType)
|
||||
val boundReceiverJvmKotlinType = receiverType?.let { JvmKotlinType(receiverType, receiverKotlinType) }
|
||||
|
||||
if (isLambda && lambdaInfo!!.isPropertyReference) {
|
||||
val asmType = state.typeMapper.mapClass(lambdaInfo.classDescriptor)
|
||||
val info = lambdaInfo.propertyReferenceInfo
|
||||
PropertyReferenceCodegen.PropertyReferenceGenerationStrategy(
|
||||
true, info!!.getFunction, info.target, asmType,
|
||||
boundReceiverJvmKotlinType,
|
||||
lambdaInfo.functionWithBodyOrCallableReference, state, true
|
||||
)
|
||||
} else {
|
||||
FunctionReferenceGenerationStrategy(state, descriptor, resolvedCall, boundReceiverJvmKotlinType, null, true)
|
||||
}
|
||||
}
|
||||
is KtFunctionLiteral -> ClosureGenerationStrategy(state, expression as KtDeclarationWithBody)
|
||||
else -> FunctionGenerationStrategy.FunctionDefault(state, expression as KtDeclarationWithBody)
|
||||
}
|
||||
|
||||
FunctionCodegen.generateMethodBody(
|
||||
adapter, descriptor, context, jvmMethodSignature, strategy, parentCodegen, state.jvmDefaultMode,
|
||||
state.languageVersionSettings.isReleaseCoroutines()
|
||||
)
|
||||
|
||||
if (isLambda) {
|
||||
codegen.propagateChildReifiedTypeParametersUsages(parentCodegen.reifiedTypeParametersUsages)
|
||||
}
|
||||
|
||||
return SMAP(parentCodegen.orCreateSourceMapper.resultMappings)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private class FakeMemberCodegen(
|
||||
val delegate: MemberCodegen<*>,
|
||||
declaration: KtElement,
|
||||
codegenContext: FieldOwnerContext<*>,
|
||||
private val className: String,
|
||||
private val parentAsInnerClasses: List<ClassDescriptor>,
|
||||
private val isInlineLambdaCodegen: Boolean
|
||||
) : MemberCodegen<KtPureElement>(delegate as MemberCodegen<KtPureElement>, declaration, codegenContext) {
|
||||
|
||||
override fun generateDeclaration() {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
|
||||
override fun generateBody() {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
|
||||
override fun generateKotlinMetadataAnnotation() {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
|
||||
override fun getInlineNameGenerator(): NameGenerator {
|
||||
return delegate.inlineNameGenerator
|
||||
}
|
||||
|
||||
override //TODO: obtain name from context
|
||||
fun getClassName(): String {
|
||||
return className
|
||||
}
|
||||
|
||||
override fun addParentsToInnerClassesIfNeeded(innerClasses: MutableCollection<ClassDescriptor>) {
|
||||
if (isInlineLambdaCodegen) {
|
||||
super.addParentsToInnerClassesIfNeeded(innerClasses)
|
||||
} else {
|
||||
innerClasses.addAll(parentAsInnerClasses)
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateAssertField() {
|
||||
delegate.generateAssertField()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDirectMemberAndCallableFromObject(): CallableMemberDescriptor {
|
||||
val directMember = JvmCodegenUtil.getDirectMember(functionDescriptor)
|
||||
return (directMember as? ImportedFromObjectCallableDescriptor<*>)?.callableFromObject ?: directMember
|
||||
}
|
||||
|
||||
internal var callDefault: Boolean = false
|
||||
|
||||
private fun mapDefault(): Method {
|
||||
// This is all available in the `Callable` passed to `PsiInlineCodegen.genCallInner`, but it's not forwarded through the inliner...
|
||||
var result = state.typeMapper.mapDefaultMethod(functionDescriptor, context.contextKind)
|
||||
if (result.name.contains("-") &&
|
||||
!state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_INLINE_CLASSES_MANGLING_SCHEME) &&
|
||||
classFileContainsMethod(functionDescriptor, state, result) == false
|
||||
) {
|
||||
state.typeMapper.useOldManglingRulesForFunctionAcceptingInlineClass = true
|
||||
result = state.typeMapper.mapDefaultMethod(functionDescriptor, context.contextKind)
|
||||
state.typeMapper.useOldManglingRulesForFunctionAcceptingInlineClass = false
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun compileInlineFunction(jvmSignature: JvmMethodSignature): SMAPAndMethodNode {
|
||||
generateInlineIntrinsic(state.languageVersionSettings, functionDescriptor, jvmSignature.asmMethod, codegen.typeSystem)?.let {
|
||||
return it
|
||||
}
|
||||
|
||||
val asmMethod = if (callDefault) mapDefault() else jvmSignature.asmMethod
|
||||
if (asmMethod.name != functionDescriptor.name.asString()) {
|
||||
KotlinLookupLocation(callElement).location?.let {
|
||||
state.trackLookup(DescriptorUtils.getFqNameSafe(functionDescriptor.containingDeclaration), asmMethod.name, it)
|
||||
}
|
||||
}
|
||||
|
||||
val directMember = getDirectMemberAndCallableFromObject()
|
||||
if (directMember is DescriptorWithContainerSource) {
|
||||
val containerId = KotlinTypeMapper.getContainingClassesForDeserializedCallable(directMember).implClassId
|
||||
val isMangled = requiresFunctionNameManglingForReturnType(functionDescriptor)
|
||||
return loadCompiledInlineFunction(containerId, asmMethod, functionDescriptor.isSuspend, isMangled, state)
|
||||
}
|
||||
|
||||
val element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor) as? KtDeclarationWithBody
|
||||
?: throw IllegalStateException("Couldn't find declaration for function $functionDescriptor")
|
||||
|
||||
val node = MethodNode(
|
||||
Opcodes.API_VERSION,
|
||||
DescriptorAsmUtil.getMethodAsmFlags(functionDescriptor, context.contextKind, state) or
|
||||
if (callDefault) Opcodes.ACC_STATIC else 0,
|
||||
asmMethod.name,
|
||||
asmMethod.descriptor, null, null
|
||||
)
|
||||
|
||||
//for maxLocals calculation
|
||||
val maxCalcAdapter = wrapWithMaxLocalCalc(node)
|
||||
val smap = if (callDefault) {
|
||||
val implementationOwner = state.typeMapper.mapImplementationOwner(functionDescriptor)
|
||||
val parentCodegen = FakeMemberCodegen(
|
||||
codegen.parentCodegen, element, context.parentContext as FieldOwnerContext<*>,
|
||||
implementationOwner.internalName,
|
||||
additionalInnerClasses,
|
||||
false
|
||||
)
|
||||
if (element !is KtNamedFunction) {
|
||||
throw IllegalStateException("Property accessors with default parameters not supported $functionDescriptor")
|
||||
}
|
||||
FunctionCodegen.generateDefaultImplBody(
|
||||
context, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT,
|
||||
element as KtNamedFunction?, parentCodegen, asmMethod
|
||||
)
|
||||
SMAP(parentCodegen.orCreateSourceMapper.resultMappings)
|
||||
} else {
|
||||
generateMethodBody(maxCalcAdapter, functionDescriptor, context, element, jvmSignature, null)
|
||||
}
|
||||
maxCalcAdapter.visitMaxs(-1, -1)
|
||||
maxCalcAdapter.visitEnd()
|
||||
|
||||
return SMAPAndMethodNode(node, smap)
|
||||
}
|
||||
|
||||
override fun hasFinallyBlocks() = codegen.hasFinallyBlocks()
|
||||
|
||||
override fun generateFinallyBlocks(finallyNode: MethodNode, curFinallyDepth: Int, returnType: Type, afterReturnLabel: Label, target: Label?) {
|
||||
// TODO use the target label for non-local break/continue
|
||||
ExpressionCodegen(
|
||||
finallyNode, codegen.frameMap, codegen.returnType,
|
||||
codegen.getContext(), codegen.state, codegen.parentCodegen
|
||||
).also {
|
||||
it.addBlockStackElementsForNonLocalReturns(codegen.blockStackElements, curFinallyDepth)
|
||||
}.generateFinallyBlocksIfNeeded(returnType, null, afterReturnLabel)
|
||||
}
|
||||
|
||||
override val isCallInsideSameModuleAsCallee: Boolean
|
||||
get() = JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), codegen.state.outDirectory)
|
||||
|
||||
override val isFinallyMarkerRequired: Boolean
|
||||
get() = isFinallyMarkerRequired(codegen.getContext())
|
||||
|
||||
override fun isSuspendLambdaCapturedByOuterObjectOrLambda(name: String): Boolean {
|
||||
// We cannot find the lambda in captured parameters: it came from object outside of the our reach:
|
||||
// this can happen when the lambda capture by non-transformed closure:
|
||||
// inline fun inlineMe(crossinline c: suspend() -> Unit) = suspend { c() }
|
||||
// inline fun inlineMe2(crossinline c: suspend() -> Unit) = suspend { inlineMe { c() }() }
|
||||
// Suppose, we inline inlineMe into inlineMe2: the only knowledge we have about inlineMe$1 is captured receiver (this$0)
|
||||
// Thus, transformed lambda from inlineMe, inlineMe3$$inlined$inlineMe2$1 contains the following bytecode
|
||||
// ALOAD 0
|
||||
// GETFIELD inlineMe2$1$invokeSuspend$$inlined$inlineMe$1.this$0 : LScratchKt$inlineMe2$1;
|
||||
// GETFIELD inlineMe2$1.$c : Lkotlin/jvm/functions/Function1;
|
||||
// Since inlineMe2's lambda is outside of reach of the inliner, find crossinline parameter from compilation context:
|
||||
var container: DeclarationDescriptor = codegen.getContext().functionDescriptor
|
||||
while (container !is ClassDescriptor) {
|
||||
container = container.containingDeclaration ?: return false
|
||||
}
|
||||
var classDescriptor: ClassDescriptor? = container
|
||||
while (classDescriptor != null) {
|
||||
val closure = state.bindingContext[CodegenBinding.CLOSURE, classDescriptor] ?: return false
|
||||
for ((param, value) in closure.captureVariables) {
|
||||
if (param is ValueParameterDescriptor && value.fieldName == name) {
|
||||
return param.type.isSuspendFunctionTypeOrSubtype
|
||||
}
|
||||
}
|
||||
classDescriptor = closure.capturedOuterClassDescriptor
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getContextLabels(): Map<String, Label?> {
|
||||
val context = codegen.getContext()
|
||||
val parentContext = context.parentContext
|
||||
val descriptor = if (parentContext is ClosureContext && parentContext.originalSuspendLambdaDescriptor != null) {
|
||||
parentContext.originalSuspendLambdaDescriptor!!
|
||||
} else context.contextDescriptor
|
||||
|
||||
val labels = getDeclarationLabels(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor)
|
||||
return labels.associateWith { null } // TODO add break/continue labels
|
||||
}
|
||||
|
||||
override fun reportSuspensionPointInsideMonitor(stackTraceElement: String) {
|
||||
org.jetbrains.kotlin.codegen.coroutines.reportSuspensionPointInsideMonitor(callElement, state, stackTraceElement)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getContext(
|
||||
descriptor: DeclarationDescriptor,
|
||||
innerDescriptor: DeclarationDescriptor,
|
||||
state: GenerationState,
|
||||
sourceFile: KtFile?,
|
||||
additionalInners: MutableList<ClassDescriptor>
|
||||
): CodegenContext<*> {
|
||||
if (descriptor is PackageFragmentDescriptor) {
|
||||
//no inners
|
||||
return PackageContext(descriptor, state.rootContext, null, sourceFile)
|
||||
}
|
||||
|
||||
val container = descriptor.containingDeclaration ?: error("No container for descriptor: $descriptor")
|
||||
val containerContext = getContext(
|
||||
container,
|
||||
descriptor,
|
||||
state,
|
||||
sourceFile,
|
||||
additionalInners
|
||||
)
|
||||
|
||||
return when (descriptor) {
|
||||
is ScriptDescriptor -> {
|
||||
val earlierScripts = state.scriptSpecific.earlierScriptsForReplInterpreter
|
||||
containerContext.intoScript(
|
||||
descriptor,
|
||||
earlierScripts ?: emptyList(),
|
||||
descriptor as ClassDescriptor, state.typeMapper
|
||||
)
|
||||
}
|
||||
is ClassDescriptor -> {
|
||||
val kind =
|
||||
when {
|
||||
DescriptorUtils.isInterface(descriptor) &&
|
||||
innerDescriptor !is ClassDescriptor &&
|
||||
!innerDescriptor.isCallableMemberCompiledToJvmDefault(state.jvmDefaultMode) ->
|
||||
OwnerKind.DEFAULT_IMPLS
|
||||
else ->
|
||||
OwnerKind.IMPLEMENTATION
|
||||
}
|
||||
|
||||
additionalInners.addIfNotNull(
|
||||
InnerClassConsumer.classForInnerClassRecord(descriptor, kind == OwnerKind.DEFAULT_IMPLS)
|
||||
)
|
||||
|
||||
if (descriptor.isInlineClass()) {
|
||||
containerContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state)
|
||||
.intoClass(descriptor, OwnerKind.ERASED_INLINE_CLASS, state)
|
||||
} else {
|
||||
containerContext.intoClass(descriptor, kind, state)
|
||||
}
|
||||
}
|
||||
is FunctionDescriptor -> {
|
||||
containerContext.intoFunction(descriptor)
|
||||
}
|
||||
else -> {
|
||||
throw IllegalStateException("Couldn't build context for $descriptor")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun DeclarationDescriptor.isInlineOrInsideInline(): Boolean =
|
||||
if (this is FunctionDescriptor && isInline) true
|
||||
else containingDeclaration?.isInlineOrInsideInline() == true
|
||||
|
||||
fun getDeclarationLabels(lambdaOrFun: PsiElement?, descriptor: DeclarationDescriptor): Set<String> {
|
||||
val result = HashSet<String>()
|
||||
|
||||
if (lambdaOrFun != null) {
|
||||
val label = LabelResolver.getLabelNameIfAny(lambdaOrFun)
|
||||
if (label != null) {
|
||||
result.add(label.asString())
|
||||
}
|
||||
}
|
||||
|
||||
if (!ExpressionTypingUtils.isFunctionLiteral(descriptor)) {
|
||||
if (!descriptor.name.isSpecial) {
|
||||
result.add(descriptor.name.asString())
|
||||
}
|
||||
result.add(FIRST_FUN_LABEL)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -6,110 +6,428 @@
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.context.*
|
||||
import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.incremental.components.LocationInfo
|
||||
import org.jetbrains.kotlin.incremental.components.Position
|
||||
import org.jetbrains.kotlin.incremental.components.ScopeKind
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
|
||||
import org.jetbrains.kotlin.resolve.isInlineClass
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.isCallableMemberCompiledToJvmDefault
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
class InlineCallSiteInfo(
|
||||
val ownerClassName: String,
|
||||
val method: Method,
|
||||
val isInlineOrInsideInline: Boolean,
|
||||
val file: PsiFile?,
|
||||
val lineNumber: Int
|
||||
)
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
interface SourceCompilerForInline {
|
||||
val state: GenerationState
|
||||
|
||||
val callElement: Any
|
||||
|
||||
val lookupLocation: LookupLocation
|
||||
|
||||
val callElementText: String
|
||||
|
||||
val callsiteFile: PsiFile?
|
||||
|
||||
val contextKind: OwnerKind
|
||||
|
||||
val inlineCallSiteInfo: InlineCallSiteInfo
|
||||
|
||||
val sourceMapper: SourceMapper
|
||||
val lazySourceMapper: SourceMapper
|
||||
|
||||
fun generateLambdaBody(lambdaInfo: ExpressionLambda, reifiedTypeParameters: ReifiedTypeParametersUsages): SMAPAndMethodNode
|
||||
|
||||
fun compileInlineFunction(jvmSignature: JvmMethodSignature): SMAPAndMethodNode
|
||||
fun doCreateMethodNodeFromSource(
|
||||
callableDescriptor: FunctionDescriptor,
|
||||
jvmSignature: JvmMethodSignature,
|
||||
callDefault: Boolean,
|
||||
asmMethod: Method
|
||||
): SMAPAndMethodNode
|
||||
|
||||
fun hasFinallyBlocks(): Boolean
|
||||
|
||||
fun generateFinallyBlocks(finallyNode: MethodNode, curFinallyDepth: Int, returnType: Type, afterReturnLabel: Label, target: Label?)
|
||||
fun createCodegenForExternalFinallyBlockGenerationOnNonLocalReturn(
|
||||
finallyNode: MethodNode,
|
||||
curFinallyDepth: Int
|
||||
): BaseExpressionCodegen
|
||||
|
||||
val isCallInsideSameModuleAsCallee: Boolean
|
||||
fun generateFinallyBlocksIfNeeded(codegen: BaseExpressionCodegen, returnType: Type, afterReturnLabel: Label, target: Label?)
|
||||
|
||||
val isFinallyMarkerRequired: Boolean
|
||||
fun isCallInsideSameModuleAsDeclared(functionDescriptor: FunctionDescriptor): Boolean
|
||||
|
||||
fun isSuspendLambdaCapturedByOuterObjectOrLambda(name: String): Boolean
|
||||
fun isFinallyMarkerRequired(): Boolean
|
||||
|
||||
val compilationContextDescriptor: DeclarationDescriptor
|
||||
|
||||
val compilationContextFunctionDescriptor: FunctionDescriptor
|
||||
|
||||
fun getContextLabels(): Map<String, Label?>
|
||||
|
||||
fun reportSuspensionPointInsideMonitor(stackTraceElement: String)
|
||||
}
|
||||
|
||||
fun GenerationState.trackLookup(container: FqName, functionName: String, location: LocationInfo) {
|
||||
val lookupTracker = configuration.get(CommonConfigurationKeys.LOOKUP_TRACKER) ?: return
|
||||
lookupTracker.record(
|
||||
location.filePath,
|
||||
if (lookupTracker.requiresPosition) location.position else Position.NO_POSITION,
|
||||
container.asString(),
|
||||
ScopeKind.CLASSIFIER,
|
||||
functionName
|
||||
)
|
||||
}
|
||||
|
||||
fun loadCompiledInlineFunction(
|
||||
containerId: ClassId,
|
||||
asmMethod: Method,
|
||||
isSuspend: Boolean,
|
||||
isMangled: Boolean,
|
||||
state: GenerationState
|
||||
): SMAPAndMethodNode {
|
||||
val containerType = AsmUtil.asmTypeByClassId(containerId)
|
||||
val bytes = state.inlineCache.classBytes.getOrPut(containerType.internalName) {
|
||||
findVirtualFile(state, containerId)?.contentsToByteArray()
|
||||
?: throw IllegalStateException("Couldn't find declaration file for $containerId")
|
||||
}
|
||||
val resultInCache = state.inlineCache.methodNodeById.getOrPut(MethodId(containerType.descriptor, asmMethod)) {
|
||||
getMethodNode(containerType, bytes, asmMethod.name, asmMethod.descriptor, isSuspend, isMangled)
|
||||
}
|
||||
return SMAPAndMethodNode(cloneMethodNode(resultInCache.node), resultInCache.classSMAP)
|
||||
}
|
||||
class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, override val callElement: KtElement) :
|
||||
SourceCompilerForInline {
|
||||
|
||||
override val state = codegen.state
|
||||
|
||||
private var context by Delegates.notNull<CodegenContext<*>>()
|
||||
|
||||
private var additionalInnerClasses = mutableListOf<ClassDescriptor>()
|
||||
|
||||
override val lookupLocation = KotlinLookupLocation(callElement)
|
||||
|
||||
|
||||
override val callElementText: String by lazy {
|
||||
callElement.text
|
||||
}
|
||||
|
||||
override val callsiteFile by lazy {
|
||||
callElement.containingFile
|
||||
}
|
||||
|
||||
override val contextKind
|
||||
get () = context.contextKind
|
||||
|
||||
override val inlineCallSiteInfo: InlineCallSiteInfo
|
||||
get() {
|
||||
var context = codegen.getContext()
|
||||
var parentCodegen = codegen.parentCodegen
|
||||
while (context is InlineLambdaContext) {
|
||||
val closureContext = context.getParentContext()
|
||||
assert(closureContext is ClosureContext) { "Parent context of inline lambda should be closure context" }
|
||||
assert(closureContext.parentContext is MethodContext) { "Closure context should appear in method context" }
|
||||
context = closureContext.parentContext as MethodContext
|
||||
assert(parentCodegen is FakeMemberCodegen) { "Parent codegen of inlined lambda should be FakeMemberCodegen" }
|
||||
parentCodegen = (parentCodegen as FakeMemberCodegen).delegate
|
||||
}
|
||||
|
||||
val signature = codegen.state.typeMapper.mapSignatureSkipGeneric(context.functionDescriptor, context.contextKind)
|
||||
return InlineCallSiteInfo(
|
||||
parentCodegen.className,
|
||||
signature.asmMethod.name,
|
||||
signature.asmMethod.descriptor,
|
||||
compilationContextFunctionDescriptor.isInlineOrInsideInline(),
|
||||
compilationContextFunctionDescriptor.isSuspend,
|
||||
CodegenUtil.getLineNumberForElement(callElement, false) ?: 0
|
||||
)
|
||||
}
|
||||
|
||||
override val lazySourceMapper
|
||||
get() = codegen.parentCodegen.orCreateSourceMapper
|
||||
|
||||
override fun generateLambdaBody(lambdaInfo: ExpressionLambda, reifiedTypeParameters: ReifiedTypeParametersUsages): SMAPAndMethodNode {
|
||||
lambdaInfo as? PsiExpressionLambda ?: error("TODO")
|
||||
val invokeMethodDescriptor = lambdaInfo.invokeMethodDescriptor
|
||||
val jvmMethodSignature = state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor)
|
||||
val asmMethod = jvmMethodSignature.asmMethod
|
||||
val methodNode = MethodNode(
|
||||
Opcodes.API_VERSION, DescriptorAsmUtil.getMethodAsmFlags(invokeMethodDescriptor, OwnerKind.IMPLEMENTATION, state),
|
||||
asmMethod.name, asmMethod.descriptor, null, null
|
||||
)
|
||||
val adapter = wrapWithMaxLocalCalc(methodNode)
|
||||
val closureContext = when {
|
||||
lambdaInfo.isPropertyReference ->
|
||||
codegen.getContext().intoAnonymousClass(lambdaInfo.classDescriptor, codegen, OwnerKind.IMPLEMENTATION)
|
||||
invokeMethodDescriptor.isSuspend ->
|
||||
codegen.getContext().intoCoroutineClosure(
|
||||
getOrCreateJvmSuspendFunctionView(invokeMethodDescriptor, state), invokeMethodDescriptor, codegen, state.typeMapper
|
||||
)
|
||||
else -> codegen.getContext().intoClosure(invokeMethodDescriptor, codegen, state.typeMapper)
|
||||
}
|
||||
val context = closureContext.intoInlinedLambda(invokeMethodDescriptor, lambdaInfo.isCrossInline, lambdaInfo.isPropertyReference)
|
||||
val smap = generateMethodBody(
|
||||
adapter, invokeMethodDescriptor, context,
|
||||
lambdaInfo.functionWithBodyOrCallableReference,
|
||||
jvmMethodSignature, lambdaInfo
|
||||
)
|
||||
adapter.visitMaxs(-1, -1)
|
||||
return SMAPAndMethodNode(methodNode, smap)
|
||||
}
|
||||
|
||||
private fun generateMethodBody(
|
||||
adapter: MethodVisitor,
|
||||
descriptor: FunctionDescriptor,
|
||||
context: MethodContext,
|
||||
expression: KtExpression,
|
||||
jvmMethodSignature: JvmMethodSignature,
|
||||
lambdaInfo: PsiExpressionLambda?
|
||||
): SMAP {
|
||||
val isLambda = lambdaInfo != null
|
||||
|
||||
// Wrapping for preventing marking actual parent codegen as containing reified markers
|
||||
val parentCodegen = FakeMemberCodegen(
|
||||
codegen.parentCodegen, expression, context.parentContext as FieldOwnerContext<*>,
|
||||
if (isLambda)
|
||||
codegen.parentCodegen.className
|
||||
else
|
||||
state.typeMapper.mapImplementationOwner(descriptor).internalName,
|
||||
if (isLambda) emptyList<ClassDescriptor>() else additionalInnerClasses,
|
||||
isLambda
|
||||
)
|
||||
|
||||
val strategy = when (expression) {
|
||||
is KtCallableReferenceExpression -> {
|
||||
val resolvedCall = expression.callableReference.getResolvedCallWithAssert(state.bindingContext)
|
||||
val receiverKotlinType = JvmCodegenUtil.getBoundCallableReferenceReceiver(resolvedCall)?.type
|
||||
val receiverType = receiverKotlinType?.let(state.typeMapper::mapType)
|
||||
val boundReceiverJvmKotlinType = receiverType?.let { JvmKotlinType(receiverType, receiverKotlinType) }
|
||||
|
||||
if (isLambda && lambdaInfo!!.isPropertyReference) {
|
||||
val asmType = state.typeMapper.mapClass(lambdaInfo.classDescriptor)
|
||||
val info = lambdaInfo.propertyReferenceInfo
|
||||
PropertyReferenceCodegen.PropertyReferenceGenerationStrategy(
|
||||
true, info!!.getFunction, info.target, asmType,
|
||||
boundReceiverJvmKotlinType,
|
||||
lambdaInfo.functionWithBodyOrCallableReference, state, true
|
||||
)
|
||||
} else {
|
||||
FunctionReferenceGenerationStrategy(state, descriptor, resolvedCall, boundReceiverJvmKotlinType, null, true)
|
||||
}
|
||||
}
|
||||
is KtFunctionLiteral -> ClosureGenerationStrategy(state, expression as KtDeclarationWithBody)
|
||||
else -> FunctionGenerationStrategy.FunctionDefault(state, expression as KtDeclarationWithBody)
|
||||
}
|
||||
|
||||
FunctionCodegen.generateMethodBody(
|
||||
adapter, descriptor, context, jvmMethodSignature, strategy, parentCodegen, state.jvmDefaultMode,
|
||||
state.languageVersionSettings.isReleaseCoroutines()
|
||||
)
|
||||
|
||||
if (isLambda) {
|
||||
codegen.propagateChildReifiedTypeParametersUsages(parentCodegen.reifiedTypeParametersUsages)
|
||||
}
|
||||
|
||||
return SMAP(parentCodegen.orCreateSourceMapper.resultMappings)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private class FakeMemberCodegen(
|
||||
internal val delegate: MemberCodegen<*>,
|
||||
declaration: KtElement,
|
||||
codegenContext: FieldOwnerContext<*>,
|
||||
private val className: String,
|
||||
private val parentAsInnerClasses: List<ClassDescriptor>,
|
||||
private val isInlineLambdaCodegen: Boolean
|
||||
) : MemberCodegen<KtPureElement>(delegate as MemberCodegen<KtPureElement>, declaration, codegenContext) {
|
||||
|
||||
override fun generateDeclaration() {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
|
||||
override fun generateBody() {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
|
||||
override fun generateKotlinMetadataAnnotation() {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
|
||||
override fun getInlineNameGenerator(): NameGenerator {
|
||||
return delegate.inlineNameGenerator
|
||||
}
|
||||
|
||||
override //TODO: obtain name from context
|
||||
fun getClassName(): String {
|
||||
return className
|
||||
}
|
||||
|
||||
override fun addParentsToInnerClassesIfNeeded(innerClasses: MutableCollection<ClassDescriptor>) {
|
||||
if (isInlineLambdaCodegen) {
|
||||
super.addParentsToInnerClassesIfNeeded(innerClasses)
|
||||
} else {
|
||||
innerClasses.addAll(parentAsInnerClasses)
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateAssertField() {
|
||||
delegate.generateAssertField()
|
||||
}
|
||||
}
|
||||
|
||||
override fun doCreateMethodNodeFromSource(
|
||||
callableDescriptor: FunctionDescriptor,
|
||||
jvmSignature: JvmMethodSignature,
|
||||
callDefault: Boolean,
|
||||
asmMethod: Method
|
||||
): SMAPAndMethodNode {
|
||||
val element = DescriptorToSourceUtils.descriptorToDeclaration(callableDescriptor)
|
||||
|
||||
if (!(element is KtNamedFunction || element is KtPropertyAccessor)) {
|
||||
throw IllegalStateException("Couldn't find declaration for function $callableDescriptor")
|
||||
}
|
||||
val inliningFunction = element as KtDeclarationWithBody?
|
||||
|
||||
val node = MethodNode(
|
||||
Opcodes.API_VERSION,
|
||||
DescriptorAsmUtil.getMethodAsmFlags(callableDescriptor, context.contextKind, state) or if (callDefault) Opcodes.ACC_STATIC else 0,
|
||||
asmMethod.name,
|
||||
asmMethod.descriptor, null, null
|
||||
)
|
||||
|
||||
//for maxLocals calculation
|
||||
val maxCalcAdapter = wrapWithMaxLocalCalc(node)
|
||||
val parentContext = context.parentContext ?: error("Context has no parent: " + context)
|
||||
val methodContext = parentContext.intoFunction(callableDescriptor)
|
||||
|
||||
val smap = if (callDefault) {
|
||||
val implementationOwner = state.typeMapper.mapImplementationOwner(callableDescriptor)
|
||||
val parentCodegen = FakeMemberCodegen(
|
||||
codegen.parentCodegen, inliningFunction!!, methodContext.parentContext as FieldOwnerContext<*>,
|
||||
implementationOwner.internalName,
|
||||
additionalInnerClasses,
|
||||
false
|
||||
)
|
||||
if (element !is KtNamedFunction) {
|
||||
throw IllegalStateException("Property accessors with default parameters not supported $callableDescriptor")
|
||||
}
|
||||
FunctionCodegen.generateDefaultImplBody(
|
||||
methodContext, callableDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT,
|
||||
inliningFunction as KtNamedFunction?, parentCodegen, asmMethod
|
||||
)
|
||||
SMAP(parentCodegen.orCreateSourceMapper.resultMappings)
|
||||
} else {
|
||||
generateMethodBody(maxCalcAdapter, callableDescriptor, methodContext, inliningFunction!!, jvmSignature, null)
|
||||
}
|
||||
maxCalcAdapter.visitMaxs(-1, -1)
|
||||
maxCalcAdapter.visitEnd()
|
||||
|
||||
return SMAPAndMethodNode(node, smap)
|
||||
}
|
||||
|
||||
override fun hasFinallyBlocks() = codegen.hasFinallyBlocks()
|
||||
|
||||
override fun generateFinallyBlocksIfNeeded(codegen: BaseExpressionCodegen, returnType: Type, afterReturnLabel: Label, target: Label?) {
|
||||
// TODO use the target label for non-local break/continue
|
||||
require(codegen is ExpressionCodegen)
|
||||
codegen.generateFinallyBlocksIfNeeded(returnType, null, afterReturnLabel)
|
||||
}
|
||||
|
||||
override fun createCodegenForExternalFinallyBlockGenerationOnNonLocalReturn(finallyNode: MethodNode, curFinallyDepth: Int) =
|
||||
ExpressionCodegen(
|
||||
finallyNode, codegen.frameMap, codegen.returnType,
|
||||
codegen.getContext(), codegen.state, codegen.parentCodegen
|
||||
).also {
|
||||
it.addBlockStackElementsForNonLocalReturns(codegen.blockStackElements, curFinallyDepth)
|
||||
}
|
||||
|
||||
override fun isCallInsideSameModuleAsDeclared(functionDescriptor: FunctionDescriptor): Boolean {
|
||||
return JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), codegen.state.outDirectory)
|
||||
}
|
||||
|
||||
override fun isFinallyMarkerRequired(): Boolean = isFinallyMarkerRequired(codegen.getContext())
|
||||
|
||||
|
||||
override val compilationContextDescriptor
|
||||
get() = codegen.getContext().contextDescriptor
|
||||
|
||||
override val compilationContextFunctionDescriptor
|
||||
get() = codegen.getContext().functionDescriptor
|
||||
|
||||
override fun getContextLabels(): Map<String, Label?> {
|
||||
val context = codegen.getContext()
|
||||
val parentContext = context.parentContext
|
||||
val descriptor = if (parentContext is ClosureContext && parentContext.originalSuspendLambdaDescriptor != null) {
|
||||
parentContext.originalSuspendLambdaDescriptor!!
|
||||
} else context.contextDescriptor
|
||||
|
||||
val labels = InlineCodegen.getDeclarationLabels(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor)
|
||||
return labels.associateWith { null } // TODO add break/continue labels
|
||||
}
|
||||
|
||||
fun initializeInlineFunctionContext(functionDescriptor: FunctionDescriptor) {
|
||||
context = getContext(
|
||||
functionDescriptor,
|
||||
functionDescriptor,
|
||||
state,
|
||||
DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor)?.containingFile as? KtFile,
|
||||
additionalInnerClasses
|
||||
)
|
||||
}
|
||||
|
||||
override fun reportSuspensionPointInsideMonitor(stackTraceElement: String) {
|
||||
org.jetbrains.kotlin.codegen.coroutines.reportSuspensionPointInsideMonitor(callElement, state, stackTraceElement)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getContext(
|
||||
descriptor: DeclarationDescriptor,
|
||||
innerDescriptor: DeclarationDescriptor,
|
||||
state: GenerationState,
|
||||
sourceFile: KtFile?,
|
||||
additionalInners: MutableList<ClassDescriptor>
|
||||
): CodegenContext<*> {
|
||||
if (descriptor is PackageFragmentDescriptor) {
|
||||
//no inners
|
||||
return PackageContext(descriptor, state.rootContext, null, sourceFile)
|
||||
}
|
||||
|
||||
val container = descriptor.containingDeclaration ?: error("No container for descriptor: $descriptor")
|
||||
val containerContext = getContext(
|
||||
container,
|
||||
descriptor,
|
||||
state,
|
||||
sourceFile,
|
||||
additionalInners
|
||||
)
|
||||
|
||||
return when (descriptor) {
|
||||
is ScriptDescriptor -> {
|
||||
val earlierScripts = state.scriptSpecific.earlierScriptsForReplInterpreter
|
||||
containerContext.intoScript(
|
||||
descriptor,
|
||||
earlierScripts ?: emptyList(),
|
||||
descriptor as ClassDescriptor, state.typeMapper
|
||||
)
|
||||
}
|
||||
is ClassDescriptor -> {
|
||||
val kind =
|
||||
when {
|
||||
DescriptorUtils.isInterface(descriptor) &&
|
||||
innerDescriptor !is ClassDescriptor &&
|
||||
!innerDescriptor.isCallableMemberCompiledToJvmDefault(state.jvmDefaultMode) ->
|
||||
OwnerKind.DEFAULT_IMPLS
|
||||
else ->
|
||||
OwnerKind.IMPLEMENTATION
|
||||
}
|
||||
|
||||
additionalInners.addIfNotNull(
|
||||
InnerClassConsumer.classForInnerClassRecord(descriptor, kind == OwnerKind.DEFAULT_IMPLS)
|
||||
)
|
||||
|
||||
if (descriptor.isInlineClass()) {
|
||||
containerContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state)
|
||||
.intoClass(descriptor, OwnerKind.ERASED_INLINE_CLASS, state)
|
||||
} else {
|
||||
containerContext.intoClass(descriptor, kind, state)
|
||||
}
|
||||
}
|
||||
is FunctionDescriptor -> {
|
||||
containerContext.intoFunction(descriptor)
|
||||
}
|
||||
else -> {
|
||||
throw IllegalStateException("Couldn't build context for $descriptor")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMethodNode(
|
||||
owner: Type,
|
||||
bytes: ByteArray,
|
||||
name: String,
|
||||
descriptor: String,
|
||||
isSuspend: Boolean,
|
||||
isMangled: Boolean
|
||||
): SMAPAndMethodNode {
|
||||
getMethodNode(owner, bytes, name, descriptor, isSuspend)?.let { return it }
|
||||
if (isMangled) {
|
||||
// Compatibility with old inline class ABI versions.
|
||||
val dashIndex = name.indexOf('-')
|
||||
val nameWithoutManglingSuffix = if (dashIndex > 0) name.substring(0, dashIndex) else name
|
||||
if (nameWithoutManglingSuffix != name) {
|
||||
getMethodNode(owner, bytes, nameWithoutManglingSuffix, descriptor, isSuspend)?.let { return it }
|
||||
}
|
||||
getMethodNode(owner, bytes, "$nameWithoutManglingSuffix-impl", descriptor, isSuspend)?.let { return it }
|
||||
}
|
||||
throw IllegalStateException("couldn't find inline method $owner.$name$descriptor")
|
||||
}
|
||||
|
||||
// If an `inline suspend fun` has a state machine, it should have a `$$forInline` version without one.
|
||||
private fun getMethodNode(owner: Type, bytes: ByteArray, name: String, descriptor: String, isSuspend: Boolean) =
|
||||
(if (isSuspend) getMethodNode(bytes, name + FOR_INLINE_SUFFIX, descriptor, owner) else null)
|
||||
?: getMethodNode(bytes, name, descriptor, owner)
|
||||
fun DeclarationDescriptor.isInlineOrInsideInline(): Boolean =
|
||||
if (this is FunctionDescriptor && isInline) true
|
||||
else containingDeclaration?.isInlineOrInsideInline() == true
|
||||
|
||||
@@ -6,13 +6,18 @@
|
||||
package org.jetbrains.kotlin.codegen.inline.coroutines
|
||||
|
||||
import com.intellij.util.ArrayUtil
|
||||
import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.coroutines.*
|
||||
import org.jetbrains.kotlin.codegen.inline.*
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
@@ -91,8 +96,8 @@ class CoroutineTransformer(
|
||||
obtainClassBuilderForCoroutineState = { classBuilder },
|
||||
reportSuspensionPointInsideMonitor = { sourceCompilerForInline.reportSuspensionPointInsideMonitor(it) },
|
||||
// TODO: this linenumbers might not be correct and since they are used only for step-over, check them.
|
||||
lineNumber = inliningContext.callSiteInfo.lineNumber,
|
||||
sourceFile = inliningContext.callSiteInfo.file?.name ?: "",
|
||||
lineNumber = sourceCompilerForInline.inlineCallSiteInfo.lineNumber,
|
||||
sourceFile = sourceCompilerForInline.callsiteFile?.name ?: "",
|
||||
languageVersionSettings = state.languageVersionSettings,
|
||||
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||
containingClassInternalName = classBuilder.thisName,
|
||||
@@ -125,8 +130,8 @@ class CoroutineTransformer(
|
||||
createNewMethodFrom(node, name), node.access, name, node.desc, null, null,
|
||||
obtainClassBuilderForCoroutineState = { (inliningContext as RegeneratedClassContext).continuationBuilders[continuationClassName]!! },
|
||||
reportSuspensionPointInsideMonitor = { sourceCompilerForInline.reportSuspensionPointInsideMonitor(it) },
|
||||
lineNumber = inliningContext.callSiteInfo.lineNumber,
|
||||
sourceFile = inliningContext.callSiteInfo.file?.name ?: "",
|
||||
lineNumber = sourceCompilerForInline.inlineCallSiteInfo.lineNumber,
|
||||
sourceFile = sourceCompilerForInline.callsiteFile?.name ?: "",
|
||||
languageVersionSettings = state.languageVersionSettings,
|
||||
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||
containingClassInternalName = classBuilder.thisName,
|
||||
@@ -233,6 +238,35 @@ fun surroundInvokesWithSuspendMarkersIfNeeded(node: MethodNode) {
|
||||
}
|
||||
}
|
||||
|
||||
// We cannot find the lambda in captured parameters: it came from object outside of the our reach:
|
||||
// this can happen when the lambda capture by non-transformed closure:
|
||||
// inline fun inlineMe(crossinline c: suspend() -> Unit) = suspend { c() }
|
||||
// inline fun inlineMe2(crossinline c: suspend() -> Unit) = suspend { inlineMe { c() }() }
|
||||
// Suppose, we inline inlineMe into inlineMe2: the only knowledge we have about inlineMe$1 is captured receiver (this$0)
|
||||
// Thus, transformed lambda from inlineMe, inlineMe3$$inlined$inlineMe2$1 contains the following bytecode
|
||||
// ALOAD 0
|
||||
// GETFIELD inlineMe2$1$invokeSuspend$$inlined$inlineMe$1.this$0 : LScratchKt$inlineMe2$1;
|
||||
// GETFIELD inlineMe2$1.$c : Lkotlin/jvm/functions/Function1;
|
||||
// Since inlineMe2's lambda is outside of reach of the inliner, find crossinline parameter from compilation context:
|
||||
fun FieldInsnNode.isSuspendLambdaCapturedByOuterObjectOrLambda(inliningContext: InliningContext): Boolean {
|
||||
var container: DeclarationDescriptor = inliningContext.root.sourceCompilerForInline.compilationContextFunctionDescriptor
|
||||
while (container !is ClassDescriptor) {
|
||||
container = container.containingDeclaration ?: return false
|
||||
}
|
||||
val bindingContext = inliningContext.state.bindingContext
|
||||
var classDescriptor: ClassDescriptor? = container
|
||||
while (classDescriptor != null) {
|
||||
val closure = bindingContext[CodegenBinding.CLOSURE, classDescriptor] ?: return false
|
||||
for ((param, value) in closure.captureVariables) {
|
||||
if (param is ValueParameterDescriptor && value.fieldName == name) {
|
||||
return param.type.isSuspendFunctionTypeOrSubtype
|
||||
}
|
||||
}
|
||||
classDescriptor = closure.capturedOuterClassDescriptor
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Interpreter, that keeps track of captured functional arguments
|
||||
private class PossibleLambdaLoad(val insn: AbstractInsnNode) : BasicValue(AsmTypes.OBJECT_TYPE)
|
||||
|
||||
|
||||
@@ -60,15 +60,15 @@ fun extractDefaultLambdaOffsetAndDescriptor(
|
||||
}
|
||||
}
|
||||
|
||||
class ExtractedDefaultLambda(val type: Type, val capturedArgs: Array<Type>, val offset: Int, val needReification: Boolean)
|
||||
|
||||
fun expandMaskConditionsAndUpdateVariableNodes(
|
||||
fun <T, R : DefaultLambda> expandMaskConditionsAndUpdateVariableNodes(
|
||||
node: MethodNode,
|
||||
maskStartIndex: Int,
|
||||
masks: List<Int>,
|
||||
methodHandlerIndex: Int,
|
||||
validOffsets: Collection<Int>
|
||||
): List<ExtractedDefaultLambda> {
|
||||
defaultLambdas: Map<Int, T>,
|
||||
lambdaConstructor: (Type, Array<Type>, T, Int, Boolean) -> R
|
||||
): List<R> {
|
||||
fun isMaskIndex(varIndex: Int): Boolean {
|
||||
return maskStartIndex <= varIndex && varIndex < maskStartIndex + masks.size
|
||||
}
|
||||
@@ -111,8 +111,7 @@ fun expandMaskConditionsAndUpdateVariableNodes(
|
||||
val toDelete = linkedSetOf<AbstractInsnNode>()
|
||||
val toInsert = arrayListOf<Pair<AbstractInsnNode, AbstractInsnNode>>()
|
||||
|
||||
val extractable = conditions.filter { it.expandNotDelete && it.varIndex in validOffsets }
|
||||
val defaultLambdasInfo = extractDefaultLambdasInfo(extractable, toDelete, toInsert)
|
||||
val defaultLambdasInfo = extractDefaultLambdasInfo(conditions, defaultLambdas, toDelete, toInsert, lambdaConstructor)
|
||||
|
||||
val indexToVarNode = node.localVariables?.filter { it.index < maskStartIndex }?.associateBy { it.index } ?: emptyMap()
|
||||
conditions.forEach {
|
||||
@@ -132,7 +131,7 @@ fun expandMaskConditionsAndUpdateVariableNodes(
|
||||
}
|
||||
|
||||
node.localVariables.removeIf {
|
||||
(it.start in toDelete && it.end in toDelete) || validOffsets.contains(it.index)
|
||||
(it.start in toDelete && it.end in toDelete) || defaultLambdas.contains(it.index)
|
||||
}
|
||||
|
||||
node.remove(toDelete)
|
||||
@@ -140,12 +139,16 @@ fun expandMaskConditionsAndUpdateVariableNodes(
|
||||
return defaultLambdasInfo
|
||||
}
|
||||
|
||||
private fun extractDefaultLambdasInfo(
|
||||
|
||||
private fun <T, R : DefaultLambda> extractDefaultLambdasInfo(
|
||||
conditions: List<Condition>,
|
||||
defaultLambdas: Map<Int, T>,
|
||||
toDelete: MutableCollection<AbstractInsnNode>,
|
||||
toInsert: MutableList<Pair<AbstractInsnNode, AbstractInsnNode>>
|
||||
): List<ExtractedDefaultLambda> {
|
||||
return conditions.map {
|
||||
toInsert: MutableList<Pair<AbstractInsnNode, AbstractInsnNode>>,
|
||||
lambdaConstructor: (Type, Array<Type>, T, Int, Boolean) -> R
|
||||
): List<R> {
|
||||
val defaultLambdaConditions = conditions.filter { it.expandNotDelete && defaultLambdas.contains(it.varIndex) }
|
||||
return defaultLambdaConditions.map {
|
||||
val varAssignmentInstruction = it.varInsNode!!
|
||||
var instanceInstuction = varAssignmentInstruction.previous
|
||||
if (instanceInstuction is TypeInsnNode && instanceInstuction.opcode == Opcodes.CHECKCAST) {
|
||||
@@ -187,7 +190,7 @@ private fun extractDefaultLambdasInfo(
|
||||
|
||||
toInsert.add(varAssignmentInstruction to defaultLambdaFakeCallStub(argTypes, it.varIndex))
|
||||
|
||||
ExtractedDefaultLambda(owner, argTypes, it.varIndex, needReification)
|
||||
lambdaConstructor(owner, argTypes, defaultLambdas[it.varIndex]!!, it.varIndex, needReification)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,8 @@ import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForCoroutineConte
|
||||
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForIntercepted
|
||||
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCoroutineUninterceptedOrReturn
|
||||
import org.jetbrains.kotlin.codegen.createMethodNodeForAlwaysEnabledAssert
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructors
|
||||
import org.jetbrains.kotlin.codegen.isBuiltinAlwaysEnabledAssert
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.TypeOfChecker
|
||||
@@ -27,42 +26,31 @@ import org.jetbrains.kotlin.types.model.TypeParameterMarker
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
fun generateInlineIntrinsicForIr(languageVersionSettings: LanguageVersionSettings, descriptor: FunctionDescriptor): SMAPAndMethodNode? =
|
||||
when {
|
||||
// TODO: implement these as codegen intrinsics (see IrIntrinsicMethods)
|
||||
internal fun generateInlineIntrinsic(
|
||||
state: GenerationState,
|
||||
descriptor: FunctionDescriptor,
|
||||
typeParameters: List<TypeParameterMarker>?,
|
||||
typeSystem: TypeSystemCommonBackendContext
|
||||
): MethodNode? {
|
||||
val languageVersionSettings = state.languageVersionSettings
|
||||
|
||||
return when {
|
||||
isSpecialEnumMethod(descriptor) ->
|
||||
createSpecialEnumMethodBody(descriptor.name.asString(), typeParameters!!.single(), typeSystem)
|
||||
TypeOfChecker.isTypeOf(descriptor) ->
|
||||
typeSystem.createTypeOfMethodBody(typeParameters!!.single())
|
||||
descriptor.isBuiltInIntercepted(languageVersionSettings) ->
|
||||
createMethodNodeForIntercepted(languageVersionSettings)
|
||||
descriptor.isBuiltInCoroutineContext(languageVersionSettings) ->
|
||||
createMethodNodeForCoroutineContext(descriptor, languageVersionSettings)
|
||||
descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) ->
|
||||
createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSettings)
|
||||
else -> null
|
||||
}?.let { SMAPAndMethodNode(it, SMAP(listOf())) }
|
||||
|
||||
internal fun generateInlineIntrinsic(
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
descriptor: FunctionDescriptor,
|
||||
asmMethod: Method,
|
||||
typeSystem: TypeSystemCommonBackendContext
|
||||
): SMAPAndMethodNode? {
|
||||
return generateInlineIntrinsicForIr(languageVersionSettings, descriptor) ?: when {
|
||||
isSpecialEnumMethod(descriptor) ->
|
||||
createSpecialEnumMethodBody(descriptor.name.asString(), descriptor.original.typeParameters.single(), typeSystem)
|
||||
TypeOfChecker.isTypeOf(descriptor) ->
|
||||
typeSystem.createTypeOfMethodBody(descriptor.original.typeParameters.single())
|
||||
descriptor.isBuiltinAlwaysEnabledAssert() ->
|
||||
createMethodNodeForAlwaysEnabledAssert(descriptor)
|
||||
descriptor is FictitiousArrayConstructor ->
|
||||
IntrinsicArrayConstructors.generateArrayConstructorBody(asmMethod)
|
||||
IntrinsicArrayConstructors.isArrayOf(descriptor) ->
|
||||
IntrinsicArrayConstructors.generateArrayOfBody(asmMethod)
|
||||
IntrinsicArrayConstructors.isEmptyArray(descriptor) ->
|
||||
IntrinsicArrayConstructors.generateEmptyArrayBody(asmMethod)
|
||||
else -> null
|
||||
}?.let { SMAPAndMethodNode(it, SMAP(listOf())) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSpecialEnumMethod(descriptor: FunctionDescriptor): Boolean {
|
||||
|
||||
@@ -37,7 +37,7 @@ private fun TypeSystemCommonBackendContext.putTypeOfReifiedTypeParameter(
|
||||
v.aconst(null)
|
||||
}
|
||||
|
||||
fun <KT : KotlinTypeMarker> TypeSystemCommonBackendContext.generateTypeOf(
|
||||
internal fun <KT : KotlinTypeMarker> TypeSystemCommonBackendContext.generateTypeOf(
|
||||
v: InstructionAdapter, type: KT, intrinsicsSupport: ReifiedTypeInliner.IntrinsicsSupport<KT>
|
||||
) {
|
||||
val typeParameter = type.typeConstructor().getTypeParameterClassifier()
|
||||
@@ -103,7 +103,7 @@ private fun <KT : KotlinTypeMarker> TypeSystemCommonBackendContext.generateNonRe
|
||||
TypeVariance.OUT -> KVariance.OUT
|
||||
}
|
||||
v.getstatic(K_VARIANCE.internalName, variance.name, K_VARIANCE.descriptor)
|
||||
v.iconst(if (typeParameter.isReified()) 1 else 0)
|
||||
v.aconst(typeParameter.isReified())
|
||||
v.invokestatic(
|
||||
REFLECTION, "typeParameter",
|
||||
Type.getMethodDescriptor(K_TYPE_PARAMETER, OBJECT_TYPE, JAVA_STRING_TYPE, K_VARIANCE, Type.BOOLEAN_TYPE),
|
||||
@@ -119,11 +119,11 @@ private fun <KT : KotlinTypeMarker> TypeSystemCommonBackendContext.generateNonRe
|
||||
if (bounds.size == 1) {
|
||||
generateTypeOf(v, bounds.single(), intrinsicsSupport)
|
||||
} else {
|
||||
v.iconst(bounds.size)
|
||||
v.aconst(bounds.size)
|
||||
v.newarray(K_TYPE)
|
||||
for ((i, bound) in bounds.withIndex()) {
|
||||
v.dup()
|
||||
v.iconst(i)
|
||||
v.aconst(i)
|
||||
generateTypeOf(v, bound, intrinsicsSupport)
|
||||
v.astore(K_TYPE)
|
||||
}
|
||||
|
||||
@@ -16,14 +16,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.intrinsics
|
||||
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.inline.ReificationArgument
|
||||
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
@@ -34,15 +30,6 @@ import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
internal object IntrinsicArrayConstructors {
|
||||
fun isArrayOf(descriptor: FunctionDescriptor): Boolean =
|
||||
descriptor.name.asString() == "arrayOf" && descriptor.containingDeclaration.isBuiltInsPackage
|
||||
|
||||
fun isEmptyArray(descriptor: FunctionDescriptor): Boolean =
|
||||
descriptor.name.asString() == "emptyArray" && descriptor.containingDeclaration.isBuiltInsPackage
|
||||
|
||||
private val DeclarationDescriptor.isBuiltInsPackage: Boolean
|
||||
get() = this is PackageFragmentDescriptor && fqName == StandardNames.BUILT_INS_PACKAGE_FQ_NAME
|
||||
|
||||
fun generateArrayConstructorBody(method: Method): MethodNode {
|
||||
val node = MethodNode(
|
||||
Opcodes.ASM6, Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC or Opcodes.ACC_FINAL, method.name, method.descriptor, null, null
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
|
||||
import org.jetbrains.kotlin.codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter
|
||||
import org.jetbrains.kotlin.psi.KtClassLiteralExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.codegen.optimization
|
||||
import org.jetbrains.kotlin.codegen.inline.insnText
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.removeAll
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
@@ -32,10 +31,12 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
|
||||
class ConstantConditionEliminationMethodTransformer : MethodTransformer() {
|
||||
private val deadCodeElimination = DeadCodeEliminationMethodTransformer()
|
||||
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
do {
|
||||
val changes = ConstantConditionsOptimization(internalClassName, methodNode).run()
|
||||
if (changes) deadCodeElimination.transform(internalClassName, methodNode)
|
||||
} while (changes)
|
||||
}
|
||||
|
||||
@@ -48,21 +49,11 @@ class ConstantConditionEliminationMethodTransformer : MethodTransformer() {
|
||||
|
||||
private fun collectRewriteActions(): List<() -> Unit> =
|
||||
arrayListOf<() -> Unit>().also { actions ->
|
||||
val deadCode = ArrayList<AbstractInsnNode>()
|
||||
|
||||
val frames = analyze(internalClassName, methodNode, ConstantPropagationInterpreter())
|
||||
val insns = methodNode.instructions.toArray()
|
||||
|
||||
for (i in frames.indices) {
|
||||
val insn = insns[i]
|
||||
val frame = frames[i]
|
||||
|
||||
if (frame == null && insn !is LabelNode) {
|
||||
deadCode.add(insn)
|
||||
continue
|
||||
}
|
||||
|
||||
if (insn !is JumpInsnNode) continue
|
||||
val frame = frames[i] ?: continue
|
||||
val insn = insns[i] as? JumpInsnNode ?: continue
|
||||
when (insn.opcode) {
|
||||
in Opcodes.IFEQ..Opcodes.IFLE ->
|
||||
tryRewriteComparisonWithZero(insn, frame, actions)
|
||||
@@ -70,12 +61,6 @@ class ConstantConditionEliminationMethodTransformer : MethodTransformer() {
|
||||
tryRewriteBinaryComparison(insn, frame, actions)
|
||||
}
|
||||
}
|
||||
|
||||
if (deadCode.isNotEmpty()) {
|
||||
actions.add {
|
||||
methodNode.instructions.removeAll(deadCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun tryRewriteComparisonWithZero(insn: JumpInsnNode, frame: Frame<BasicValue>, actions: ArrayList<() -> Unit>) {
|
||||
|
||||
@@ -17,9 +17,8 @@
|
||||
package org.jetbrains.kotlin.codegen.optimization
|
||||
|
||||
import org.jetbrains.kotlin.codegen.inline.remove
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.InstructionLivenessAnalyzer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.removeEmptyCatchBlocks
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.removeUnusedLocalVariables
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.LabelNode
|
||||
@@ -28,14 +27,21 @@ import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
class DeadCodeEliminationMethodTransformer : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
val liveness = InstructionLivenessAnalyzer(methodNode).analyze()
|
||||
transformWithResult(internalClassName, methodNode)
|
||||
}
|
||||
|
||||
fun transformWithResult(internalClassName: String, methodNode: MethodNode): Result {
|
||||
val frames = analyze(internalClassName, methodNode, OptimizationBasicInterpreter())
|
||||
return removeDeadCodeByFrames(methodNode, frames)
|
||||
}
|
||||
|
||||
fun removeDeadCodeByFrames(methodNode: MethodNode, frames: Array<out Any?>): Result {
|
||||
val insnsToRemove = ArrayList<AbstractInsnNode>()
|
||||
|
||||
val insns = methodNode.instructions.toArray()
|
||||
for (i in insns.indices) {
|
||||
val insn = insns[i]
|
||||
if (shouldRemove(insn, i, liveness)) {
|
||||
if (shouldRemove(insn, i, frames)) {
|
||||
insnsToRemove.add(insn)
|
||||
}
|
||||
}
|
||||
@@ -45,31 +51,46 @@ class DeadCodeEliminationMethodTransformer : MethodTransformer() {
|
||||
// Remove empty try-catch blocks to make sure we don't break data flow analysis invariants by dead code elimination.
|
||||
methodNode.removeEmptyCatchBlocks()
|
||||
|
||||
methodNode.removeUnusedLocalVariables()
|
||||
return Result(insnsToRemove.toSet())
|
||||
}
|
||||
|
||||
private fun shouldRemove(insn: AbstractInsnNode, index: Int, liveness: BooleanArray): Boolean {
|
||||
if (insn !is LineNumberNode) return !liveness[index]
|
||||
private fun shouldRemove(insn: AbstractInsnNode, index: Int, frames: Array<out Any?>): Boolean =
|
||||
when (insn) {
|
||||
is LabelNode ->
|
||||
// Do not remove label nodes because they can be referred by try/catch blocks or local variables table
|
||||
false
|
||||
is LineNumberNode ->
|
||||
isDeadLineNumber(insn, index, frames)
|
||||
else ->
|
||||
frames[index] == null
|
||||
}
|
||||
|
||||
private fun isDeadLineNumber(insn: LineNumberNode, index: Int, frames: Array<out Any?>): Boolean {
|
||||
// Line number node is "dead" if the corresponding line number interval
|
||||
// contains at least one "dead" meaningful instruction and no "live" meaningful instructions.
|
||||
var finger: AbstractInsnNode = insn
|
||||
var fingerIndex = index
|
||||
var hasDeadInsn = false
|
||||
while (true) {
|
||||
loop@ while (true) {
|
||||
finger = finger.next ?: break
|
||||
fingerIndex++
|
||||
when (finger) {
|
||||
is LabelNode ->
|
||||
continue
|
||||
continue@loop
|
||||
is LineNumberNode ->
|
||||
if (finger.line != insn.line) return hasDeadInsn
|
||||
else -> {
|
||||
if (liveness[fingerIndex]) return false
|
||||
if (frames[fingerIndex] != null) return false
|
||||
hasDeadInsn = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
class Result(private val removedNodes: Set<AbstractInsnNode>) {
|
||||
fun hasRemovedAnything() = removedNodes.isNotEmpty()
|
||||
fun isRemoved(node: AbstractInsnNode) = removedNodes.contains(node)
|
||||
fun isAlive(node: AbstractInsnNode) = !isRemoved(node)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* 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.codegen.optimization.common
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
|
||||
class InstructionLivenessAnalyzer(val method: MethodNode) {
|
||||
private val instructions = method.instructions
|
||||
private val nInsns = instructions.size()
|
||||
|
||||
private val isLive = BooleanArray(nInsns)
|
||||
|
||||
private val handlers: Array<MutableList<TryCatchBlockNode>?> = arrayOfNulls(nInsns)
|
||||
private val queued = BooleanArray(nInsns)
|
||||
private val queue = IntArray(nInsns)
|
||||
private var top = 0
|
||||
|
||||
private val AbstractInsnNode.indexOf get() = instructions.indexOf(this)
|
||||
|
||||
fun analyze(): BooleanArray {
|
||||
if (nInsns == 0) return isLive
|
||||
checkAssertions()
|
||||
computeExceptionHandlersForEachInsn(method)
|
||||
initControlFlowAnalysis()
|
||||
traverseCfg()
|
||||
|
||||
// We consider labels referenced by LVs and TCBs always implicitly reachable
|
||||
// (so that they don't get accidentally removed, producing corrupted class files),
|
||||
// and let the client code decide what to do with redundant LVs and TCBs.
|
||||
localVariableAndTryCatchBlockLabelsAreAlwaysLive()
|
||||
|
||||
// Last label in a method is always implicitly reachable (preserving our implicit invariants).
|
||||
if (instructions.last is LabelNode) {
|
||||
isLive[instructions.last.indexOf] = true
|
||||
}
|
||||
|
||||
return isLive
|
||||
}
|
||||
|
||||
private fun traverseCfg() {
|
||||
while (top > 0) {
|
||||
val insn = queue[--top]
|
||||
val insnNode = method.instructions[insn]
|
||||
val insnOpcode = insnNode.opcode
|
||||
|
||||
when (insnNode.type) {
|
||||
AbstractInsnNode.LABEL, AbstractInsnNode.LINE, AbstractInsnNode.FRAME ->
|
||||
visitOpInsn(insn)
|
||||
AbstractInsnNode.JUMP_INSN ->
|
||||
visitJumpInsnNode(insnNode as JumpInsnNode, insn, insnOpcode)
|
||||
AbstractInsnNode.LOOKUPSWITCH_INSN ->
|
||||
visitLookupSwitchInsnNode(insnNode as LookupSwitchInsnNode)
|
||||
AbstractInsnNode.TABLESWITCH_INSN ->
|
||||
visitTableSwitchInsnNode(insnNode as TableSwitchInsnNode)
|
||||
else -> {
|
||||
if (insnOpcode != Opcodes.ATHROW && (insnOpcode < Opcodes.IRETURN || insnOpcode > Opcodes.RETURN)) {
|
||||
visitOpInsn(insn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handlers[insn]?.forEach { tcb ->
|
||||
visitControlFlowEdge(tcb.handler.indexOf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun localVariableAndTryCatchBlockLabelsAreAlwaysLive() {
|
||||
for (localVariable in method.localVariables) {
|
||||
isLive[localVariable.start.indexOf] = true
|
||||
isLive[localVariable.end.indexOf] = true
|
||||
}
|
||||
|
||||
for (tcb in method.tryCatchBlocks) {
|
||||
isLive[tcb.start.indexOf] = true
|
||||
isLive[tcb.end.indexOf] = true
|
||||
isLive[tcb.handler.indexOf] = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkAssertions() {
|
||||
if (instructions.any { it.opcode == Opcodes.JSR || it.opcode == Opcodes.RET })
|
||||
throw AssertionError("Subroutines are deprecated since Java 6")
|
||||
}
|
||||
|
||||
private fun visitOpInsn(insn: Int) {
|
||||
visitControlFlowEdge(insn + 1)
|
||||
}
|
||||
|
||||
private fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode) {
|
||||
var jump = insnNode.dflt.indexOf
|
||||
visitControlFlowEdge(jump)
|
||||
for (label in insnNode.labels) {
|
||||
jump = instructions.indexOf(label)
|
||||
visitControlFlowEdge(jump)
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode) {
|
||||
var jump = insnNode.dflt.indexOf
|
||||
visitControlFlowEdge(jump)
|
||||
for (label in insnNode.labels) {
|
||||
jump = label.indexOf
|
||||
visitControlFlowEdge(jump)
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitJumpInsnNode(insnNode: JumpInsnNode, insn: Int, insnOpcode: Int) {
|
||||
if (insnOpcode != Opcodes.GOTO && insnOpcode != Opcodes.JSR) {
|
||||
visitControlFlowEdge(insn + 1)
|
||||
}
|
||||
val jump = insnNode.label.indexOf
|
||||
visitControlFlowEdge(jump)
|
||||
}
|
||||
|
||||
private fun initControlFlowAnalysis() {
|
||||
visitControlFlowEdge(0)
|
||||
}
|
||||
|
||||
private fun computeExceptionHandlersForEachInsn(m: MethodNode) {
|
||||
for (tcb in m.tryCatchBlocks) {
|
||||
val begin = tcb.start.indexOf
|
||||
val end = tcb.end.indexOf
|
||||
for (j in begin until end) {
|
||||
var insnHandlers = handlers[j]
|
||||
if (insnHandlers == null) {
|
||||
insnHandlers = ArrayList<TryCatchBlockNode>()
|
||||
handlers[j] = insnHandlers
|
||||
}
|
||||
insnHandlers.add(tcb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitControlFlowEdge(insn: Int) {
|
||||
val changes = !isLive[insn]
|
||||
isLive[insn] = true
|
||||
if (changes && !queued[insn]) {
|
||||
queued[insn] = true
|
||||
queue[top++] = insn
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -62,7 +62,7 @@ import java.util.*
|
||||
* @author Dmitry Petrov
|
||||
*/
|
||||
open class MethodAnalyzer<V : Value>(
|
||||
private val owner: String,
|
||||
val owner: String,
|
||||
val method: MethodNode,
|
||||
protected val interpreter: Interpreter<V>
|
||||
) {
|
||||
|
||||
@@ -39,9 +39,9 @@ import org.jetbrains.org.objectweb.asm.tree.*
|
||||
|
||||
class RedundantNullCheckMethodTransformer(private val generationState: GenerationState) : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
do {
|
||||
val changes = TransformerPass(internalClassName, methodNode, generationState).run()
|
||||
} while (changes)
|
||||
@Suppress("ControlFlowWithEmptyBody")
|
||||
while (TransformerPass(internalClassName, methodNode, generationState).run()) {
|
||||
}
|
||||
}
|
||||
|
||||
private class TransformerPass(val internalClassName: String, val methodNode: MethodNode, val generationState: GenerationState) {
|
||||
@@ -170,14 +170,14 @@ class RedundantNullCheckMethodTransformer(private val generationState: Generatio
|
||||
}
|
||||
|
||||
private fun collectVariableDependentChecks() {
|
||||
for (insn in methodNode.instructions) {
|
||||
insnLoop@ for (insn in methodNode.instructions) {
|
||||
when {
|
||||
insn.isInstanceOfOrNullCheck() -> {
|
||||
val previous = insn.previous ?: continue
|
||||
val previous = insn.previous ?: continue@insnLoop
|
||||
if (previous.opcode == Opcodes.ALOAD) {
|
||||
addDependentCheck(insn, previous as VarInsnNode)
|
||||
} else if (previous.opcode == Opcodes.DUP) {
|
||||
val previous2 = previous.previous ?: continue
|
||||
val previous2 = previous.previous ?: continue@insnLoop
|
||||
if (previous2.opcode == Opcodes.ALOAD) {
|
||||
addDependentCheck(insn, previous2 as VarInsnNode)
|
||||
}
|
||||
@@ -185,36 +185,36 @@ class RedundantNullCheckMethodTransformer(private val generationState: Generatio
|
||||
}
|
||||
|
||||
insn.isCheckNotNull() -> {
|
||||
val previous = insn.previous ?: continue
|
||||
val previous = insn.previous ?: continue@insnLoop
|
||||
val aLoadInsn = if (previous.opcode == Opcodes.DUP) {
|
||||
previous.previous ?: continue
|
||||
previous.previous ?: continue@insnLoop
|
||||
} else previous
|
||||
if (aLoadInsn.opcode != Opcodes.ALOAD) continue
|
||||
if (aLoadInsn.opcode != Opcodes.ALOAD) continue@insnLoop
|
||||
addDependentCheck(insn, aLoadInsn as VarInsnNode)
|
||||
}
|
||||
|
||||
insn.isCheckParameterIsNotNull() -> {
|
||||
val ldcInsn = insn.previous ?: continue
|
||||
if (ldcInsn.opcode != Opcodes.LDC) continue
|
||||
val aLoadInsn = ldcInsn.previous ?: continue
|
||||
if (aLoadInsn.opcode != Opcodes.ALOAD) continue
|
||||
val ldcInsn = insn.previous ?: continue@insnLoop
|
||||
if (ldcInsn.opcode != Opcodes.LDC) continue@insnLoop
|
||||
val aLoadInsn = ldcInsn.previous ?: continue@insnLoop
|
||||
if (aLoadInsn.opcode != Opcodes.ALOAD) continue@insnLoop
|
||||
addDependentCheck(insn, aLoadInsn as VarInsnNode)
|
||||
}
|
||||
|
||||
insn.isCheckExpressionValueIsNotNull() -> {
|
||||
val ldcInsn = insn.previous ?: continue
|
||||
if (ldcInsn.opcode != Opcodes.LDC) continue
|
||||
val ldcInsn = insn.previous ?: continue@insnLoop
|
||||
if (ldcInsn.opcode != Opcodes.LDC) continue@insnLoop
|
||||
var aLoadInsn: VarInsnNode? = null
|
||||
val insn1 = ldcInsn.previous ?: continue
|
||||
val insn1 = ldcInsn.previous ?: continue@insnLoop
|
||||
if (insn1.opcode == Opcodes.ALOAD) {
|
||||
aLoadInsn = insn1 as VarInsnNode
|
||||
} else if (insn1.opcode == Opcodes.DUP) {
|
||||
val insn2 = insn1.previous ?: continue
|
||||
val insn2 = insn1.previous ?: continue@insnLoop
|
||||
if (insn2.opcode == Opcodes.ALOAD) {
|
||||
aLoadInsn = insn2 as VarInsnNode
|
||||
}
|
||||
}
|
||||
if (aLoadInsn == null) continue
|
||||
if (aLoadInsn == null) continue@insnLoop
|
||||
addDependentCheck(insn, aLoadInsn)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,13 +36,6 @@ enum class CompilerSystemProperties(val property: String, val alwaysDirectAccess
|
||||
KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY("kotlin.environment.keepalive"),
|
||||
COMPILE_DAEMON_CUSTOM_RUN_FILES_PATH_FOR_TESTS("kotlin.daemon.custom.run.files.path.for.tests"),
|
||||
KOTLIN_COLORS_ENABLED_PROPERTY("kotlin.colors.enabled"),
|
||||
|
||||
KOTLIN_STAT_ENABLED_PROPERTY("kotlin.plugin.stat.enabled"),
|
||||
KOTLIN_STAT_ENDPOINT_PROPERTY("kotlin.plugin.stat.endpoint"),
|
||||
KOTLIN_STAT_USER_PROPERTY("kotlin.plugin.stat.user"),
|
||||
KOTLIN_STAT_PASSWORD_PROPERTY("kotlin.plugin.stat.password"),
|
||||
KOTLIN_STAT_LABEl_PROPERTY("kotlin.plugin.stat.label"),
|
||||
|
||||
OS_NAME("os.name", alwaysDirectAccess = true),
|
||||
TMP_DIR("java.io.tmpdir"),
|
||||
USER_HOME("user.home", alwaysDirectAccess = true),
|
||||
|
||||
@@ -384,7 +384,6 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
|
||||
"Unknown value for parameter -Xexplicit-api: '$explicitApi'. Value should be one of ${ExplicitApiMode.availableValues()}"
|
||||
)
|
||||
put(AnalysisFlags.extendedCompilerChecks, extendedCompilerChecks)
|
||||
put(AnalysisFlags.allowKotlinPackage, allowKotlinPackage)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -187,6 +187,11 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
messageCollectorLogger(configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY] ?: error("Could not find message collector"))
|
||||
)
|
||||
|
||||
val friendAbsolutePaths = friendLibraries.map { File(it).absolutePath }
|
||||
val friendDependencies = resolvedLibraries.getFullList().filter {
|
||||
it.libraryFile.absolutePath in friendAbsolutePaths
|
||||
}
|
||||
|
||||
if (arguments.irProduceKlibDir || arguments.irProduceKlibFile) {
|
||||
if (arguments.irProduceKlibFile) {
|
||||
require(outputFile.extension == KLIB_FILE_EXTENSION) { "Please set up .klib file as output" }
|
||||
@@ -197,8 +202,8 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
files = sourcesFiles,
|
||||
analyzer = AnalyzerWithCompilerReport(config.configuration),
|
||||
configuration = config.configuration,
|
||||
dependencies = libraries,
|
||||
friendDependencies = friendLibraries,
|
||||
allDependencies = resolvedLibraries,
|
||||
friendDependencies = friendDependencies,
|
||||
irFactory = PersistentIrFactory(), // TODO IrFactoryImpl?
|
||||
outputKlibPath = outputFile.path,
|
||||
nopack = arguments.irProduceKlibDir,
|
||||
@@ -230,8 +235,8 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
config.configuration,
|
||||
PhaseConfig(wasmPhases),
|
||||
IrFactoryImpl,
|
||||
dependencies = libraries,
|
||||
friendDependencies = friendLibraries,
|
||||
allDependencies = resolvedLibraries,
|
||||
friendDependencies = friendDependencies,
|
||||
exportedDeclarations = setOf(FqName("main"))
|
||||
)
|
||||
val outputWasmFile = outputFile.withReplacedExtensionOrNull(outputFile.extension, "wasm")!!
|
||||
@@ -257,8 +262,8 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
config.configuration,
|
||||
phaseConfig,
|
||||
if (arguments.irDceDriven) PersistentIrFactory() else IrFactoryImpl,
|
||||
dependencies = libraries,
|
||||
friendDependencies = friendLibraries,
|
||||
allDependencies = resolvedLibraries,
|
||||
friendDependencies = friendDependencies,
|
||||
mainArguments = mainCallArguments,
|
||||
generateFullJs = !arguments.irDce,
|
||||
generateDceJs = arguments.irDce,
|
||||
|
||||
@@ -209,8 +209,7 @@ object TopDownAnalyzerFacadeForJVM {
|
||||
moduleClassResolver.compiledCodeResolver.packageFragmentProvider,
|
||||
dependenciesContainer.get<JvmBuiltInsPackageFragmentProvider>(),
|
||||
dependenciesContainer.get<OptionalAnnotationPackageFragmentProvider>()
|
||||
),
|
||||
"CompositeProvider@TopDownAnalyzerForJvm for dependencies ${dependenciesContext.module}"
|
||||
)
|
||||
)
|
||||
)
|
||||
dependenciesContext.module
|
||||
@@ -284,8 +283,7 @@ object TopDownAnalyzerFacadeForJVM {
|
||||
listOf(
|
||||
container.get<KotlinCodeAnalyzer>().packageFragmentProvider,
|
||||
container.get<OptionalAnnotationPackageFragmentProvider>()
|
||||
) + additionalProviders,
|
||||
"CompositeProvider@TopDownAnalzyerForJvm for $module"
|
||||
) + additionalProviders
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -53,7 +53,4 @@ object AnalysisFlags {
|
||||
|
||||
@JvmStatic
|
||||
val extendedCompilerChecks by AnalysisFlag.Delegates.Boolean
|
||||
|
||||
@JvmStatic
|
||||
val allowKotlinPackage by AnalysisFlag.Delegates.Boolean
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
public final class A : R|kotlin/Any| {
|
||||
public final fun arrays(s: R|@R|test/Ann|(klass = <getClass>(<getClass>(R|kotlin/Int|))) kotlin/Array<kotlin/Int>|, t: R|@R|test/Ann|(klass = <getClass>(<getClass>(R|kotlin/IntArray|))) kotlin/Array<kotlin/IntArray>|, u: R|@R|test/Ann|(klass = <getClass>(<getClass>(R|kotlin/Int|))) kotlin/Array<kotlin/Array<kotlin/Int>>|, v: R|@R|test/Ann|(klass = <getClass>(<getClass>(R|kotlin/String|))) kotlin/Array<kotlin/Array<kotlin/Array<kotlin/String>>>|): R|kotlin/Unit|
|
||||
public final fun arrays(s: @R|test/Ann|(klass = <getClass>(<getClass>(R|kotlin/Int|))) R|kotlin/Array<kotlin/Int>|, t: @R|test/Ann|(klass = <getClass>(<getClass>(R|kotlin/IntArray|))) R|kotlin/Array<kotlin/IntArray>|, u: @R|test/Ann|(klass = <getClass>(<getClass>(R|kotlin/Int|))) R|kotlin/Array<kotlin/Array<kotlin/Int>>|, v: @R|test/Ann|(klass = <getClass>(<getClass>(R|kotlin/String|))) R|kotlin/Array<kotlin/Array<kotlin/Array<kotlin/String>>>|): R|kotlin/Unit|
|
||||
|
||||
public final fun generic(s: R|@R|test/Ann|(klass = <getClass>(<getClass>(R|test/Generic|))) kotlin/String|): R|kotlin/Unit|
|
||||
public final fun generic(s: @R|test/Ann|(klass = <getClass>(<getClass>(R|test/Generic|))) R|kotlin/String|): R|kotlin/Unit|
|
||||
|
||||
public final fun innerGeneric(s: R|@R|test/Ann|(klass = <getClass>(<getClass>(R|test/InnerGeneric.Inner|))) kotlin/String|): R|kotlin/Unit|
|
||||
public final fun innerGeneric(s: @R|test/Ann|(klass = <getClass>(<getClass>(R|test/InnerGeneric.Inner|))) R|kotlin/String|): R|kotlin/Unit|
|
||||
|
||||
public final fun simple(s: R|@R|test/Ann|(klass = <getClass>(<getClass>(R|test/Simple|))) kotlin/String|): R|kotlin/Unit|
|
||||
public final fun simple(s: @R|test/Ann|(klass = <getClass>(<getClass>(R|test/Simple|))) R|kotlin/String|): R|kotlin/Unit|
|
||||
|
||||
public constructor(): R|test/A|
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
public final fun R|@R|test/A|() kotlin/String|.foo(): R|kotlin/Unit|
|
||||
public final fun @R|test/A|() R|kotlin/String|.foo(): R|kotlin/Unit|
|
||||
|
||||
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(R|kotlin/annotation/AnnotationTarget.TYPE|())) public final annotation class A : R|kotlin/Annotation| {
|
||||
public constructor(): R|test/A|
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
}
|
||||
|
||||
public final class SimpleTypeAnnotation : R|kotlin/Any| {
|
||||
public final fun foo(x: R|@R|test/A|() kotlin/ranges/IntRange|): R|@R|test/A|() kotlin/Int|
|
||||
public final fun foo(x: @R|test/A|() R|kotlin/ranges/IntRange|): @R|test/A|() R|kotlin/Int|
|
||||
|
||||
public constructor(): R|test/SimpleTypeAnnotation|
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
}
|
||||
|
||||
public abstract interface Foo<T : R|@R|test/A|() kotlin/Number|> : R|java/io/Serializable| {
|
||||
public abstract interface Foo<T : R|kotlin/Number|> : R|java/io/Serializable| {
|
||||
public abstract fun <E, F : R|E|> bar(): R|kotlin/Unit|
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
}
|
||||
|
||||
public final class TypeAnnotationWithArguments : R|kotlin/Any| {
|
||||
public final fun foo(param: R|@R|test/Ann|(x = String(param), y = Double(3.14)) kotlin/ranges/IntRange|): R|@R|test/Ann|(x = String(fun), y = Double(2.72)) kotlin/Unit|
|
||||
public final fun foo(param: @R|test/Ann|(x = String(param), y = Double(3.14)) R|kotlin/ranges/IntRange|): @R|test/Ann|(x = String(fun), y = Double(2.72)) R|kotlin/Unit|
|
||||
|
||||
public constructor(): R|test/TypeAnnotationWithArguments|
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
public final fun foo(bar: R|kotlin/collections/Map<@R|test/A|() kotlin/String, kotlin/collections/List<@R|test/A|() kotlin/Int>>|): R|kotlin/Unit|
|
||||
public final fun foo(bar: R|kotlin/collections/Map<kotlin/String, kotlin/collections/List<kotlin/Int>>|): R|kotlin/Unit|
|
||||
|
||||
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(R|kotlin/annotation/AnnotationTarget.TYPE|())) public final annotation class A : R|kotlin/Annotation| {
|
||||
public constructor(): R|test/A|
|
||||
|
||||
@@ -10,8 +10,8 @@ FILE: lambdaInUnresolvedCall.kt
|
||||
)
|
||||
}
|
||||
public final fun test_2(): R|kotlin/Unit| {
|
||||
<Unresolved name: myRun>#(<L> = myRun@fun <anonymous>(): <ERROR TYPE REF: Cannot infer argument for type parameter R> <inline=Unknown> {
|
||||
^ R|/materialize|<R|ERROR CLASS: Cannot infer argument for type parameter R|>()
|
||||
<Unresolved name: myRun>#(<L> = myRun@fun <anonymous>(): R|kotlin/Any?| <inline=Unknown> {
|
||||
^ R|/materialize|<R|kotlin/Any?|>()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FILE: varargOfLambdasWithReceiver.kt
|
||||
public final fun runLambdas(vararg values: R|kotlin/Array<out @ExtensionFunctionType kotlin/Function1<kotlin/String, kotlin/Unit>>|): R|kotlin/Unit| {
|
||||
public final fun runLambdas(vararg values: @R|kotlin/ExtensionFunctionType|() R|kotlin/Array<out @ExtensionFunctionType kotlin/Function1<kotlin/String, kotlin/Unit>>|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
R|/runLambdas|(vararg(runLambdas@fun R|kotlin/String|.<anonymous>(): R|kotlin/Unit| <inline=Unknown> {
|
||||
|
||||
@@ -148,34 +148,11 @@ FILE: conflictingProjection.kt
|
||||
^test15 R|/InOuter.InOuter|<R|kotlin/Int|>().R|SubstitutionOverride</InOuter.OutIntermediate.OutIntermediate>|<R|kotlin/String|>().R|SubstitutionOverride</InOuter.OutIntermediate.InInner.InInner>|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test16(): R|InOuter.OutIntermediate.InInner<out kotlin/Char, kotlin/String, kotlin/Int>| {
|
||||
^test16 R|/InOuter.InOuter|<R|kotlin/Int|>().R|SubstitutionOverride</InOuter.OutIntermediate.OutIntermediate>|<R|kotlin/String|>().<CS errors: /InOuter.OutIntermediate.InInner.InInner>#<R|ERROR CLASS: Cannot infer argument for type parameter G|>()
|
||||
^test16 R|/InOuter.InOuter|<R|kotlin/Int|>().R|SubstitutionOverride</InOuter.OutIntermediate.OutIntermediate>|<R|kotlin/String|>().R|SubstitutionOverride</InOuter.OutIntermediate.InInner.InInner>|<R|kotlin/Any?|>()
|
||||
}
|
||||
public final fun test17(): R|InOuter.OutIntermediate.InInner<kotlin/Char, out kotlin/String, in kotlin/Int>| {
|
||||
^test17 R|/InOuter.InOuter|<R|kotlin/Int|>().R|SubstitutionOverride</InOuter.OutIntermediate.OutIntermediate>|<R|kotlin/String|>().R|SubstitutionOverride</InOuter.OutIntermediate.InInner.InInner>|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test18(): R|InOuter.OutIntermediate.InInner<out kotlin/Char, in kotlin/String, kotlin/Int>| {
|
||||
^test18 R|/InOuter.InOuter|<R|kotlin/Int|>().R|SubstitutionOverride</InOuter.OutIntermediate.OutIntermediate>|<R|kotlin/String|>().<CS errors: /InOuter.OutIntermediate.InInner.InInner>#<R|ERROR CLASS: Cannot infer argument for type parameter G|>()
|
||||
}
|
||||
public final class TwoParametersOuter<T, in T1> : R|kotlin/Any| {
|
||||
public constructor<T, in T1>(): R|TwoParametersOuter<T, T1>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final inner class TwoParametersIntermediate<out K, K1, T, in T1> : R|kotlin/Any| {
|
||||
public constructor<out K, K1>(): R|TwoParametersOuter.TwoParametersIntermediate<K, K1, T, T1>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final inner class InInner<in G, G1, out K, K1, T, in T1> : R|kotlin/Any| {
|
||||
public constructor<in G, G1>(): R|TwoParametersOuter.TwoParametersIntermediate.InInner<G, G1, K, K1, T, T1>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test19(): R|TwoParametersOuter.TwoParametersIntermediate.InInner<kotlin/Char, kotlin/Char, in kotlin/String, kotlin/Int, kotlin/Int, out kotlin/String>?| {
|
||||
^test19 Null(null)
|
||||
^test18 R|/InOuter.InOuter|<R|kotlin/Int|>().R|SubstitutionOverride</InOuter.OutIntermediate.OutIntermediate>|<R|kotlin/String|>().R|SubstitutionOverride</InOuter.OutIntermediate.InInner.InInner>|<R|kotlin/Any?|>()
|
||||
}
|
||||
|
||||
@@ -7,12 +7,12 @@ fun a2(value: None<in Int>) {}
|
||||
fun a3(value: None<out Int>) {}
|
||||
|
||||
fun a4(value: In<Int>) {}
|
||||
fun a5(value: In<<!REDUNDANT_PROJECTION!>in<!> Int>) {}
|
||||
fun a6(value: In<<!CONFLICTING_PROJECTION!>out<!> Int>) {}
|
||||
fun a5(value: In<in Int>) {}
|
||||
fun a6(value: <!CONFLICTING_PROJECTION!>In<out Int><!>) {}
|
||||
|
||||
fun a7(value: Out<Int>) {}
|
||||
fun a8(value: Out<<!CONFLICTING_PROJECTION!>in<!> Int>) {}
|
||||
fun a9(value: Out<<!REDUNDANT_PROJECTION!>out<!> Int>) {}
|
||||
fun a8(value: <!CONFLICTING_PROJECTION!>Out<in Int><!>) {}
|
||||
fun a9(value: Out<out Int>) {}
|
||||
|
||||
typealias A1<K> = None<K>
|
||||
typealias A2<K> = None<in K>
|
||||
@@ -27,28 +27,28 @@ typealias A8<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = None<in K>
|
||||
typealias A9<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = None<out K>
|
||||
|
||||
typealias A10<K> = In<K>
|
||||
typealias A11<K> = In<<!REDUNDANT_PROJECTION!>in<!> K>
|
||||
typealias A12<K> = In<<!CONFLICTING_PROJECTION!>out<!> K>
|
||||
typealias A11<K> = In<in K>
|
||||
typealias A12<K> = <!CONFLICTING_PROJECTION!>In<out K><!>
|
||||
|
||||
typealias A13<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = In<K>
|
||||
typealias A14<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = In<<!REDUNDANT_PROJECTION!>in<!> K>
|
||||
typealias A15<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = In<<!CONFLICTING_PROJECTION!>out<!> K>
|
||||
typealias A14<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = In<in K>
|
||||
typealias A15<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = <!CONFLICTING_PROJECTION!>In<out K><!>
|
||||
|
||||
typealias A16<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = In<K>
|
||||
typealias A17<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = In<<!REDUNDANT_PROJECTION!>in<!> K>
|
||||
typealias A18<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = In<<!CONFLICTING_PROJECTION!>out<!> K>
|
||||
typealias A17<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = In<in K>
|
||||
typealias A18<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = <!CONFLICTING_PROJECTION!>In<out K><!>
|
||||
|
||||
typealias A19<K> = Out<K>
|
||||
typealias A20<K> = Out<<!CONFLICTING_PROJECTION!>in<!> K>
|
||||
typealias A21<K> = Out<<!REDUNDANT_PROJECTION!>out<!> K>
|
||||
typealias A20<K> = <!CONFLICTING_PROJECTION!>Out<in K><!>
|
||||
typealias A21<K> = Out<out K>
|
||||
|
||||
typealias A22<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = Out<K>
|
||||
typealias A23<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = Out<<!CONFLICTING_PROJECTION!>in<!> K>
|
||||
typealias A24<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = Out<<!REDUNDANT_PROJECTION!>out<!> K>
|
||||
typealias A23<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = <!CONFLICTING_PROJECTION!>Out<in K><!>
|
||||
typealias A24<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = Out<out K>
|
||||
|
||||
typealias A25<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = Out<K>
|
||||
typealias A26<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = Out<<!CONFLICTING_PROJECTION!>in<!> K>
|
||||
typealias A27<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = Out<<!REDUNDANT_PROJECTION!>out<!> K>
|
||||
typealias A26<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = <!CONFLICTING_PROJECTION!>Out<in K><!>
|
||||
typealias A27<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = Out<out K>
|
||||
|
||||
class Outer<T> {
|
||||
inner class Intermediate<K> {
|
||||
@@ -82,23 +82,14 @@ class InOuter<in T> {
|
||||
|
||||
fun test10(): InOuter<Int>.OutIntermediate<String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
|
||||
fun test11(): InOuter<<!REDUNDANT_PROJECTION!>in<!> Int>.OutIntermediate<String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
fun test12(): InOuter<<!CONFLICTING_PROJECTION!>out<!> Int>.OutIntermediate<String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
fun test11(): InOuter<in Int>.OutIntermediate<String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
fun test12(): <!CONFLICTING_PROJECTION!>InOuter<out Int>.OutIntermediate<String>.InInner<Char><!> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
|
||||
fun test13(): InOuter<Int>.OutIntermediate<<!CONFLICTING_PROJECTION!>in<!> String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
fun test14(): InOuter<Int>.OutIntermediate<<!REDUNDANT_PROJECTION!>out<!> String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
fun test13(): <!CONFLICTING_PROJECTION!>InOuter<Int>.OutIntermediate<in String>.InInner<Char><!> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
fun test14(): InOuter<Int>.OutIntermediate<out String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
|
||||
fun test15(): InOuter<Int>.OutIntermediate<String>.InInner<<!REDUNDANT_PROJECTION!>in<!> Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
fun test16(): InOuter<Int>.OutIntermediate<String>.InInner<<!CONFLICTING_PROJECTION!>out<!> Char> = InOuter<Int>().OutIntermediate<String>().<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>InInner<!>()
|
||||
fun test15(): InOuter<Int>.OutIntermediate<String>.InInner<in Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
fun test16(): <!CONFLICTING_PROJECTION!>InOuter<Int>.OutIntermediate<String>.InInner<out Char><!> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
|
||||
fun test17(): InOuter<<!REDUNDANT_PROJECTION!>in<!> Int>.OutIntermediate<<!REDUNDANT_PROJECTION!>out<!> String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
fun test18(): InOuter<Int>.OutIntermediate<<!CONFLICTING_PROJECTION!>in<!> String>.InInner<<!CONFLICTING_PROJECTION!>out<!> Char> = InOuter<Int>().OutIntermediate<String>().<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>InInner<!>()
|
||||
|
||||
class TwoParametersOuter<T, in T1> {
|
||||
inner class TwoParametersIntermediate<out K, K1> {
|
||||
inner class InInner<in G, G1> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun test19(): TwoParametersOuter<Int, <!CONFLICTING_PROJECTION!>out<!> String>.TwoParametersIntermediate<<!CONFLICTING_PROJECTION!>in<!> String, Int>.InInner<Char, Char>? = null
|
||||
fun test17(): InOuter<in Int>.OutIntermediate<out String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
fun test18(): <!CONFLICTING_PROJECTION!>InOuter<Int>.OutIntermediate<in String>.InInner<out Char><!> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
|
||||
@@ -70,5 +70,5 @@ FILE: upperBoundViolated.kt
|
||||
}
|
||||
public final val np1: R|NumberPhile<kotlin/Int>| = R|/NumberPhile.NumberPhile|<R|kotlin/Int|>(Int(10))
|
||||
public get(): R|NumberPhile<kotlin/Int>|
|
||||
public final val np2: R|NumberPhile<ERROR CLASS: Cannot infer argument for type parameter T>| = <Inapplicable(INAPPLICABLE): /NumberPhile.NumberPhile>#<R|ERROR CLASS: Cannot infer argument for type parameter T|>(String(Test))
|
||||
public get(): R|NumberPhile<ERROR CLASS: Cannot infer argument for type parameter T>|
|
||||
public final val np2: R|NumberPhile<kotlin/Number>| = <Inapplicable(INAPPLICABLE): /NumberPhile.NumberPhile>#<R|kotlin/Number|>(String(Test))
|
||||
public get(): R|NumberPhile<kotlin/Number>|
|
||||
|
||||
@@ -18,5 +18,5 @@ FILE: typeParameters.kt
|
||||
}
|
||||
public final fun main(fooImpl: R|FooImpl|, bar: R|Bar|): R|kotlin/Unit| {
|
||||
lval a: R|FooImpl| = R|/foo|<R|FooImpl|>(R|<local>/fooImpl|)
|
||||
lval b: <ERROR TYPE REF: Cannot infer argument for type parameter T> = <Inapplicable(INAPPLICABLE): /foo>#<R|ERROR CLASS: Cannot infer argument for type parameter T|>(R|<local>/bar|)
|
||||
lval b: R|Foo| = <Inapplicable(INAPPLICABLE): /foo>#<R|Foo|>(R|<local>/bar|)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ FILE: RedundantExplicitTypeChecker.kt
|
||||
|
||||
}
|
||||
public final fun annotated(): R|kotlin/Unit| {
|
||||
lval x: R|@R|A|() kotlin/Int| = Int(1)
|
||||
lval x: @R|A|() R|kotlin/Int| = Int(1)
|
||||
}
|
||||
public final object SomeObj : R|kotlin/Any| {
|
||||
private constructor(): R|SomeObj| {
|
||||
|
||||
@@ -22,7 +22,7 @@ FILE: RedundantReturnUnitTypeChecker.kt
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final fun too(): R|@R|kotlin/Annotation|() kotlin/Unit| {
|
||||
public final fun too(): @R|kotlin/Annotation|() R|@R|kotlin/Annotation|() kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final fun foo(): R|kotlin/Unit| {
|
||||
|
||||
@@ -5,7 +5,7 @@ FILE: fakeRecursiveSupertype.kt
|
||||
}
|
||||
|
||||
}
|
||||
public open class Your : <ERROR TYPE REF: Loop in supertype: /Your -> /His> {
|
||||
public open class Your : R|His| {
|
||||
public constructor(): R|Your| {
|
||||
super<R|His|>()
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import incorrect.directory.My
|
||||
|
||||
open class My : <!CYCLIC_INHERITANCE_HIERARCHY!>My<!>()
|
||||
open class My : <!OTHER_ERROR!>My<!>()
|
||||
|
||||
open class Your : <!CYCLIC_INHERITANCE_HIERARCHY!>His<!>()
|
||||
open class Your : His()
|
||||
|
||||
open class His : <!CYCLIC_INHERITANCE_HIERARCHY!>Your<!>()
|
||||
open class His : <!OTHER_ERROR!>Your<!>()
|
||||
|
||||
@@ -2,4 +2,4 @@ import incorrect.directory.Your
|
||||
|
||||
typealias My = <!UNRESOLVED_REFERENCE!>incorrect.directory.My<!>
|
||||
|
||||
typealias Your = <!RECURSIVE_TYPEALIAS_EXPANSION!>Your<!>
|
||||
typealias Your = <!OTHER_ERROR!>Your<!>
|
||||
|
||||
@@ -4,7 +4,7 @@ interface List<out T : Any> {
|
||||
infix fun concat(other: List<<!TYPE_VARIANCE_CONFLICT!>T<!>>): List<T>
|
||||
}
|
||||
|
||||
typealias StringList = List<<!REDUNDANT_PROJECTION!>out<!> String>
|
||||
typealias StringList = List<out String>
|
||||
typealias AnyList = List<*>
|
||||
|
||||
abstract class AbstractList<out T : Any> : List<T>
|
||||
|
||||
@@ -15,7 +15,7 @@ FILE: nestedExtensionFunctionType.kt
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_2(a: R|A|, vararg zs: R|kotlin/Array<out @ExtensionFunctionType kotlin/Function1<A, kotlin/Unit>>|): R|kotlin/Unit| {
|
||||
public final fun test_2(a: R|A|, vararg zs: @R|kotlin/ExtensionFunctionType|() R|kotlin/Array<out @ExtensionFunctionType kotlin/Function1<A, kotlin/Unit>>|): R|kotlin/Unit| {
|
||||
{
|
||||
lval <iterator>: R|kotlin/collections/Iterator<@ExtensionFunctionType kotlin/Function1<A, kotlin/Unit>>| = R|<local>/zs|.R|SubstitutionOverride<kotlin/Array.iterator: R|kotlin/collections/Iterator<CapturedType(out @ExtensionFunctionType kotlin/Function1<A, kotlin/Unit>)>|>|()
|
||||
while(R|<local>/<iterator>|.R|kotlin/collections/Iterator.hasNext|()) {
|
||||
|
||||
@@ -63,15 +63,15 @@ FILE: main.kt
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
@R|annotations/Simple|() public abstract fun foo(@R|annotations/WithString|(String(abc)) arg: R|@R|annotations/Simple|() kotlin/Double|): R|kotlin/Unit|
|
||||
@R|annotations/Simple|() public abstract fun foo(@R|annotations/WithString|(String(abc)) arg: @R|annotations/Simple|() R|kotlin/Double|): R|kotlin/Unit|
|
||||
|
||||
@R|annotations/Complex|(R|annotations/WithInt.WithInt|(Int(7)), R|annotations/WithString.WithString|(String())) public abstract val v: R|kotlin/String|
|
||||
public get(): R|kotlin/String|
|
||||
|
||||
}
|
||||
@R|annotations/WithString|(String(xyz)) public final class Second : R|@R|annotations/WithInt|(Int(0)) test/First| {
|
||||
@R|annotations/WithString|(String(xyz)) public final class Second : @R|annotations/WithInt|(Int(0)) R|test/First| {
|
||||
public constructor(y: R|kotlin/Char|): R|test/Second| {
|
||||
super<R|@R|annotations/WithInt|(Int(0)) test/First|>()
|
||||
super<@R|annotations/WithInt|(Int(0)) R|test/First|>()
|
||||
}
|
||||
|
||||
public final val y: R|kotlin/Char| = R|<local>/y|
|
||||
@@ -90,4 +90,4 @@ FILE: main.kt
|
||||
}
|
||||
|
||||
}
|
||||
@R|annotations/WithInt|(Int(24)) @R|annotations/VeryComplex|(Float(3.14), Double(6.67E-11), Boolean(false), Long(123456789012345), Null(null)) @R|annotations/WithInt|(Int(24)) @R|annotations/VeryComplex|(Float(3.14), Double(6.67E-11), Boolean(false), Long(123456789012345), Null(null)) public final typealias Third = R|@R|annotations/Simple|() test/Second|
|
||||
@R|annotations/WithInt|(Int(24)) @R|annotations/VeryComplex|(Float(3.14), Double(6.67E-11), Boolean(false), Long(123456789012345), Null(null)) @R|annotations/WithInt|(Int(24)) @R|annotations/VeryComplex|(Float(3.14), Double(6.67E-11), Boolean(false), Long(123456789012345), Null(null)) public final typealias Third = @R|annotations/Simple|() R|test/Second|
|
||||
|
||||
@@ -8,7 +8,7 @@ open class A {
|
||||
|
||||
class B : A() {
|
||||
override fun foo(): B = this
|
||||
fun <!VIRTUAL_MEMBER_HIDDEN!>bar<!>(): B = this // Missing 'override'
|
||||
fun bar(): B = this // Ambiguity, no override here (really it's just "missing override" and no ambiguity)
|
||||
override fun buz(p: B): B = this //No override as B not :> A
|
||||
|
||||
fun test() {
|
||||
|
||||
@@ -24,5 +24,5 @@ FILE: supertypeGenericsComplex.kt
|
||||
}
|
||||
public final fun f(list: R|kotlin/collections/MutableList<X>|, s: R|kotlin/collections/MutableList<kotlin/CharSequence>|): R|kotlin/Unit| {
|
||||
R|/C.C|().R|SubstitutionOverride</C.f: R|kotlin/Unit|>|<R|X|>(R|<local>/list|, R|<local>/s|)
|
||||
R|/C.C|().<Inapplicable(INAPPLICABLE): /C.f>#<R|ERROR CLASS: Cannot infer argument for type parameter D|>(R|<local>/s|, R|<local>/list|)
|
||||
R|/C.C|().<Inapplicable(INAPPLICABLE): /C.f>#<R|Out<kotlin/CharSequence>|>(R|<local>/s|, R|<local>/list|)
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class LightClassWrapper<!> : Light(),
|
||||
}
|
||||
|
||||
public abstract class Light : Field, TypeParametersOwner {
|
||||
fun <!VIRTUAL_MEMBER_HIDDEN!>getTypeParameters<!>() = listOf()
|
||||
fun getTypeParameters() = listOf()
|
||||
}
|
||||
|
||||
public interface Field : Named
|
||||
|
||||
@@ -40,8 +40,8 @@ FILE: referenceToExtension.kt
|
||||
}
|
||||
|
||||
public final fun test_2(): R|kotlin/Unit| {
|
||||
lval extensionValRef: R|kotlin/reflect/KProperty1<GenericTest.B<*>, GenericTest.A<CapturedType(*)>>| = Q|GenericTest.B|::R|/GenericTest.extensionVal<kotlin/Any?>|
|
||||
lval extensionFunRef: R|@ExtensionFunctionType kotlin/reflect/KFunction1<GenericTest.B<*>, GenericTest.A<CapturedType(*)>>| = Q|GenericTest.B|::R|/GenericTest.extensionFun<kotlin/Any?>|
|
||||
lval extensionValRef: <ERROR TYPE REF: Unresolved reference: extensionVal> = Q|GenericTest.B|::<Unresolved reference: extensionVal>#
|
||||
lval extensionFunRef: <ERROR TYPE REF: Unresolved reference: extensionFun> = Q|GenericTest.B|::<Unresolved reference: extensionFun>#
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ class GenericTest {
|
||||
}
|
||||
|
||||
fun test_2() {
|
||||
val extensionValRef = B<*>::<!EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED!>extensionVal<!>
|
||||
val extensionFunRef = B<*>::<!EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED!>extensionFun<!>
|
||||
val extensionValRef = B<*>::<!UNRESOLVED_REFERENCE!>extensionVal<!>
|
||||
val extensionFunRef = B<*>::<!UNRESOLVED_REFERENCE!>extensionFun<!>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ FILE: main.kt
|
||||
^ R|<local>/x|.R|kotlin/Any.toString|()
|
||||
}
|
||||
)
|
||||
<CS errors: /MyFunction>#<R|ERROR CLASS: Cannot infer argument for type parameter T|, R|ERROR CLASS: Cannot infer argument for type parameter R|>(<L> = MyFunction@fun <anonymous>(x: <ERROR TYPE REF: Cannot infer argument for type parameter T>): <ERROR TYPE REF: Cannot infer argument for type parameter R> <inline=NoInline> {
|
||||
R|/MyFunction|<R|kotlin/Nothing|, R|kotlin/Any?|>(<L> = MyFunction@fun <anonymous>(x: R|ft<kotlin/Nothing, kotlin/Nothing?>|): R|kotlin/Any?| <inline=NoInline> {
|
||||
^ String()
|
||||
}
|
||||
)
|
||||
|
||||
@@ -14,7 +14,7 @@ fun main() {
|
||||
x.toString()
|
||||
}
|
||||
|
||||
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>MyFunction<!> { <!CANNOT_INFER_PARAMETER_TYPE!>x<!> ->
|
||||
MyFunction { x ->
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ FILE: tryInference.kt
|
||||
R|/materialize|<R|A|>()
|
||||
}
|
||||
finally {
|
||||
<CS errors: /materialize>#<R|ERROR CLASS: Cannot infer argument for type parameter T|>()
|
||||
R|/materialize|<R|kotlin/Nothing|>()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ fun test() {
|
||||
} catch (e: Exception) {
|
||||
materialize()
|
||||
} finally {
|
||||
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>materialize<!>() // Should be an errror
|
||||
materialize() // Should be an errror
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -71,13 +71,13 @@ typealias Out1<X> = Out<X>
|
||||
typealias Invariant1<X> = Invariant<X>
|
||||
|
||||
|
||||
fun test_5(a: A, in1: In1<A>, in2: In1<<!REDUNDANT_PROJECTION!>in<!> A>, in3: In1<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>out<!> A>) {
|
||||
fun test_5(a: A, in1: In1<A>, in2: In1<in A>, in3: In1<out A>) {
|
||||
in1.take(a)
|
||||
in2.take(a)
|
||||
in3.<!UNRESOLVED_REFERENCE!>take<!>(a)
|
||||
}
|
||||
|
||||
fun test_6(a: A, out1: Out1<A>, out2: Out1<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>in<!> A>, out3: Out1<<!REDUNDANT_PROJECTION!>out<!> A>) {
|
||||
fun test_6(a: A, out1: Out1<A>, out2: Out1<in A>, out3: Out1<out A>) {
|
||||
out1.value().foo()
|
||||
out2.<!UNRESOLVED_REFERENCE!>value<!>().foo()
|
||||
out3.value().foo()
|
||||
|
||||
@@ -6,5 +6,5 @@ FILE: ambiguityWhenNoApplicableCallableReferenceCandidate.kt
|
||||
public final fun <T> bar(f: R|(T) -> kotlin/Unit|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
<CS errors: /bar>#<R|ERROR CLASS: Cannot infer argument for type parameter T|>(::<Ambiguity: foo, [/foo, /foo]>#)
|
||||
R|/bar|<R|kotlin/Any?|>(::<Ambiguity: foo, [/foo, /foo]>#)
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@ fun foo(y: String) {}
|
||||
fun <T> bar(f: (T) -> Unit) {}
|
||||
|
||||
fun test() {
|
||||
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>bar<!>(::<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>)
|
||||
bar(::<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>)
|
||||
}
|
||||
|
||||
@@ -30,14 +30,14 @@ FILE: chooseCallableReferenceDependingOnInferredReceiver.kt
|
||||
^bar R|kotlin/TODO|()
|
||||
}
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
<CS errors: /myWith>#<R|A|, R|ERROR CLASS: Cannot infer argument for type parameter R|>(R|/A.A|(), <L> = myWith@fun R|A|.<anonymous>(): <ERROR TYPE REF: Cannot infer argument for type parameter R> <inline=Inline, kind=UNKNOWN> {
|
||||
R|/myWith|<R|A|, R|kotlin/Nothing|>(R|/A.A|(), <L> = myWith@fun R|A|.<anonymous>(): R|kotlin/Nothing| <inline=Inline, kind=UNKNOWN> {
|
||||
lval t1: R|A| = R|/bar|<R|A|>(::R|/A.foo|)
|
||||
lval t2: R|A| = R|/bar|<R|A|>(::R|/A.baz|)
|
||||
^ R|/myWith|<R|B|, R|ERROR CLASS: Cannot infer argument for type parameter R|>(R|/B.B|(), <L> = myWith@fun R|B|.<anonymous>(): <ERROR TYPE REF: Cannot infer argument for type parameter R> <inline=Inline, kind=UNKNOWN> {
|
||||
^ R|/myWith|<R|B|, R|kotlin/Nothing|>(R|/B.B|(), <L> = myWith@fun R|B|.<anonymous>(): R|kotlin/Nothing| <inline=Inline, kind=UNKNOWN> {
|
||||
lval a: R|A| = R|/bar|<R|A|>(::R|/A.foo|)
|
||||
lval b: R|B| = R|/bar|<R|B|>(::R|/B.foo|)
|
||||
lval t3: R|B| = R|/bar|<R|B|>(::R|/B.baz|)
|
||||
^ R|/bar|<R|ERROR CLASS: Cannot infer argument for type parameter T|>(::<Ambiguity: foo, [/B.foo, /B.foo]>#)
|
||||
^ R|/bar|<R|kotlin/Nothing|>(::<Ambiguity: foo, [/B.foo, /B.foo]>#)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class B {
|
||||
fun <T> bar(f: (T) -> Unit): T = TODO()
|
||||
|
||||
fun test() {
|
||||
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>myWith<!>(A()) {
|
||||
myWith(A()) {
|
||||
val t1 = bar(::foo)
|
||||
|
||||
val t2 = bar(::baz)
|
||||
|
||||
@@ -21,5 +21,5 @@ FILE: eagerAndPostponedCallableReferences.kt
|
||||
lval a4: R|B| = R|/foo|<R|B|>(::R|/multiple|, ::R|/singleB|)
|
||||
lval a5: R|A| = R|/foo|<R|A|>(::R|/singleA|, ::R|/singleA|)
|
||||
lval a6: R|it(A & B)| = R|/foo|<R|it(A & B)|>(::R|/singleA|, ::R|/singleB|)
|
||||
<CS errors: /foo>#<R|ERROR CLASS: Cannot infer argument for type parameter T|>(::<Ambiguity: multiple, [/multiple, /multiple]>#, ::<Ambiguity: multiple, [/multiple, /multiple]>#)
|
||||
R|/foo|<R|kotlin/Nothing|>(::<Ambiguity: multiple, [/multiple, /multiple]>#, ::<Ambiguity: multiple, [/multiple, /multiple]>#)
|
||||
}
|
||||
|
||||
@@ -22,5 +22,5 @@ fun test() {
|
||||
|
||||
val a6 = foo(::singleA, ::singleB)
|
||||
|
||||
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>foo<!>(::<!OVERLOAD_RESOLUTION_AMBIGUITY!>multiple<!>, ::<!OVERLOAD_RESOLUTION_AMBIGUITY!>multiple<!>)
|
||||
foo(::<!OVERLOAD_RESOLUTION_AMBIGUITY!>multiple<!>, ::<!OVERLOAD_RESOLUTION_AMBIGUITY!>multiple<!>)
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ FILE: implicitTypes.kt
|
||||
public final fun bar(x: R|kotlin/String|): R|kotlin/Int| {
|
||||
^bar Int(1)
|
||||
}
|
||||
public final fun loop1(): R|(ERROR CLASS: Cannot infer argument for type parameter T) -> ERROR CLASS: Cannot infer argument for type parameter R| {
|
||||
^loop1 <Inapplicable(INAPPLICABLE): /use>#<R|ERROR CLASS: Cannot infer argument for type parameter T|, R|ERROR CLASS: Cannot infer argument for type parameter R|>(::<Unresolved reference: loop2>#)
|
||||
public final fun loop1(): R|(kotlin/Any?) -> kotlin/Nothing| {
|
||||
^loop1 <Inapplicable(INAPPLICABLE): /use>#<R|kotlin/Any?|, R|kotlin/Nothing|>(::<Unresolved reference: loop2>#)
|
||||
}
|
||||
public final fun loop2(): <ERROR TYPE REF: cycle> {
|
||||
^loop2 R|/loop1|()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
||||
import kotlin.contracts.*
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
||||
import kotlin.contracts.*
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
||||
import kotlin.contracts.*
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
||||
import kotlin.contracts.*
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
||||
import kotlin.contracts.*
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
||||
import kotlin.contracts.*
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
||||
import kotlin.contracts.*
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
|
||||
@@ -14,7 +14,7 @@ public class A {
|
||||
|
||||
class B : A() {
|
||||
override fun foo(): B = this
|
||||
fun <!VIRTUAL_MEMBER_HIDDEN!>bar<!>(): B = this // Here we should have "missing override" but no ambiguity
|
||||
fun bar(): B = this // Here we should have "missing override" but no ambiguity
|
||||
|
||||
fun test() {
|
||||
foo()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FILE: K1.kt
|
||||
public final class K2 : <ERROR TYPE REF: Loop in supertype: /K2 -> /J1> {
|
||||
public final class K2 : R|J1| {
|
||||
public constructor(): R|K2| {
|
||||
super<R|J1|>()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// FIR_IDE_IGNORE
|
||||
// FILE: K1.kt
|
||||
class K2: <!CYCLIC_INHERITANCE_HIERARCHY!>J1<!>() {
|
||||
class K2: J1() {
|
||||
class Q : <!UNRESOLVED_REFERENCE!>Nested<!>()
|
||||
fun bar() {
|
||||
<!UNRESOLVED_REFERENCE!>foo<!>()
|
||||
|
||||
@@ -20,7 +20,7 @@ FILE: KtFirCompositeScope.kt
|
||||
public final fun getAllNames(): R|kotlin/collections/Set<kotlin/String>| {
|
||||
^getAllNames R|/withValidityAssertion|<R|kotlin/collections/Set<kotlin/String>|>(<L> = withValidityAssertion@fun <anonymous>(): R|kotlin/collections/Set<kotlin/String>| <inline=Inline, kind=UNKNOWN> {
|
||||
^ R|/buildSet|<R|kotlin/String|>(<L> = buildSet@fun R|kotlin/collections/MutableSet<kotlin/String>|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=UNKNOWN> {
|
||||
this@R|/KtFirCompositeScope|.R|/KtFirCompositeScope.subScopes|.R|kotlin/collections/flatMapTo|<R|KtScope|, R|kotlin/String|, R|kotlin/collections/MutableSet<Stub: TypeVariable(E)>|>(this@R|special/anonymous|, <L> = flatMapTo@fun <anonymous>(it: R|KtScope|): R|kotlin/collections/Iterable<kotlin/String>| <inline=Inline, kind=UNKNOWN> {
|
||||
this@R|/KtFirCompositeScope|.R|/KtFirCompositeScope.subScopes|.R|kotlin/collections/flatMapTo|<R|KtScope|, R|kotlin/String|, R|kotlin/collections/MutableSet<kotlin/String>|>(this@R|special/anonymous|, <L> = flatMapTo@fun <anonymous>(it: R|KtScope|): R|kotlin/collections/Iterable<kotlin/String>| <inline=Inline, kind=UNKNOWN> {
|
||||
^ R|<local>/it|.R|/KtScope.getAllNames|()
|
||||
}
|
||||
)
|
||||
|
||||
@@ -11579,12 +11579,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/imports/importFunctionWithAllUnderImportAfterNamedImport.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ImportFunctionWithPackageName.kt")
|
||||
public void testImportFunctionWithPackageName() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/imports/ImportFunctionWithPackageName.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ImportHidingDefinitionInTheSameFile.kt")
|
||||
public void testImportHidingDefinitionInTheSameFile() throws Exception {
|
||||
@@ -11645,12 +11639,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/imports/ImportResolutionOrder.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ImportStaticFunctionWithNonStaticSibling.kt")
|
||||
public void testImportStaticFunctionWithNonStaticSibling() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/imports/ImportStaticFunctionWithNonStaticSibling.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ImportTwoTimes.kt")
|
||||
public void testImportTwoTimes() throws Exception {
|
||||
@@ -12209,12 +12197,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/inference/expectedTypeWithGenerics.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectedTypeWithGenericsSafeCalls.kt")
|
||||
public void testExpectedTypeWithGenericsSafeCalls() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/expectedTypeWithGenericsSafeCalls.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionLambdasAndArrow.kt")
|
||||
public void testExtensionLambdasAndArrow() throws Exception {
|
||||
@@ -12944,12 +12926,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturingFromArgumentOfFlexibleType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("dontCheckNewCapturedTypeSpecificChecksForOldOnes.kt")
|
||||
public void testDontCheckNewCapturedTypeSpecificChecksForOldOnes() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/dontCheckNewCapturedTypeSpecificChecksForOldOnes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectedTypeMismatchWithInVariance.kt")
|
||||
public void testExpectedTypeMismatchWithInVariance() throws Exception {
|
||||
@@ -19111,12 +19087,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/AssertNotNull.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("augmentedAssignment.kt")
|
||||
public void testAugmentedAssignment() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/augmentedAssignment.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("dataFlowInfoAfterExclExcl.kt")
|
||||
public void testDataFlowInfoAfterExclExcl() throws Exception {
|
||||
@@ -20916,12 +20886,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inferenceFrom.kt")
|
||||
public void testInferenceFrom() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/inferenceFrom.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("listSuperType.kt")
|
||||
public void testListSuperType() throws Exception {
|
||||
@@ -26669,18 +26633,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
public void testStabilityOfSmartcastsAgainstGenericFunctions() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/stabilityOfSmartcastsAgainstGenericFunctions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("syntheticPropertyOnUnstableSmartcast.kt")
|
||||
public void testSyntheticPropertyOnUnstableSmartcast() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/syntheticPropertyOnUnstableSmartcast.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unneededUnstableSmartcast.kt")
|
||||
public void testUnneededUnstableSmartcast() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/unneededUnstableSmartcast.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -28177,12 +28129,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/subtyping/kt3159.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt47148.kt")
|
||||
public void testKt47148() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/subtyping/kt47148.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt-1457.kt")
|
||||
public void testKt_1457() throws Exception {
|
||||
@@ -31067,18 +31013,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/when/ExhaustiveWithNullabilityCheckElse.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intersectionExhaustivenessComplex.kt")
|
||||
public void testIntersectionExhaustivenessComplex() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/when/intersectionExhaustivenessComplex.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intersectionExhaustivenessSimple.kt")
|
||||
public void testIntersectionExhaustivenessSimple() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/when/intersectionExhaustivenessSimple.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt10439.kt")
|
||||
public void testKt10439() throws Exception {
|
||||
@@ -34357,12 +34291,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/fullFqNameUsage.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("implicitUsages.kt")
|
||||
public void testImplicitUsages() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("importStatement.kt")
|
||||
public void testImportStatement() throws Exception {
|
||||
@@ -34381,12 +34309,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectUseExperimental.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("noRetentionAfter.kt")
|
||||
public void testNoRetentionAfter() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/noRetentionAfter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("override.kt")
|
||||
public void testOverride() throws Exception {
|
||||
@@ -34399,12 +34321,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/overrideDifferentExperimentalities.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("overrideInAnonymousObject.kt")
|
||||
public void testOverrideInAnonymousObject() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/overrideInAnonymousObject.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("topLevel.kt")
|
||||
public void testTopLevel() throws Exception {
|
||||
|
||||
@@ -11579,12 +11579,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/imports/importFunctionWithAllUnderImportAfterNamedImport.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ImportFunctionWithPackageName.kt")
|
||||
public void testImportFunctionWithPackageName() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/imports/ImportFunctionWithPackageName.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ImportHidingDefinitionInTheSameFile.kt")
|
||||
public void testImportHidingDefinitionInTheSameFile() throws Exception {
|
||||
@@ -11645,12 +11639,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/imports/ImportResolutionOrder.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ImportStaticFunctionWithNonStaticSibling.kt")
|
||||
public void testImportStaticFunctionWithNonStaticSibling() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/imports/ImportStaticFunctionWithNonStaticSibling.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ImportTwoTimes.kt")
|
||||
public void testImportTwoTimes() throws Exception {
|
||||
@@ -12209,12 +12197,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/inference/expectedTypeWithGenerics.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectedTypeWithGenericsSafeCalls.kt")
|
||||
public void testExpectedTypeWithGenericsSafeCalls() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/expectedTypeWithGenericsSafeCalls.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionLambdasAndArrow.kt")
|
||||
public void testExtensionLambdasAndArrow() throws Exception {
|
||||
@@ -12944,12 +12926,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturingFromArgumentOfFlexibleType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("dontCheckNewCapturedTypeSpecificChecksForOldOnes.kt")
|
||||
public void testDontCheckNewCapturedTypeSpecificChecksForOldOnes() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/dontCheckNewCapturedTypeSpecificChecksForOldOnes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectedTypeMismatchWithInVariance.kt")
|
||||
public void testExpectedTypeMismatchWithInVariance() throws Exception {
|
||||
@@ -19111,12 +19087,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/AssertNotNull.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("augmentedAssignment.kt")
|
||||
public void testAugmentedAssignment() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/augmentedAssignment.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("dataFlowInfoAfterExclExcl.kt")
|
||||
public void testDataFlowInfoAfterExclExcl() throws Exception {
|
||||
@@ -20916,12 +20886,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inferenceFrom.kt")
|
||||
public void testInferenceFrom() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/inferenceFrom.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("listSuperType.kt")
|
||||
public void testListSuperType() throws Exception {
|
||||
@@ -26669,18 +26633,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
public void testStabilityOfSmartcastsAgainstGenericFunctions() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/stabilityOfSmartcastsAgainstGenericFunctions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("syntheticPropertyOnUnstableSmartcast.kt")
|
||||
public void testSyntheticPropertyOnUnstableSmartcast() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/syntheticPropertyOnUnstableSmartcast.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unneededUnstableSmartcast.kt")
|
||||
public void testUnneededUnstableSmartcast() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/unneededUnstableSmartcast.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -28177,12 +28129,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/subtyping/kt3159.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt47148.kt")
|
||||
public void testKt47148() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/subtyping/kt47148.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt-1457.kt")
|
||||
public void testKt_1457() throws Exception {
|
||||
@@ -31067,18 +31013,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/when/ExhaustiveWithNullabilityCheckElse.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intersectionExhaustivenessComplex.kt")
|
||||
public void testIntersectionExhaustivenessComplex() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/when/intersectionExhaustivenessComplex.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intersectionExhaustivenessSimple.kt")
|
||||
public void testIntersectionExhaustivenessSimple() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/when/intersectionExhaustivenessSimple.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt10439.kt")
|
||||
public void testKt10439() throws Exception {
|
||||
@@ -34357,12 +34291,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/fullFqNameUsage.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("implicitUsages.kt")
|
||||
public void testImplicitUsages() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("importStatement.kt")
|
||||
public void testImportStatement() throws Exception {
|
||||
@@ -34381,12 +34309,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectUseExperimental.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("noRetentionAfter.kt")
|
||||
public void testNoRetentionAfter() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/noRetentionAfter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("override.kt")
|
||||
public void testOverride() throws Exception {
|
||||
@@ -34399,12 +34321,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/overrideDifferentExperimentalities.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("overrideInAnonymousObject.kt")
|
||||
public void testOverrideInAnonymousObject() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/overrideInAnonymousObject.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("topLevel.kt")
|
||||
public void testTopLevel() throws Exception {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user