mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-11 08:31:29 +00:00
Compare commits
430 Commits
rr/stdlib/
...
1.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84f2ff12e2 | ||
|
|
96bf749d4d | ||
|
|
1870487ce6 | ||
|
|
54c0000332 | ||
|
|
31ac07d6e2 | ||
|
|
0b9bbe02f1 | ||
|
|
b5bbbc6450 | ||
|
|
a5422b159e | ||
|
|
a72f820893 | ||
|
|
57361fd6dc | ||
|
|
514e825e95 | ||
|
|
878482fe8f | ||
|
|
a5df656f52 | ||
|
|
5d26297999 | ||
|
|
ac908715bb | ||
|
|
a32e69a699 | ||
|
|
caeec04816 | ||
|
|
72e2bbd2e0 | ||
|
|
5f61ecdd8d | ||
|
|
58046aead2 | ||
|
|
615d801bc9 | ||
|
|
17010d98be | ||
|
|
e4e1dbfd96 | ||
|
|
6f6a30dfc8 | ||
|
|
0132c53055 | ||
|
|
37dfa2498d | ||
|
|
97682e8e01 | ||
|
|
0d21a52b46 | ||
|
|
60ef74a78d | ||
|
|
0749cff2dd | ||
|
|
4c937703a0 | ||
|
|
cb9ed57682 | ||
|
|
13801c4cea | ||
|
|
82b1f44e13 | ||
|
|
7f67c1f4a5 | ||
|
|
a19baa9c73 | ||
|
|
70669f26f6 | ||
|
|
eae271fe9e | ||
|
|
8b7143c931 | ||
|
|
1694e73f24 | ||
|
|
164838d72b | ||
|
|
3ba932ea62 | ||
|
|
5745ee3cf6 | ||
|
|
82e5574634 | ||
|
|
7791003b7c | ||
|
|
96193111e6 | ||
|
|
bbb0795904 | ||
|
|
cef6c71154 | ||
|
|
235ba4864f | ||
|
|
a2818a876d | ||
|
|
3e86fe940d | ||
|
|
57726d2cde | ||
|
|
f3a3b37452 | ||
|
|
d4a4c62b90 | ||
|
|
d3b8b9297f | ||
|
|
74e61b071c | ||
|
|
90a20f95ad | ||
|
|
9e03b75f8e | ||
|
|
12e41557b5 | ||
|
|
3d3fce65f9 | ||
|
|
abe6693af7 | ||
|
|
22222c8fd0 | ||
|
|
cc035f7f41 | ||
|
|
c7bc74291d | ||
|
|
dd62c1ebfd | ||
|
|
2d4807f90a | ||
|
|
87becfd470 | ||
|
|
2a895ed273 | ||
|
|
1329624481 | ||
|
|
6aea25b08f | ||
|
|
8041879ae9 | ||
|
|
ef082199b0 | ||
|
|
6f135248dc | ||
|
|
9a6a6c427a | ||
|
|
0495864483 | ||
|
|
5e41d261df | ||
|
|
69c3714d88 | ||
|
|
7659eb1405 | ||
|
|
8cd22016e7 | ||
|
|
8f6bbcf2ee | ||
|
|
9c9da4a7d8 | ||
|
|
16c74fbfe5 | ||
|
|
737fb0fe81 | ||
|
|
77c5791c4d | ||
|
|
4a12f0e3a1 | ||
|
|
c1fb928b34 | ||
|
|
1475f6b110 | ||
|
|
02b02b9c92 | ||
|
|
4087c8dd66 | ||
|
|
edcbdb813d | ||
|
|
2e0e8b6c0d | ||
|
|
79fa7d8c5d | ||
|
|
44537f9dfc | ||
|
|
ed224224dc | ||
|
|
9c31b291c9 | ||
|
|
0b509f7a1b | ||
|
|
c678d7aa6a | ||
|
|
fba163cec0 | ||
|
|
3164cfd963 | ||
|
|
2e0383eeb3 | ||
|
|
0c8bd72deb | ||
|
|
8d0bdd16b4 | ||
|
|
d646a543f2 | ||
|
|
3cd0c5a8f7 | ||
|
|
27b8c4e097 | ||
|
|
2249a95a81 | ||
|
|
3d729fa7d0 | ||
|
|
d31ec51ecc | ||
|
|
9b1a39bff8 | ||
|
|
94df721eb9 | ||
|
|
40e0f4df67 | ||
|
|
3a122ce8cd | ||
|
|
3856afec0a | ||
|
|
c7fbc42440 | ||
|
|
37ef5f8142 | ||
|
|
f10d78514c | ||
|
|
a6d4de60b3 | ||
|
|
348e68eb5e | ||
|
|
76c0691e9e | ||
|
|
1ac9183044 | ||
|
|
42ca4a00e9 | ||
|
|
211d7056cd | ||
|
|
caf6e2b444 | ||
|
|
e204b002f7 | ||
|
|
e186ea7e84 | ||
|
|
cea006ab4b | ||
|
|
370f4e045d | ||
|
|
facf20b68c | ||
|
|
8c63dabe3d | ||
|
|
b68e759e16 | ||
|
|
5e7b7dccd3 | ||
|
|
500b13e605 | ||
|
|
ffbb468870 | ||
|
|
14f253de70 | ||
|
|
9df3ee986a | ||
|
|
7a25bf8aa0 | ||
|
|
be5b8371f0 | ||
|
|
60903a8534 | ||
|
|
57b93904ed | ||
|
|
2900cddc40 | ||
|
|
4558aed787 | ||
|
|
9020e1c233 | ||
|
|
5357f0871f | ||
|
|
515ccb672e | ||
|
|
4e4c99bc39 | ||
|
|
c35011eb13 | ||
|
|
7755f11b97 | ||
|
|
f5acebd50b | ||
|
|
fa92420aaa | ||
|
|
6f776c1b68 | ||
|
|
3f8f80df02 | ||
|
|
fbf983bbc1 | ||
|
|
941dd26df8 | ||
|
|
58b96f8c60 | ||
|
|
742058ea80 | ||
|
|
fb9a329972 | ||
|
|
532a215829 | ||
|
|
12fc174182 | ||
|
|
a3b07758a5 | ||
|
|
9dd1a0ef1e | ||
|
|
7b4cddef64 | ||
|
|
6906c2ea5d | ||
|
|
7da062d780 | ||
|
|
f4ef085d1d | ||
|
|
36b1672da9 | ||
|
|
57d0c4538c | ||
|
|
b6e107ef2a | ||
|
|
453680d050 | ||
|
|
62ad8fd760 | ||
|
|
4eeb5558aa | ||
|
|
c40dea86cc | ||
|
|
ef93784b48 | ||
|
|
f500a6fd94 | ||
|
|
a66f8ff100 | ||
|
|
23f5083a20 | ||
|
|
02147f6f2e | ||
|
|
a1f87da48a | ||
|
|
2f77419fa2 | ||
|
|
96c68e530b | ||
|
|
9d38ac9665 | ||
|
|
3cd03a380a | ||
|
|
e983a884de | ||
|
|
244e077432 | ||
|
|
21c6bfc3db | ||
|
|
bef5636ce5 | ||
|
|
9044f3b57d | ||
|
|
bc8943bfce | ||
|
|
792ac45b19 | ||
|
|
c84324070b | ||
|
|
c796643434 | ||
|
|
fe20d025ed | ||
|
|
9bc3dafb02 | ||
|
|
e8a9a44c25 | ||
|
|
9e0dacf53c | ||
|
|
60be62d021 | ||
|
|
0659c5f54b | ||
|
|
679bc7a6af | ||
|
|
3c9ef4ab4d | ||
|
|
6b71029755 | ||
|
|
1b19ba6374 | ||
|
|
24762a4e93 | ||
|
|
53f6967992 | ||
|
|
a545675a63 | ||
|
|
0a2d49b986 | ||
|
|
104c160e01 | ||
|
|
ddae613557 | ||
|
|
eda10360a7 | ||
|
|
117d552931 | ||
|
|
1cc313dfc3 | ||
|
|
7a02615d78 | ||
|
|
526d073e66 | ||
|
|
99367595e6 | ||
|
|
66ca7c06cb | ||
|
|
422625e0cf | ||
|
|
225d112388 | ||
|
|
720f3061eb | ||
|
|
93f47c0947 | ||
|
|
b9ae5d3eba | ||
|
|
5900dd739e | ||
|
|
dbb91694fe | ||
|
|
fd3ea84bb2 | ||
|
|
259939ff41 | ||
|
|
a9a099401f | ||
|
|
dd21f357cc | ||
|
|
fc54152b81 | ||
|
|
f2247509c4 | ||
|
|
cafb01ad47 | ||
|
|
fe1eb542d8 | ||
|
|
38f425731b | ||
|
|
107eef020c | ||
|
|
3f022feff1 | ||
|
|
09ef8ddd98 | ||
|
|
49274d8bbf | ||
|
|
5a53b0ca92 | ||
|
|
fb6f7b2353 | ||
|
|
ff549574c8 | ||
|
|
0e020965a6 | ||
|
|
e8f3c78232 | ||
|
|
49f431b033 | ||
|
|
4fae55661e | ||
|
|
ea5e656b86 | ||
|
|
194a11ecb7 | ||
|
|
4bbdee8dfd | ||
|
|
f8c36e47b2 | ||
|
|
ea13b30f82 | ||
|
|
4afe6e01cb | ||
|
|
11a07e9705 | ||
|
|
3d03b8d43e | ||
|
|
8b2f311135 | ||
|
|
2160d4ad81 | ||
|
|
33693dcab4 | ||
|
|
f7890bd2c0 | ||
|
|
0e639ef7e8 | ||
|
|
d8c4cc84ef | ||
|
|
74ed159cb0 | ||
|
|
0ed3b58cac | ||
|
|
c350177a19 | ||
|
|
ef38a193bd | ||
|
|
22ad7533dc | ||
|
|
e140128cbb | ||
|
|
29d75c74a6 | ||
|
|
adc8d769fd | ||
|
|
3df74e3090 | ||
|
|
0888aa9571 | ||
|
|
a9faccd921 | ||
|
|
a7da318836 | ||
|
|
5b3e86df68 | ||
|
|
ffdfc5fd87 | ||
|
|
081214f087 | ||
|
|
96dd293734 | ||
|
|
0bec2cc7f8 | ||
|
|
7282c0d319 | ||
|
|
3f8f5b91a5 | ||
|
|
aa37d002a2 | ||
|
|
7513c41ecf | ||
|
|
296efbdb10 | ||
|
|
c2c39abc24 | ||
|
|
4bd548eb20 | ||
|
|
7b6f1654e0 | ||
|
|
9c899a3e11 | ||
|
|
7652ef0b99 | ||
|
|
ee342d5e5c | ||
|
|
412611acd6 | ||
|
|
9b01b5ad59 | ||
|
|
a422759e54 | ||
|
|
64f3540c89 | ||
|
|
1f4a0fe5ae | ||
|
|
f969403405 | ||
|
|
e258fde2af | ||
|
|
5829437933 | ||
|
|
d576348990 | ||
|
|
9fa62d7b3c | ||
|
|
31a389d317 | ||
|
|
99b0352d86 | ||
|
|
09cc8d0e2b | ||
|
|
1983570688 | ||
|
|
65c164892f | ||
|
|
bd1eefc432 | ||
|
|
06f73005ad | ||
|
|
b2dc504504 | ||
|
|
0fdae44562 | ||
|
|
7ba48146fc | ||
|
|
cb4068ba6c | ||
|
|
0a2e0ef406 | ||
|
|
789b2db7b5 | ||
|
|
edbc1ac405 | ||
|
|
2355ea791a | ||
|
|
ca3bec732e | ||
|
|
fd64b50c54 | ||
|
|
0e4e1b6941 | ||
|
|
8b5c5fb16a | ||
|
|
51b848c67f | ||
|
|
969828bf81 | ||
|
|
1bd837007e | ||
|
|
3dfba8272f | ||
|
|
076ccca14f | ||
|
|
e8e73bce15 | ||
|
|
b6b01dd4c5 | ||
|
|
2a24d9cb5a | ||
|
|
4e51cef541 | ||
|
|
67bb952df9 | ||
|
|
0969f95dfa | ||
|
|
f0eb72ad6b | ||
|
|
85e0a1b7bc | ||
|
|
02e276ce30 | ||
|
|
c029a34e0d | ||
|
|
c008822d9f | ||
|
|
1af800a07f | ||
|
|
0484a51a50 | ||
|
|
76e5e84a56 | ||
|
|
29be9d447a | ||
|
|
2cd5354c22 | ||
|
|
5c266ba184 | ||
|
|
7cdc9612f7 | ||
|
|
c169610b57 | ||
|
|
181fb81473 | ||
|
|
e980c75cab | ||
|
|
ab1f8af88b | ||
|
|
1655c3a7ca | ||
|
|
76ebec5d37 | ||
|
|
5e54f84ecd | ||
|
|
a847efdef7 | ||
|
|
40607b14a9 | ||
|
|
a5074a91ab | ||
|
|
943259dfcb | ||
|
|
0fa3c9b338 | ||
|
|
f832890360 | ||
|
|
986f999206 | ||
|
|
44c07154a2 | ||
|
|
7aa291076d | ||
|
|
b9b94c4fe3 | ||
|
|
4add819658 | ||
|
|
30df42743d | ||
|
|
09467ddc9d | ||
|
|
f9ef065c7b | ||
|
|
ecc384fbfc | ||
|
|
fd31e28903 | ||
|
|
3d89a08022 | ||
|
|
8f07ea2348 | ||
|
|
d52c49cf59 | ||
|
|
3dc3ce4c6e | ||
|
|
0702d33970 | ||
|
|
6e0ba8bd8a | ||
|
|
6c7d062cd7 | ||
|
|
d6e4309b39 | ||
|
|
184742e779 | ||
|
|
aed19965c0 | ||
|
|
f7d5f989aa | ||
|
|
38e661295e | ||
|
|
88abe52633 | ||
|
|
16b272a7cf | ||
|
|
b270e19786 | ||
|
|
2763dd068d | ||
|
|
7fd19555fc | ||
|
|
ba3cdb7fb6 | ||
|
|
2ece6f579e | ||
|
|
c9010f2756 | ||
|
|
fab69d2f22 | ||
|
|
b8d9f8dadd | ||
|
|
ea0cf43cec | ||
|
|
13394a4669 | ||
|
|
94368f1afb | ||
|
|
1ff86abdce | ||
|
|
f87d2b2feb | ||
|
|
b20749e259 | ||
|
|
9e91cf2bf1 | ||
|
|
f17fe0bf0e | ||
|
|
310a46ee73 | ||
|
|
56300b4ef7 | ||
|
|
a0286c533f | ||
|
|
7674acb45c | ||
|
|
67114fcfdc | ||
|
|
64081b71f0 | ||
|
|
10032ee259 | ||
|
|
a6ab49bf9d | ||
|
|
4ec1ca807f | ||
|
|
3b24b74340 | ||
|
|
92c481cadf | ||
|
|
dc4eb1e6c0 | ||
|
|
b506b4d91a | ||
|
|
afb6552618 | ||
|
|
42ea253765 | ||
|
|
e2561cb091 | ||
|
|
4b6fa98c09 | ||
|
|
f36e35070e | ||
|
|
4cbdaebb36 | ||
|
|
dac967d804 | ||
|
|
b930e6e8e8 | ||
|
|
7c99348051 | ||
|
|
47f1ff8a36 | ||
|
|
c5fc729297 | ||
|
|
da0fb1cbb0 | ||
|
|
24a22fe127 | ||
|
|
32c03876f2 | ||
|
|
6daa43895a | ||
|
|
82cc6ba1e3 | ||
|
|
9fff156d6c | ||
|
|
6129012d4f | ||
|
|
dd4b0d7296 | ||
|
|
f2bc5da814 | ||
|
|
5470b9a7a8 | ||
|
|
36b84247b1 | ||
|
|
66352155df | ||
|
|
7405c31d18 | ||
|
|
f44b85b326 | ||
|
|
02d1d832f1 | ||
|
|
8e696bcbf1 | ||
|
|
929957e963 | ||
|
|
9f428daad9 | ||
|
|
1b519b340e |
2
.idea/inspectionProfiles/idea_default.xml
generated
2
.idea/inspectionProfiles/idea_default.xml
generated
@@ -105,6 +105,8 @@
|
||||
<Problem reference="org.jetbrains.java.decompiler.main.decompiler.BaseDecompiler#addSpace" reason="Method was replaced with outher methods in 182. Use addSpaceEx instead." />
|
||||
<Problem reference="com.intellij.psi.codeStyle.CommonCodeStyleSettings#copyFrom" reason="Absent in 173. Use CompatibilityKt.copyFromEx instead." />
|
||||
<Problem reference="com.intellij.psi.codeStyle.CommonCodeStyleSettingsManager#copy" reason="Removed since 181. Use CompatibilityKt.copyFromEx instead." />
|
||||
<Problem reference="com.intellij.notification.NotificationAction#createSimple" reason="Absent in 173." />
|
||||
<Problem reference="com.intellij.notification.NotificationAction#create" reason="Absent in 173." />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
|
||||
6505
ChangeLog.md
6505
ChangeLog.md
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.build
|
||||
|
||||
val DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS = listOf("kt", "kts")
|
||||
|
||||
@@ -21,11 +21,8 @@ import java.io.File
|
||||
fun File.isJavaFile() =
|
||||
extension.equals("java", ignoreCase = true)
|
||||
|
||||
fun File.isKotlinFile(): Boolean =
|
||||
extension.let {
|
||||
"kt".equals(it, ignoreCase = true) ||
|
||||
"kts".equals(it, ignoreCase = true)
|
||||
}
|
||||
fun File.isKotlinFile(sourceFilesExtensions: List<String>): Boolean =
|
||||
!isJavaFile() && sourceFilesExtensions.any { it.equals(extension, ignoreCase = true) }
|
||||
|
||||
fun File.isClassFile(): Boolean =
|
||||
extension.equals("class", ignoreCase = true)
|
||||
|
||||
@@ -13,7 +13,7 @@ import proguard.gradle.ProGuardTask
|
||||
buildscript {
|
||||
extra["defaultSnapshotVersion"] = "1.3-SNAPSHOT"
|
||||
|
||||
kotlinBootstrapFrom(BootstrapOption.TeamCity("1.3.0-dev-496", onlySuccessBootstrap = false))
|
||||
kotlinBootstrapFrom(BootstrapOption.TeamCity("1.3.0-rc-74", projectExtId = "Kotlin_130_Compiler", onlySuccessBootstrap = false))
|
||||
|
||||
repositories {
|
||||
bootstrapKotlinRepo?.let(::maven)
|
||||
@@ -122,8 +122,8 @@ extra["versions.junit"] = "4.12"
|
||||
extra["versions.javaslang"] = "2.0.6"
|
||||
extra["versions.ant"] = "1.8.2"
|
||||
extra["versions.android"] = "2.3.1"
|
||||
extra["versions.kotlinx-coroutines-core"] = "0.20"
|
||||
extra["versions.kotlinx-coroutines-jdk8"] = "0.20"
|
||||
extra["versions.kotlinx-coroutines-core"] = "0.26.1-eap13"
|
||||
extra["versions.kotlinx-coroutines-jdk8"] = "0.26.1-eap13"
|
||||
extra["versions.json"] = "20160807"
|
||||
extra["versions.native-platform"] = "0.14"
|
||||
extra["versions.ant-launcher"] = "1.8.0"
|
||||
@@ -273,8 +273,7 @@ allprojects {
|
||||
val commonCompilerArgs = listOfNotNull(
|
||||
"-Xallow-kotlin-package",
|
||||
"-Xread-deserialized-contracts",
|
||||
"-Xprogressive".takeIf { hasProperty("test.progressive.mode") }, // TODO: change to "-progressive" after bootstrap
|
||||
"-XXLanguage:-ReleaseCoroutines"
|
||||
"-Xprogressive".takeIf { hasProperty("test.progressive.mode") } // TODO: change to "-progressive" after bootstrap
|
||||
)
|
||||
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
|
||||
@@ -511,7 +510,8 @@ tasks {
|
||||
":kotlin-noarg-compiler-plugin:test",
|
||||
":kotlin-sam-with-receiver-compiler-plugin:test",
|
||||
":plugins:uast-kotlin:test",
|
||||
":kotlin-annotation-processing-gradle:test")
|
||||
":kotlin-annotation-processing-gradle:test",
|
||||
":kotlinx-serialization-ide-plugin:test")
|
||||
}
|
||||
|
||||
|
||||
|
||||
9
buildSrc/gradle.properties.as34
Normal file
9
buildSrc/gradle.properties.as34
Normal file
@@ -0,0 +1,9 @@
|
||||
org.gradle.daemon=true
|
||||
org.gradle.parallel=false
|
||||
org.gradle.configureondemand=false
|
||||
org.gradle.jvmargs=-Duser.country=US -Dkotlin.daemon.jvm.options=-Xmx1600m
|
||||
|
||||
#buildSrc.kotlin.repo=https://jcenter.bintray.com
|
||||
#buildSrc.kotlin.version=1.1.50
|
||||
|
||||
intellijUltimateEnabled=false
|
||||
@@ -191,7 +191,6 @@ fun ConfigurationContainer.getOrCreate(name: String): Configuration = findByName
|
||||
fun Jar.setupPublicJar(baseName: String, classifier: String = "") {
|
||||
val buildNumber = project.rootProject.extra["buildNumber"] as String
|
||||
this.baseName = baseName
|
||||
this.version = buildNumber
|
||||
this.classifier = classifier
|
||||
manifest.attributes.apply {
|
||||
put("Implementation-Vendor", "JetBrains")
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
|
||||
object CodegenUtil {
|
||||
@JvmStatic
|
||||
@@ -200,16 +201,25 @@ object CodegenUtil {
|
||||
trace: DiagnosticSink?
|
||||
): List<ValueParameterDescriptor> {
|
||||
if (descriptor.isActual) {
|
||||
val actualParameters = descriptor.valueParameters
|
||||
if (actualParameters.any { it.declaresOrInheritsDefaultValue() }) {
|
||||
// This is incorrect code: actual function cannot have default values, they should be declared in the expected function.
|
||||
// But until KT-22818 is fixed, we need to provide a workaround for the exception that happens on complex default values
|
||||
// in the expected function. One may suppress the error then, and declare default values _both_ in expect and actual.
|
||||
// With this code, we'll generate actual default values if they're present, and expected default values otherwise.
|
||||
return actualParameters
|
||||
}
|
||||
|
||||
val expected = CodegenUtil.findExpectedFunctionForActual(descriptor)
|
||||
if (expected != null && expected.valueParameters.any(ValueParameterDescriptor::declaresDefaultValue)) {
|
||||
val element = DescriptorToSourceUtils.descriptorToDeclaration(expected)
|
||||
if (element == null) {
|
||||
if (trace != null) {
|
||||
val actualDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor)
|
||||
?: error("Not a source declaration: $descriptor")
|
||||
?: error("Not a source declaration: $descriptor")
|
||||
trace.report(Errors.EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND.on(actualDeclaration))
|
||||
}
|
||||
return descriptor.valueParameters
|
||||
return actualParameters
|
||||
}
|
||||
|
||||
return expected.valueParameters
|
||||
@@ -218,12 +228,14 @@ object CodegenUtil {
|
||||
|
||||
return descriptor.valueParameters
|
||||
}
|
||||
|
||||
// This function is private here because no one is supposed to use it except for the hack above.
|
||||
// Please use ValueParameterDescriptor.hasDefaultValue instead.
|
||||
private fun ValueParameterDescriptor.declaresOrInheritsDefaultValue(): Boolean {
|
||||
return DFS.ifAny(
|
||||
listOf(this),
|
||||
{ current -> current.overriddenDescriptors.map(ValueParameterDescriptor::getOriginal) },
|
||||
{ it.declaresDefaultValue() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun DeclarationDescriptor.isTopLevelInPackage(name: String, packageName: String): Boolean {
|
||||
if (name != this.name.asString()) return false
|
||||
|
||||
val containingDeclaration = containingDeclaration as? PackageFragmentDescriptor ?: return false
|
||||
val packageFqName = containingDeclaration.fqName.asString()
|
||||
return packageName == packageFqName
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.coroutinesIntrinsicsPackageFqName
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.isTopLevelInPackage
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
val COROUTINE_SUSPENDED_NAME = Name.identifier("COROUTINE_SUSPENDED")
|
||||
|
||||
@@ -639,10 +639,18 @@ public class AsmUtil {
|
||||
) {
|
||||
assert !info.isStatic();
|
||||
Type fieldType = info.getFieldType();
|
||||
KotlinType fieldKotlinType = info.getFieldKotlinType();
|
||||
KotlinType nullableAny;
|
||||
if (fieldKotlinType != null) {
|
||||
nullableAny = fieldKotlinType.getConstructor().getBuiltIns().getNullableAnyType();
|
||||
} else {
|
||||
nullableAny = null;
|
||||
}
|
||||
|
||||
iv.load(ownerIndex, info.getOwnerType());//this
|
||||
if (cast) {
|
||||
iv.load(index, AsmTypes.OBJECT_TYPE); //param
|
||||
StackValue.coerce(AsmTypes.OBJECT_TYPE, fieldType, iv);
|
||||
StackValue.coerce(AsmTypes.OBJECT_TYPE, nullableAny, fieldType, fieldKotlinType, iv);
|
||||
} else {
|
||||
iv.load(index, fieldType); //param
|
||||
}
|
||||
@@ -907,19 +915,20 @@ public class AsmUtil {
|
||||
if (state.isCallAssertionsDisabled()) return stackValue;
|
||||
if (runtimeAssertionInfo == null || !runtimeAssertionInfo.getNeedNotNullAssertion()) return stackValue;
|
||||
|
||||
return new StackValue(stackValue.type) {
|
||||
return new StackValue(stackValue.type, stackValue.kotlinType) {
|
||||
|
||||
@Override
|
||||
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
|
||||
Type innerType = stackValue.type;
|
||||
stackValue.put(innerType, v);
|
||||
KotlinType innerKotlinType = stackValue.kotlinType;
|
||||
stackValue.put(innerType, innerKotlinType, v);
|
||||
if (innerType.getSort() == Type.OBJECT || innerType.getSort() == Type.ARRAY) {
|
||||
v.dup();
|
||||
v.visitLdcInsn(runtimeAssertionInfo.getMessage());
|
||||
v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkExpressionValueIsNotNull",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;)V", false);
|
||||
}
|
||||
StackValue.coerce(innerType, type, v);
|
||||
StackValue.coerce(innerType, innerKotlinType, type, kotlinType, v);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.isTopLevelInPackage
|
||||
import org.jetbrains.kotlin.codegen.coroutines.createCustomCopy
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.config.JVMAssertionsMode
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.isTopLevelInPackage
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.BindingTraceContext
|
||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||
|
||||
@@ -66,13 +66,16 @@ interface CallGenerator {
|
||||
}
|
||||
|
||||
val value = codegen.gen(argumentExpression)
|
||||
value.put(parameterType, valueParameterDescriptor.original.type, v)
|
||||
value.put(parameterType, valueParameterDescriptor.unsubstitutedType, v)
|
||||
|
||||
if (isVarargInvoke) {
|
||||
v.astore(OBJECT_TYPE)
|
||||
}
|
||||
}
|
||||
|
||||
private val ValueParameterDescriptor.unsubstitutedType
|
||||
get() = containingDeclaration.original.valueParameters[index].type
|
||||
|
||||
override fun putCapturedValueOnStack(
|
||||
stackValue: StackValue, valueType: Type, paramIndex: Int) {
|
||||
stackValue.put(stackValue.type, stackValue.kotlinType, codegen.v)
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.SimpleType;
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils;
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
@@ -490,13 +491,14 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
List<FieldInfo> args = Lists.newArrayList();
|
||||
ClassDescriptor captureThis = closure.getCapturedOuterClassDescriptor();
|
||||
if (captureThis != null) {
|
||||
Type type = typeMapper.mapType(captureThis);
|
||||
args.add(FieldInfo.createForHiddenField(ownerType, type, CAPTURED_THIS_FIELD));
|
||||
SimpleType thisType = captureThis.getDefaultType();
|
||||
Type type = typeMapper.mapType(thisType);
|
||||
args.add(FieldInfo.createForHiddenField(ownerType, type, thisType, CAPTURED_THIS_FIELD));
|
||||
}
|
||||
KotlinType captureReceiverType = closure.getCapturedReceiverFromOuterContext();
|
||||
if (captureReceiverType != null) {
|
||||
String fieldName = closure.getCapturedReceiverFieldName(typeMapper.getBindingContext(), languageVersionSettings);
|
||||
args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiverType), fieldName));
|
||||
args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiverType), captureReceiverType, fieldName));
|
||||
}
|
||||
|
||||
for (EnclosedValueDescriptor enclosedValueDescriptor : closure.getCaptureVariables().values()) {
|
||||
@@ -505,7 +507,10 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
ExpressionTypingUtils.isLocalFunction(descriptor)) {
|
||||
args.add(
|
||||
FieldInfo.createForHiddenField(
|
||||
ownerType, enclosedValueDescriptor.getType(), enclosedValueDescriptor.getFieldName()
|
||||
ownerType,
|
||||
enclosedValueDescriptor.getType(),
|
||||
enclosedValueDescriptor.getKotlinType(),
|
||||
enclosedValueDescriptor.getFieldName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -513,7 +513,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
}
|
||||
|
||||
return StackValue.operation(asmType, v -> {
|
||||
return StackValue.operation(asmType, kotlinType, v -> {
|
||||
Label elseLabel = new Label();
|
||||
BranchedValue.Companion.condJump(condition, elseLabel, true, v);
|
||||
|
||||
@@ -3239,7 +3239,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
private StackValue genLazyUnlessProvided(@Nullable StackValue pregenerated, @NotNull KtExpression expr, @NotNull Type type) {
|
||||
return pregenerated != null ? StackValue.coercion(pregenerated, type, null) : genLazy(expr, type);
|
||||
return genLazyUnlessProvided(pregenerated, expr, type, null);
|
||||
}
|
||||
|
||||
private StackValue genLazyUnlessProvided(
|
||||
@Nullable StackValue pregenerated,
|
||||
@NotNull KtExpression expr,
|
||||
@NotNull Type type,
|
||||
@Nullable KotlinType kotlinType
|
||||
) {
|
||||
return pregenerated != null ? StackValue.coercion(pregenerated, type, kotlinType) : genLazy(expr, type, kotlinType);
|
||||
}
|
||||
|
||||
private StackValue genUnlessProvided(@Nullable StackValue pregenerated, @NotNull KtExpression expr, @NotNull Type type) {
|
||||
@@ -3384,8 +3393,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
KotlinType leftKotlinType = kotlinType(left);
|
||||
KotlinType rightKotlinType = kotlinType(right);
|
||||
|
||||
StackValue leftValue = genLazyUnlessProvided(pregeneratedSubject, left, leftType);
|
||||
StackValue rightValue = genLazy(right, rightType);
|
||||
StackValue leftValue = genLazyUnlessProvided(pregeneratedSubject, left, leftType, leftKotlinType);
|
||||
StackValue rightValue = genLazy(right, rightType, rightKotlinType);
|
||||
|
||||
return StackValue.operation(Type.BOOLEAN_TYPE, v -> {
|
||||
KotlinType nullableAnyType = state.getModule().getBuiltIns().getNullableAnyType();
|
||||
@@ -4354,8 +4363,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
Type elementType = isGetter ? callableMethod.getReturnType() : ArrayUtil.getLastElement(argumentTypes);
|
||||
KotlinType elementKotlinType = isGetter ?
|
||||
operationDescriptor.getReturnType() :
|
||||
CollectionsKt.last(operationDescriptor.getValueParameters()).getType();
|
||||
operationDescriptor.getOriginal().getReturnType() :
|
||||
CollectionsKt.last(operationDescriptor.getOriginal().getValueParameters()).getType();
|
||||
return StackValue.collectionElement(
|
||||
collectionElementReceiver, elementType, elementKotlinType, resolvedGetCall, resolvedSetCall, this
|
||||
);
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.CompanionObjectMapping;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isNonCompanionObject;
|
||||
@@ -29,7 +31,9 @@ public class FieldInfo {
|
||||
ClassDescriptor ownerDescriptor = DescriptorUtils.getParentOfType(classDescriptor, ClassDescriptor.class);
|
||||
assert ownerDescriptor != null : "Owner not found for class: " + classDescriptor;
|
||||
Type ownerType = typeMapper.mapClass(ownerDescriptor);
|
||||
return new FieldInfo(ownerType, typeMapper.mapType(classDescriptor), classDescriptor.getName().asString(), true);
|
||||
KotlinType fieldKotlinType = classDescriptor.getDefaultType();
|
||||
Type fieldType = typeMapper.mapType(fieldKotlinType);
|
||||
return new FieldInfo(ownerType, fieldType, fieldKotlinType, classDescriptor.getName().asString(), true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -38,23 +42,43 @@ public class FieldInfo {
|
||||
@NotNull KotlinTypeMapper typeMapper,
|
||||
@NotNull String name
|
||||
) {
|
||||
Type type = typeMapper.mapType(classDescriptor);
|
||||
return new FieldInfo(type, type, name, true);
|
||||
Type owner = typeMapper.mapClass(classDescriptor);
|
||||
KotlinType fieldKotlinType = classDescriptor.getDefaultType();
|
||||
Type fieldType = typeMapper.mapType(fieldKotlinType);
|
||||
return new FieldInfo(owner, fieldType, fieldKotlinType, name, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FieldInfo createForHiddenField(@NotNull Type owner, @NotNull Type fieldType, @NotNull String fieldName) {
|
||||
return new FieldInfo(owner, fieldType, fieldName, false);
|
||||
return createForHiddenField(owner, fieldType, null, fieldName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FieldInfo createForHiddenField(
|
||||
@NotNull Type owner,
|
||||
@NotNull Type fieldType,
|
||||
@Nullable KotlinType fieldKotlinType,
|
||||
@NotNull String fieldName
|
||||
) {
|
||||
return new FieldInfo(owner, fieldType, fieldKotlinType, fieldName, false);
|
||||
}
|
||||
|
||||
private final Type fieldType;
|
||||
private final KotlinType fieldKotlinType;
|
||||
private final Type ownerType;
|
||||
private final String fieldName;
|
||||
private final boolean isStatic;
|
||||
|
||||
private FieldInfo(@NotNull Type ownerType, @NotNull Type fieldType, @NotNull String fieldName, boolean isStatic) {
|
||||
private FieldInfo(
|
||||
@NotNull Type ownerType,
|
||||
@NotNull Type fieldType,
|
||||
@Nullable KotlinType fieldKotlinType,
|
||||
@NotNull String fieldName,
|
||||
boolean isStatic
|
||||
) {
|
||||
this.ownerType = ownerType;
|
||||
this.fieldType = fieldType;
|
||||
this.fieldKotlinType = fieldKotlinType;
|
||||
this.fieldName = fieldName;
|
||||
this.isStatic = isStatic;
|
||||
}
|
||||
@@ -64,6 +88,11 @@ public class FieldInfo {
|
||||
return fieldType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public KotlinType getFieldKotlinType() {
|
||||
return fieldKotlinType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Type getOwnerType() {
|
||||
return ownerType;
|
||||
|
||||
@@ -76,6 +76,7 @@ import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUtilKt.isEf
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.InlineClassManglingRulesKt.shouldHideConstructorDueToInlineClassTypeValueParameters;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt.hasJvmDefaultAnnotation;
|
||||
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
||||
@@ -226,13 +227,10 @@ public class FunctionCodegen {
|
||||
asmMethod.getDescriptor()
|
||||
);
|
||||
|
||||
if (CodegenContextUtil.isImplementationOwner(owner, functionDescriptor)) {
|
||||
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, CodegenUtilKt.unwrapFrontendVersion(functionDescriptor), asmMethod);
|
||||
}
|
||||
recordMethodForFunctionIfAppropriate(functionDescriptor, asmMethod);
|
||||
|
||||
AnnotationCodegen.forMethod(mv, memberCodegen, typeMapper).genAnnotations(functionDescriptor, asmMethod.getReturnType());
|
||||
generateMethodAnnotationsIfRequired(functionDescriptor, asmMethod, jvmSignature, mv);
|
||||
|
||||
generateParameterAnnotations(functionDescriptor, mv, jvmSignature, memberCodegen, state);
|
||||
GenerateJava8ParameterNamesKt.generateParameterNames(functionDescriptor, mv, jvmSignature, state, (flags & ACC_SYNTHETIC) != 0);
|
||||
|
||||
if (contextKind != OwnerKind.ERASED_INLINE_CLASS) {
|
||||
@@ -269,6 +267,49 @@ public class FunctionCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
private void recordMethodForFunctionIfAppropriate(
|
||||
@NotNull FunctionDescriptor functionDescriptor,
|
||||
Method asmMethod
|
||||
) {
|
||||
if (functionDescriptor instanceof AccessorForConstructorDescriptor) {
|
||||
ConstructorDescriptor originalConstructor = ((AccessorForConstructorDescriptor) functionDescriptor).getCalleeDescriptor();
|
||||
if (shouldHideConstructorDueToInlineClassTypeValueParameters(originalConstructor)) {
|
||||
functionDescriptor = originalConstructor;
|
||||
}
|
||||
}
|
||||
else if (shouldHideConstructorDueToInlineClassTypeValueParameters(functionDescriptor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
functionDescriptor = CodegenUtilKt.unwrapFrontendVersion(functionDescriptor);
|
||||
|
||||
if (!CodegenContextUtil.isImplementationOwner(owner, functionDescriptor)) return;
|
||||
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod);
|
||||
}
|
||||
|
||||
private void generateMethodAnnotationsIfRequired(
|
||||
@NotNull FunctionDescriptor functionDescriptor,
|
||||
@NotNull Method asmMethod,
|
||||
@NotNull JvmMethodGenericSignature jvmSignature,
|
||||
@NotNull MethodVisitor mv
|
||||
) {
|
||||
FunctionDescriptor annotationsOwner;
|
||||
if (shouldHideConstructorDueToInlineClassTypeValueParameters(functionDescriptor)) {
|
||||
if (functionDescriptor instanceof AccessorForConstructorDescriptor) {
|
||||
annotationsOwner = ((AccessorForConstructorDescriptor) functionDescriptor).getCalleeDescriptor();
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
annotationsOwner = functionDescriptor;
|
||||
}
|
||||
|
||||
AnnotationCodegen.forMethod(mv, memberCodegen, typeMapper).genAnnotations(annotationsOwner, asmMethod.getReturnType());
|
||||
generateParameterAnnotations(annotationsOwner, mv, jvmSignature, memberCodegen, state);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MethodVisitor newMethod(
|
||||
@NotNull JvmDeclarationOrigin origin,
|
||||
|
||||
@@ -197,8 +197,8 @@ public class JvmCodegenUtil {
|
||||
if (KotlinTypeMapper.isAccessor(property)) return false;
|
||||
|
||||
CodegenContext context = contextBeforeInline.getFirstCrossInlineOrNonInlineContext();
|
||||
// Inline functions or inline classes can't use direct access because a field may not be visible at the call site
|
||||
if (context.isInlineMethodContext() || (context.getEnclosingClass() != null && context.getEnclosingClass().isInline())) {
|
||||
// Inline functions can't use direct access because a field may not be visible at the call site
|
||||
if (context.isInlineMethodContext()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -406,7 +406,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
return typeMapper.mapDefaultImpls(classDescriptor);
|
||||
}
|
||||
}
|
||||
return typeMapper.mapType(classDescriptor);
|
||||
return typeMapper.mapClass(classDescriptor);
|
||||
}
|
||||
else if (outermost instanceof MultifileClassFacadeContext || outermost instanceof DelegatingToPartContext) {
|
||||
Type implementationOwnerType = CodegenContextUtil.getImplementationOwnerClassType(outermost);
|
||||
|
||||
@@ -246,7 +246,7 @@ class MultifileClassCodegenImpl(
|
||||
val facadeContext = state.rootContext.intoMultifileClass(packageFragment, facadeClassType, partType)
|
||||
val memberCodegen = createCodegenForDelegatesInMultifileFacade(facadeContext)
|
||||
for (declaration in CodegenUtil.getDeclarationsToGenerate(file, state.bindingContext)) {
|
||||
if (declaration is KtNamedFunction || declaration is KtProperty || declaration is KtTypeAlias) {
|
||||
if (shouldGenerateInFacade(declaration)) {
|
||||
val descriptor = state.bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration)
|
||||
if (descriptor !is MemberDescriptor) {
|
||||
throw AssertionError("Expected callable member, was " + descriptor + " for " + declaration.text)
|
||||
@@ -256,6 +256,15 @@ class MultifileClassCodegenImpl(
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldGenerateInFacade(declaration: KtDeclaration): Boolean {
|
||||
if (declaration is KtNamedFunction || declaration is KtProperty) return true
|
||||
|
||||
// In light classes, we intentionally do not analyze type aliases, since they're metadata-only
|
||||
if (declaration is KtTypeAlias && state.classBuilderMode.generateMetadata) return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun shouldGenerateInFacade(descriptor: MemberDescriptor): Boolean {
|
||||
if (Visibilities.isPrivate(descriptor.visibility)) return false
|
||||
if (AsmUtil.getVisibilityAccessFlag(descriptor) == Opcodes.ACC_PRIVATE) return false
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.isTopLevelInPackage
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.RANGES_PACKAGE_FQ_NAME
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
|
||||
@@ -318,7 +318,19 @@ public abstract class StackValue {
|
||||
|
||||
@NotNull
|
||||
public static Field field(@NotNull Type type, @NotNull Type owner, @NotNull String name, boolean isStatic, @NotNull StackValue receiver) {
|
||||
return field(type, null, owner, name, isStatic, receiver, null);
|
||||
return field(type, null, owner, name, isStatic, receiver);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Field field(
|
||||
@NotNull Type type,
|
||||
@Nullable KotlinType kotlinType,
|
||||
@NotNull Type owner,
|
||||
@NotNull String name,
|
||||
boolean isStatic,
|
||||
@NotNull StackValue receiver
|
||||
) {
|
||||
return field(type, kotlinType, owner, name, isStatic, receiver, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -341,7 +353,14 @@ public abstract class StackValue {
|
||||
|
||||
@NotNull
|
||||
public static Field field(@NotNull FieldInfo info, @NotNull StackValue receiver) {
|
||||
return field(info.getFieldType(), Type.getObjectType(info.getOwnerInternalName()), info.getFieldName(), info.isStatic(), receiver);
|
||||
return field(
|
||||
info.getFieldType(),
|
||||
info.getFieldKotlinType(),
|
||||
Type.getObjectType(info.getOwnerInternalName()),
|
||||
info.getFieldName(),
|
||||
info.isStatic(),
|
||||
receiver
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -721,7 +740,7 @@ public abstract class StackValue {
|
||||
) {
|
||||
// Coerce 'this' for the case when it is smart cast.
|
||||
// Do not coerce for other cases due to the 'protected' access issues (JVMS 7, 4.9.2 Structural Constraints).
|
||||
boolean coerceType = descriptor.getKind() == ClassKind.INTERFACE || (castReceiver && !isSuper);
|
||||
boolean coerceType = descriptor.getKind() == ClassKind.INTERFACE || descriptor.isInline() || (castReceiver && !isSuper);
|
||||
return new ThisOuter(codegen, descriptor, isSuper, coerceType);
|
||||
}
|
||||
|
||||
@@ -1426,7 +1445,7 @@ public abstract class StackValue {
|
||||
|
||||
Type lastParameterType = ArraysKt.last(setter.getParameterTypes());
|
||||
KotlinType lastParameterKotlinType =
|
||||
CollectionsKt.last(resolvedSetCall.getResultingDescriptor().getValueParameters()).getType();
|
||||
CollectionsKt.last(resolvedSetCall.getResultingDescriptor().getOriginal().getValueParameters()).getType();
|
||||
|
||||
coerce(topOfStackType, topOfStackKotlinType, lastParameterType, lastParameterKotlinType, v);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.kotlin.codegen.StackValue;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
public final class EnclosedValueDescriptor {
|
||||
@@ -29,18 +30,21 @@ public final class EnclosedValueDescriptor {
|
||||
private final StackValue.StackValueWithSimpleReceiver innerValue;
|
||||
private final StackValue instanceValue;
|
||||
private final Type type;
|
||||
private final KotlinType kotlinType;
|
||||
|
||||
public EnclosedValueDescriptor(
|
||||
@NotNull String fieldName,
|
||||
@Nullable DeclarationDescriptor descriptor,
|
||||
@NotNull StackValue.StackValueWithSimpleReceiver innerValue,
|
||||
@NotNull Type type
|
||||
@NotNull Type type,
|
||||
@Nullable KotlinType kotlinType
|
||||
) {
|
||||
this.fieldName = fieldName;
|
||||
this.descriptor = descriptor;
|
||||
this.innerValue = innerValue;
|
||||
this.instanceValue = innerValue;
|
||||
this.type = type;
|
||||
this.kotlinType = kotlinType;
|
||||
}
|
||||
|
||||
public EnclosedValueDescriptor(
|
||||
@@ -48,13 +52,15 @@ public final class EnclosedValueDescriptor {
|
||||
@Nullable DeclarationDescriptor descriptor,
|
||||
@NotNull StackValue.StackValueWithSimpleReceiver innerValue,
|
||||
@NotNull StackValue.Field instanceValue,
|
||||
@NotNull Type type
|
||||
@NotNull Type type,
|
||||
@Nullable KotlinType kotlinType
|
||||
) {
|
||||
this.fieldName = name;
|
||||
this.descriptor = descriptor;
|
||||
this.innerValue = innerValue;
|
||||
this.instanceValue = instanceValue;
|
||||
this.type = type;
|
||||
this.kotlinType = kotlinType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -82,6 +88,11 @@ public final class EnclosedValueDescriptor {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public KotlinType getKotlinType() {
|
||||
return kotlinType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return fieldName + " " + type + " -> " + descriptor;
|
||||
|
||||
@@ -63,11 +63,11 @@ public interface LocalLookup {
|
||||
if (sharedVarType != null) {
|
||||
StackValue.Field wrapperValue = StackValue.receiverWithRefWrapper(localType, classType, fieldName, thiz, vd);
|
||||
innerValue = StackValue.fieldForSharedVar(localType, classType, fieldName, wrapperValue, vd);
|
||||
enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, wrapperValue, type);
|
||||
enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, wrapperValue, type, kotlinType);
|
||||
}
|
||||
else {
|
||||
innerValue = StackValue.field(type, kotlinType, classType, fieldName, false, thiz, vd);
|
||||
enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, type);
|
||||
enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, type, kotlinType);
|
||||
}
|
||||
|
||||
closure.captureVariable(enclosedValueDescriptor);
|
||||
@@ -118,7 +118,7 @@ public interface LocalLookup {
|
||||
localType, null, classType, fieldName, false, StackValue.LOCAL_0, vd
|
||||
);
|
||||
|
||||
closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType));
|
||||
closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType, null));
|
||||
|
||||
return innerValue;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
@@ -64,8 +65,9 @@ public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
|
||||
public StackValue getReceiverExpression(KotlinTypeMapper typeMapper) {
|
||||
assert getCallableDescriptorWithReceiver() != null;
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
Type asmType = typeMapper.mapType(getCallableDescriptorWithReceiver().getExtensionReceiverParameter().getType());
|
||||
return StackValue.local(AsmUtil.getReceiverIndex(this, getContextDescriptor()), asmType);
|
||||
KotlinType kotlinType = getCallableDescriptorWithReceiver().getExtensionReceiverParameter().getType();
|
||||
Type asmType = typeMapper.mapType(kotlinType);
|
||||
return StackValue.local(AsmUtil.getReceiverIndex(this, getContextDescriptor()), asmType, kotlinType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.coroutines
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.isPrimitiveBoxing
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.topLevelClassInternalName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
private val BOXING_CLASS_INTERNAL_NAME =
|
||||
RELEASE_COROUTINES_VERSION_SETTINGS.coroutinesJvmInternalPackageFqName().child(Name.identifier("Boxing")).topLevelClassInternalName()
|
||||
|
||||
object ChangeBoxingMethodTransformer : MethodTransformer() {
|
||||
private val wrapperToInternalBoxing: Map<String, String>
|
||||
|
||||
init {
|
||||
val map = hashMapOf<String, String>()
|
||||
for (primitiveType in JvmPrimitiveType.values()) {
|
||||
val name = primitiveType.wrapperFqName.topLevelClassInternalName()
|
||||
map[name] = "box${primitiveType.javaKeywordName.capitalize()}"
|
||||
}
|
||||
wrapperToInternalBoxing = map
|
||||
}
|
||||
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
for (boxing in methodNode.instructions.asSequence().filter { it.isPrimitiveBoxing() }) {
|
||||
assert(boxing.opcode == Opcodes.INVOKESTATIC) {
|
||||
"boxing shall be INVOKESTATIC wrapper.valueOf"
|
||||
}
|
||||
boxing as MethodInsnNode
|
||||
val methodName = wrapperToInternalBoxing[boxing.owner].sure {
|
||||
"expected primitive wrapper, but got ${boxing.owner}"
|
||||
}
|
||||
methodNode.instructions.set(
|
||||
boxing,
|
||||
MethodInsnNode(boxing.opcode, BOXING_CLASS_INTERNAL_NAME, methodName, boxing.desc, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,7 +347,7 @@ class CoroutineCodegenForLambda private constructor(
|
||||
// pass captured closure to constructor
|
||||
val constructorParameters = calculateConstructorParameters(typeMapper, languageVersionSettings, closure, owner)
|
||||
for (parameter in constructorParameters) {
|
||||
StackValue.field(parameter, thisInstance).put(parameter.fieldType, this)
|
||||
StackValue.field(parameter, thisInstance).put(parameter.fieldType, parameter.fieldKotlinType, this)
|
||||
}
|
||||
|
||||
// load resultContinuation
|
||||
@@ -377,7 +377,11 @@ class CoroutineCodegenForLambda private constructor(
|
||||
load(1, AsmTypes.OBJECT_TYPE)
|
||||
iconst(index - 1)
|
||||
aload(AsmTypes.OBJECT_TYPE)
|
||||
StackValue.coerce(AsmTypes.OBJECT_TYPE, fieldInfoForCoroutineLambdaParameter.fieldType, this)
|
||||
StackValue.coerce(
|
||||
AsmTypes.OBJECT_TYPE, builtIns.nullableAnyType,
|
||||
fieldInfoForCoroutineLambdaParameter.fieldType, fieldInfoForCoroutineLambdaParameter.fieldKotlinType,
|
||||
this
|
||||
)
|
||||
putfield(
|
||||
fieldInfoForCoroutineLambdaParameter.ownerInternalName,
|
||||
fieldInfoForCoroutineLambdaParameter.fieldName,
|
||||
@@ -386,7 +390,11 @@ class CoroutineCodegenForLambda private constructor(
|
||||
} else {
|
||||
if (generateErasedCreate) {
|
||||
load(index, AsmTypes.OBJECT_TYPE)
|
||||
StackValue.coerce(AsmTypes.OBJECT_TYPE, fieldInfoForCoroutineLambdaParameter.fieldType, this)
|
||||
StackValue.coerce(
|
||||
AsmTypes.OBJECT_TYPE, builtIns.nullableAnyType,
|
||||
fieldInfoForCoroutineLambdaParameter.fieldType, fieldInfoForCoroutineLambdaParameter.fieldKotlinType,
|
||||
this
|
||||
)
|
||||
} else {
|
||||
load(index, fieldInfoForCoroutineLambdaParameter.fieldType)
|
||||
}
|
||||
@@ -434,6 +442,7 @@ class CoroutineCodegenForLambda private constructor(
|
||||
FieldInfo.createForHiddenField(
|
||||
typeMapper.mapClass(closureContext.thisDescriptor),
|
||||
typeMapper.mapType(type),
|
||||
type,
|
||||
name
|
||||
)
|
||||
|
||||
@@ -448,7 +457,8 @@ class CoroutineCodegenForLambda private constructor(
|
||||
return CoroutineTransformerMethodVisitor(
|
||||
mv, access, name, desc, null, null,
|
||||
obtainClassBuilderForCoroutineState = { v },
|
||||
lineNumber = CodegenUtil.getLineNumberForElement(element, false) ?: 0,
|
||||
element = element,
|
||||
diagnostics = state.diagnostics,
|
||||
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||
containingClassInternalName = v.thisName,
|
||||
isForNamedFunction = false,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.codegen.coroutines
|
||||
|
||||
import com.intellij.util.containers.Stack
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
@@ -19,7 +20,10 @@ import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
@@ -56,9 +60,11 @@ class CoroutineTransformerMethodVisitor(
|
||||
obtainClassBuilderForCoroutineState: () -> ClassBuilder,
|
||||
private val isForNamedFunction: Boolean,
|
||||
private val shouldPreserveClassInitialization: Boolean,
|
||||
private val lineNumber: Int,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val sourceFile: String,
|
||||
// These two are needed to report diagnostics about suspension points inside critical section
|
||||
private val element: KtElement,
|
||||
private val diagnostics: DiagnosticSink,
|
||||
// It's only matters for named functions, may differ from '!isStatic(access)' in case of DefaultImpls
|
||||
private val needDispatchReceiver: Boolean = false,
|
||||
// May differ from containingClassInternalName in case of DefaultImpls
|
||||
@@ -68,6 +74,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
) : TransformationMethodVisitor(delegate, access, name, desc, signature, exceptions) {
|
||||
|
||||
private val classBuilderForCoroutineState: ClassBuilder by lazy(obtainClassBuilderForCoroutineState)
|
||||
private val lineNumber = element?.let { CodegenUtil.getLineNumberForElement(it, false) } ?: 0
|
||||
|
||||
private var continuationIndex = if (isForNamedFunction) -1 else 0
|
||||
private var dataIndex = if (isForNamedFunction) -1 else 1
|
||||
@@ -83,14 +90,18 @@ class CoroutineTransformerMethodVisitor(
|
||||
|
||||
FixStackMethodTransformer().transform(containingClassInternalName, methodNode)
|
||||
RedundantLocalsEliminationMethodTransformer(languageVersionSettings).transform(containingClassInternalName, methodNode)
|
||||
if (languageVersionSettings.isReleaseCoroutines()) {
|
||||
ChangeBoxingMethodTransformer.transform(containingClassInternalName, methodNode)
|
||||
}
|
||||
updateMaxStack(methodNode)
|
||||
|
||||
val suspensionPoints = collectSuspensionPoints(methodNode)
|
||||
|
||||
checkForSuspensionPointInsideMonitor(methodNode, suspensionPoints)
|
||||
|
||||
// First instruction in the method node may change in case of named function
|
||||
val actualCoroutineStart = methodNode.instructions.first
|
||||
|
||||
var startLabelNode: LabelNode? = null
|
||||
if (isForNamedFunction) {
|
||||
ReturnUnitMethodTransformer.transform(containingClassInternalName, methodNode)
|
||||
|
||||
@@ -105,7 +116,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
}
|
||||
continuationIndex = methodNode.maxLocals++
|
||||
|
||||
startLabelNode = prepareMethodNodePreludeForNamedFunction(methodNode)
|
||||
prepareMethodNodePreludeForNamedFunction(methodNode)
|
||||
} else {
|
||||
ReturnUnitMethodTransformer.cleanUpReturnsUnitMarkers(methodNode, ReturnUnitMethodTransformer.findReturnsUnitMarks(methodNode))
|
||||
}
|
||||
@@ -131,10 +142,10 @@ class CoroutineTransformerMethodVisitor(
|
||||
transformCallAndReturnContinuationLabel(it.index + 1, it.value, methodNode, suspendMarkerVarIndex)
|
||||
}
|
||||
|
||||
val defaultLabel = LabelNode()
|
||||
val tableSwitchLabel = LabelNode()
|
||||
methodNode.instructions.apply {
|
||||
val startLabel = LabelNode()
|
||||
val firstStateLabel = LabelNode()
|
||||
val defaultLabel = LabelNode()
|
||||
|
||||
// tableswitch(this.label)
|
||||
insertBefore(
|
||||
@@ -151,13 +162,13 @@ class CoroutineTransformerMethodVisitor(
|
||||
0,
|
||||
suspensionPoints.size,
|
||||
defaultLabel,
|
||||
startLabel, *suspensionPointLabels.toTypedArray()
|
||||
firstStateLabel, *suspensionPointLabels.toTypedArray()
|
||||
),
|
||||
startLabel
|
||||
firstStateLabel
|
||||
)
|
||||
)
|
||||
|
||||
insert(startLabel, withInstructionAdapter {
|
||||
insert(firstStateLabel, withInstructionAdapter {
|
||||
generateResumeWithExceptionCheck(languageVersionSettings.isReleaseCoroutines(), dataIndex, exceptionIndex)
|
||||
})
|
||||
insert(last, defaultLabel)
|
||||
@@ -171,13 +182,13 @@ class CoroutineTransformerMethodVisitor(
|
||||
dropSuspensionMarkers(methodNode, suspensionPoints)
|
||||
methodNode.removeEmptyCatchBlocks()
|
||||
|
||||
if (isForNamedFunction) {
|
||||
addContinuationToLvt(
|
||||
methodNode,
|
||||
startLabelNode.sure { "start label has not been initialized during prelude generation" },
|
||||
defaultLabel
|
||||
)
|
||||
}
|
||||
// The parameters (and 'this') shall live throughout the method, otherwise, d8 emits warning about invalid debug info
|
||||
val startLabel = LabelNode()
|
||||
val endLabel = LabelNode()
|
||||
methodNode.instructions.insertBefore(methodNode.instructions.first, startLabel)
|
||||
methodNode.instructions.insert(methodNode.instructions.last, endLabel)
|
||||
|
||||
fixLvtForParameters(methodNode, startLabel, endLabel)
|
||||
|
||||
if (languageVersionSettings.isReleaseCoroutines() && !isCrossinlineLambda) {
|
||||
val suspensionPointLabelNodes = listOf(tableSwitchLabel) + suspensionPointLabels.map {
|
||||
@@ -188,6 +199,71 @@ class CoroutineTransformerMethodVisitor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun findSuspensionPointLineNumber(suspensionPoint: SuspensionPoint) =
|
||||
suspensionPoint.suspensionCallBegin.findPreviousOrNull { it is LineNumberNode } as LineNumberNode?
|
||||
|
||||
private fun checkForSuspensionPointInsideMonitor(methodNode: MethodNode, suspensionPoints: List<SuspensionPoint>) {
|
||||
if (methodNode.instructions.asSequence().none { it.opcode == Opcodes.MONITORENTER }) return
|
||||
|
||||
val cfg = ControlFlowGraph.build(methodNode)
|
||||
val monitorDepthMap = hashMapOf<AbstractInsnNode, Int>()
|
||||
fun addMonitorDepthToSuccs(index: Int, depth: Int) {
|
||||
val insn = methodNode.instructions[index]
|
||||
monitorDepthMap[insn] = depth
|
||||
val newDepth = when (insn.opcode) {
|
||||
Opcodes.MONITORENTER -> depth + 1
|
||||
Opcodes.MONITOREXIT -> depth - 1
|
||||
else -> depth
|
||||
}
|
||||
for (succIndex in cfg.getSuccessorsIndices(index)) {
|
||||
if (monitorDepthMap[methodNode.instructions[succIndex]] == null) {
|
||||
addMonitorDepthToSuccs(succIndex, newDepth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addMonitorDepthToSuccs(0, 0)
|
||||
|
||||
for (suspensionPoint in suspensionPoints) {
|
||||
if (monitorDepthMap[suspensionPoint.suspensionCallBegin]?.let { it > 0 } == true) {
|
||||
// TODO: Support crossinline suspend lambdas
|
||||
val stackTraceElement = StackTraceElement(
|
||||
containingClassInternalName,
|
||||
methodNode.name,
|
||||
sourceFile,
|
||||
findSuspensionPointLineNumber(suspensionPoint)?.line ?: -1
|
||||
)
|
||||
diagnostics.report(ErrorsJvm.SUSPENSION_POINT_INSIDE_MONITOR.on(element, "$stackTraceElement"))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fixLvtForParameters(methodNode: MethodNode, startLabel: LabelNode, endLabel: LabelNode) {
|
||||
// We need to skip continuation, since the inliner likes to remap variables there.
|
||||
// But this is not a problem, since we have separate $continuation LVT entry
|
||||
|
||||
val paramsNum =
|
||||
/* this */ (if (internalNameForDispatchReceiver != null) 1 else 0) +
|
||||
/* real params */ Type.getArgumentTypes(methodNode.desc).size -
|
||||
/* no continuation */ if (isForNamedFunction) 1 else 0
|
||||
|
||||
for (i in 0..paramsNum) {
|
||||
fixRangeOfLvtRecord(methodNode, i, startLabel, endLabel)
|
||||
}
|
||||
}
|
||||
|
||||
private fun fixRangeOfLvtRecord(methodNode: MethodNode, index: Int, startLabel: LabelNode, endLabel: LabelNode) {
|
||||
val vars = methodNode.localVariables.filter { it.index == index }
|
||||
assert(vars.size <= 1) {
|
||||
"Someone else occupies parameter's slot at $index"
|
||||
}
|
||||
vars.firstOrNull()?.let {
|
||||
it.start = startLabel
|
||||
it.end = endLabel
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeDebugMetadata(
|
||||
methodNode: MethodNode,
|
||||
suspensionPointLabels: List<LabelNode>,
|
||||
@@ -220,7 +296,11 @@ class CoroutineTransformerMethodVisitor(
|
||||
metadata.visitEnd()
|
||||
}
|
||||
|
||||
private fun addContinuationToLvt(methodNode: MethodNode, startLabel: LabelNode, endLabel: LabelNode) {
|
||||
// Warning! This is _continuation_, not _completion_, it can be allocated inside the method, thus, it is incorrect to treat it
|
||||
// as a parameter
|
||||
private fun addContinuationToLvt(methodNode: MethodNode, startLabel: LabelNode) {
|
||||
val endLabel = LabelNode()
|
||||
methodNode.instructions.insert(methodNode.instructions.last, endLabel)
|
||||
methodNode.localVariables.add(
|
||||
LocalVariableNode(
|
||||
"\$continuation",
|
||||
@@ -288,7 +368,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
)
|
||||
}
|
||||
|
||||
private fun prepareMethodNodePreludeForNamedFunction(methodNode: MethodNode): LabelNode {
|
||||
private fun prepareMethodNodePreludeForNamedFunction(methodNode: MethodNode) {
|
||||
val objectTypeForState = Type.getObjectType(classBuilderForCoroutineState.thisName)
|
||||
val continuationArgumentIndex = getLastParameterIndex(methodNode.desc, methodNode.access)
|
||||
methodNode.instructions.asSequence().filterIsInstance<VarInsnNode>().forEach {
|
||||
@@ -297,8 +377,6 @@ class CoroutineTransformerMethodVisitor(
|
||||
it.`var` = continuationIndex
|
||||
}
|
||||
|
||||
val startLabel = LabelNode()
|
||||
|
||||
methodNode.instructions.insert(withInstructionAdapter {
|
||||
val createStateInstance = Label()
|
||||
val afterCoroutineStateCreated = Label()
|
||||
@@ -318,7 +396,6 @@ class CoroutineTransformerMethodVisitor(
|
||||
// `doResume` just before calling the suspend function (see kotlin.coroutines.experimental.jvm.internal.CoroutineImplForNamedFunction).
|
||||
// So, if it's set we're in continuation.
|
||||
|
||||
visitLabel(startLabel.label)
|
||||
visitVarInsn(Opcodes.ALOAD, continuationArgumentIndex)
|
||||
instanceOf(objectTypeForState)
|
||||
ifeq(createStateInstance)
|
||||
@@ -360,6 +437,8 @@ class CoroutineTransformerMethodVisitor(
|
||||
|
||||
visitLabel(afterCoroutineStateCreated)
|
||||
|
||||
addContinuationToLvt(methodNode, LabelNode(afterCoroutineStateCreated))
|
||||
|
||||
visitVarInsn(Opcodes.ALOAD, continuationIndex)
|
||||
getfield(classBuilderForCoroutineState.thisName, languageVersionSettings.dataFieldName(), AsmTypes.OBJECT_TYPE.descriptor)
|
||||
visitVarInsn(Opcodes.ASTORE, dataIndex)
|
||||
@@ -370,7 +449,6 @@ class CoroutineTransformerMethodVisitor(
|
||||
visitVarInsn(Opcodes.ASTORE, exceptionIndex)
|
||||
}
|
||||
})
|
||||
return startLabel
|
||||
}
|
||||
|
||||
private fun removeUnreachableSuspensionPointsAndExitPoints(methodNode: MethodNode, suspensionPoints: MutableList<SuspensionPoint>) {
|
||||
@@ -880,7 +958,7 @@ private fun allSuspensionPointsAreTailCalls(
|
||||
}
|
||||
}
|
||||
|
||||
internal class IgnoringCopyOperationSourceInterpreter : SourceInterpreter() {
|
||||
internal class IgnoringCopyOperationSourceInterpreter : SourceInterpreter(OPTIMIZATION_ASM_API_VERSION) {
|
||||
override fun copyOperation(insn: AbstractInsnNode?, value: SourceValue?) = value
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,8 @@ open class SuspendFunctionGenerationStrategy(
|
||||
return CoroutineTransformerMethodVisitor(
|
||||
mv, access, name, desc, null, null, containingClassInternalName, this::classBuilderForCoroutineState,
|
||||
isForNamedFunction = true,
|
||||
lineNumber = CodegenUtil.getLineNumberForElement(declaration, false) ?: 0,
|
||||
element = declaration,
|
||||
diagnostics = state.diagnostics,
|
||||
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||
needDispatchReceiver = originalSuspendDescriptor.dispatchReceiverParameter != null,
|
||||
internalNameForDispatchReceiver = containingClassInternalNameOrNull(),
|
||||
|
||||
@@ -56,7 +56,7 @@ const val DO_RESUME_METHOD_NAME = "doResume"
|
||||
const val INVOKE_SUSPEND_METHOD_NAME = "invokeSuspend"
|
||||
const val EXCEPTION_FIELD_NAME = "exception"
|
||||
|
||||
private val RELEASE_COROUTINES_VERSION_SETTINGS = LanguageVersionSettingsImpl(LanguageVersion.KOTLIN_1_3, ApiVersion.KOTLIN_1_3)
|
||||
val RELEASE_COROUTINES_VERSION_SETTINGS = LanguageVersionSettingsImpl(LanguageVersion.KOTLIN_1_3, ApiVersion.KOTLIN_1_3)
|
||||
|
||||
fun LanguageVersionSettings.isResumeImplMethodName(name: String) =
|
||||
if (isReleaseCoroutines())
|
||||
|
||||
@@ -169,7 +169,7 @@ private fun checkUpdatedExpectedType(was: Type?, new: Type) {
|
||||
}
|
||||
}
|
||||
|
||||
private class MySourceInterpreter : SourceInterpreter() {
|
||||
private class MySourceInterpreter : SourceInterpreter(OPTIMIZATION_ASM_API_VERSION) {
|
||||
override fun copyOperation(insn: AbstractInsnNode, value: SourceValue) =
|
||||
when {
|
||||
insn.isStoreOperation() || insn.isLoadOperation() -> SourceValue(value.size, insn)
|
||||
|
||||
@@ -21,8 +21,10 @@ import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable
|
||||
import org.jetbrains.kotlin.protobuf.MessageLite
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
@@ -131,10 +133,9 @@ class AnonymousObjectTransformer(
|
||||
constructor!!, allCapturedParamBuilder, constructorParamBuilder,transformationInfo, parentRemapper
|
||||
)
|
||||
|
||||
val crossinlineSuspendElement = capturedCrossinlineSuspendElement()
|
||||
val capturesCrossinlineSuspend = (!inliningContext.isInliningLambda || inliningContext.isContinuation) &&
|
||||
inliningContext.expressionMap.values.any { lambda ->
|
||||
lambda is PsiExpressionLambda && lambda.isCrossInline && lambda.invokeMethodDescriptor.isSuspend
|
||||
}
|
||||
crossinlineSuspendElement != null
|
||||
|
||||
val deferringMethods = ArrayList<DeferredMethodVisitor>()
|
||||
|
||||
@@ -158,11 +159,18 @@ class AnonymousObjectTransformer(
|
||||
capturesCrossinlineSuspend && !inliningContext.isContinuation && continuationClassName != null
|
||||
|
||||
val deferringVisitor =
|
||||
when {
|
||||
generateStateMachineForLambda -> newStateMachineForLambda(classBuilder, next)
|
||||
generateStateMachineForNamedFunction -> newStateMachineForNamedFunction(classBuilder, next, continuationClassName!!)
|
||||
else -> newMethod(classBuilder, next)
|
||||
}
|
||||
if (crossinlineSuspendElement != null) {
|
||||
when {
|
||||
generateStateMachineForLambda -> newStateMachineForLambda(classBuilder, next, crossinlineSuspendElement)
|
||||
generateStateMachineForNamedFunction -> newStateMachineForNamedFunction(
|
||||
classBuilder,
|
||||
next,
|
||||
continuationClassName!!,
|
||||
crossinlineSuspendElement
|
||||
)
|
||||
else -> newMethod(classBuilder, next)
|
||||
}
|
||||
} else newMethod(classBuilder, next)
|
||||
val funResult = inlineMethodAndUpdateGlobalResult(parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false)
|
||||
|
||||
val returnType = Type.getReturnType(next.desc)
|
||||
@@ -227,6 +235,10 @@ class AnonymousObjectTransformer(
|
||||
return transformationResult
|
||||
}
|
||||
|
||||
private fun capturedCrossinlineSuspendElement(): KtExpression? = inliningContext.expressionMap.values.find { lambda ->
|
||||
lambda is PsiExpressionLambda && lambda.isCrossInline && lambda.invokeMethodDescriptor.isSuspend
|
||||
}?.cast<PsiExpressionLambda>()?.functionWithBodyOrCallableReference
|
||||
|
||||
private fun writeTransformedMetadata(header: KotlinClassHeader, classBuilder: ClassBuilder) {
|
||||
writeKotlinMetadata(classBuilder, state, header.kind, header.extraInt) action@ { av ->
|
||||
val (newProto, newStringTable) = transformMetadata(header) ?: run {
|
||||
@@ -435,7 +447,7 @@ class AnonymousObjectTransformer(
|
||||
}
|
||||
}
|
||||
|
||||
private fun newStateMachineForLambda(builder: ClassBuilder, original: MethodNode): DeferredMethodVisitor {
|
||||
private fun newStateMachineForLambda(builder: ClassBuilder, original: MethodNode, element: KtExpression): DeferredMethodVisitor {
|
||||
return DeferredMethodVisitor(
|
||||
MethodNode(
|
||||
original.access, original.name, original.desc, original.signature,
|
||||
@@ -448,7 +460,8 @@ class AnonymousObjectTransformer(
|
||||
ArrayUtil.toStringArray(original.exceptions)
|
||||
), original.access, original.name, original.desc, null, null,
|
||||
obtainClassBuilderForCoroutineState = { builder },
|
||||
lineNumber = 0, // <- TODO
|
||||
element = element,
|
||||
diagnostics = state.diagnostics,
|
||||
languageVersionSettings = languageVersionSettings,
|
||||
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||
containingClassInternalName = builder.thisName,
|
||||
@@ -462,7 +475,8 @@ class AnonymousObjectTransformer(
|
||||
private fun newStateMachineForNamedFunction(
|
||||
builder: ClassBuilder,
|
||||
original: MethodNode,
|
||||
continuationClassName: String
|
||||
continuationClassName: String,
|
||||
element: KtExpression
|
||||
): DeferredMethodVisitor {
|
||||
assert(inliningContext is RegeneratedClassContext)
|
||||
return DeferredMethodVisitor(
|
||||
@@ -477,7 +491,8 @@ class AnonymousObjectTransformer(
|
||||
ArrayUtil.toStringArray(original.exceptions)
|
||||
), original.access, original.name, original.desc, null, null,
|
||||
obtainClassBuilderForCoroutineState = { (inliningContext as RegeneratedClassContext).continuationBuilders[continuationClassName]!! },
|
||||
lineNumber = 0, // <- TODO
|
||||
element = element,
|
||||
diagnostics = state.diagnostics,
|
||||
languageVersionSettings = languageVersionSettings,
|
||||
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||
containingClassInternalName = builder.thisName,
|
||||
|
||||
@@ -255,25 +255,27 @@ class PsiExpressionLambda(
|
||||
arrayListOf<CapturedParamDesc>().apply {
|
||||
val captureThis = closure.capturedOuterClassDescriptor
|
||||
if (captureThis != null) {
|
||||
val type = typeMapper.mapType(captureThis)
|
||||
val kotlinType = captureThis.defaultType
|
||||
val type = typeMapper.mapType(kotlinType)
|
||||
val descriptor = EnclosedValueDescriptor(
|
||||
AsmUtil.CAPTURED_THIS_FIELD, null,
|
||||
StackValue.field(type, lambdaClassType, AsmUtil.CAPTURED_THIS_FIELD, false, StackValue.LOCAL_0),
|
||||
type
|
||||
type, kotlinType
|
||||
)
|
||||
add(getCapturedParamInfo(descriptor))
|
||||
}
|
||||
|
||||
if (closure.capturedReceiverFromOuterContext != null) {
|
||||
val type = typeMapper.mapType(closure.capturedReceiverFromOuterContext!!).let {
|
||||
val capturedReceiver = closure.capturedReceiverFromOuterContext
|
||||
if (capturedReceiver != null) {
|
||||
val type = typeMapper.mapType(capturedReceiver).let {
|
||||
if (isBoundCallableReference) it.boxReceiverForBoundReference() else it
|
||||
}
|
||||
|
||||
val fieldName = closure.getCapturedReceiverFieldName(typeMapper.bindingContext, languageVersionSettings)
|
||||
val descriptor = EnclosedValueDescriptor(
|
||||
fieldName, null,
|
||||
StackValue.field(type, lambdaClassType, fieldName, false, StackValue.LOCAL_0),
|
||||
type
|
||||
StackValue.field(type, capturedReceiver, lambdaClassType, fieldName, false, StackValue.LOCAL_0),
|
||||
type, capturedReceiver
|
||||
)
|
||||
add(getCapturedParamInfo(descriptor))
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.codegen.optimization.boxing
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OPTIMIZATION_ASM_API_VERSION
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.debugText
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.isLoadOperation
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
||||
@@ -119,7 +120,7 @@ class PopBackwardPropagationTransformer : MethodTransformer() {
|
||||
throw AssertionError("Incorrect bytecode at ${methodNode.instructions.indexOf(insn)}: ${insn.debugText} $frame")
|
||||
}
|
||||
|
||||
private inner class HazardsTrackingInterpreter : SourceInterpreter() {
|
||||
private inner class HazardsTrackingInterpreter : SourceInterpreter(OPTIMIZATION_ASM_API_VERSION) {
|
||||
override fun naryOperation(insn: AbstractInsnNode, values: MutableList<out SourceValue>): SourceValue {
|
||||
for (value in values) {
|
||||
value.insns.markAsDontTouch()
|
||||
@@ -313,4 +314,4 @@ fun AbstractInsnNode.isUnitInstance() =
|
||||
this is FieldInsnNode && owner == "kotlin/Unit" && name == "INSTANCE"
|
||||
|
||||
fun AbstractInsnNode.isPrimitiveTypeConversion() =
|
||||
opcode in Opcodes.I2L..Opcodes.I2S
|
||||
opcode in Opcodes.I2L..Opcodes.I2S
|
||||
|
||||
@@ -27,6 +27,8 @@ import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
|
||||
const val OPTIMIZATION_ASM_API_VERSION = Opcodes.ASM5
|
||||
|
||||
val AbstractInsnNode.isMeaningful: Boolean
|
||||
get() =
|
||||
when (this.type) {
|
||||
@@ -221,4 +223,4 @@ internal inline fun <reified T : AbstractInsnNode> AbstractInsnNode.takeInsnIf(o
|
||||
|
||||
fun InsnList.removeAll(nodes: Collection<AbstractInsnNode>) {
|
||||
for (node in nodes) remove(node)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,31 +509,35 @@ public class KotlinTypeMapper {
|
||||
);
|
||||
}
|
||||
|
||||
// Make sure this method is called only from back-end
|
||||
// It uses staticTypeMappingConfiguration that throws exception on error types
|
||||
@NotNull
|
||||
public static Type mapInlineClassTypeAsDeclaration(@NotNull KotlinType kotlinType) {
|
||||
return mapInlineClassType(kotlinType, TypeMappingMode.CLASS_DECLARATION);
|
||||
return mapInlineClassType(kotlinType, TypeMappingMode.CLASS_DECLARATION, staticTypeMappingConfiguration);
|
||||
}
|
||||
|
||||
// Make sure this method is called only from back-end
|
||||
// It uses staticTypeMappingConfiguration that throws exception on error types
|
||||
@NotNull
|
||||
public static Type mapUnderlyingTypeOfInlineClassType(@NotNull KotlinType kotlinType) {
|
||||
KotlinType underlyingType = InlineClassesUtilsKt.unsubstitutedUnderlyingType(kotlinType);
|
||||
if (underlyingType == null) {
|
||||
throw new IllegalStateException("There should be underlying type for inline class type: " + kotlinType);
|
||||
}
|
||||
return mapInlineClassType(underlyingType, TypeMappingMode.DEFAULT);
|
||||
return mapInlineClassType(underlyingType, TypeMappingMode.DEFAULT, staticTypeMappingConfiguration);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Type mapInlineClassType(@NotNull KotlinType kotlinType) {
|
||||
return mapInlineClassType(kotlinType, TypeMappingMode.DEFAULT);
|
||||
private Type mapInlineClassType(@NotNull KotlinType kotlinType) {
|
||||
return mapInlineClassType(kotlinType, TypeMappingMode.DEFAULT, typeMappingConfiguration);
|
||||
}
|
||||
|
||||
private static Type mapInlineClassType(
|
||||
@NotNull KotlinType kotlinType,
|
||||
@NotNull TypeMappingMode mode
|
||||
@NotNull TypeMappingMode mode,
|
||||
@NotNull TypeMappingConfiguration<Type> configuration
|
||||
) {
|
||||
return TypeSignatureMappingKt.mapType(
|
||||
kotlinType, AsmTypeFactory.INSTANCE, mode, staticTypeMappingConfiguration, null,
|
||||
kotlinType, AsmTypeFactory.INSTANCE, mode, configuration, null,
|
||||
(ktType, asmType, typeMappingMode) -> Unit.INSTANCE,
|
||||
false
|
||||
);
|
||||
@@ -1400,7 +1404,7 @@ public class KotlinTypeMapper {
|
||||
* In that case the generated method's return type should be boxed: otherwise it's not possible to use
|
||||
* this class from Java since javac issues errors when loading the class (incompatible return types)
|
||||
*/
|
||||
private static boolean forceBoxedReturnType(@NotNull FunctionDescriptor descriptor) {
|
||||
private boolean forceBoxedReturnType(@NotNull FunctionDescriptor descriptor) {
|
||||
if (isBoxMethodForInlineClass(descriptor)) return true;
|
||||
|
||||
//noinspection ConstantConditions
|
||||
@@ -1414,7 +1418,7 @@ public class KotlinTypeMapper {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isJvmPrimitive(@NotNull KotlinType kotlinType) {
|
||||
private boolean isJvmPrimitive(@NotNull KotlinType kotlinType) {
|
||||
if (KotlinBuiltIns.isPrimitiveType(kotlinType)) return true;
|
||||
|
||||
if (InlineClassesUtilsKt.isInlineClassType(kotlinType) && !KotlinTypeKt.isError(kotlinType)) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.firstOverridden
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor
|
||||
import org.jetbrains.kotlin.resolve.isInlineClassType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.getEffectiveVariance
|
||||
@@ -78,12 +79,19 @@ private val METHODS_WITH_DECLARATION_SITE_WILDCARDS = setOf(
|
||||
fun TypeMappingMode.updateArgumentModeFromAnnotations(type: KotlinType): TypeMappingMode {
|
||||
type.suppressWildcardsMode()?.let {
|
||||
return TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode(
|
||||
skipDeclarationSiteWildcards = it, isForAnnotationParameter = isForAnnotationParameter)
|
||||
skipDeclarationSiteWildcards = it,
|
||||
isForAnnotationParameter = isForAnnotationParameter,
|
||||
needInlineClassWrapping = needInlineClassWrapping
|
||||
)
|
||||
}
|
||||
|
||||
if (type.annotations.hasAnnotation(JVM_WILDCARD_ANNOTATION_FQ_NAME)) {
|
||||
return TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode(
|
||||
skipDeclarationSiteWildcards = false, isForAnnotationParameter = isForAnnotationParameter, fallbackMode = this)
|
||||
skipDeclarationSiteWildcards = false,
|
||||
isForAnnotationParameter = isForAnnotationParameter,
|
||||
fallbackMode = this,
|
||||
needInlineClassWrapping = needInlineClassWrapping
|
||||
)
|
||||
}
|
||||
|
||||
return this
|
||||
@@ -97,7 +105,10 @@ internal fun extractTypeMappingModeFromAnnotation(
|
||||
(outerType.suppressWildcardsMode() ?: callableDescriptor?.suppressWildcardsMode())?.let {
|
||||
if (outerType.arguments.isNotEmpty())
|
||||
TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode(
|
||||
skipDeclarationSiteWildcards = it, isForAnnotationParameter = isForAnnotationParameter)
|
||||
skipDeclarationSiteWildcards = it,
|
||||
isForAnnotationParameter = isForAnnotationParameter,
|
||||
needInlineClassWrapping = !outerType.isInlineClassType()
|
||||
)
|
||||
else
|
||||
TypeMappingMode.DEFAULT
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ abstract class SwitchCodegen(
|
||||
v.mark(endLabel)
|
||||
|
||||
subjectVariableDescriptor?.let {
|
||||
codegen.frameMap.leave(it)
|
||||
v.visitLocalVariable(
|
||||
it.name.asString(), subjectType.descriptor, null,
|
||||
beginLabel, endLabel, subjectLocal
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.cli.common.arguments
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
|
||||
object CliArgumentStringBuilder {
|
||||
private const val languagePrefix = "-XXLanguage:"
|
||||
|
||||
private val LanguageFeature.State.sign: String
|
||||
get() = when (this) {
|
||||
LanguageFeature.State.ENABLED -> "+"
|
||||
LanguageFeature.State.DISABLED -> "-"
|
||||
LanguageFeature.State.ENABLED_WITH_WARNING -> "+" // not supported normally
|
||||
LanguageFeature.State.ENABLED_WITH_ERROR -> "-" // not supported normally
|
||||
}
|
||||
|
||||
fun LanguageFeature.buildArgumentString(state: LanguageFeature.State): String {
|
||||
return "$languagePrefix${state.sign}$name"
|
||||
}
|
||||
|
||||
fun String.replaceLanguageFeature(
|
||||
feature: LanguageFeature,
|
||||
state: LanguageFeature.State,
|
||||
prefix: String = "",
|
||||
postfix: String = "",
|
||||
separator: String = ", ",
|
||||
quoted: Boolean = true
|
||||
): String {
|
||||
val existingFeatureIndex = indexOf(feature.name)
|
||||
val languagePrefixIndex = lastIndexOf(languagePrefix, existingFeatureIndex)
|
||||
val featureArgumentString = feature.buildArgumentString(state)
|
||||
val quote = if (quoted) "\"" else ""
|
||||
return if (languagePrefixIndex != -1) {
|
||||
replaceRange(languagePrefixIndex, existingFeatureIndex + feature.name.length, featureArgumentString)
|
||||
} else {
|
||||
val splitText = if (postfix.isNotEmpty()) split(postfix) else listOf(this, "")
|
||||
if (splitText.size != 2) {
|
||||
"$prefix$quote$featureArgumentString$quote$postfix"
|
||||
} else {
|
||||
val (mainPart, commentPart) = splitText
|
||||
// In Groovy / Kotlin DSL, we can have comment after [...] or listOf(...)
|
||||
mainPart + "$separator$quote$featureArgumentString$quote$postfix" + commentPart
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli.common.arguments
|
||||
|
||||
import java.io.Serializable
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
abstract class Freezable {
|
||||
protected open inner class FreezableVar<T>(private var value: T) : ReadWriteProperty<Any, T> {
|
||||
protected open inner class FreezableVar<T>(private var value: T) : ReadWriteProperty<Any, T>, Serializable {
|
||||
override fun getValue(thisRef: Any, property: KProperty<*>) = value
|
||||
|
||||
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
|
||||
|
||||
@@ -110,7 +110,9 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
||||
@Argument(
|
||||
value = "-Xnormalize-constructor-calls",
|
||||
valueDescription = "{disable|enable}",
|
||||
description = "Normalize constructor calls (disable: don't normalize; enable: normalize), default is disable"
|
||||
description = "Normalize constructor calls (disable: don't normalize; enable: normalize),\n" +
|
||||
"default is 'disable' in language version 1.2 and below,\n" +
|
||||
"'enable' since language version 1.3"
|
||||
)
|
||||
var constructorCallNormalizationMode: String? by NullableStringFreezableVar(null)
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@ private const val EXPERIMENTAL_ARGFILE_ARGUMENT = "-Xargfile="
|
||||
private const val SINGLE_QUOTE = '\''
|
||||
private const val DOUBLE_QUOTE = '"'
|
||||
private const val BACKSLASH = '\\'
|
||||
private const val WHITESPACE = ' '
|
||||
private const val NEWLINE = '\n'
|
||||
|
||||
/**
|
||||
* Performs initial preprocessing of arguments, passed to the compiler.
|
||||
@@ -56,13 +54,14 @@ private fun Reader.parseNextArgument(): String? {
|
||||
val sb = StringBuilder()
|
||||
|
||||
var r = nextChar()
|
||||
while (r != null && (r == WHITESPACE || r == NEWLINE)) {
|
||||
while (r != null && r.isWhitespace()) {
|
||||
r = nextChar()
|
||||
}
|
||||
|
||||
loop@ while (r != null) {
|
||||
while (r != null) {
|
||||
if (r.isWhitespace()) break
|
||||
|
||||
when (r) {
|
||||
WHITESPACE, NEWLINE -> break@loop
|
||||
DOUBLE_QUOTE, SINGLE_QUOTE -> consumeRestOfEscapedSequence(sb, r)
|
||||
BACKSLASH -> nextChar()?.apply(sb::append)
|
||||
else -> sb.append(r)
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.vfs.impl.ZipHandler
|
||||
import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
|
||||
import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
|
||||
import org.jetbrains.kotlin.build.JvmSourceRoot
|
||||
import org.jetbrains.kotlin.cli.common.CLICompiler
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
@@ -559,6 +560,13 @@ class CompileServiceImpl(
|
||||
k2jvmArgs.commonSources = parsedModule.modules.flatMap { it.getCommonSourceFiles() }.toTypedArray().takeUnless { it.isEmpty() }
|
||||
|
||||
val allKotlinFiles = parsedModule.modules.flatMap { it.getSourceFiles().map(::File) }
|
||||
val allKotlinExtensions = (
|
||||
DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS +
|
||||
allKotlinFiles.asSequence()
|
||||
.map { it.extension }
|
||||
.filter { !it.equals("java", ignoreCase = true) }
|
||||
.asIterable()
|
||||
).distinct()
|
||||
k2jvmArgs.friendPaths = parsedModule.modules.flatMap(Module::getFriendPaths).toTypedArray()
|
||||
|
||||
val changedFiles = if (incrementalCompilationOptions.areFileChangesKnown) {
|
||||
@@ -592,7 +600,8 @@ class CompileServiceImpl(
|
||||
buildHistoryFile = incrementalCompilationOptions.multiModuleICSettings.buildHistoryFile,
|
||||
localStateDirs = incrementalCompilationOptions.localStateDirs,
|
||||
usePreciseJavaTracking = incrementalCompilationOptions.usePreciseJavaTracking,
|
||||
modulesApiHistory = modulesApiHistory
|
||||
modulesApiHistory = modulesApiHistory,
|
||||
kotlinSourceFilesExtensions = allKotlinExtensions
|
||||
)
|
||||
return compiler.compile(allKotlinFiles, k2jvmArgs, compilerMessageCollector, changedFiles)
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ public class SingleAbstractMethodUtils {
|
||||
// Otherwise android data binding can cause resolve re-entrance
|
||||
// For details see KT-18687, KT-16149
|
||||
// TODO: prevent resolve re-entrance on architecture level, or (alternatively) ask data binding owners not to do it
|
||||
if (DescriptorUtilsKt.getFqNameSafe(klass).asString().equals("android.databinding.DataBindingComponent")) {
|
||||
if (DescriptorUtilsKt.getFqNameSafe(klass).asString().endsWith(".databinding.DataBindingComponent")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -281,18 +281,19 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass {
|
||||
return resolveNameByInternalName(name, innerClasses);
|
||||
}
|
||||
|
||||
// See ReflectKotlinStructure.classLiteralValue
|
||||
@NotNull
|
||||
private static ClassLiteralId resolveKotlinNameByType(@NotNull Type type, @NotNull InnerClassesInfo innerClasses) {
|
||||
String typeDesc = type.getDescriptor();
|
||||
int nestedness = typeDesc.charAt(0) == '[' ? type.getDimensions() : 0;
|
||||
String elementDesc = nestedness == 0 ? typeDesc : type.getElementType().getDescriptor();
|
||||
int dimensions = typeDesc.charAt(0) == '[' ? type.getDimensions() : 0;
|
||||
String elementDesc = dimensions == 0 ? typeDesc : type.getElementType().getDescriptor();
|
||||
JvmPrimitiveType primType = JvmPrimitiveType.getByDesc(elementDesc);
|
||||
if (primType != null) {
|
||||
return new ClassLiteralId(ClassId.topLevel(primType.getPrimitiveType().getTypeFqName()), nestedness);
|
||||
return new ClassLiteralId(ClassId.topLevel(primType.getPrimitiveType().getTypeFqName()), dimensions);
|
||||
}
|
||||
ClassId javaClassId = resolveNameByDesc(elementDesc, innerClasses);
|
||||
ClassId kotlinClassId = JavaToKotlinClassMap.INSTANCE.mapJavaToKotlin(javaClassId.asSingleFqName());
|
||||
return new ClassLiteralId(kotlinClassId != null ? kotlinClassId : javaClassId, nestedness);
|
||||
return new ClassLiteralId(kotlinClassId != null ? kotlinClassId : javaClassId, dimensions);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.resolve.jvm.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.isTopLevelInPackage
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
||||
import org.jetbrains.kotlin.psi.KtValueArgumentList
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.findEnclosingSuspendFunction
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
|
||||
class SuspensionPointInSynchronizedCallChecker : CallChecker {
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
val descriptor = resolvedCall.candidateDescriptor
|
||||
if (descriptor !is FunctionDescriptor || !descriptor.isSuspend) return
|
||||
|
||||
val enclosingSuspendFunctionSource = findEnclosingSuspendFunction(context)?.source?.getPsi() ?: return
|
||||
|
||||
// Search for `synchronized` call
|
||||
var parent = reportOn
|
||||
var child = reportOn
|
||||
var insideLambda = false
|
||||
while (parent != enclosingSuspendFunctionSource) {
|
||||
if (parent is KtCallExpression) {
|
||||
if (checkCall(context, parent, child, insideLambda, reportOn, resolvedCall)) break
|
||||
}
|
||||
if (parent is KtLambdaExpression) {
|
||||
insideLambda = true
|
||||
}
|
||||
// The lambda is inside parentheses -> keep the child the same to check whether it is the second argument
|
||||
if (parent !is KtValueArgumentList) {
|
||||
child = parent
|
||||
}
|
||||
// parent.parent can be null if we edit the file, see EA-2158254 and KT-27484
|
||||
parent = parent.parent ?: return
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkCall(
|
||||
context: CallCheckerContext,
|
||||
parent: KtCallExpression,
|
||||
child: PsiElement,
|
||||
insideLambda: Boolean,
|
||||
reportOn: PsiElement,
|
||||
resolvedCall: ResolvedCall<*>
|
||||
): Boolean {
|
||||
val call = context.trace[BindingContext.CALL, parent.calleeExpression] ?: return false
|
||||
val resolved = context.trace[BindingContext.RESOLVED_CALL, call] ?: return false
|
||||
val isSynchronized = resolved.resultingDescriptor.isTopLevelInPackage("synchronized", "kotlin")
|
||||
if (isSynchronized) {
|
||||
val isSecondArgument = (resolved.valueArgumentsByIndex?.get(1) as? ExpressionValueArgument)?.valueArgument == child
|
||||
if (insideLambda && isSecondArgument) {
|
||||
context.trace.report(ErrorsJvm.SUSPENSION_POINT_INSIDE_SYNCHRONIZED.on(reportOn, resolvedCall.resultingDescriptor))
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.resolve.jvm.diagnostics;
|
||||
@@ -147,6 +136,8 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
|
||||
MAP.put(USAGE_OF_JVM_DEFAULT_THROUGH_SUPER_CALL, "Super calls of '@JvmDefault' members are only allowed with -Xjvm-default option");
|
||||
MAP.put(NON_JVM_DEFAULT_OVERRIDES_JAVA_DEFAULT, "Non-@JvmDefault interface method cannot override default Java method. Please annotate this method with @JvmDefault");
|
||||
MAP.put(EXPLICIT_METADATA_IS_DISALLOWED, "Explicit @Metadata is disallowed");
|
||||
MAP.put(SUSPENSION_POINT_INSIDE_MONITOR, "A suspension point at {0} is inside a critical section", STRING);
|
||||
MAP.put(SUSPENSION_POINT_INSIDE_SYNCHRONIZED, "The ''{0}'' suspension point is inside a synchronized block", NAME);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -1,22 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.resolve.jvm.diagnostics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.diagnostics.*;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
@@ -132,6 +122,9 @@ public interface ErrorsJvm {
|
||||
|
||||
DiagnosticFactory1<KtAnnotationEntry, String> ANNOTATION_TARGETS_NON_EXISTENT_ACCESSOR = DiagnosticFactory1.create(WARNING);
|
||||
|
||||
DiagnosticFactory1<PsiElement, String> SUSPENSION_POINT_INSIDE_MONITOR = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, CallableDescriptor> SUSPENSION_POINT_INSIDE_SYNCHRONIZED = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
Object _initializer = new Object() {
|
||||
{
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.resolve.jvm.platform
|
||||
@@ -52,6 +41,7 @@ object JvmPlatformConfigurator : PlatformConfigurator(
|
||||
|
||||
additionalCallCheckers = listOf(
|
||||
JavaAnnotationCallChecker(),
|
||||
SuspensionPointInSynchronizedCallChecker(),
|
||||
JavaClassOnCompanionChecker(),
|
||||
ProtectedInSuperClassCompanionCallChecker(),
|
||||
UnsupportedSyntheticCallableReferenceChecker(),
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.script
|
||||
|
||||
import kotlinx.coroutines.experimental.runBlocking
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlin.script.experimental.dependencies.DependenciesResolver
|
||||
import kotlin.script.dependencies.Environment
|
||||
import kotlin.script.dependencies.ScriptContents
|
||||
|
||||
@@ -45,7 +45,6 @@ import org.jetbrains.kotlin.resolve.TargetPlatform
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.storage.getValue
|
||||
import java.util.*
|
||||
import kotlin.coroutines.experimental.buildSequence
|
||||
|
||||
class ResolverForModule(
|
||||
val packageFragmentProvider: PackageFragmentProvider,
|
||||
@@ -346,7 +345,7 @@ class LazyModuleDependencies<M : ModuleInfo>(
|
||||
) : ModuleDependencies {
|
||||
private val dependencies = storageManager.createLazyValue {
|
||||
val moduleDescriptor = resolverForProject.descriptorForModule(module)
|
||||
buildSequence {
|
||||
sequence {
|
||||
if (firstDependency != null) {
|
||||
yield(resolverForProject.descriptorForModule(firstDependency))
|
||||
}
|
||||
@@ -502,4 +501,7 @@ private object DiagnoseUnknownModuleInfoReporter {
|
||||
private fun errorInSpecialModuleInfoResolver(message: String): Nothing = throw AssertionError(message)
|
||||
|
||||
private fun otherError(message: String): Nothing = throw AssertionError(message)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> ModuleInfo.getCapability(capability: ModuleDescriptor.Capability<T>) = capabilities[capability] as? T
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.container.useImpl
|
||||
import org.jetbrains.kotlin.container.useInstance
|
||||
import org.jetbrains.kotlin.context.ModuleContext
|
||||
import org.jetbrains.kotlin.context.ProjectContext
|
||||
import org.jetbrains.kotlin.contracts.ContractDeserializerImpl
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
@@ -165,6 +166,7 @@ object CommonAnalyzerFacade : ResolverForModuleFactory() {
|
||||
useInstance(metadataPartProvider)
|
||||
useInstance(declarationProviderFactory)
|
||||
useImpl<MetadataPackageFragmentProvider>()
|
||||
useImpl<ContractDeserializerImpl>()
|
||||
|
||||
val metadataFinderFactory = ServiceManager.getService(moduleContext.project, MetadataFinderFactory::class.java)
|
||||
?: error("No MetadataFinderFactory in project")
|
||||
|
||||
@@ -23,7 +23,22 @@ import org.jetbrains.kotlin.descriptors.ValueDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
|
||||
|
||||
class ESDataFlowValue(descriptor: ValueDescriptor, val dataFlowValue: DataFlowValue) : ESVariable(descriptor)
|
||||
class ESDataFlowValue(descriptor: ValueDescriptor, val dataFlowValue: DataFlowValue) : ESVariable(descriptor) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as ESDataFlowValue
|
||||
|
||||
if (dataFlowValue != other.dataFlowValue) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return dataFlowValue.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
class ESLambda(val lambda: KtLambdaExpression) : ESValue(null) {
|
||||
override fun <T> accept(visitor: ESExpressionVisitor<T>): T {
|
||||
|
||||
@@ -34,29 +34,43 @@ import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind
|
||||
|
||||
class ContractParsingServices(val languageVersionSettings: LanguageVersionSettings) {
|
||||
/**
|
||||
* ! IMPORTANT NOTICE !
|
||||
*
|
||||
* This function has very important non-obvious implicit contract:
|
||||
* it *must* call [org.jetbrains.kotlin.contracts.description.LazyContractProvider.setContractDescription]
|
||||
* if FunctionDescriptor had [LazyContractProvider] in the user data.
|
||||
*
|
||||
* Otherwise, it may lead to inconsistent resolve state and failed assertions
|
||||
*/
|
||||
fun checkContractAndRecordIfPresent(expression: KtExpression, trace: BindingTrace, scope: LexicalScope, isFirstStatement: Boolean) {
|
||||
if (!expression.isContractDescriptionCallPsiCheck()) return // fastpath
|
||||
// Fastpath. Note that it doesn't violates invariant described in KDoc, because 'isContractDescriptionCallPsiCheck'
|
||||
// is a *necessary* (but not sufficient, actually) condition for presence of 'LazyContractProvider'
|
||||
if (!expression.isContractDescriptionCallPsiCheck()) return
|
||||
|
||||
val collector = TraceBasedCollector(trace, expression)
|
||||
val callContext = ContractCallContext(expression, isFirstStatement, scope, trace.bindingContext)
|
||||
val contractProviderIfAny = (scope.ownerDescriptor as? FunctionDescriptor)?.getUserData(ContractProviderKey)
|
||||
|
||||
if (!callContext.isContractDescriptionCallPreciseCheck()) {
|
||||
contractProviderIfAny?.setContractDescription(null)
|
||||
return
|
||||
}
|
||||
|
||||
val parsedContract = doCheckContract(collector, callContext)
|
||||
|
||||
collector.flushDiagnostics(parsingFailed = parsedContract == null)
|
||||
|
||||
val contractProviderIfAny = (scope.ownerDescriptor as? FunctionDescriptor)?.getUserData(ContractProviderKey)
|
||||
|
||||
if (collector.hasErrors())
|
||||
contractProviderIfAny?.setContractDescription(null)
|
||||
else
|
||||
contractProviderIfAny?.setContractDescription(parsedContract)
|
||||
}
|
||||
|
||||
private fun ContractCallContext.isContractDescriptionCallPreciseCheck(): Boolean =
|
||||
contractCallExpression.isContractDescriptionCallPreciseCheck(bindingContext)
|
||||
|
||||
private fun doCheckContract(collector: ContractParsingDiagnosticsCollector, callContext: ContractCallContext): ContractDescription? {
|
||||
val expression = callContext.contractCallExpression
|
||||
val bindingContext = callContext.bindingContext
|
||||
|
||||
if (!expression.isContractDescriptionCallPreciseCheck(bindingContext)) return null
|
||||
|
||||
checkFeatureEnabled(collector)
|
||||
checkContractAllowedHere(collector, callContext)
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ fun DeclarationDescriptor.isCallsInPlaceEffectDescriptor(): Boolean = equalsDslD
|
||||
fun DeclarationDescriptor.isInvocationKindEnum(): Boolean = equalsDslDescriptor(INVOCATION_KIND_ENUM)
|
||||
|
||||
fun DeclarationDescriptor.isEqualsDescriptor(): Boolean =
|
||||
this is FunctionDescriptor && this.name == Name.identifier("equals") && // fast checks
|
||||
this is FunctionDescriptor && this.name == Name.identifier("equals") && dispatchReceiverParameter != null && // fast checks
|
||||
this.returnType?.isBoolean() == true && this.valueParameters.singleOrNull()?.type?.isNullableAny() == true // signature matches
|
||||
|
||||
internal fun ResolvedCall<*>.firstArgumentAsExpressionOrNull(): KtExpression? =
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.coroutines
|
||||
|
||||
import org.jetbrains.kotlin.builtins.isFunctionOrSuspendFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
@@ -24,3 +25,5 @@ import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
||||
val CallableDescriptor.isSuspendLambda get() = this is AnonymousFunctionDescriptor && this.isSuspend
|
||||
|
||||
val ValueParameterDescriptor.hasSuspendFunctionType get() = returnType?.isSuspendFunctionType == true
|
||||
|
||||
val ValueParameterDescriptor.hasFunctionOrSuspendFunctionType get() = returnType?.isFunctionOrSuspendFunctionType == true
|
||||
|
||||
@@ -244,7 +244,7 @@ public interface Errors {
|
||||
DiagnosticFactory2<PsiElement, FqName, DeclarationDescriptor> EXPERIMENTAL_OVERRIDE = DiagnosticFactory2.create(WARNING);
|
||||
DiagnosticFactory2<PsiElement, FqName, DeclarationDescriptor> EXPERIMENTAL_OVERRIDE_ERROR = DiagnosticFactory2.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<PsiElement> EXPERIMENTAL_IS_NOT_ENABLED = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> EXPERIMENTAL_IS_NOT_ENABLED = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> EXPERIMENTAL_CAN_ONLY_BE_USED_AS_ANNOTATION = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement>
|
||||
EXPERIMENTAL_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_USE_EXPERIMENTAL = DiagnosticFactory0.create(ERROR);
|
||||
@@ -788,6 +788,8 @@ public interface Errors {
|
||||
DiagnosticFactory3<KtBinaryExpression, KtSimpleNameExpression, KotlinType, KotlinType> EQUALITY_NOT_APPLICABLE =
|
||||
DiagnosticFactory3.create(ERROR);
|
||||
|
||||
DiagnosticFactory2<KtElement, KotlinType, KotlinType> INCOMPATIBLE_ENUM_COMPARISON =
|
||||
DiagnosticFactory2.create(WARNING);
|
||||
|
||||
DiagnosticFactory1<KtExpression, KotlinType> HAS_NEXT_MISSING = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<KtExpression, KotlinType> HAS_NEXT_FUNCTION_AMBIGUITY = DiagnosticFactory1.create(ERROR);
|
||||
@@ -1037,6 +1039,7 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtDeclaration> OVERRIDE_BY_INLINE = DiagnosticFactory0.create(WARNING, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<PsiElement> REIFIED_TYPE_PARAMETER_IN_OVERRIDE = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, CallableDescriptor> INLINE_CALL_CYCLE = DiagnosticFactory1.create(ERROR, DEFAULT);
|
||||
DiagnosticFactory1<PsiElement, CallableDescriptor> SUSPENSION_POINT_INSIDE_MONITOR = DiagnosticFactory1.create(ERROR, DEFAULT);
|
||||
DiagnosticFactory0<PsiElement> NON_LOCAL_RETURN_IN_DISABLED_INLINE = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtDeclaration> INLINE_PROPERTY_WITH_BACKING_FIELD = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtAnnotationEntry> NON_INTERNAL_PUBLISHED_API = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
@@ -729,6 +729,8 @@ public class DefaultErrorMessages {
|
||||
return nameExpression.getReferencedName();
|
||||
}, RENDER_TYPE, RENDER_TYPE);
|
||||
|
||||
MAP.put(INCOMPATIBLE_ENUM_COMPARISON, "Comparison of incompatible enums ''{0}'' and ''{1}'' is always unsuccessful", RENDER_TYPE, RENDER_TYPE);
|
||||
|
||||
MAP.put(SENSELESS_COMPARISON, "Condition ''{0}'' is always ''{1}''", ELEMENT_TEXT, TO_STRING);
|
||||
MAP.put(SENSELESS_NULL_IN_WHEN, "Expression under 'when' is never equal to null");
|
||||
|
||||
@@ -934,6 +936,7 @@ public class DefaultErrorMessages {
|
||||
//Inline non locals
|
||||
MAP.put(NON_LOCAL_RETURN_NOT_ALLOWED, "Can''t inline ''{0}'' here: it may contain non-local returns. Add ''crossinline'' modifier to parameter declaration ''{0}''", ELEMENT_TEXT);
|
||||
MAP.put(INLINE_CALL_CYCLE, "The ''{0}'' invocation is a part of inline cycle", NAME);
|
||||
MAP.put(SUSPENSION_POINT_INSIDE_MONITOR, "The ''{0}'' suspension point is inside a critical section", NAME);
|
||||
MAP.put(NON_LOCAL_RETURN_IN_DISABLED_INLINE, "Non-local returns are not allowed with inlining disabled");
|
||||
MAP.put(NON_LOCAL_SUSPENSION_POINT, "Suspension functions can be called only within coroutine body");
|
||||
MAP.put(ILLEGAL_SUSPEND_FUNCTION_CALL, "Suspend function ''{0}'' should be called only from a coroutine or another suspend function", NAME);
|
||||
|
||||
@@ -42,3 +42,6 @@ fun AnnotationDescriptor.argumentValue(parameterName: String): ConstantValue<*>?
|
||||
DeprecationLevel.ERROR
|
||||
)
|
||||
val JVM_FIELD_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmField")
|
||||
|
||||
val KOTLINX_SERIALIZABLE_FQ_NAME = FqName("kotlinx.serialization.Serializable")
|
||||
val KOTLINX_SERIALIZER_FQ_NAME = FqName("kotlinx.serialization.Serializer")
|
||||
|
||||
@@ -198,10 +198,14 @@ public class BindingContextUtils {
|
||||
return expression instanceof KtReferenceExpression;
|
||||
}
|
||||
|
||||
public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) {
|
||||
public static boolean isCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof VariableDescriptor) || descriptor instanceof PropertyDescriptor) return false;
|
||||
VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
|
||||
return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null && variableDescriptor.isVar();
|
||||
return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null;
|
||||
}
|
||||
|
||||
public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) {
|
||||
return isCapturedInClosure(bindingContext, descriptor) && ((VariableDescriptor) descriptor).isVar();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -55,7 +55,9 @@ class OverloadChecker(val specificityComparator: TypeSpecificityComparator) {
|
||||
// They can be disambiguated by providing explicit type parameters.
|
||||
if (a.typeParameters.isEmpty() != b.typeParameters.isEmpty()) return true
|
||||
|
||||
if (ErrorUtils.containsErrorType(a) || ErrorUtils.containsErrorType(b)) return true
|
||||
if (a is FunctionDescriptor && ErrorUtils.containsErrorTypeInParameters(a) ||
|
||||
b is FunctionDescriptor && ErrorUtils.containsErrorTypeInParameters(b)
|
||||
) return true
|
||||
if (a.varargParameterPosition() != b.varargParameterPosition()) return true
|
||||
|
||||
val aSignature = FlatSignature.createFromCallableDescriptor(a)
|
||||
|
||||
@@ -414,7 +414,7 @@ class GenericCandidateResolver(
|
||||
|
||||
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
|
||||
|
||||
if (isCoroutineCallWithAdditionalInference(valueParameterDescriptor, valueArgument)) {
|
||||
if (isCoroutineCallWithAdditionalInference(valueParameterDescriptor, valueArgument, languageVersionSettings)) {
|
||||
coroutineInferenceSupport.analyzeCoroutine(functionLiteral, valueArgument, constraintSystem, context, effectiveExpectedType)
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ class ResultTypeWithNullableOperatorsChecker : CallChecker {
|
||||
|
||||
when {
|
||||
operationNode?.elementType == KtTokens.SAFE_ACCESS -> {
|
||||
val receiver = resolvedCall.resultingDescriptor.dispatchReceiverParameter ?: return
|
||||
val resultingDescriptor = resolvedCall.resultingDescriptor
|
||||
val receiver = resultingDescriptor.extensionReceiverParameter ?: resultingDescriptor.dispatchReceiverParameter ?: return
|
||||
if (receiver.type.isResultType()) {
|
||||
context.trace.report(Errors.RESULT_CLASS_WITH_NULLABLE_OPERATOR.on(operationNode!!.psi, "?."))
|
||||
}
|
||||
|
||||
@@ -46,9 +46,15 @@ fun FunctionDescriptor.isBuiltInCoroutineContext(languageVersionSettings: Langua
|
||||
fun PropertyDescriptor.isBuiltInCoroutineContext(languageVersionSettings: LanguageVersionSettings) =
|
||||
this.fqNameSafe.isBuiltInCoroutineContext(languageVersionSettings)
|
||||
|
||||
object CoroutineSuspendCallChecker : CallChecker {
|
||||
private val ALLOWED_SCOPE_KINDS = setOf(LexicalScopeKind.FUNCTION_INNER_SCOPE, LexicalScopeKind.FUNCTION_HEADER_FOR_DESTRUCTURING)
|
||||
private val ALLOWED_SCOPE_KINDS = setOf(LexicalScopeKind.FUNCTION_INNER_SCOPE, LexicalScopeKind.FUNCTION_HEADER_FOR_DESTRUCTURING)
|
||||
|
||||
fun findEnclosingSuspendFunction(context: CallCheckerContext): FunctionDescriptor? = context.scope
|
||||
.parentsWithSelf.firstOrNull {
|
||||
it is LexicalScope && it.kind in ALLOWED_SCOPE_KINDS &&
|
||||
it.ownerDescriptor.safeAs<FunctionDescriptor>()?.isSuspend == true
|
||||
}?.cast<LexicalScope>()?.ownerDescriptor?.cast()
|
||||
|
||||
object CoroutineSuspendCallChecker : CallChecker {
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
val descriptor = resolvedCall.candidateDescriptor
|
||||
when (descriptor) {
|
||||
@@ -61,11 +67,7 @@ object CoroutineSuspendCallChecker : CallChecker {
|
||||
else -> return
|
||||
}
|
||||
|
||||
val enclosingSuspendFunction = context.scope
|
||||
.parentsWithSelf.firstOrNull {
|
||||
it is LexicalScope && it.kind in ALLOWED_SCOPE_KINDS &&
|
||||
it.ownerDescriptor.safeAs<FunctionDescriptor>()?.isSuspend == true
|
||||
}?.cast<LexicalScope>()?.ownerDescriptor?.cast<FunctionDescriptor>()
|
||||
val enclosingSuspendFunction = findEnclosingSuspendFunction(context)
|
||||
|
||||
when {
|
||||
enclosingSuspendFunction != null -> {
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
package org.jetbrains.kotlin.resolve.calls.inference
|
||||
|
||||
import org.jetbrains.kotlin.builtins.*
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.coroutines.hasFunctionOrSuspendFunctionType
|
||||
import org.jetbrains.kotlin.coroutines.hasSuspendFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
@@ -31,6 +34,8 @@ import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasBuilderInferenceAnnotation
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE
|
||||
@@ -38,9 +43,7 @@ import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.checker.TypeCheckerContext
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class TypeTemplate(
|
||||
@@ -82,8 +85,28 @@ class CoroutineInferenceData {
|
||||
} ?: type
|
||||
}
|
||||
|
||||
fun addConstraint(subType: KotlinType, superType: KotlinType) {
|
||||
csBuilder.addSubtypeConstraint(toNewVariableType(subType), toNewVariableType(superType), ConstraintPositionKind.SPECIAL.position())
|
||||
internal fun addConstraint(subType: KotlinType, superType: KotlinType, allowOnlyTrivialConstraints: Boolean) {
|
||||
val newSubType = toNewVariableType(subType)
|
||||
val newSuperType = toNewVariableType(superType)
|
||||
|
||||
if (allowOnlyTrivialConstraints) {
|
||||
if (isTrivialConstraint(subType, superType)) {
|
||||
// It's important to avoid adding even trivial constraints from extensions,
|
||||
// because we allow only calls that don't matter at all and here we can get
|
||||
// into a situation when type is inferred from only trivial constraints to Any?, for example.
|
||||
|
||||
// Actually, this is a more general problem about inferring type without constraints (KT-5464)
|
||||
return
|
||||
} else {
|
||||
badCallHappened()
|
||||
}
|
||||
}
|
||||
|
||||
csBuilder.addSubtypeConstraint(newSubType, newSuperType, ConstraintPositionKind.SPECIAL.position())
|
||||
}
|
||||
|
||||
private fun isTrivialConstraint(subType: KotlinType, superType: KotlinType): Boolean {
|
||||
return subType is SimpleType && subType.isNothing() || superType is SimpleType && superType.isNullableAny()
|
||||
}
|
||||
|
||||
fun reportInferenceResult(externalCSBuilder: ConstraintSystem.Builder) {
|
||||
@@ -110,6 +133,8 @@ class CoroutineInferenceSupport(
|
||||
@set:Inject
|
||||
lateinit var callCompleter: CallCompleter
|
||||
|
||||
private val languageVersionSettings get() = expressionTypingServices.languageVersionSettings
|
||||
|
||||
fun analyzeCoroutine(
|
||||
functionLiteral: KtFunction,
|
||||
valueArgument: ValueArgument,
|
||||
@@ -118,7 +143,8 @@ class CoroutineInferenceSupport(
|
||||
lambdaExpectedType: KotlinType
|
||||
) {
|
||||
val argumentExpression = valueArgument.getArgumentExpression() ?: return
|
||||
if (!lambdaExpectedType.isSuspendFunctionType) return
|
||||
if (!checkExpectedTypeForArgument(lambdaExpectedType)) return
|
||||
|
||||
val lambdaReceiverType = lambdaExpectedType.getReceiverTypeFromFunctionType() ?: return
|
||||
|
||||
val inferenceData = CoroutineInferenceData()
|
||||
@@ -172,6 +198,13 @@ class CoroutineInferenceSupport(
|
||||
inferenceData.reportInferenceResult(csBuilder)
|
||||
}
|
||||
|
||||
private fun checkExpectedTypeForArgument(expectedType: KotlinType): Boolean {
|
||||
return if (languageVersionSettings.supportsFeature(LanguageFeature.ExperimentalBuilderInference))
|
||||
expectedType.isFunctionOrSuspendFunctionType
|
||||
else
|
||||
expectedType.isSuspendFunctionType
|
||||
}
|
||||
|
||||
fun checkCoroutineCalls(
|
||||
context: BasicCallResolutionContext,
|
||||
tracingStrategy: TracingStrategy,
|
||||
@@ -186,45 +219,69 @@ class CoroutineInferenceSupport(
|
||||
callCompleter.completeCall(context, overloadResults, tracingStrategy)
|
||||
if (!resultingCall.isReallySuccess()) return
|
||||
|
||||
if (isBadCall(resultingCall.resultingDescriptor)) {
|
||||
val resultingDescriptor = resultingCall.resultingDescriptor
|
||||
if (!isGoodCall(resultingDescriptor)) {
|
||||
inferenceData.badCallHappened()
|
||||
}
|
||||
|
||||
forceInferenceForArguments(context) { valueArgument: ValueArgument, kotlinType: KotlinType ->
|
||||
val argumentMatch = resultingCall.getArgumentMapping(valueArgument) as? ArgumentMatch
|
||||
?: return@forceInferenceForArguments
|
||||
val argumentMatch = resultingCall.getArgumentMapping(valueArgument) as? ArgumentMatch ?: return@forceInferenceForArguments
|
||||
|
||||
with(NewKotlinTypeChecker) {
|
||||
val parameterType = getEffectiveExpectedType(argumentMatch.valueParameter, valueArgument, context)
|
||||
CoroutineTypeCheckerContext().isSubtypeOf(kotlinType.unwrap(), parameterType.unwrap())
|
||||
CoroutineTypeCheckerContext(allowOnlyTrivialConstraints = false).isSubtypeOf(kotlinType.unwrap(), parameterType.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
val extensionReceiver = resultingCall.resultingDescriptor.extensionReceiverParameter ?: return
|
||||
val extensionReceiver = resultingDescriptor.extensionReceiverParameter ?: return
|
||||
val allowOnlyTrivialConstraintsForReceiver =
|
||||
if (languageVersionSettings.supportsFeature(LanguageFeature.ExperimentalBuilderInference))
|
||||
!resultingDescriptor.hasBuilderInferenceAnnotation()
|
||||
else
|
||||
false
|
||||
|
||||
resultingCall.extensionReceiver?.let { actualReceiver ->
|
||||
with(NewKotlinTypeChecker) {
|
||||
CoroutineTypeCheckerContext().isSubtypeOf(actualReceiver.type.unwrap(), extensionReceiver.value.type.unwrap())
|
||||
CoroutineTypeCheckerContext(allowOnlyTrivialConstraints = allowOnlyTrivialConstraintsForReceiver).isSubtypeOf(
|
||||
actualReceiver.type.unwrap(), extensionReceiver.value.type.unwrap()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isBadCall(resultingDescriptor: CallableDescriptor): Boolean {
|
||||
fun KotlinType.containsTypeTemplate() = contains { it is TypeTemplate }
|
||||
private fun KotlinType.containsTypeTemplate() = contains { it is TypeTemplate }
|
||||
|
||||
val returnType = resultingDescriptor.returnType ?: return true
|
||||
if (returnType.containsTypeTemplate()) return true
|
||||
|
||||
if (resultingDescriptor !is FunctionDescriptor || resultingDescriptor.isSuspend) return false
|
||||
|
||||
for (valueParameter in resultingDescriptor.valueParameters) {
|
||||
if (valueParameter.type.containsTypeTemplate()) return true
|
||||
private fun isGoodCall(resultingDescriptor: CallableDescriptor): Boolean {
|
||||
if (!languageVersionSettings.supportsFeature(LanguageFeature.ExperimentalBuilderInference)) {
|
||||
return isGoodCallForOldCoroutines(resultingDescriptor)
|
||||
}
|
||||
return false
|
||||
|
||||
if (resultingDescriptor.isExtension && !resultingDescriptor.hasBuilderInferenceAnnotation()) {
|
||||
return resultingDescriptor.extensionReceiverParameter?.type?.containsTypeTemplate() == false
|
||||
}
|
||||
|
||||
val returnType = resultingDescriptor.returnType ?: return false
|
||||
return !returnType.containsTypeTemplate()
|
||||
}
|
||||
|
||||
private class CoroutineTypeCheckerContext : TypeCheckerContext(errorTypeEqualsToAnything = true) {
|
||||
private fun isGoodCallForOldCoroutines(resultingDescriptor: CallableDescriptor): Boolean {
|
||||
val returnType = resultingDescriptor.returnType ?: return false
|
||||
if (returnType.containsTypeTemplate()) return false
|
||||
|
||||
if (resultingDescriptor !is FunctionDescriptor || resultingDescriptor.isSuspend) return true
|
||||
|
||||
if (resultingDescriptor.valueParameters.any { it.type.containsTypeTemplate() }) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private class CoroutineTypeCheckerContext(
|
||||
private val allowOnlyTrivialConstraints: Boolean
|
||||
) : TypeCheckerContext(errorTypeEqualsToAnything = true) {
|
||||
|
||||
override fun addSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType): Boolean? {
|
||||
(subType as? TypeTemplate ?: superType as? TypeTemplate)?.coroutineInferenceData?.addConstraint(subType, superType)
|
||||
val typeTemplate = subType as? TypeTemplate ?: superType as? TypeTemplate
|
||||
typeTemplate?.coroutineInferenceData?.addConstraint(subType, superType, allowOnlyTrivialConstraints)
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -260,11 +317,20 @@ class CoroutineInferenceSupport(
|
||||
}
|
||||
}
|
||||
|
||||
fun isCoroutineCallWithAdditionalInference(parameterDescriptor: ValueParameterDescriptor, argument: ValueArgument) =
|
||||
parameterDescriptor.hasSuspendFunctionType &&
|
||||
fun isCoroutineCallWithAdditionalInference(
|
||||
parameterDescriptor: ValueParameterDescriptor,
|
||||
argument: ValueArgument,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): Boolean {
|
||||
val parameterHasOptIn = if (languageVersionSettings.supportsFeature(LanguageFeature.ExperimentalBuilderInference))
|
||||
parameterDescriptor.hasBuilderInferenceAnnotation() && parameterDescriptor.hasFunctionOrSuspendFunctionType
|
||||
else
|
||||
parameterDescriptor.hasSuspendFunctionType
|
||||
|
||||
return parameterHasOptIn &&
|
||||
argument.getArgumentExpression() is KtLambdaExpression &&
|
||||
parameterDescriptor.type.let { it.isBuiltinFunctionalType && it.getReceiverTypeFromFunctionType() != null }
|
||||
|
||||
}
|
||||
|
||||
fun OverloadResolutionResultsImpl<*>.isResultWithCoroutineInference() = getCoroutineInferenceData() != null
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ internal fun VariableDescriptor.variableKind(
|
||||
}
|
||||
|
||||
|
||||
private fun hasNoWritersInClosures(
|
||||
fun hasNoWritersInClosures(
|
||||
variableContainingDeclaration: DeclarationDescriptor,
|
||||
writers: Set<AssignedVariablesSearcher.Writer>,
|
||||
bindingContext: BindingContext
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.tower
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
@@ -37,7 +38,8 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class KotlinResolutionStatelessCallbacksImpl(
|
||||
private val deprecationResolver: DeprecationResolver
|
||||
private val deprecationResolver: DeprecationResolver,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
) : KotlinResolutionStatelessCallbacks {
|
||||
override fun isDescriptorFromSource(descriptor: CallableDescriptor) =
|
||||
DescriptorToSourceUtils.descriptorToDeclaration(descriptor) != null
|
||||
@@ -72,5 +74,5 @@ class KotlinResolutionStatelessCallbacksImpl(
|
||||
functionCall.safeAs<PSIKotlinCallForInvoke>()?.variableCall
|
||||
|
||||
override fun isCoroutineCall(argument: KotlinCallArgument, parameter: ValueParameterDescriptor): Boolean =
|
||||
isCoroutineCallWithAdditionalInference(parameter, argument.psiCallArgument.valueArgument)
|
||||
isCoroutineCallWithAdditionalInference(parameter, argument.psiCallArgument.valueArgument, languageVersionSettings)
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getTopmostParentQualifiedExpressionForSelector
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||
@@ -259,9 +260,6 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
|
||||
}
|
||||
}
|
||||
|
||||
val experimentalities = targetDescriptor.loadExperimentalities(moduleAnnotationsResolver, context.languageVersionSettings)
|
||||
reportNotAcceptedExperimentalities(experimentalities, element, context)
|
||||
|
||||
val targetClass = when (targetDescriptor) {
|
||||
is ClassDescriptor -> targetDescriptor
|
||||
is TypeAliasDescriptor -> targetDescriptor.classDescriptor
|
||||
@@ -276,6 +274,11 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (element.getParentOfType<KtImportDirective>(false) == null) {
|
||||
val experimentalities = targetDescriptor.loadExperimentalities(moduleAnnotationsResolver, context.languageVersionSettings)
|
||||
reportNotAcceptedExperimentalities(experimentalities, element, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkUsageOfKotlinExperimentalOrUseExperimental(element: PsiElement, context: CheckerContext) {
|
||||
|
||||
@@ -322,6 +322,11 @@ class DeprecationResolver(
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
// This is a temporary workaround before @DeprecatedSinceKotlin is introduced, see KT-23575
|
||||
if (shouldSkipDeprecationOnKotlinIoReadBytes(this, languageVersionSettings)) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val result = SmartList<Deprecation>()
|
||||
|
||||
fun addDeprecationIfPresent(target: DeclarationDescriptor) {
|
||||
@@ -365,6 +370,15 @@ class DeprecationResolver(
|
||||
return result.distinct()
|
||||
}
|
||||
|
||||
private fun shouldSkipDeprecationOnKotlinIoReadBytes(
|
||||
descriptor: DeclarationDescriptor, languageVersionSettings: LanguageVersionSettings
|
||||
): Boolean =
|
||||
descriptor.name.asString() == "readBytes" &&
|
||||
(descriptor.containingDeclaration as? PackageFragmentDescriptor)?.fqName?.asString() == "kotlin.io" &&
|
||||
descriptor is FunctionDescriptor &&
|
||||
descriptor.valueParameters.singleOrNull()?.type?.let(KotlinBuiltIns::isInt) == true &&
|
||||
languageVersionSettings.apiVersion < ApiVersion.KOTLIN_1_3
|
||||
|
||||
private fun getDeprecationByCoroutinesVersion(target: DeclarationDescriptor): DeprecatedExperimentalCoroutine? {
|
||||
if (target !is DeserializedMemberDescriptor) return null
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.CallHandle;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl;
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -40,6 +41,11 @@ public class TypeIntersector {
|
||||
return intersectTypes(new LinkedHashSet<>(Arrays.asList(typeA, typeB))) == null;
|
||||
}
|
||||
|
||||
public static boolean isIncompatibleEnums(@NotNull KotlinType typeA, @NotNull KotlinType typeB) {
|
||||
if (!TypeUtilsKt.isEnum(typeA) || !TypeUtilsKt.isEnum(typeB)) return false;
|
||||
return !typeA.getConstructor().equals(typeB.getConstructor());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static KotlinType intersectTypes(@NotNull Collection<KotlinType> types) {
|
||||
assert !types.isEmpty() : "Attempting to intersect empty collection of types, this case should be dealt with on the call site.";
|
||||
|
||||
@@ -1429,6 +1429,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
if (TypeIntersector.isIntersectionEmpty(leftType, rightType)) {
|
||||
context.trace.report(EQUALITY_NOT_APPLICABLE.on(expression, expression.getOperationReference(), leftType, rightType));
|
||||
}
|
||||
else if (TypeIntersector.isIncompatibleEnums(leftType, rightType)) {
|
||||
context.trace.report(INCOMPATIBLE_ENUM_COMPARISON.on(expression, leftType, rightType));
|
||||
}
|
||||
|
||||
SenselessComparisonChecker.checkSenselessComparisonWithNull(
|
||||
expression, left, right, context,
|
||||
expr -> facade.getTypeInfo(expr, context).getType(),
|
||||
|
||||
@@ -53,7 +53,6 @@ import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import org.jetbrains.kotlin.utils.yieldIfNotNull
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.coroutines.experimental.buildSequence
|
||||
|
||||
sealed class DoubleColonLHS(val type: KotlinType) {
|
||||
/**
|
||||
@@ -715,13 +714,13 @@ class DoubleColonExpressionResolver(
|
||||
?.apply { commitTrace() }?.results
|
||||
}
|
||||
|
||||
val resultSequence = buildSequence {
|
||||
val resultSequence = sequence {
|
||||
when (lhs) {
|
||||
is DoubleColonLHS.Type -> {
|
||||
val classifier = lhsType.constructor.declarationDescriptor
|
||||
if (classifier !is ClassDescriptor) {
|
||||
c.trace.report(CALLABLE_REFERENCE_LHS_NOT_A_CLASS.on(expression))
|
||||
return@buildSequence
|
||||
return@sequence
|
||||
}
|
||||
|
||||
val qualifier = c.trace.get(BindingContext.QUALIFIER, expression.receiverExpression!!)
|
||||
|
||||
@@ -410,7 +410,13 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
||||
possibleTypesForSubject: Set<KotlinType>
|
||||
) {
|
||||
val subjectExpression = expression.subjectExpression ?: return
|
||||
for (possibleCastType in possibleTypesForSubject) {
|
||||
// Using "reversed()" here is a kind of hack to fix KT-27221
|
||||
// KT-27221 was a breaking change introduced after DataFlowImpl optimization that changed the order of possible types to reversed,
|
||||
// and it led to the wrong sealed class being chosen.
|
||||
// But it seems that order of collected types shouldn't matter at all
|
||||
// (at least because the order of relevant checks might change the behavior, see KT-27252)
|
||||
// TODO: Read the comment above, wait for resolution in KT-27252 and get rid of "reversed" call here
|
||||
for (possibleCastType in possibleTypesForSubject.reversed()) {
|
||||
val possibleCastClass = possibleCastType.constructor.declarationDescriptor as? ClassDescriptor ?: continue
|
||||
if (possibleCastClass.kind == ClassKind.ENUM_CLASS || possibleCastClass.modality == Modality.SEALED) {
|
||||
if (checkSmartCastToExpectedTypeInSubject(
|
||||
@@ -678,6 +684,10 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
||||
return
|
||||
}
|
||||
|
||||
if (TypeIntersector.isIncompatibleEnums(type, subjectType)) {
|
||||
context.trace.report(INCOMPATIBLE_ENUM_COMPARISON.on(reportErrorOn, subjectType, type))
|
||||
}
|
||||
|
||||
// check if the pattern is essentially a 'null' expression
|
||||
if (KotlinBuiltIns.isNullableNothing(type) && !TypeUtils.isNullableType(subjectType)) {
|
||||
context.trace.report(SENSELESS_NULL_IN_WHEN.on(reportErrorOn))
|
||||
|
||||
@@ -10,7 +10,8 @@ import java.io.File
|
||||
|
||||
class DirtyFilesContainer(
|
||||
private val caches: IncrementalCachesManager<*>,
|
||||
private val reporter: ICReporter
|
||||
private val reporter: ICReporter,
|
||||
private val sourceFilesExtensions: List<String>
|
||||
) {
|
||||
private val myDirtyFiles = HashSet<File>()
|
||||
|
||||
@@ -18,7 +19,7 @@ class DirtyFilesContainer(
|
||||
ArrayList(myDirtyFiles)
|
||||
|
||||
fun add(files: Iterable<File>) {
|
||||
val existingKotlinFiles = files.filter { it.isKotlinFile() }
|
||||
val existingKotlinFiles = files.filter { it.isKotlinFile(sourceFilesExtensions) }
|
||||
if (existingKotlinFiles.isNotEmpty()) {
|
||||
myDirtyFiles.addAll(existingKotlinFiles)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.incremental
|
||||
|
||||
import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
|
||||
import org.jetbrains.kotlin.build.GeneratedFile
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
@@ -50,6 +51,7 @@ abstract class IncrementalCompilerRunner<
|
||||
protected val cacheDirectory = File(workingDir, cacheDirName)
|
||||
protected val dirtySourcesSinceLastTimeFile = File(workingDir, DIRTY_SOURCES_FILE_NAME)
|
||||
protected val lastBuildInfoFile = File(workingDir, LAST_BUILD_INFO_FILE_NAME)
|
||||
protected open val kotlinSourceFilesExtensions: List<String> = DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
|
||||
|
||||
protected abstract fun isICEnabled(): Boolean
|
||||
protected abstract fun createCacheManager(args: Args): CacheManager
|
||||
@@ -85,7 +87,7 @@ abstract class IncrementalCompilerRunner<
|
||||
if (providedChangedFiles == null) {
|
||||
caches.inputsCache.sourceSnapshotMap.compareAndUpdate(allSourceFiles)
|
||||
}
|
||||
val allKotlinFiles = allSourceFiles.filter { it.isKotlinFile() }
|
||||
val allKotlinFiles = allSourceFiles.filter { it.isKotlinFile(kotlinSourceFilesExtensions) }
|
||||
return compileIncrementally(args, caches, allKotlinFiles, CompilationMode.Rebuild(), messageCollector)
|
||||
}
|
||||
|
||||
@@ -281,8 +283,8 @@ abstract class IncrementalCompilerRunner<
|
||||
changedFiles: ChangedFiles.Known
|
||||
): DirtyData {
|
||||
val removedClasses = HashSet<String>()
|
||||
val dirtyFiles = changedFiles.modified.filterTo(HashSet()) { it.isKotlinFile() }
|
||||
val removedFiles = changedFiles.removed.filterTo(HashSet()) { it.isKotlinFile() }
|
||||
val dirtyFiles = changedFiles.modified.filterTo(HashSet()) { it.isKotlinFile(kotlinSourceFilesExtensions) }
|
||||
val removedFiles = changedFiles.removed.filterTo(HashSet()) { it.isKotlinFile(kotlinSourceFilesExtensions) }
|
||||
|
||||
val existingClasses = classesFqNames(dirtyFiles)
|
||||
val previousClasses = caches.platformCache
|
||||
|
||||
@@ -90,7 +90,7 @@ class IncrementalJsCompilerRunner(
|
||||
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile)
|
||||
?: return CompilationMode.Rebuild { "No information on previous build" }
|
||||
|
||||
val dirtyFiles = DirtyFilesContainer(caches, reporter)
|
||||
val dirtyFiles = DirtyFilesContainer(caches, reporter, kotlinSourceFilesExtensions)
|
||||
initDirtyFiles(dirtyFiles, changedFiles)
|
||||
|
||||
val libs = (args.libraries ?: "").split(File.pathSeparator).map { File(it) }
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiFileFactory
|
||||
import com.intellij.psi.PsiJavaFile
|
||||
import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
|
||||
import org.jetbrains.kotlin.build.GeneratedFile
|
||||
import org.jetbrains.kotlin.build.GeneratedJvmClass
|
||||
import org.jetbrains.kotlin.build.JvmSourceRoot
|
||||
@@ -40,7 +41,6 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.incremental.multiproject.EmptyModulesApiHistory
|
||||
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistory
|
||||
import org.jetbrains.kotlin.incremental.storage.version.CacheVersionManager
|
||||
import org.jetbrains.kotlin.incremental.util.Either
|
||||
import org.jetbrains.kotlin.load.java.JavaClassesTracker
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
||||
@@ -57,8 +57,8 @@ fun makeIncrementally(
|
||||
messageCollector: MessageCollector = MessageCollector.NONE,
|
||||
reporter: ICReporter = EmptyICReporter
|
||||
) {
|
||||
val kotlinExtensions = listOf("kt", "kts")
|
||||
val allExtensions = kotlinExtensions + listOf("java")
|
||||
val kotlinExtensions = DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
|
||||
val allExtensions = kotlinExtensions + "java"
|
||||
val rootsWalk = sourceRoots.asSequence().flatMap { it.walk() }
|
||||
val files = rootsWalk.filter(File::isFile)
|
||||
val sourceFiles = files.filter { it.extension.toLowerCase() in allExtensions }.toList()
|
||||
@@ -75,7 +75,8 @@ fun makeIncrementally(
|
||||
usePreciseJavaTracking = true,
|
||||
localStateDirs = emptyList(),
|
||||
buildHistoryFile = buildHistoryFile,
|
||||
modulesApiHistory = EmptyModulesApiHistory
|
||||
modulesApiHistory = EmptyModulesApiHistory,
|
||||
kotlinSourceFilesExtensions = kotlinExtensions
|
||||
)
|
||||
compiler.compile(sourceFiles, args, messageCollector, providedChangedFiles = null)
|
||||
}
|
||||
@@ -104,9 +105,10 @@ class IncrementalJvmCompilerRunner(
|
||||
cachesVersionManagers: List<CacheVersionManager>,
|
||||
reporter: ICReporter,
|
||||
private val usePreciseJavaTracking: Boolean,
|
||||
buildHistoryFile: File,
|
||||
buildHistoryFile: File,
|
||||
localStateDirs: Collection<File>,
|
||||
private val modulesApiHistory: ModulesApiHistory
|
||||
private val modulesApiHistory: ModulesApiHistory,
|
||||
override val kotlinSourceFilesExtensions: List<String> = DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
|
||||
) : IncrementalCompilerRunner<K2JVMCompilerArguments, IncrementalJvmCachesManager>(
|
||||
workingDir,
|
||||
"caches-jvm",
|
||||
@@ -145,7 +147,7 @@ class IncrementalJvmCompilerRunner(
|
||||
changedFiles: ChangedFiles.Known,
|
||||
args: K2JVMCompilerArguments
|
||||
): CompilationMode {
|
||||
val dirtyFiles = DirtyFilesContainer(caches, reporter)
|
||||
val dirtyFiles = DirtyFilesContainer(caches, reporter, kotlinSourceFilesExtensions)
|
||||
initDirtyFiles(dirtyFiles, changedFiles)
|
||||
|
||||
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile) ?: return CompilationMode.Rebuild { "No information on previous build" }
|
||||
|
||||
@@ -291,6 +291,11 @@ public class IncrementalJsCompilerRunnerTestGenerated extends AbstractIncrementa
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/inlinePropertyOnTopLevel/");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineSuspendFunctionChanged")
|
||||
public void testInlineSuspendFunctionChanged() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/inlineSuspendFunctionChanged/");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineTwoFunctionsOneChanged")
|
||||
public void testInlineTwoFunctionsOneChanged() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/inlineTwoFunctionsOneChanged/");
|
||||
|
||||
@@ -291,6 +291,11 @@ public class IncrementalJvmCompilerRunnerTestGenerated extends AbstractIncrement
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/inlinePropertyOnTopLevel/");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineSuspendFunctionChanged")
|
||||
public void testInlineSuspendFunctionChanged() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/inlineSuspendFunctionChanged/");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineTwoFunctionsOneChanged")
|
||||
public void testInlineTwoFunctionsOneChanged() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/inlineTwoFunctionsOneChanged/");
|
||||
|
||||
@@ -28,7 +28,7 @@ import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
||||
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl
|
||||
import com.intellij.psi.impl.source.tree.TreeElement
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -54,7 +54,13 @@ fun buildLightClass(
|
||||
context.module,
|
||||
context.bindingContext,
|
||||
files.toList(),
|
||||
CompilerConfiguration.EMPTY
|
||||
context.languageVersionSettings?.let {
|
||||
CompilerConfiguration().apply {
|
||||
languageVersionSettings = it
|
||||
isReadOnly = true
|
||||
}
|
||||
} ?: CompilerConfiguration.EMPTY
|
||||
|
||||
).generateDeclaredClassFilter(generateClassFilter).wantsDiagnostics(false).build()
|
||||
state.beforeCompile()
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
||||
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl
|
||||
import com.intellij.psi.impl.source.tree.TreeElement
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -56,7 +56,12 @@ fun buildLightClass(
|
||||
context.module,
|
||||
context.bindingContext,
|
||||
files.toList(),
|
||||
CompilerConfiguration.EMPTY
|
||||
context.languageVersionSettings?.let {
|
||||
CompilerConfiguration().apply {
|
||||
languageVersionSettings = it
|
||||
isReadOnly = true
|
||||
}
|
||||
} ?: CompilerConfiguration.EMPTY
|
||||
).generateDeclaredClassFilter(generateClassFilter).wantsDiagnostics(false).build()
|
||||
state.beforeCompile()
|
||||
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.asJava.builder
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
open class LightClassConstructionContext(
|
||||
val bindingContext: BindingContext,
|
||||
val module: ModuleDescriptor
|
||||
val module: ModuleDescriptor,
|
||||
val languageVersionSettings: LanguageVersionSettings? = null
|
||||
)
|
||||
@@ -28,7 +28,7 @@ object KotlinStubVersions {
|
||||
// Binary stub version should be increased if stub format (org.jetbrains.kotlin.psi.stubs.impl) is changed
|
||||
// or changes are made to the core stub building code (org.jetbrains.kotlin.idea.decompiler.stubBuilder).
|
||||
// Increasing this version will lead to reindexing of all binary files that are potentially kotlin binaries (including all class files).
|
||||
private const val BINARY_STUB_VERSION = 69
|
||||
private const val BINARY_STUB_VERSION = 70
|
||||
|
||||
// Classfile stub version should be increased if changes are made to classfile stub building subsystem (org.jetbrains.kotlin.idea.decompiler.classFile)
|
||||
// Increasing this version will lead to reindexing of all classfiles.
|
||||
|
||||
@@ -6,3 +6,5 @@
|
||||
package test
|
||||
|
||||
val foo = 42
|
||||
|
||||
typealias A = String
|
||||
|
||||
4
compiler/testData/cli/jvm/extraHelp.out
vendored
4
compiler/testData/cli/jvm/extraHelp.out
vendored
@@ -13,7 +13,9 @@ where advanced options include:
|
||||
-Xbuild-file=<path> Path to the .xml build file to compile
|
||||
-Xcompile-java Reuse javac analysis and compile Java source files
|
||||
-Xnormalize-constructor-calls={disable|enable}
|
||||
Normalize constructor calls (disable: don't normalize; enable: normalize), default is disable
|
||||
Normalize constructor calls (disable: don't normalize; enable: normalize),
|
||||
default is 'disable' in language version 1.2 and below,
|
||||
'enable' since language version 1.3
|
||||
-Xdump-declarations-to=<path> Path to JSON file to dump Java to Kotlin declaration mappings
|
||||
-Xdisable-default-scripting-plugin
|
||||
Do not enable scripting plugin by default
|
||||
|
||||
3
compiler/testData/cli/jvm/suspensionPointInMonitor.args
vendored
Normal file
3
compiler/testData/cli/jvm/suspensionPointInMonitor.args
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
$TESTDATA_DIR$/suspensionPointInMonitor.kt
|
||||
-d
|
||||
$TEMP_DIR$
|
||||
68
compiler/testData/cli/jvm/suspensionPointInMonitor.kt
vendored
Normal file
68
compiler/testData/cli/jvm/suspensionPointInMonitor.kt
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
fun builder(c: suspend () -> Unit) {}
|
||||
|
||||
private val lock = Any()
|
||||
|
||||
suspend fun suspensionPoint() {}
|
||||
|
||||
private inline fun inlineMe(c: () -> Unit) {
|
||||
synchronized(lock) {
|
||||
c()
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun monitorInFinally(a: () -> Unit, b: () -> Unit) {
|
||||
try {
|
||||
a()
|
||||
} finally {
|
||||
synchronized(lock) {
|
||||
b()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
builder {
|
||||
synchronized(lock) {
|
||||
suspensionPoint()
|
||||
}
|
||||
}
|
||||
|
||||
builder {
|
||||
inlineMe {
|
||||
suspensionPoint()
|
||||
}
|
||||
}
|
||||
|
||||
builder {
|
||||
monitorInFinally(
|
||||
{},
|
||||
{ suspensionPoint() }
|
||||
)
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
builder {
|
||||
suspensionPoint()
|
||||
}
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
object : SuspendRunnable {
|
||||
override suspend fun run() {
|
||||
suspensionPoint()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object : SuspendRunnable {
|
||||
override suspend fun run() {
|
||||
synchronized(lock) {
|
||||
suspensionPoint()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface SuspendRunnable {
|
||||
suspend fun run()
|
||||
}
|
||||
7
compiler/testData/cli/jvm/suspensionPointInMonitor.out
vendored
Normal file
7
compiler/testData/cli/jvm/suspensionPointInMonitor.out
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
compiler/testData/cli/jvm/suspensionPointInMonitor.kt:26:13: error: the 'suspensionPoint' suspension point is inside a synchronized block
|
||||
suspensionPoint()
|
||||
^
|
||||
compiler/testData/cli/jvm/suspensionPointInMonitor.kt:60:17: error: the 'suspensionPoint' suspension point is inside a synchronized block
|
||||
suspensionPoint()
|
||||
^
|
||||
COMPILATION_ERROR
|
||||
@@ -25,7 +25,7 @@ fun box(): String {
|
||||
|
||||
result = ""
|
||||
invokeOrder = ""
|
||||
result = inlineFun(constraints = { invokeOrder += "constraints";A("C") }(),
|
||||
result = inlineFun(constraints = *arrayOf({ invokeOrder += "constraints";A("C") }()),
|
||||
receiver = { invokeOrder += " receiver"; "R" }(),
|
||||
init = { invokeOrder += " init"; "I" }())
|
||||
if (result != "C, R, I") return "fail 1: $result"
|
||||
@@ -35,7 +35,7 @@ fun box(): String {
|
||||
result = ""
|
||||
invokeOrder = ""
|
||||
result = inlineFun(init = { invokeOrder += "init"; "I" }(),
|
||||
constraints = { invokeOrder += "constraints";A("C") }(),
|
||||
constraints = *arrayOf({ invokeOrder += "constraints";A("C") }()),
|
||||
receiver = { invokeOrder += " receiver"; "R" }()
|
||||
)
|
||||
if (result != "C, R, I") return "fail 3: $result"
|
||||
@@ -45,7 +45,7 @@ fun box(): String {
|
||||
result = ""
|
||||
invokeOrder = ""
|
||||
result = inlineFun(init = { invokeOrder += "init"; "I" }(),
|
||||
constraints = { invokeOrder += " constraints";A("C") }())
|
||||
constraints = *arrayOf({ invokeOrder += " constraints";A("C") }()))
|
||||
if (result != "C, DEFAULT, I") return "fail 5: $result"
|
||||
if (invokeOrder != "init constraints default receiver") return "fail 6: $invokeOrder"
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// !LANGUAGE: -ReleaseCoroutines -ExperimentalBuilderInference
|
||||
// IGNORE_BACKEND: JVM_IR, JS_IR
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// COMMON_COROUTINES_TEST
|
||||
|
||||
import helpers.*
|
||||
import COROUTINES_PACKAGE.*
|
||||
import COROUTINES_PACKAGE.intrinsics.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
import kotlin.coroutines.experimental.intrinsics.*
|
||||
|
||||
interface AsyncGenerator<in T> {
|
||||
suspend fun yield(value: T)
|
||||
141
compiler/testData/codegen/box/coroutines/asyncIteratorNullMerge_1_3.kt
vendored
Normal file
141
compiler/testData/codegen/box/coroutines/asyncIteratorNullMerge_1_3.kt
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
// !LANGUAGE: +ReleaseCoroutines +ExperimentalBuilderInference
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
|
||||
import helpers.*
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
import kotlin.experimental.ExperimentalTypeInference
|
||||
|
||||
interface AsyncGenerator<in T> {
|
||||
suspend fun yield(value: T)
|
||||
}
|
||||
|
||||
interface AsyncSequence<out T> {
|
||||
operator fun iterator(): AsyncIterator<T>
|
||||
}
|
||||
|
||||
interface AsyncIterator<out T> {
|
||||
operator suspend fun hasNext(): Boolean
|
||||
operator suspend fun next(): T
|
||||
}
|
||||
|
||||
@UseExperimental(ExperimentalTypeInference::class)
|
||||
fun <T> asyncGenerate(@BuilderInference block: suspend AsyncGenerator<T>.() -> Unit): AsyncSequence<T> = object : AsyncSequence<T> {
|
||||
override fun iterator(): AsyncIterator<T> {
|
||||
val iterator = AsyncGeneratorIterator<T>()
|
||||
iterator.nextStep = block.createCoroutine(receiver = iterator, completion = iterator)
|
||||
return iterator
|
||||
}
|
||||
}
|
||||
|
||||
class AsyncGeneratorIterator<T>: AsyncIterator<T>, AsyncGenerator<T>, ContinuationAdapter<Unit>() {
|
||||
var computedNext = false
|
||||
var nextValue: T? = null
|
||||
var nextStep: Continuation<Unit>? = null
|
||||
|
||||
// if (computesNext) computeContinuation is Continuation<T>
|
||||
// if (!computesNext) computeContinuation is Continuation<Boolean>
|
||||
var computesNext = false
|
||||
var computeContinuation: Continuation<*>? = null
|
||||
|
||||
override val context = EmptyCoroutineContext
|
||||
|
||||
suspend fun computeHasNext(): Boolean = suspendCoroutineUninterceptedOrReturn { c ->
|
||||
computesNext = false
|
||||
computeContinuation = c
|
||||
nextStep!!.resume(Unit)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
|
||||
suspend fun computeNext(): T = suspendCoroutineUninterceptedOrReturn { c ->
|
||||
computesNext = true
|
||||
computeContinuation = c
|
||||
nextStep!!.resume(Unit)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun resumeIterator(exception: Throwable?) {
|
||||
if (exception != null) {
|
||||
done()
|
||||
computeContinuation!!.resumeWithException(exception)
|
||||
return
|
||||
}
|
||||
if (computesNext) {
|
||||
computedNext = false
|
||||
(computeContinuation as Continuation<T>).resume(nextValue as T)
|
||||
} else {
|
||||
(computeContinuation as Continuation<Boolean>).resume(nextStep != null)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun hasNext(): Boolean {
|
||||
if (!computedNext) return computeHasNext()
|
||||
return nextStep != null
|
||||
}
|
||||
|
||||
override suspend fun next(): T {
|
||||
if (!computedNext) return computeNext()
|
||||
computedNext = false
|
||||
return nextValue as T
|
||||
}
|
||||
|
||||
private fun done() {
|
||||
computedNext = true
|
||||
nextStep = null
|
||||
}
|
||||
|
||||
// Completion continuation implementation
|
||||
override fun resume(value: Unit) {
|
||||
done()
|
||||
resumeIterator(null)
|
||||
}
|
||||
|
||||
override fun resumeWithException(exception: Throwable) {
|
||||
done()
|
||||
resumeIterator(exception)
|
||||
}
|
||||
|
||||
// Generator implementation
|
||||
override suspend fun yield(value: T): Unit = suspendCoroutineUninterceptedOrReturn { c ->
|
||||
computedNext = true
|
||||
nextValue = value
|
||||
nextStep = c
|
||||
resumeIterator(null)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun cst(a: Any?): String? = a as String?
|
||||
fun any(a: Any?): Any? = a
|
||||
|
||||
fun box(): String {
|
||||
val seq = asyncGenerate {
|
||||
yield("O")
|
||||
yield("K")
|
||||
}
|
||||
|
||||
var res = ""
|
||||
|
||||
builder {
|
||||
// type of `prev` should be j/l/Object everywhere (even in a expected type position)
|
||||
var prev: Any? = null
|
||||
for (i in seq) {
|
||||
res += i
|
||||
prev = any(res)
|
||||
// merge of NULL_VALUE and j/l/Object should result in common j/l/Object value
|
||||
// but it was NULL_VALUE and we do not spill null values, we just put
|
||||
// ACONST_NULL after suspension point instead
|
||||
}
|
||||
|
||||
res = cst(prev) ?: "fail 1"
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// !LANGUAGE: -ReleaseCoroutines -ExperimentalBuilderInference
|
||||
// IGNORE_BACKEND: JVM_IR, JS_IR
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// COMMON_COROUTINES_TEST
|
||||
|
||||
import helpers.*
|
||||
import COROUTINES_PACKAGE.*
|
||||
import COROUTINES_PACKAGE.intrinsics.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
import kotlin.coroutines.experimental.intrinsics.*
|
||||
|
||||
interface AsyncGenerator<in T> {
|
||||
suspend fun yield(value: T)
|
||||
136
compiler/testData/codegen/box/coroutines/asyncIteratorToList_1_3.kt
vendored
Normal file
136
compiler/testData/codegen/box/coroutines/asyncIteratorToList_1_3.kt
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
// !LANGUAGE: +ReleaseCoroutines +ExperimentalBuilderInference
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
|
||||
import helpers.*
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
import kotlin.experimental.ExperimentalTypeInference
|
||||
|
||||
interface AsyncGenerator<in T> {
|
||||
suspend fun yield(value: T)
|
||||
}
|
||||
|
||||
interface AsyncSequence<out T> {
|
||||
operator fun iterator(): AsyncIterator<T>
|
||||
}
|
||||
|
||||
interface AsyncIterator<out T> {
|
||||
operator suspend fun hasNext(): Boolean
|
||||
operator suspend fun next(): T
|
||||
}
|
||||
|
||||
@UseExperimental(ExperimentalTypeInference::class)
|
||||
fun <T> asyncGenerate(@BuilderInference block: suspend AsyncGenerator<T>.() -> Unit): AsyncSequence<T> = object : AsyncSequence<T> {
|
||||
override fun iterator(): AsyncIterator<T> {
|
||||
val iterator = AsyncGeneratorIterator<T>()
|
||||
iterator.nextStep = block.createCoroutine(receiver = iterator, completion = iterator)
|
||||
return iterator
|
||||
}
|
||||
}
|
||||
|
||||
class AsyncGeneratorIterator<T>: AsyncIterator<T>, AsyncGenerator<T>, ContinuationAdapter<Unit>() {
|
||||
var computedNext = false
|
||||
var nextValue: T? = null
|
||||
var nextStep: Continuation<Unit>? = null
|
||||
|
||||
// if (computesNext) computeContinuation is Continuation<T>
|
||||
// if (!computesNext) computeContinuation is Continuation<Boolean>
|
||||
var computesNext = false
|
||||
var computeContinuation: Continuation<*>? = null
|
||||
|
||||
override val context = EmptyCoroutineContext
|
||||
|
||||
suspend fun computeHasNext(): Boolean = suspendCoroutineUninterceptedOrReturn { c ->
|
||||
computesNext = false
|
||||
computeContinuation = c
|
||||
nextStep!!.resume(Unit)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
|
||||
suspend fun computeNext(): T = suspendCoroutineUninterceptedOrReturn { c ->
|
||||
computesNext = true
|
||||
computeContinuation = c
|
||||
nextStep!!.resume(Unit)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun resumeIterator(exception: Throwable?) {
|
||||
if (exception != null) {
|
||||
done()
|
||||
computeContinuation!!.resumeWithException(exception)
|
||||
return
|
||||
}
|
||||
if (computesNext) {
|
||||
computedNext = false
|
||||
(computeContinuation as Continuation<T>).resume(nextValue as T)
|
||||
} else {
|
||||
(computeContinuation as Continuation<Boolean>).resume(nextStep != null)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun hasNext(): Boolean {
|
||||
if (!computedNext) return computeHasNext()
|
||||
return nextStep != null
|
||||
}
|
||||
|
||||
override suspend fun next(): T {
|
||||
if (!computedNext) return computeNext()
|
||||
computedNext = false
|
||||
return nextValue as T
|
||||
}
|
||||
|
||||
private fun done() {
|
||||
computedNext = true
|
||||
nextStep = null
|
||||
}
|
||||
|
||||
// Completion continuation implementation
|
||||
override fun resume(value: Unit) {
|
||||
done()
|
||||
resumeIterator(null)
|
||||
}
|
||||
|
||||
override fun resumeWithException(exception: Throwable) {
|
||||
done()
|
||||
resumeIterator(exception)
|
||||
}
|
||||
|
||||
// Generator implementation
|
||||
override suspend fun yield(value: T): Unit = suspendCoroutineUninterceptedOrReturn { c ->
|
||||
computedNext = true
|
||||
nextValue = value
|
||||
nextStep = c
|
||||
resumeIterator(null)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun <T> AsyncSequence<T>.toList(): List<T> {
|
||||
val out = arrayListOf<T>()
|
||||
for (e in this@toList) out += e // fails at this line
|
||||
return out
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val seq = asyncGenerate {
|
||||
yield("O")
|
||||
yield("K")
|
||||
}
|
||||
|
||||
var res = listOf<String>()
|
||||
|
||||
builder {
|
||||
res = seq.toList()
|
||||
}
|
||||
|
||||
if (res.size > 2) return "fail 1: ${res.size}"
|
||||
|
||||
return res[0] + res[1]
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// !LANGUAGE: -ReleaseCoroutines -ExperimentalBuilderInference
|
||||
// IGNORE_BACKEND: JVM_IR, JS_IR
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// COMMON_COROUTINES_TEST
|
||||
|
||||
import helpers.*
|
||||
import COROUTINES_PACKAGE.*
|
||||
import COROUTINES_PACKAGE.intrinsics.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
import kotlin.coroutines.experimental.intrinsics.*
|
||||
|
||||
interface AsyncGenerator<in T> {
|
||||
suspend fun yield(value: T)
|
||||
130
compiler/testData/codegen/box/coroutines/asyncIterator_1_3.kt
vendored
Normal file
130
compiler/testData/codegen/box/coroutines/asyncIterator_1_3.kt
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
// !LANGUAGE: +ReleaseCoroutines +ExperimentalBuilderInference
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
|
||||
import helpers.*
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
import kotlin.experimental.ExperimentalTypeInference
|
||||
|
||||
interface AsyncGenerator<in T> {
|
||||
suspend fun yield(value: T)
|
||||
}
|
||||
|
||||
interface AsyncSequence<out T> {
|
||||
operator fun iterator(): AsyncIterator<T>
|
||||
}
|
||||
|
||||
interface AsyncIterator<out T> {
|
||||
operator suspend fun hasNext(): Boolean
|
||||
operator suspend fun next(): T
|
||||
}
|
||||
|
||||
@UseExperimental(ExperimentalTypeInference::class)
|
||||
fun <T> asyncGenerate(@BuilderInference block: suspend AsyncGenerator<T>.() -> Unit): AsyncSequence<T> = object : AsyncSequence<T> {
|
||||
override fun iterator(): AsyncIterator<T> {
|
||||
val iterator = AsyncGeneratorIterator<T>()
|
||||
iterator.nextStep = block.createCoroutine(receiver = iterator, completion = iterator)
|
||||
return iterator
|
||||
}
|
||||
}
|
||||
|
||||
class AsyncGeneratorIterator<T>: AsyncIterator<T>, AsyncGenerator<T>, ContinuationAdapter<Unit>() {
|
||||
var computedNext = false
|
||||
var nextValue: T? = null
|
||||
var nextStep: Continuation<Unit>? = null
|
||||
|
||||
// if (computesNext) computeContinuation is Continuation<T>
|
||||
// if (!computesNext) computeContinuation is Continuation<Boolean>
|
||||
var computesNext = false
|
||||
var computeContinuation: Continuation<*>? = null
|
||||
|
||||
override val context = EmptyCoroutineContext
|
||||
|
||||
suspend fun computeHasNext(): Boolean = suspendCoroutineUninterceptedOrReturn { c ->
|
||||
computesNext = false
|
||||
computeContinuation = c
|
||||
nextStep!!.resume(Unit)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
|
||||
suspend fun computeNext(): T = suspendCoroutineUninterceptedOrReturn { c ->
|
||||
computesNext = true
|
||||
computeContinuation = c
|
||||
nextStep!!.resume(Unit)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun resumeIterator(exception: Throwable?) {
|
||||
if (exception != null) {
|
||||
done()
|
||||
computeContinuation!!.resumeWithException(exception)
|
||||
return
|
||||
}
|
||||
if (computesNext) {
|
||||
computedNext = false
|
||||
(computeContinuation as Continuation<T>).resume(nextValue as T)
|
||||
} else {
|
||||
(computeContinuation as Continuation<Boolean>).resume(nextStep != null)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun hasNext(): Boolean {
|
||||
if (!computedNext) return computeHasNext()
|
||||
return nextStep != null
|
||||
}
|
||||
|
||||
override suspend fun next(): T {
|
||||
if (!computedNext) return computeNext()
|
||||
computedNext = false
|
||||
return nextValue as T
|
||||
}
|
||||
|
||||
private fun done() {
|
||||
computedNext = true
|
||||
nextStep = null
|
||||
}
|
||||
|
||||
// Completion continuation implementation
|
||||
override fun resume(value: Unit) {
|
||||
done()
|
||||
resumeIterator(null)
|
||||
}
|
||||
|
||||
override fun resumeWithException(exception: Throwable) {
|
||||
done()
|
||||
resumeIterator(exception)
|
||||
}
|
||||
|
||||
// Generator implementation
|
||||
override suspend fun yield(value: T): Unit = suspendCoroutineUninterceptedOrReturn { c ->
|
||||
computedNext = true
|
||||
nextValue = value
|
||||
nextStep = c
|
||||
resumeIterator(null)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val seq = asyncGenerate {
|
||||
yield("O")
|
||||
yield("K")
|
||||
}
|
||||
|
||||
var res = ""
|
||||
|
||||
builder {
|
||||
for (i in seq) {
|
||||
res += i
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
@@ -2,10 +2,9 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// COMMON_COROUTINES_TEST
|
||||
// LANGUAGE_VERSION: 1.2
|
||||
import helpers.*
|
||||
import COROUTINES_PACKAGE.*
|
||||
import COROUTINES_PACKAGE.intrinsics.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
|
||||
enum class Foo(vararg expected: String) {
|
||||
A("start", "A", "end"),
|
||||
48
compiler/testData/codegen/box/coroutines/controlFlow/kt22694_1_3.kt
vendored
Normal file
48
compiler/testData/codegen/box/coroutines/controlFlow/kt22694_1_3.kt
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// LANGUAGE_VERSION: 1.3
|
||||
import helpers.*
|
||||
import kotlin.coroutines.*
|
||||
|
||||
enum class Foo(vararg expected: String) {
|
||||
A("start", "A", "end"),
|
||||
B("start", "BCD", "end"),
|
||||
C("start", "BCD", "end"),
|
||||
D("start", "BCD", "end"),
|
||||
E("start", "E", "end"),
|
||||
F("start", "end");
|
||||
|
||||
val expected = expected.toList()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
for (c in Foo.values()) {
|
||||
val actual = getSequence(c).toList()
|
||||
if (actual != c.expected) {
|
||||
return "FAIL: -- ${c.expected} != $actual"
|
||||
}
|
||||
}
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
fun getSequence(a: Foo) =
|
||||
sequence {
|
||||
yield("start")
|
||||
when (a) {
|
||||
Foo.A -> {
|
||||
yield("A")
|
||||
}
|
||||
Foo.B,
|
||||
Foo.C,
|
||||
Foo.D-> {
|
||||
yield("BCD")
|
||||
}
|
||||
Foo.E-> {
|
||||
yield("E")
|
||||
}
|
||||
}
|
||||
yield("end")
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// LANGUAGE_VERSION: 1.3
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// IGNORE_BACKEND: NATIVE
|
||||
// IGNORE_BACKEND: JS_IR, JS
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user