mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-04-11 15:52:06 +00:00
Compare commits
342 Commits
abannykh/v
...
1.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2bc2cc53c | ||
|
|
2e7da8fcae | ||
|
|
e14de32939 | ||
|
|
40b00ee5b5 | ||
|
|
47369d1191 | ||
|
|
e85d6d9803 | ||
|
|
4d26204ef9 | ||
|
|
e62255b517 | ||
|
|
073c3bd7da | ||
|
|
87cc248fca | ||
|
|
5110affb2c | ||
|
|
7a8b85a916 | ||
|
|
d363ae94d8 | ||
|
|
9cf54bf83f | ||
|
|
63b6f90926 | ||
|
|
b8b9e43c05 | ||
|
|
98f0acdb8c | ||
|
|
ce1be19da6 | ||
|
|
6c1bb136ad | ||
|
|
c6a33fb9cb | ||
|
|
dc065cb362 | ||
|
|
f3d769d8d5 | ||
|
|
2c235b0585 | ||
|
|
161c67c2ac | ||
|
|
1bf290903a | ||
|
|
b7888138cf | ||
|
|
c25e26fd0d | ||
|
|
ec6189a860 | ||
|
|
4c4c62e815 | ||
|
|
da50776e80 | ||
|
|
6bcffb8289 | ||
|
|
072524946f | ||
|
|
a02ffd6d2b | ||
|
|
20d92e161e | ||
|
|
94cbe71eff | ||
|
|
97420afb3d | ||
|
|
8c2bcc6eaa | ||
|
|
a4ea155d22 | ||
|
|
fe956668b3 | ||
|
|
1e8e740816 | ||
|
|
f177af12d7 | ||
|
|
7a63d1af24 | ||
|
|
7e59108cae | ||
|
|
b18f790d10 | ||
|
|
b861a432c9 | ||
|
|
951b1d527a | ||
|
|
8c3d13b31f | ||
|
|
fc135efb21 | ||
|
|
596adb9b1e | ||
|
|
c506871195 | ||
|
|
15b99c3629 | ||
|
|
4f859fd727 | ||
|
|
716d00338e | ||
|
|
d2ab12bc97 | ||
|
|
cefa344a77 | ||
|
|
19814558f8 | ||
|
|
c8a00fc012 | ||
|
|
9d942383f1 | ||
|
|
e81f19c30a | ||
|
|
896be11aaa | ||
|
|
a9b5ddd7d2 | ||
|
|
340036fbcb | ||
|
|
4d80738dd6 | ||
|
|
307a5001ac | ||
|
|
0cfaea28a1 | ||
|
|
6f651d7338 | ||
|
|
9329eaa457 | ||
|
|
50ffc8d0c5 | ||
|
|
01a1aa9b62 | ||
|
|
4b2f4f0bc2 | ||
|
|
6a449faf5d | ||
|
|
d0f7edab08 | ||
|
|
716956f917 | ||
|
|
daf4711478 | ||
|
|
30c2c2f17f | ||
|
|
b9efc2e1ac | ||
|
|
9e0d31714c | ||
|
|
1e8c4933f1 | ||
|
|
6648a1f669 | ||
|
|
37f0bc1716 | ||
|
|
8a0a9152da | ||
|
|
53c3e75740 | ||
|
|
a9ef3845fd | ||
|
|
17d05bb7fd | ||
|
|
fbe67da5f1 | ||
|
|
02d8c193c8 | ||
|
|
9240d7695c | ||
|
|
f16f97583f | ||
|
|
50be60d71b | ||
|
|
e30cd05bea | ||
|
|
9c831cca8b | ||
|
|
4467ac0b42 | ||
|
|
07a48b080b | ||
|
|
09c6feddb6 | ||
|
|
9b44a7ea82 | ||
|
|
9013f50b28 | ||
|
|
5614874bf7 | ||
|
|
009f991ac3 | ||
|
|
9711854a2c | ||
|
|
ed98ff3dc0 | ||
|
|
7e098e8827 | ||
|
|
4b011767ef | ||
|
|
324819d20b | ||
|
|
4897af1ef9 | ||
|
|
be0537f3f8 | ||
|
|
899ca8bc65 | ||
|
|
86ffd634ec | ||
|
|
f30d0904fc | ||
|
|
d9b45f667d | ||
|
|
e159028c97 | ||
|
|
11847c121a | ||
|
|
ba857a83ff | ||
|
|
7019dcf3b1 | ||
|
|
46f7c37021 | ||
|
|
70de1a7d2a | ||
|
|
ec7b3c6240 | ||
|
|
499b6c2b91 | ||
|
|
5d56da2567 | ||
|
|
0e030241a6 | ||
|
|
1d3ff1d81a | ||
|
|
358f572b1f | ||
|
|
5a14d97642 | ||
|
|
d1f4c4c348 | ||
|
|
44dd831e71 | ||
|
|
da5ddd76c8 | ||
|
|
fe62995274 | ||
|
|
f67f387daa | ||
|
|
e9f33c4045 | ||
|
|
5f24329dca | ||
|
|
c6e9e992a4 | ||
|
|
c38180efa8 | ||
|
|
683f61fdc2 | ||
|
|
8e5853e5c3 | ||
|
|
4bbdeb00be | ||
|
|
45b060d0dd | ||
|
|
5c065efa20 | ||
|
|
83ca7d9b64 | ||
|
|
9166f5ba9d | ||
|
|
7a65e59d39 | ||
|
|
c91f6fabd1 | ||
|
|
49f1c95171 | ||
|
|
d77f20dc63 | ||
|
|
f9fb6c6a34 | ||
|
|
29eb286df4 | ||
|
|
becd00f33d | ||
|
|
9beabdeb34 | ||
|
|
9c738177b8 | ||
|
|
8f3cfb5b1b | ||
|
|
c2fd91da65 | ||
|
|
a574943696 | ||
|
|
69b302e4f6 | ||
|
|
9eb3925048 | ||
|
|
ee977bc0a1 | ||
|
|
07629e8a48 | ||
|
|
8197240eec | ||
|
|
175d74ce5f | ||
|
|
c06592ed6c | ||
|
|
b34363317a | ||
|
|
2ab47b4d6b | ||
|
|
aee36ac552 | ||
|
|
48c64e9b43 | ||
|
|
d2284af69d | ||
|
|
f9e45a1cea | ||
|
|
7710d4576d | ||
|
|
733f1166af | ||
|
|
b98b2b6846 | ||
|
|
f0fcb4c513 | ||
|
|
d265383968 | ||
|
|
103cd381f4 | ||
|
|
c8c8894f91 | ||
|
|
8c829564f1 | ||
|
|
9d1fec77b8 | ||
|
|
7000b3ef33 | ||
|
|
8ab204819d | ||
|
|
6a31cd834a | ||
|
|
8ba9e0271f | ||
|
|
9391ff4141 | ||
|
|
d73d42cc23 | ||
|
|
832e777b2a | ||
|
|
c1cd139396 | ||
|
|
09a6e9c591 | ||
|
|
4101206e12 | ||
|
|
fbe49d0cc9 | ||
|
|
78e4295c2c | ||
|
|
426944744d | ||
|
|
52a310f202 | ||
|
|
894ee4ce4f | ||
|
|
08915389e2 | ||
|
|
fc6465084b | ||
|
|
beff463a92 | ||
|
|
b67e3f824c | ||
|
|
c578e8b8f1 | ||
|
|
0395d90ef7 | ||
|
|
dfb21a81a0 | ||
|
|
4c69df28b4 | ||
|
|
da1dc9cfe7 | ||
|
|
3413cb977c | ||
|
|
d9c54449a4 | ||
|
|
cc6127a343 | ||
|
|
e44d0c4d5d | ||
|
|
e6c27e7f32 | ||
|
|
82c2ce3a33 | ||
|
|
679efb61ab | ||
|
|
ab44f5cc0e | ||
|
|
277b1cbf1e | ||
|
|
1ceb7f5656 | ||
|
|
ccffa26add | ||
|
|
cfc08328e0 | ||
|
|
f53c5ed30e | ||
|
|
fe44159962 | ||
|
|
74e9a632a9 | ||
|
|
bb1354660d | ||
|
|
b95875536f | ||
|
|
fb74040dde | ||
|
|
4cf2bce003 | ||
|
|
982e67276f | ||
|
|
9a255169ee | ||
|
|
cdeb2e80b5 | ||
|
|
b2c7521277 | ||
|
|
b416769434 | ||
|
|
ad5e3a52ff | ||
|
|
0a54b6104a | ||
|
|
f516b21e5b | ||
|
|
f64a25801f | ||
|
|
77fc61ce73 | ||
|
|
eaaf656ec9 | ||
|
|
bb892a8510 | ||
|
|
936e787d58 | ||
|
|
b82ad57472 | ||
|
|
1c4ac5a74b | ||
|
|
1a74058dc8 | ||
|
|
5ed5008db4 | ||
|
|
34192a1785 | ||
|
|
9ce396ad54 | ||
|
|
04364f4b3e | ||
|
|
6028a4facc | ||
|
|
1aba4fe4da | ||
|
|
54367bd8e8 | ||
|
|
5c73c59b9e | ||
|
|
a0c3187a93 | ||
|
|
9b118ff81d | ||
|
|
483b59516c | ||
|
|
607db11011 | ||
|
|
d04b7e9784 | ||
|
|
0320fe8261 | ||
|
|
cf99fc4908 | ||
|
|
52c7bdf280 | ||
|
|
7ab3afd00d | ||
|
|
f49ef8e919 | ||
|
|
0e1b61b422 | ||
|
|
aaddfa8561 | ||
|
|
05cfe4ca39 | ||
|
|
65437a5c21 | ||
|
|
1026605627 | ||
|
|
a08bc11064 | ||
|
|
5c694bf95b | ||
|
|
44ea407de5 | ||
|
|
a455b46073 | ||
|
|
3c22087a50 | ||
|
|
52aead1143 | ||
|
|
7ee259de02 | ||
|
|
1102517554 | ||
|
|
3518cbeb12 | ||
|
|
ef519dc14f | ||
|
|
d6663a0c77 | ||
|
|
536181bf06 | ||
|
|
0e30e13dec | ||
|
|
8a345be259 | ||
|
|
1608fde341 | ||
|
|
f7d731d1b9 | ||
|
|
00018650f8 | ||
|
|
cc4ee6d888 | ||
|
|
ac241e2676 | ||
|
|
d59b9e7059 | ||
|
|
10079ceba3 | ||
|
|
4c3f221c38 | ||
|
|
66db1449d1 | ||
|
|
0bbb53a03d | ||
|
|
e069aad656 | ||
|
|
5823d05d32 | ||
|
|
a8c35f3cb7 | ||
|
|
3befac7138 | ||
|
|
b4e2705a99 | ||
|
|
b22044216a | ||
|
|
1531915c1b | ||
|
|
273ea38e01 | ||
|
|
0b5baabfb2 | ||
|
|
d4a82ffafe | ||
|
|
6d489f2d17 | ||
|
|
4eca1585e7 | ||
|
|
0ada85d692 | ||
|
|
7726e01bcc | ||
|
|
44867affbe | ||
|
|
42dd6453fe | ||
|
|
cf9af05420 | ||
|
|
db77866cb7 | ||
|
|
3e40bc15b3 | ||
|
|
1bf7e9cbad | ||
|
|
f516a08415 | ||
|
|
c6ad7ffeca | ||
|
|
2fe8f449b3 | ||
|
|
d5f692c206 | ||
|
|
24c0e4fea8 | ||
|
|
9b75934b47 | ||
|
|
70703c6184 | ||
|
|
d0cb701907 | ||
|
|
4b41ccdb72 | ||
|
|
d7640a7047 | ||
|
|
5adc19e4da | ||
|
|
9f9287368c | ||
|
|
f1970ac7c8 | ||
|
|
141803b156 | ||
|
|
fbca946420 | ||
|
|
a7054bce15 | ||
|
|
0d8a4b61a6 | ||
|
|
fd349ae104 | ||
|
|
0ad979823e | ||
|
|
fcb2e5ed19 | ||
|
|
57a9ec8b29 | ||
|
|
3373e49fd0 | ||
|
|
a008a4e8c3 | ||
|
|
17d0daff86 | ||
|
|
2be9922b71 | ||
|
|
e25ce9548e | ||
|
|
45a7fa9f08 | ||
|
|
b1bf048295 | ||
|
|
4f906ac65f | ||
|
|
eb03c50ca8 | ||
|
|
44b156e1a7 | ||
|
|
b3754e7194 | ||
|
|
fde2b7607d | ||
|
|
51c510fb0c | ||
|
|
770cbad36f | ||
|
|
350b89e14e | ||
|
|
5002f7159a | ||
|
|
34ca29cee7 | ||
|
|
2db2c449f5 | ||
|
|
1fe5fbff5b | ||
|
|
3ede93d496 | ||
|
|
00ffa08659 | ||
|
|
4cc3212c9a | ||
|
|
b1b0770a86 |
2
.idea/libraries/uast_java.xml
generated
2
.idea/libraries/uast_java.xml
generated
@@ -3,13 +3,11 @@
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/uast-common.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/uast-java.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/uast-tests.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/uast-common-sources.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/uast-java-sources.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/uast-tests-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
2372
ChangeLog.md
2372
ChangeLog.md
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,10 @@ import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.config.KotlinCompilerVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion
|
||||
import org.jetbrains.kotlin.load.kotlin.DeserializedDescriptorResolver
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.build.deserializeFromPlainText
|
||||
import org.jetbrains.kotlin.build.serializeToPlainText
|
||||
|
||||
/**
|
||||
* If you want to add a new field, check its type is supported by [serializeToPlainText], [deserializeFromPlainText]
|
||||
@@ -59,7 +62,7 @@ data class JvmBuildMetaInfo(
|
||||
}
|
||||
|
||||
fun JvmBuildMetaInfo(args: CommonCompilerArguments): JvmBuildMetaInfo =
|
||||
JvmBuildMetaInfo(isEAP = KotlinCompilerVersion.isPreRelease(),
|
||||
JvmBuildMetaInfo(isEAP = DeserializedDescriptorResolver.IS_PRE_RELEASE,
|
||||
compilerBuildVersion = KotlinCompilerVersion.VERSION,
|
||||
languageVersionString = args.languageVersion ?: LanguageVersion.LATEST.versionString,
|
||||
apiVersionString = args.apiVersion ?: ApiVersion.LATEST.versionString,
|
||||
@@ -72,4 +75,4 @@ fun JvmBuildMetaInfo(args: CommonCompilerArguments): JvmBuildMetaInfo =
|
||||
metadataVersionPatch = JvmMetadataVersion.INSTANCE.patch,
|
||||
bytecodeVersionMajor = JvmBytecodeBinaryVersion.INSTANCE.major,
|
||||
bytecodeVersionMinor = JvmBytecodeBinaryVersion.INSTANCE.minor,
|
||||
bytecodeVersionPatch = JvmBytecodeBinaryVersion.INSTANCE.patch)
|
||||
bytecodeVersionPatch = JvmBytecodeBinaryVersion.INSTANCE.patch)
|
||||
55
build.xml
55
build.xml
@@ -406,9 +406,12 @@
|
||||
byline="true" encoding="UTF-8" />
|
||||
</target>
|
||||
|
||||
<target name="js-stdlib">
|
||||
<property environment="env"/>
|
||||
<target name="js-stdlib-preprocess">
|
||||
<kotlin-pp src="libraries/stdlib/src" output="${intermediate-sources}/stdlib/js" profile="JS" />
|
||||
</target>
|
||||
|
||||
<target name="js-stdlib" depends="js-stdlib-preprocess">
|
||||
<property environment="env"/>
|
||||
<cleandir dir="${js.stdlib.output.dir}"/>
|
||||
|
||||
<!-- We don't want descriptors for built-ins to be serialized, so we compile these files separately. -->
|
||||
@@ -474,7 +477,7 @@
|
||||
<copy file="${kotlin-home}/lib/kotlin-stdlib-js.jar" tofile="${kotlin-home}/lib/kotlin-jslib.jar" />
|
||||
</target>
|
||||
|
||||
<target name="pack-js-stdlib-sources">
|
||||
<target name="pack-js-stdlib-sources" depends="js-stdlib-preprocess">
|
||||
<jar destfile="${kotlin-home}/lib/kotlin-stdlib-js-sources.jar" duplicate="fail">
|
||||
<resources refid="js.lib.files" />
|
||||
<fileset refid="kotlin.builtin.files" />
|
||||
@@ -617,6 +620,13 @@
|
||||
</target>
|
||||
|
||||
<target name="compiler">
|
||||
<taskdef resource="proguard/ant/task.properties">
|
||||
<classpath>
|
||||
<pathelement path="${dependencies}/proguard.jar"/>
|
||||
<pathelement path="${dependencies}/proguard-anttask.jar"/>
|
||||
</classpath>
|
||||
</taskdef>
|
||||
|
||||
<cleandir dir="${output}/classes/compiler"/>
|
||||
|
||||
<javac2 destdir="${output}/classes/compiler" debug="true" debuglevel="lines,vars,source" includeAntRuntime="false"
|
||||
@@ -638,32 +648,17 @@
|
||||
unless:true="${shrink}" />
|
||||
|
||||
<sequential if:true="${shrink}">
|
||||
<shrink configuration="${basedir}/compiler/compiler.pro"/>
|
||||
</sequential>
|
||||
|
||||
<pack-compiler-for-maven/>
|
||||
</target>
|
||||
|
||||
<macrodef name="shrink">
|
||||
<attribute name="configuration"/>
|
||||
|
||||
<sequential>
|
||||
<taskdef resource="proguard/ant/task.properties">
|
||||
<classpath>
|
||||
<pathelement path="${dependencies}/proguard.jar"/>
|
||||
<pathelement path="${dependencies}/proguard-anttask.jar"/>
|
||||
</classpath>
|
||||
</taskdef>
|
||||
|
||||
<available property="rtjar" value="${java.home}/lib/rt.jar" file="${java.home}/lib/rt.jar"/>
|
||||
<available property="rtjar" value="${java.home}/../Classes/classes.jar" file="${java.home}/../Classes/classes.jar"/>
|
||||
|
||||
<available property="jssejar" value="${java.home}/lib/jsse.jar" file="${java.home}/lib/jsse.jar"/>
|
||||
<available property="jssejar" value="${java.home}/../Classes/jsse.jar" file="${java.home}/../Classes/jsse.jar"/>
|
||||
|
||||
<proguard configuration="@{configuration}"/>
|
||||
<proguard configuration="${basedir}/compiler/compiler.pro"/>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
|
||||
<pack-compiler-for-maven/>
|
||||
</target>
|
||||
|
||||
<macrodef name="pack-compiler-for-maven">
|
||||
<sequential>
|
||||
@@ -1032,13 +1027,13 @@
|
||||
<sequential>
|
||||
<java classname="org.jetbrains.kotlin.preloading.Preloader" failonerror="true" fork="true" maxmemory="${max.heap.size.for.forked.jvm}">
|
||||
<classpath>
|
||||
<pathelement location="${kotlin-home}/lib/kotlin-preloader.jar"/>
|
||||
<pathelement location="${bootstrap.compiler.home}/lib/kotlin-preloader.jar"/>
|
||||
</classpath>
|
||||
<assertions>
|
||||
<enable/>
|
||||
</assertions>
|
||||
<arg value="-cp"/>
|
||||
<arg value="${kotlin-home}/lib/kotlin-compiler.jar"/>
|
||||
<arg value="${bootstrap.compiler.home}/lib/kotlin-compiler.jar"/>
|
||||
<arg value="org.jetbrains.kotlin.preprocessor.PreprocessorCLI"/>
|
||||
<arg value="@{src}"/>
|
||||
<arg value="@{output}"/>
|
||||
@@ -1232,10 +1227,11 @@
|
||||
</manifest>
|
||||
</jar>
|
||||
|
||||
<delete file="${output}/kotlin-reflect-jarjar.jar" failonerror="false"/>
|
||||
|
||||
<sequential if:true="${obfuscate.reflect}">
|
||||
<taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask" classpath="dependencies/jarjar.jar"/>
|
||||
<delete file="${output}/kotlin-reflect-after-jarjar.jar" failonerror="false"/>
|
||||
<jarjar jarfile="${output}/kotlin-reflect-after-jarjar.jar" filesonly="true" filesetmanifest="merge">
|
||||
<jarjar jarfile="${output}/kotlin-reflect-jarjar.jar" filesonly="true" filesetmanifest="merge">
|
||||
<zipfileset src="${output}/kotlin-reflect-before-jarjar.jar"/>
|
||||
<rule pattern="org.jetbrains.kotlin.**" result="kotlin.reflect.jvm.internal.impl.@1"/>
|
||||
<rule pattern="javax.inject.**" result="kotlin.reflect.jvm.internal.impl.javax.inject.@1"/>
|
||||
@@ -1246,18 +1242,17 @@
|
||||
<compilerarg value="-script"/>
|
||||
<compilerarg value="kotlin/Metadata"/> <!-- Annotation to strip -->
|
||||
<compilerarg value="kotlin/reflect/jvm/internal/impl/.*"/> <!-- Classes to strip from -->
|
||||
<compilerarg value="${output}/kotlin-reflect-after-jarjar.jar"/>
|
||||
<compilerarg value="${output}/kotlin-reflect-before-proguard.jar"/>
|
||||
<compilerarg value="${output}/kotlin-reflect-jarjar.jar"/>
|
||||
<compilerarg value="${kotlin-home}/lib/kotlin-reflect.jar"/>
|
||||
<classpath>
|
||||
<pathelement location="${idea.sdk}/lib/asm-all.jar"/>
|
||||
</classpath>
|
||||
</kotlinc>
|
||||
|
||||
<shrink configuration="${basedir}/core/reflection.jvm/reflection.pro"/>
|
||||
</sequential>
|
||||
|
||||
<sequential unless:true="${obfuscate.reflect}">
|
||||
<echo message="Obfuscation of kotlin-reflect is disabled"/>
|
||||
<copy file="${output}/kotlin-reflect-before-jarjar.jar" tofile="${output}/kotlin-reflect-jarjar.jar" overwrite="true"/>
|
||||
<copy file="${output}/kotlin-reflect-before-jarjar.jar" tofile="${kotlin-home}/lib/kotlin-reflect.jar" overwrite="true"/>
|
||||
</sequential>
|
||||
</target>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
||||
@@ -32,12 +31,7 @@ abstract class ArgumentGenerator {
|
||||
*
|
||||
* @see kotlin.reflect.jvm.internal.KCallableImpl.callBy
|
||||
*/
|
||||
open fun generate(
|
||||
valueArgumentsByIndex: List<ResolvedValueArgument>,
|
||||
actualArgs: List<ResolvedValueArgument>,
|
||||
// may be null for a constructor of an object literal
|
||||
calleeDescriptor: CallableDescriptor?
|
||||
): DefaultCallArgs {
|
||||
open fun generate(valueArgumentsByIndex: List<ResolvedValueArgument>, actualArgs: List<ResolvedValueArgument>): DefaultCallArgs {
|
||||
assert(valueArgumentsByIndex.size == actualArgs.size) {
|
||||
"Value arguments collection should have same size, but ${valueArgumentsByIndex.size} != ${actualArgs.size}"
|
||||
}
|
||||
@@ -54,8 +48,7 @@ abstract class ArgumentGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
// Use unwrapped version, because additional synthetic parameters can't have default values
|
||||
val defaultArgs = DefaultCallArgs(calleeDescriptor?.unwrapFrontendVersion()?.valueParameters?.size ?: 0)
|
||||
val defaultArgs = DefaultCallArgs(valueArgumentsByIndex.size)
|
||||
|
||||
for (argumentWithDeclIndex in actualArgsWithDeclIndex) {
|
||||
val argument = argumentWithDeclIndex.arg
|
||||
|
||||
@@ -770,7 +770,6 @@ public class AsmUtil {
|
||||
if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
|
||||
if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
|
||||
if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
|
||||
if (left == Type.CHAR_TYPE || right == Type.CHAR_TYPE) return Type.CHAR_TYPE;
|
||||
return Type.INT_TYPE;
|
||||
}
|
||||
|
||||
|
||||
@@ -210,12 +210,7 @@ class NumberCompare(
|
||||
) : BranchedValue(left, right, operandType, NumberCompare.getNumberCompareOpcode(opToken)) {
|
||||
|
||||
override fun patchOpcode(opcode: Int, v: InstructionAdapter): Int {
|
||||
// Opcode takes one int operand from the stack
|
||||
assert(opcode in IFEQ..IFLE) {
|
||||
"Opcode for comparing must be in range ${IFEQ..IFLE}, but $opcode was found"
|
||||
}
|
||||
|
||||
return when (operandType) {
|
||||
when (operandType) {
|
||||
Type.FLOAT_TYPE, Type.DOUBLE_TYPE -> {
|
||||
if (opToken == KtTokens.GT || opToken == KtTokens.GTEQ) {
|
||||
v.cmpl(operandType)
|
||||
@@ -223,19 +218,17 @@ class NumberCompare(
|
||||
else {
|
||||
v.cmpg(operandType)
|
||||
}
|
||||
|
||||
opcode
|
||||
}
|
||||
Type.LONG_TYPE -> {
|
||||
v.lcmp()
|
||||
|
||||
opcode
|
||||
}
|
||||
else -> {
|
||||
opcode + (IF_ICMPEQ - IFEQ)
|
||||
return opcode + (IF_ICMPEQ - IFEQ)
|
||||
}
|
||||
}
|
||||
return opcode
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getNumberCompareOpcode(opToken: IElementType): Int {
|
||||
return when (opToken) {
|
||||
@@ -269,4 +262,4 @@ class ObjectCompare(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,13 +17,10 @@
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.psi.ValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*;
|
||||
import org.jetbrains.kotlin.types.FlexibleTypesKt;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
import java.util.List;
|
||||
@@ -56,12 +53,11 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
|
||||
@Override
|
||||
public DefaultCallArgs generate(
|
||||
@NotNull List<? extends ResolvedValueArgument> valueArgumentsByIndex,
|
||||
@NotNull List<? extends ResolvedValueArgument> valueArgs,
|
||||
@Nullable CallableDescriptor calleeDescriptor
|
||||
@NotNull List<? extends ResolvedValueArgument> valueArgs
|
||||
) {
|
||||
boolean shouldMarkLineNumbers = this.codegen.isShouldMarkLineNumbers();
|
||||
this.codegen.setShouldMarkLineNumbers(false);
|
||||
DefaultCallArgs defaultArgs = super.generate(valueArgumentsByIndex, valueArgs, calleeDescriptor);
|
||||
DefaultCallArgs defaultArgs = super.generate(valueArgumentsByIndex, valueArgs);
|
||||
this.codegen.setShouldMarkLineNumbers(shouldMarkLineNumbers);
|
||||
return defaultArgs;
|
||||
}
|
||||
@@ -88,9 +84,7 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
|
||||
protected void generateVararg(int i, @NotNull VarargValueArgument argument) {
|
||||
ValueParameterDescriptor parameter = valueParameters.get(i);
|
||||
Type type = valueParameterTypes.get(i);
|
||||
// Upper bound for type of vararg parameter should always have a form of 'Array<out T>',
|
||||
// while its lower bound may be Nothing-typed after approximation
|
||||
codegen.genVarargs(argument, FlexibleTypesKt.upperIfFlexible(parameter.getType()));
|
||||
codegen.genVarargs(argument, parameter.getType());
|
||||
callGenerator.afterParameterPut(type, null, i);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
|
||||
import org.jetbrains.kotlin.codegen.context.ClosureContext;
|
||||
import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
|
||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension;
|
||||
@@ -35,11 +34,13 @@ import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader;
|
||||
import org.jetbrains.kotlin.psi.KtElement;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
||||
@@ -62,6 +63,7 @@ import java.util.List;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConst;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLOSURE;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass;
|
||||
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHOD_FOR_FUNCTION;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
|
||||
@@ -396,9 +398,6 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
}
|
||||
else if (container instanceof PackageFragmentDescriptor) {
|
||||
iv.aconst(state.getTypeMapper().mapOwner(descriptor));
|
||||
// Note that this name is not used in reflection. There should be the name of the referenced declaration's module instead,
|
||||
// but there's no nice API to obtain that name here yet
|
||||
// TODO: write the referenced declaration's module name and use it in reflection
|
||||
iv.aconst(state.getModuleName());
|
||||
iv.invokestatic(REFLECTION, "getOrCreateKotlinPackage",
|
||||
Type.getMethodDescriptor(K_DECLARATION_CONTAINER_TYPE, getType(Class.class), getType(String.class)), false);
|
||||
@@ -470,6 +469,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
@NotNull CalculatedClosure closure,
|
||||
@NotNull Type ownerType
|
||||
) {
|
||||
BindingContext bindingContext = typeMapper.getBindingContext();
|
||||
List<FieldInfo> args = Lists.newArrayList();
|
||||
ClassDescriptor captureThis = closure.getCaptureThis();
|
||||
if (captureThis != null) {
|
||||
@@ -481,15 +481,23 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiverType), CAPTURED_RECEIVER_FIELD));
|
||||
}
|
||||
|
||||
for (EnclosedValueDescriptor enclosedValueDescriptor : closure.getCaptureVariables().values()) {
|
||||
DeclarationDescriptor descriptor = enclosedValueDescriptor.getDescriptor();
|
||||
if ((descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) ||
|
||||
ExpressionTypingUtils.isLocalFunction(descriptor)) {
|
||||
args.add(
|
||||
FieldInfo.createForHiddenField(
|
||||
ownerType, enclosedValueDescriptor.getType(), enclosedValueDescriptor.getFieldName()
|
||||
)
|
||||
);
|
||||
for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) {
|
||||
if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
|
||||
Type type = typeMapper.getSharedVarType(descriptor);
|
||||
if (type == null && descriptor instanceof LocalVariableDescriptor) {
|
||||
KotlinType delegateType = JvmCodegenUtil.getPropertyDelegateType((LocalVariableDescriptor) descriptor, bindingContext);
|
||||
if (delegateType != null) {
|
||||
type = typeMapper.mapType(delegateType);
|
||||
}
|
||||
}
|
||||
if (type == null) {
|
||||
type = typeMapper.mapType((VariableDescriptor) descriptor);
|
||||
}
|
||||
args.add(FieldInfo.createForHiddenField(ownerType, type, "$" + descriptor.getName().asString()));
|
||||
}
|
||||
else if (ExpressionTypingUtils.isLocalFunction(descriptor)) {
|
||||
Type classType = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor);
|
||||
args.add(FieldInfo.createForHiddenField(ownerType, classType, "$" + descriptor.getName().asString()));
|
||||
}
|
||||
else if (descriptor instanceof FunctionDescriptor) {
|
||||
assert captureReceiverType != null;
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
@@ -128,13 +129,11 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
|
||||
) {
|
||||
val typeMapper = state.typeMapper
|
||||
val isStatic = AsmUtil.isStaticMethod(contextKind, functionDescriptor)
|
||||
val baseMethodFlags = AsmUtil.getCommonCallableFlags(functionDescriptor) and Opcodes.ACC_VARARGS.inv()
|
||||
val remainingParameters = getRemainingParameters(functionDescriptor.original, substituteCount)
|
||||
val flags =
|
||||
baseMethodFlags or
|
||||
val flags = AsmUtil.getCommonCallableFlags(functionDescriptor) or
|
||||
(if (isStatic) Opcodes.ACC_STATIC else 0) or
|
||||
(if (functionDescriptor.modality == Modality.FINAL && functionDescriptor !is ConstructorDescriptor) Opcodes.ACC_FINAL else 0) or
|
||||
(if (remainingParameters.lastOrNull()?.varargElementType != null) Opcodes.ACC_VARARGS else 0)
|
||||
(if (functionDescriptor.modality == Modality.FINAL && functionDescriptor !is ConstructorDescriptor) Opcodes.ACC_FINAL else 0)
|
||||
|
||||
val remainingParameters = getRemainingParameters(functionDescriptor.original, substituteCount)
|
||||
val signature = typeMapper.mapSignature(functionDescriptor, contextKind, remainingParameters, false)
|
||||
val mv = classBuilder.newMethod(OtherOrigin(methodElement, functionDescriptor), flags,
|
||||
signature.asmMethod.name,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -1518,10 +1518,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
KotlinType expectedType = bindingContext.getType(expression);
|
||||
if (expectedType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return compileTimeValue.toConstantValue(expectedType);
|
||||
}
|
||||
|
||||
@@ -1709,7 +1705,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
ArgumentGenerator argumentGenerator =
|
||||
new CallBasedArgumentGenerator(ExpressionCodegen.this, defaultCallGenerator, valueParameters, mappedTypes);
|
||||
|
||||
argumentGenerator.generate(valueArguments, valueArguments, null);
|
||||
argumentGenerator.generate(valueArguments, valueArguments);
|
||||
}
|
||||
|
||||
Collection<ClassConstructorDescriptor> constructors = classDescriptor.getConstructors();
|
||||
@@ -2502,14 +2498,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
public int lookupLocalIndex(DeclarationDescriptor descriptor) {
|
||||
int index = myFrameMap.getIndex(descriptor);
|
||||
if (index != -1) return index;
|
||||
return myFrameMap.getIndex(getParameterSynonymOrThis(descriptor));
|
||||
}
|
||||
|
||||
private DeclarationDescriptor getParameterSynonymOrThis(DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof ValueParameterDescriptor)) return descriptor;
|
||||
|
||||
if (!(descriptor instanceof ValueParameterDescriptor)) return -1;
|
||||
DeclarationDescriptor synonym = bindingContext.get(CodegenBinding.PARAMETER_SYNONYM, (ValueParameterDescriptor) descriptor);
|
||||
if (synonym == null) return -1;
|
||||
|
||||
return myFrameMap.getIndex(synonym);
|
||||
return synonym != null ? synonym : descriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -2867,11 +2863,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
assert valueArguments != null : "Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor();
|
||||
|
||||
DefaultCallArgs defaultArgs =
|
||||
argumentGenerator.generate(
|
||||
valueArguments,
|
||||
new ArrayList<ResolvedValueArgument>(resolvedCall.getValueArguments().values()),
|
||||
resolvedCall.getResultingDescriptor()
|
||||
);
|
||||
argumentGenerator.generate(valueArguments, new ArrayList<ResolvedValueArgument>(resolvedCall.getValueArguments().values()));
|
||||
|
||||
if (tailRecursionCodegen.isTailRecursion(resolvedCall)) {
|
||||
tailRecursionCodegen.generateTailRecursion(resolvedCall);
|
||||
@@ -3029,8 +3021,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
@NotNull
|
||||
CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall<?> resolvedCall, @NotNull CallableDescriptor descriptor) {
|
||||
Map<TypeParameterDescriptor, KotlinType> typeArguments = getTypeArgumentsForResolvedCall(resolvedCall, descriptor);
|
||||
|
||||
Map<TypeParameterDescriptor, KotlinType> typeArguments = resolvedCall.getTypeArguments();
|
||||
TypeParameterMappings mappings = new TypeParameterMappings();
|
||||
for (Map.Entry<TypeParameterDescriptor, KotlinType> entry : typeArguments.entrySet()) {
|
||||
TypeParameterDescriptor key = entry.getKey();
|
||||
@@ -3055,38 +3046,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return getOrCreateCallGenerator(descriptor, resolvedCall.getCall().getCallElement(), mappings, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Map<TypeParameterDescriptor, KotlinType> getTypeArgumentsForResolvedCall(
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@NotNull CallableDescriptor descriptor
|
||||
) {
|
||||
if (!(descriptor instanceof TypeAliasConstructorDescriptor)) {
|
||||
return resolvedCall.getTypeArguments();
|
||||
}
|
||||
|
||||
TypeAliasConstructorDescriptor typeAliasConstructorDescriptor = (TypeAliasConstructorDescriptor) descriptor;
|
||||
ClassConstructorDescriptor underlyingConstructorDescriptor = typeAliasConstructorDescriptor.getUnderlyingConstructorDescriptor();
|
||||
KotlinType resultingType = typeAliasConstructorDescriptor.getReturnType();
|
||||
List<TypeProjection> typeArgumentsForReturnType = resultingType.getArguments();
|
||||
List<TypeParameterDescriptor> typeParameters = underlyingConstructorDescriptor.getTypeParameters();
|
||||
|
||||
assert typeParameters.size() == typeArgumentsForReturnType.size() :
|
||||
"Type parameters of the underlying constructor " + underlyingConstructorDescriptor +
|
||||
"should correspond to type arguments for the resulting type " + resultingType;
|
||||
|
||||
Map<TypeParameterDescriptor, KotlinType> typeArgumentsMap = Maps.newHashMapWithExpectedSize(typeParameters.size());
|
||||
for (TypeParameterDescriptor typeParameter: typeParameters) {
|
||||
KotlinType typeArgument = typeArgumentsForReturnType.get(typeParameter.getIndex()).getType();
|
||||
typeArgumentsMap.put(typeParameter, typeArgument);
|
||||
}
|
||||
|
||||
return typeArgumentsMap;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private static Pair<TypeParameterDescriptor, ReificationArgument> extractReificationArgument(@NotNull KotlinType type) {
|
||||
@@ -3196,7 +3158,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
boolean isSingleton = calleeContainingClass.getKind().isSingleton();
|
||||
if (isSingleton) {
|
||||
if (calleeContainingClass.equals(context.getThisDescriptor()) &&
|
||||
!CodegenUtilKt.isJvmStaticInObjectOrClass(context.getFunctionDescriptor())) {
|
||||
!CodegenUtilKt.isJvmStaticInObjectOrClass(context.getContextDescriptor())) {
|
||||
return StackValue.local(0, typeMapper.mapType(calleeContainingClass));
|
||||
}
|
||||
else if (isEnumEntry(calleeContainingClass)) {
|
||||
|
||||
@@ -231,7 +231,7 @@ public class FunctionCodegen {
|
||||
boolean staticInCompanionObject = CodegenUtilKt.isJvmStaticInCompanionObject(functionDescriptor);
|
||||
if (staticInCompanionObject) {
|
||||
ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
|
||||
parentBodyCodegen.addAdditionalTask(new JvmStaticInCompanionObjectGenerator(functionDescriptor, origin, state, parentBodyCodegen));
|
||||
parentBodyCodegen.addAdditionalTask(new JvmStaticGenerator(functionDescriptor, origin, state, parentBodyCodegen));
|
||||
}
|
||||
|
||||
if (!state.getClassBuilderMode().generateBodies || isAbstractMethod(functionDescriptor, contextKind, state)) {
|
||||
@@ -256,8 +256,7 @@ public class FunctionCodegen {
|
||||
else if (staticInCompanionObject) {
|
||||
// native @JvmStatic foo() in companion object should delegate to the static native function moved to the outer class
|
||||
mv.visitCode();
|
||||
FunctionDescriptor staticFunctionDescriptor = JvmStaticInCompanionObjectGenerator
|
||||
.createStaticFunctionDescriptor(functionDescriptor);
|
||||
FunctionDescriptor staticFunctionDescriptor = JvmStaticGenerator.createStaticFunctionDescriptor(functionDescriptor);
|
||||
Method accessorMethod =
|
||||
typeMapper.mapAsmMethod(memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor, null));
|
||||
Type owningType = typeMapper.mapClass((ClassifierDescriptor) staticFunctionDescriptor.getContainingDeclaration());
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
|
||||
class JvmStaticInCompanionObjectGenerator(
|
||||
class JvmStaticGenerator(
|
||||
val descriptor: FunctionDescriptor,
|
||||
val declarationOrigin: JvmDeclarationOrigin,
|
||||
val state: GenerationState,
|
||||
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||
import org.jetbrains.kotlin.fileClasses.FileClasses;
|
||||
@@ -238,20 +237,14 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
Annotations annotations = typeAliasDescriptor.getAnnotations();
|
||||
if (!isAnnotationsMethodOwner || annotations.getAllAnnotations().isEmpty()) return;
|
||||
|
||||
int flags = ACC_DEPRECATED | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC;
|
||||
String name = JvmAbi.getSyntheticMethodNameForAnnotatedTypeAlias(typeAliasDescriptor.getName());
|
||||
generateSyntheticAnnotationsMethod(typeAliasDescriptor, new Method(name, "()V"), annotations, null);
|
||||
}
|
||||
String desc = "()V";
|
||||
Method syntheticMethod = new Method(name, desc);
|
||||
|
||||
protected void generateSyntheticAnnotationsMethod(
|
||||
@NotNull MemberDescriptor descriptor,
|
||||
@NotNull Method syntheticMethod,
|
||||
@NotNull Annotations annotations,
|
||||
@Nullable AnnotationUseSiteTarget allowedTarget
|
||||
) {
|
||||
int flags = ACC_DEPRECATED | ACC_STATIC | ACC_SYNTHETIC | AsmUtil.getVisibilityAccessFlag(descriptor);
|
||||
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(descriptor), flags, syntheticMethod.getName(),
|
||||
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(typeAliasDescriptor), flags, syntheticMethod.getName(),
|
||||
syntheticMethod.getDescriptor(), null, null);
|
||||
AnnotationCodegen.forMethod(mv, this, typeMapper).genAnnotations(new AnnotatedSimple(annotations), Type.VOID_TYPE, allowedTarget);
|
||||
AnnotationCodegen.forMethod(mv, this, typeMapper).genAnnotations(new AnnotatedSimple(annotations), Type.VOID_TYPE, null);
|
||||
mv.visitCode();
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitEnd();
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.annotation.AnnotatedSimple;
|
||||
import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithFakeAnnotations;
|
||||
import org.jetbrains.kotlin.codegen.context.*;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
@@ -60,6 +61,7 @@ import static org.jetbrains.kotlin.codegen.AsmUtil.getVisibilityForBackingField;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.isPropertyWithBackingFieldCopyInOuterClass;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConstOrHasJvmFieldAnnotation;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.FIELD_FOR_PROPERTY;
|
||||
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.SYNTHETIC_METHOD_FOR_PROPERTY;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
|
||||
@@ -271,7 +273,7 @@ public class PropertyCodegen {
|
||||
}
|
||||
|
||||
// Annotations on properties are stored in bytecode on an empty synthetic method. This way they're still
|
||||
// accessible via reflection, and 'deprecated' and 'synthetic' flags prevent this method from being called accidentally
|
||||
// accessible via reflection, and 'deprecated' and 'private' flags prevent this method from being called accidentally
|
||||
private void generateSyntheticMethodIfNeeded(@NotNull PropertyDescriptor descriptor, @NotNull Annotations annotations) {
|
||||
if (annotations.getAllAnnotations().isEmpty()) return;
|
||||
|
||||
@@ -279,9 +281,15 @@ public class PropertyCodegen {
|
||||
if (!isInterface(contextDescriptor) ||
|
||||
(FunctionCodegen.processInterface(contextDescriptor, kind, state) ||
|
||||
(kind == OwnerKind.DEFAULT_IMPLS && state.getGenerateDefaultImplsForJvm8()))) {
|
||||
memberCodegen.generateSyntheticAnnotationsMethod(
|
||||
descriptor, getSyntheticMethodSignature(descriptor), annotations, AnnotationUseSiteTarget.PROPERTY
|
||||
);
|
||||
int flags = ACC_DEPRECATED | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC;
|
||||
Method syntheticMethod = getSyntheticMethodSignature(descriptor);
|
||||
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(descriptor), flags, syntheticMethod.getName(),
|
||||
syntheticMethod.getDescriptor(), null, null);
|
||||
AnnotationCodegen.forMethod(mv, memberCodegen, typeMapper)
|
||||
.genAnnotations(new AnnotatedSimple(annotations), Type.VOID_TYPE, AnnotationUseSiteTarget.PROPERTY);
|
||||
mv.visitCode();
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -281,33 +281,24 @@ public abstract class StackValue {
|
||||
}
|
||||
|
||||
private static void box(Type type, Type toType, InstructionAdapter v) {
|
||||
if (type == Type.BYTE_TYPE || toType.getInternalName().equals(NULLABLE_BYTE_TYPE_NAME) && type == Type.INT_TYPE) {
|
||||
v.cast(type, Type.BYTE_TYPE);
|
||||
v.invokestatic(NULLABLE_BYTE_TYPE_NAME, "valueOf", "(B)L" + NULLABLE_BYTE_TYPE_NAME + ";", false);
|
||||
}
|
||||
else if (type == Type.SHORT_TYPE || toType.getInternalName().equals(NULLABLE_SHORT_TYPE_NAME) && type == Type.INT_TYPE) {
|
||||
v.cast(type, Type.SHORT_TYPE);
|
||||
v.invokestatic(NULLABLE_SHORT_TYPE_NAME, "valueOf", "(S)L" + NULLABLE_SHORT_TYPE_NAME + ";", false);
|
||||
}
|
||||
else if (type == Type.LONG_TYPE || toType.getInternalName().equals(NULLABLE_LONG_TYPE_NAME) && type == Type.INT_TYPE) {
|
||||
v.cast(type, Type.LONG_TYPE);
|
||||
v.invokestatic(NULLABLE_LONG_TYPE_NAME, "valueOf", "(J)L" + NULLABLE_LONG_TYPE_NAME + ";", false);
|
||||
}
|
||||
else if (type == Type.INT_TYPE) {
|
||||
v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
|
||||
}
|
||||
else if (type == Type.BOOLEAN_TYPE) {
|
||||
v.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
|
||||
}
|
||||
else if (type == Type.CHAR_TYPE) {
|
||||
v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
|
||||
}
|
||||
else if (type == Type.FLOAT_TYPE) {
|
||||
v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
|
||||
}
|
||||
else if (type == Type.DOUBLE_TYPE) {
|
||||
v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
|
||||
if (type == Type.INT_TYPE) {
|
||||
if (toType.getInternalName().equals(NULLABLE_BYTE_TYPE_NAME)) {
|
||||
type = Type.BYTE_TYPE;
|
||||
}
|
||||
else if (toType.getInternalName().equals(NULLABLE_SHORT_TYPE_NAME)) {
|
||||
type = Type.SHORT_TYPE;
|
||||
}
|
||||
else if (toType.getInternalName().equals(NULLABLE_LONG_TYPE_NAME)) {
|
||||
type = Type.LONG_TYPE;
|
||||
}
|
||||
v.cast(Type.INT_TYPE, type);
|
||||
}
|
||||
|
||||
Type boxedType = AsmUtil.boxType(type);
|
||||
if (boxedType == type) return;
|
||||
|
||||
v.invokestatic(boxedType.getInternalName(), "valueOf", Type.getMethodDescriptor(boxedType, type), false);
|
||||
coerce(boxedType, toType, v);
|
||||
}
|
||||
|
||||
private static void unbox(Type type, InstructionAdapter v) {
|
||||
@@ -883,7 +874,7 @@ public abstract class StackValue {
|
||||
newReceiver.put(newReceiver.type, v);
|
||||
callGenerator.processAndPutHiddenParameters(false);
|
||||
|
||||
defaultArgs = generator.generate(valueArguments, valueArguments, call.getResultingDescriptor());
|
||||
defaultArgs = generator.generate(valueArguments, valueArguments);
|
||||
}
|
||||
|
||||
private ArgumentGenerator createArgumentGenerator() {
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.cfg.TailRecursionKind;
|
||||
import org.jetbrains.kotlin.codegen.context.MethodContext;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||
@@ -66,7 +65,7 @@ public class TailRecursionCodegen {
|
||||
}
|
||||
|
||||
public void generateTailRecursion(ResolvedCall<?> resolvedCall) {
|
||||
CallableDescriptor fd = CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(resolvedCall.getResultingDescriptor());
|
||||
CallableDescriptor fd = resolvedCall.getResultingDescriptor();
|
||||
assert fd instanceof FunctionDescriptor : "Resolved call doesn't refer to the function descriptor: " + fd;
|
||||
CallableMethod callable = (CallableMethod) codegen.resolveToCallable((FunctionDescriptor) fd, false, resolvedCall);
|
||||
|
||||
@@ -74,11 +73,6 @@ public class TailRecursionCodegen {
|
||||
if (arguments == null) {
|
||||
throw new IllegalStateException("Failed to arrange value arguments by index: " + fd);
|
||||
}
|
||||
|
||||
if (((FunctionDescriptor) fd).isSuspend()) {
|
||||
AsmUtil.pop(v, callable.getValueParameters().get(callable.getValueParameters().size() - 1).getAsmType());
|
||||
}
|
||||
|
||||
assignParameterValues(fd, callable, arguments);
|
||||
if (callable.getExtensionReceiverType() != null) {
|
||||
if (resolvedCall.getExtensionReceiver() != fd.getExtensionReceiverParameter().getValue()) {
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.codegen.binding;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.StackValue;
|
||||
import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
@@ -138,7 +137,7 @@ public final class MutableClosure implements CalculatedClosure {
|
||||
isSuspendLambda = true;
|
||||
}
|
||||
|
||||
private void recordField(String name, Type type) {
|
||||
public void recordField(String name, Type type) {
|
||||
if (recordedFields == null) {
|
||||
recordedFields = new LinkedList<Pair<String, Type>>();
|
||||
}
|
||||
@@ -146,8 +145,6 @@ public final class MutableClosure implements CalculatedClosure {
|
||||
}
|
||||
|
||||
public void captureVariable(EnclosedValueDescriptor value) {
|
||||
recordField(value.getFieldName(), value.getType());
|
||||
|
||||
if (captureVariables == null) {
|
||||
captureVariables = new LinkedHashMap<DeclarationDescriptor, EnclosedValueDescriptor>();
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ private fun Iterable<PackageParts>.addCompiledParts(state: GenerationState): Lis
|
||||
val incrementalCache = state.incrementalCacheForThisTarget ?: return this.toList()
|
||||
val moduleMappingData = incrementalCache.getModuleMappingData() ?: return this.toList()
|
||||
|
||||
val mapping = ModuleMapping.create(moduleMappingData, "<incremental>", state.deserializationConfiguration)
|
||||
val mapping = ModuleMapping.create(moduleMappingData, "<incremental>")
|
||||
|
||||
incrementalCache.getObsoletePackageParts().forEach { internalName ->
|
||||
val qualifier = internalName.substringBeforeLast('/', "").replace('/', '.')
|
||||
|
||||
@@ -75,6 +75,7 @@ public interface LocalLookup {
|
||||
enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, type);
|
||||
}
|
||||
|
||||
closure.recordField(fieldName, type);
|
||||
closure.captureVariable(enclosedValueDescriptor);
|
||||
|
||||
return innerValue;
|
||||
@@ -114,6 +115,7 @@ public interface LocalLookup {
|
||||
StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(localType, classType, fieldName, false,
|
||||
StackValue.LOCAL_0, vd);
|
||||
|
||||
closure.recordField(fieldName, localType);
|
||||
closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType));
|
||||
|
||||
return innerValue;
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
|
||||
@@ -40,10 +41,11 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
@@ -72,7 +74,7 @@ class CoroutineCodegen private constructor(
|
||||
// protected fun doResume(result, throwable)
|
||||
private val doResumeDescriptor =
|
||||
SimpleFunctionDescriptorImpl.create(
|
||||
classDescriptor, Annotations.EMPTY, Name.identifier(DO_RESUME_METHOD_NAME), CallableMemberDescriptor.Kind.DECLARATION,
|
||||
classDescriptor, Annotations.EMPTY, Name.identifier("doResume"), CallableMemberDescriptor.Kind.DECLARATION,
|
||||
funDescriptor.source
|
||||
).apply doResume@{
|
||||
initialize(
|
||||
@@ -114,7 +116,7 @@ class CoroutineCodegen private constructor(
|
||||
}
|
||||
|
||||
override fun generateClosureBody() {
|
||||
for (parameter in allFunctionParameters()) {
|
||||
for (parameter in allLambdaParameters()) {
|
||||
val fieldInfo = parameter.getFieldInfoForCoroutineLambdaParameter()
|
||||
v.newField(
|
||||
OtherOrigin(parameter),
|
||||
@@ -153,7 +155,7 @@ class CoroutineCodegen private constructor(
|
||||
}
|
||||
})
|
||||
|
||||
if (allFunctionParameters().size <= 1) {
|
||||
if (allLambdaParameters().size <= 1) {
|
||||
val delegate = typeMapper.mapSignatureSkipGeneric(createCoroutineDescriptor).asmMethod
|
||||
|
||||
val bridgeParameters = (1..delegate.argumentTypes.size - 1).map { AsmTypes.OBJECT_TYPE } + delegate.argumentTypes.last()
|
||||
@@ -239,7 +241,7 @@ class CoroutineCodegen private constructor(
|
||||
}
|
||||
|
||||
// load resultContinuation
|
||||
load(allFunctionParameters().map { typeMapper.mapType(it.type).size }.sum() + 1, AsmTypes.OBJECT_TYPE)
|
||||
load(allLambdaParameters().map { typeMapper.mapType(it.type).size }.sum() + 1, AsmTypes.OBJECT_TYPE)
|
||||
|
||||
invokespecial(owner.internalName, constructorToUseFromInvoke.name, constructorToUseFromInvoke.descriptor, false)
|
||||
|
||||
@@ -248,7 +250,7 @@ class CoroutineCodegen private constructor(
|
||||
|
||||
// Pass lambda parameters to 'invoke' call on newly constructed object
|
||||
var index = 1
|
||||
for (parameter in allFunctionParameters()) {
|
||||
for (parameter in allLambdaParameters()) {
|
||||
val fieldInfoForCoroutineLambdaParameter = parameter.getFieldInfoForCoroutineLambdaParameter()
|
||||
load(index, fieldInfoForCoroutineLambdaParameter.fieldType)
|
||||
AsmUtil.genAssignInstanceFieldFromParam(fieldInfoForCoroutineLambdaParameter, index, this, cloneIndex)
|
||||
@@ -261,36 +263,27 @@ class CoroutineCodegen private constructor(
|
||||
}
|
||||
|
||||
private fun ExpressionCodegen.initializeCoroutineParameters() {
|
||||
if (!isSuspendLambda && !originalSuspendFunctionDescriptor.isTailrec) return
|
||||
for (parameter in allFunctionParameters()) {
|
||||
val fieldStackValue =
|
||||
if (isSuspendLambda)
|
||||
StackValue.field(
|
||||
parameter.getFieldInfoForCoroutineLambdaParameter(), generateThisOrOuter(context.thisDescriptor, false)
|
||||
)
|
||||
else
|
||||
closureContext.lookupInContext(parameter, null, state, /* ignoreNoOuter = */ false)
|
||||
|
||||
for (parameter in allLambdaParameters()) {
|
||||
val mappedType = typeMapper.mapType(parameter.type)
|
||||
fieldStackValue.put(mappedType, v)
|
||||
|
||||
val newIndex = myFrameMap.enter(parameter, mappedType)
|
||||
|
||||
generateLoadField(parameter.getFieldInfoForCoroutineLambdaParameter())
|
||||
v.store(newIndex, mappedType)
|
||||
}
|
||||
|
||||
// necessary for proper tailrec codegen
|
||||
val actualMethodStartLabel = Label()
|
||||
v.visitLabel(actualMethodStartLabel)
|
||||
context.setMethodStartLabel(actualMethodStartLabel)
|
||||
|
||||
if (isSuspendLambda) {
|
||||
initializeVariablesForDestructuredLambdaParameters(this, originalSuspendFunctionDescriptor.valueParameters)
|
||||
}
|
||||
}
|
||||
|
||||
private fun allFunctionParameters() =
|
||||
originalSuspendFunctionDescriptor.extensionReceiverParameter.singletonOrEmptyList() +
|
||||
originalSuspendFunctionDescriptor.valueParameters.orEmpty()
|
||||
private fun allLambdaParameters() =
|
||||
if (isSuspendLambda)
|
||||
originalSuspendFunctionDescriptor.extensionReceiverParameter.singletonOrEmptyList() + originalSuspendFunctionDescriptor.valueParameters.orEmpty()
|
||||
else
|
||||
emptyList()
|
||||
|
||||
private fun ExpressionCodegen.generateLoadField(fieldInfo: FieldInfo) {
|
||||
StackValue.field(fieldInfo, generateThisOrOuter(context.thisDescriptor, false)).put(fieldInfo.fieldType, v)
|
||||
}
|
||||
|
||||
private fun ParameterDescriptor.getFieldInfoForCoroutineLambdaParameter() =
|
||||
createHiddenFieldInfo(type, COROUTINE_LAMBDA_PARAMETER_PREFIX + (this.safeAs<ValueParameterDescriptor>()?.index ?: ""))
|
||||
|
||||
@@ -141,12 +141,12 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
List<CapturedParamInfo> additionalFakeParams =
|
||||
extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder,
|
||||
transformationInfo, parentRemapper);
|
||||
List<DeferredMethodVisitor> deferringMethods = new ArrayList<DeferredMethodVisitor>();
|
||||
List<MethodVisitor> deferringMethods = new ArrayList<MethodVisitor>();
|
||||
|
||||
generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, parentRemapper, additionalFakeParams);
|
||||
|
||||
for (MethodNode next : methodsToTransform) {
|
||||
DeferredMethodVisitor deferringVisitor = newMethod(classBuilder, next);
|
||||
MethodVisitor deferringVisitor = newMethod(classBuilder, next);
|
||||
InlineResult funResult =
|
||||
inlineMethodAndUpdateGlobalResult(parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false);
|
||||
|
||||
@@ -161,8 +161,7 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
deferringMethods.add(deferringVisitor);
|
||||
}
|
||||
|
||||
for (DeferredMethodVisitor method : deferringMethods) {
|
||||
InlineCodegenUtil.removeFinallyMarkers(method.getIntermediate());
|
||||
for (MethodVisitor method : deferringMethods) {
|
||||
method.visitEnd();
|
||||
}
|
||||
|
||||
@@ -314,7 +313,6 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
MethodNode intermediateMethodNode =
|
||||
new MethodNode(AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
inlineMethodAndUpdateGlobalResult(parentRemapper, intermediateMethodNode, constructor, constructorInlineBuilder, true);
|
||||
InlineCodegenUtil.removeFinallyMarkers(intermediateMethodNode);
|
||||
|
||||
AbstractInsnNode first = intermediateMethodNode.instructions.getFirst();
|
||||
final Label oldStartLabel = first instanceof LabelNode ? ((LabelNode) first).getLabel() : null;
|
||||
|
||||
@@ -466,9 +466,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
adapter, infos, ((StackValue.Local) remapper.remap(parameters.getArgsSizeOnStack() + 1).value).index
|
||||
);
|
||||
removeStaticInitializationTrigger(adapter);
|
||||
if (!InlineCodegenUtil.isFinallyMarkerRequired(codegen.getContext())) {
|
||||
InlineCodegenUtil.removeFinallyMarkers(adapter);
|
||||
}
|
||||
removeFinallyMarkers(adapter);
|
||||
|
||||
adapter.accept(new MethodBodyVisitor(codegen.v));
|
||||
|
||||
@@ -1026,6 +1024,25 @@ public class InlineCodegen extends CallGenerator {
|
||||
//processor.substituteLocalVarTable(intoNode);
|
||||
}
|
||||
|
||||
private void removeFinallyMarkers(@NotNull MethodNode intoNode) {
|
||||
if (InlineCodegenUtil.isFinallyMarkerRequired(codegen.getContext())) return;
|
||||
|
||||
InsnList instructions = intoNode.instructions;
|
||||
AbstractInsnNode curInstr = instructions.getFirst();
|
||||
while (curInstr != null) {
|
||||
if (InlineCodegenUtil.isFinallyMarker(curInstr)) {
|
||||
AbstractInsnNode marker = curInstr;
|
||||
//just to assert
|
||||
getConstant(marker.getPrevious());
|
||||
curInstr = curInstr.getNext();
|
||||
instructions.remove(marker.getPrevious());
|
||||
instructions.remove(marker);
|
||||
continue;
|
||||
}
|
||||
curInstr = curInstr.getNext();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap, @NotNull SourceMapper parent) {
|
||||
return new NestedSourceMapper(parent, nodeAndSmap.getSortedRanges(), nodeAndSmap.getClassSMAP().getSourceInfo());
|
||||
|
||||
@@ -466,23 +466,6 @@ public class InlineCodegenUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeFinallyMarkers(@NotNull MethodNode intoNode) {
|
||||
InsnList instructions = intoNode.instructions;
|
||||
AbstractInsnNode curInstr = instructions.getFirst();
|
||||
while (curInstr != null) {
|
||||
if (isFinallyMarker(curInstr)) {
|
||||
AbstractInsnNode marker = curInstr;
|
||||
//just to assert
|
||||
getConstant(marker.getPrevious());
|
||||
curInstr = curInstr.getNext();
|
||||
instructions.remove(marker.getPrevious());
|
||||
instructions.remove(marker);
|
||||
continue;
|
||||
}
|
||||
curInstr = curInstr.getNext();
|
||||
}
|
||||
}
|
||||
|
||||
public static void addInlineMarker(@NotNull InstructionAdapter v, boolean isStartNotEnd) {
|
||||
v.visitMethodInsn(
|
||||
Opcodes.INVOKESTATIC, INLINE_MARKER_CLASS_NAME,
|
||||
|
||||
@@ -463,7 +463,6 @@ public class MethodInliner {
|
||||
Map<Integer, LambdaInfo> lambdaMapping = new HashMap<Integer, LambdaInfo>();
|
||||
|
||||
int offset = 0;
|
||||
boolean capturesAnonymousObjectThatMustBeRegenerated = false;
|
||||
for (int i = 0; i < paramCount; i++) {
|
||||
SourceValue sourceValue = frame.getStack(firstParameterIndex + i);
|
||||
LambdaInfo lambdaInfo = MethodInlinerUtilKt.getLambdaIfExistsAndMarkInstructions(
|
||||
@@ -472,17 +471,12 @@ public class MethodInliner {
|
||||
if (lambdaInfo != null) {
|
||||
lambdaMapping.put(offset, lambdaInfo);
|
||||
}
|
||||
else if (i < argTypes.length && isAnonymousClassThatMustBeRegenerated(argTypes[i])) {
|
||||
capturesAnonymousObjectThatMustBeRegenerated = true;
|
||||
}
|
||||
|
||||
offset += i == 0 ? 1 : argTypes[i - 1].getSize();
|
||||
}
|
||||
|
||||
transformations.add(
|
||||
buildConstructorInvocation(
|
||||
owner, desc, lambdaMapping, awaitClassReification, capturesAnonymousObjectThatMustBeRegenerated
|
||||
)
|
||||
buildConstructorInvocation(owner, desc, lambdaMapping, awaitClassReification)
|
||||
);
|
||||
awaitClassReification = false;
|
||||
}
|
||||
@@ -544,12 +538,6 @@ public class MethodInliner {
|
||||
return node;
|
||||
}
|
||||
|
||||
private boolean isAnonymousClassThatMustBeRegenerated(@Nullable Type type) {
|
||||
if (type == null || type.getSort() != Type.OBJECT) return false;
|
||||
AnonymousObjectTransformationInfo info = inliningContext.findAnonymousObjectTransformationInfo(type.getInternalName());
|
||||
return info != null && info.shouldRegenerate(true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Frame<SourceValue>[] analyzeMethodNodeBeforeInline(@NotNull MethodNode node) {
|
||||
try {
|
||||
@@ -596,8 +584,7 @@ public class MethodInliner {
|
||||
@NotNull String anonymousType,
|
||||
@NotNull String desc,
|
||||
@NotNull Map<Integer, LambdaInfo> lambdaMapping,
|
||||
boolean needReification,
|
||||
boolean capturesAnonymousObjectThatMustBeRegenerated
|
||||
boolean needReification
|
||||
) {
|
||||
boolean memoizeAnonymousObject = inliningContext.findAnonymousObjectTransformationInfo(anonymousType) == null;
|
||||
|
||||
@@ -607,8 +594,7 @@ public class MethodInliner {
|
||||
isAlreadyRegenerated(anonymousType),
|
||||
desc,
|
||||
false,
|
||||
inliningContext.nameGenerator,
|
||||
capturesAnonymousObjectThatMustBeRegenerated
|
||||
inliningContext.nameGenerator
|
||||
);
|
||||
|
||||
if (memoizeAnonymousObject) {
|
||||
|
||||
@@ -68,8 +68,7 @@ class AnonymousObjectTransformationInfo internal constructor(
|
||||
private val alreadyRegenerated: Boolean,
|
||||
val constructorDesc: String?,
|
||||
private val isStaticOrigin: Boolean,
|
||||
parentNameGenerator: NameGenerator,
|
||||
private val capturesAnonymousObjectThatMustBeRegenerated: Boolean = false
|
||||
parentNameGenerator: NameGenerator
|
||||
) : TransformationInfo {
|
||||
|
||||
override val nameGenerator by lazy {
|
||||
@@ -94,8 +93,7 @@ class AnonymousObjectTransformationInfo internal constructor(
|
||||
) : this(ownerInternalName, needReification, hashMapOf(), false, alreadyRegenerated, null, isStaticOrigin, nameGenerator)
|
||||
|
||||
override fun shouldRegenerate(sameModule: Boolean): Boolean =
|
||||
!alreadyRegenerated &&
|
||||
(!lambdasToInline.isEmpty() || !sameModule || capturedOuterRegenerated || needReification || capturesAnonymousObjectThatMustBeRegenerated)
|
||||
!alreadyRegenerated && (!lambdasToInline.isEmpty() || !sameModule || capturedOuterRegenerated || needReification)
|
||||
|
||||
override fun canRemoveAfterTransformation(): Boolean {
|
||||
// Note: It is unsafe to remove anonymous class that is referenced by GETSTATIC within lambda
|
||||
|
||||
@@ -25,7 +25,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
class CompareTo : IntrinsicMethod() {
|
||||
private fun genInvoke(type: Type?, v: InstructionAdapter) {
|
||||
when (type) {
|
||||
Type.INT_TYPE, Type.CHAR_TYPE -> v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "compare", "(II)I", false)
|
||||
Type.INT_TYPE -> v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "compare", "(II)I", false)
|
||||
Type.LONG_TYPE -> v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "compare", "(JJ)I", false)
|
||||
Type.FLOAT_TYPE -> v.invokestatic("java/lang/Float", "compare", "(FF)I", false)
|
||||
Type.DOUBLE_TYPE -> v.invokestatic("java/lang/Double", "compare", "(DD)I", false)
|
||||
|
||||
@@ -47,12 +47,12 @@ class Concat : IntrinsicMethod() {
|
||||
codegen.invokeAppend(element.right)
|
||||
}
|
||||
else {
|
||||
// Explicit plus call LHS?.plus(RHS) or LHS.plus(RHS)
|
||||
receiver.put(AsmTypes.JAVA_STRING_TYPE, v)
|
||||
// LHS?.plus(RHS)
|
||||
receiver.put(AsmTypes.OBJECT_TYPE, v)
|
||||
genStringBuilderConstructor(v)
|
||||
v.swap()
|
||||
genInvokeAppendMethod(v, returnType)
|
||||
codegen.invokeAppend(arguments[0])
|
||||
codegen.invokeAppend(arguments.get(0))
|
||||
}
|
||||
|
||||
v.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false)
|
||||
|
||||
@@ -20,53 +20,35 @@ import com.intellij.openapi.util.Pair
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.utils.toReadOnlyList
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import java.util.*
|
||||
|
||||
abstract class BoxedBasicValue(type: Type) : StrictBasicValue(type) {
|
||||
abstract val descriptor: BoxedValueDescriptor
|
||||
abstract fun taint(): BoxedBasicValue
|
||||
|
||||
override fun equals(other: Any?) = this === other
|
||||
override fun hashCode() = System.identityHashCode(this)
|
||||
}
|
||||
|
||||
|
||||
class CleanBoxedValue(
|
||||
class BoxedBasicValue(
|
||||
boxedType: Type,
|
||||
boxingInsn: AbstractInsnNode,
|
||||
progressionIterator: ProgressionIteratorBasicValue?
|
||||
) : BoxedBasicValue(boxedType) {
|
||||
override val descriptor = BoxedValueDescriptor(boxedType, boxingInsn, progressionIterator)
|
||||
|
||||
private var tainted: TaintedBoxedValue? = null
|
||||
override fun taint(): BoxedBasicValue = tainted ?: TaintedBoxedValue(this).also { tainted = it }
|
||||
}
|
||||
|
||||
|
||||
class TaintedBoxedValue(val boxedBasicValue: CleanBoxedValue) : BoxedBasicValue(boxedBasicValue.type) {
|
||||
override val descriptor get() = boxedBasicValue.descriptor
|
||||
|
||||
override fun taint(): BoxedBasicValue = this
|
||||
}
|
||||
|
||||
|
||||
class BoxedValueDescriptor(
|
||||
val boxedType: Type,
|
||||
val boxingInsn: AbstractInsnNode,
|
||||
val progressionIterator: ProgressionIteratorBasicValue?
|
||||
) {
|
||||
) : StrictBasicValue(boxedType) {
|
||||
private val associatedInsns = HashSet<AbstractInsnNode>()
|
||||
private val unboxingWithCastInsns = HashSet<Pair<AbstractInsnNode, Type>>()
|
||||
private val associatedVariables = HashSet<Int>()
|
||||
private val mergedWith = HashSet<BoxedValueDescriptor>()
|
||||
private val mergedWith = HashSet<BoxedBasicValue>()
|
||||
|
||||
val primitiveType: Type = unboxType(boxedType)
|
||||
var isSafeToRemove = true; private set
|
||||
val unboxedType: Type = getUnboxedType(boxedType)
|
||||
|
||||
fun getAssociatedInsns() = associatedInsns.toReadOnlyList()
|
||||
override fun equals(other: Any?) =
|
||||
this === other
|
||||
|
||||
fun typeEquals(other: BasicValue) =
|
||||
other is BoxedBasicValue && type == other.type
|
||||
|
||||
override fun hashCode() =
|
||||
System.identityHashCode(this)
|
||||
|
||||
fun getAssociatedInsns(): List<AbstractInsnNode> =
|
||||
ArrayList(associatedInsns)
|
||||
|
||||
fun addInsn(insnNode: AbstractInsnNode) {
|
||||
associatedInsns.add(insnNode)
|
||||
@@ -79,20 +61,22 @@ class BoxedValueDescriptor(
|
||||
fun getVariablesIndexes(): List<Int> =
|
||||
ArrayList(associatedVariables)
|
||||
|
||||
fun addMergedWith(descriptor: BoxedValueDescriptor) {
|
||||
mergedWith.add(descriptor)
|
||||
fun addMergedWith(value: BoxedBasicValue) {
|
||||
mergedWith.add(value)
|
||||
}
|
||||
|
||||
fun getMergedWith(): Iterable<BoxedValueDescriptor> =
|
||||
fun getMergedWith(): Iterable<BoxedBasicValue> =
|
||||
mergedWith
|
||||
|
||||
fun markAsUnsafeToRemove() {
|
||||
isSafeToRemove = false
|
||||
}
|
||||
|
||||
fun isDoubleSize() = unboxedType.size == 2
|
||||
fun isDoubleSize() =
|
||||
primitiveType.size == 2
|
||||
|
||||
fun isFromProgressionIterator() = progressionIterator != null
|
||||
fun isFromProgressionIterator() =
|
||||
progressionIterator != null
|
||||
|
||||
fun addUnboxingWithCastTo(insn: AbstractInsnNode, type: Type) {
|
||||
unboxingWithCastInsns.add(Pair.create(insn, type))
|
||||
@@ -100,14 +84,15 @@ class BoxedValueDescriptor(
|
||||
|
||||
fun getUnboxingWithCastInsns(): Set<Pair<AbstractInsnNode, Type>> =
|
||||
unboxingWithCastInsns
|
||||
}
|
||||
|
||||
|
||||
fun getUnboxedType(boxedType: Type): Type {
|
||||
val primitiveType = AsmUtil.unboxPrimitiveTypeOrNull(boxedType)
|
||||
if (primitiveType != null) return primitiveType
|
||||
|
||||
if (boxedType == AsmTypes.K_CLASS_TYPE) return AsmTypes.JAVA_CLASS_TYPE
|
||||
|
||||
throw IllegalArgumentException("Expected primitive type wrapper or KClass, got: $boxedType")
|
||||
|
||||
companion object {
|
||||
private fun unboxType(boxedType: Type): Type {
|
||||
val primitiveType = AsmUtil.unboxPrimitiveTypeOrNull(boxedType)
|
||||
if (primitiveType != null) return primitiveType
|
||||
|
||||
if (boxedType == AsmTypes.K_CLASS_TYPE) return AsmTypes.JAVA_CLASS_TYPE
|
||||
|
||||
throw IllegalArgumentException("Expected primitive type wrapper or KClass, got: $boxedType")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnList
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import java.util.*
|
||||
|
||||
@@ -38,23 +39,14 @@ open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasic
|
||||
protected open fun createNewBoxing(insn: AbstractInsnNode, type: Type, progressionIterator: ProgressionIteratorBasicValue?): BasicValue {
|
||||
val index = insnList.indexOf(insn)
|
||||
return boxingPlaces.getOrPut(index) {
|
||||
val boxedBasicValue = CleanBoxedValue(type, insn, progressionIterator)
|
||||
val boxedBasicValue = BoxedBasicValue(type, insn, progressionIterator)
|
||||
onNewBoxedValue(boxedBasicValue)
|
||||
boxedBasicValue
|
||||
}
|
||||
}
|
||||
|
||||
protected fun checkUsedValue(value: BasicValue) {
|
||||
if (value is TaintedBoxedValue) {
|
||||
onMergeFail(value)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(AnalyzerException::class)
|
||||
override fun naryOperation(insn: AbstractInsnNode, values: List<BasicValue>): BasicValue? {
|
||||
values.forEach {
|
||||
checkUsedValue(it)
|
||||
}
|
||||
|
||||
val value = super.naryOperation(insn, values)
|
||||
val firstArg = values.firstOrNull() ?: return value
|
||||
|
||||
@@ -88,39 +80,36 @@ open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasic
|
||||
}
|
||||
}
|
||||
|
||||
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? {
|
||||
checkUsedValue(value)
|
||||
|
||||
return if (insn.opcode == Opcodes.CHECKCAST && isExactValue(value))
|
||||
value
|
||||
else
|
||||
super.unaryOperation(insn, value)
|
||||
}
|
||||
@Throws(AnalyzerException::class)
|
||||
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? =
|
||||
if (insn.opcode == Opcodes.CHECKCAST && isExactValue(value))
|
||||
value
|
||||
else
|
||||
super.unaryOperation(insn, value)
|
||||
|
||||
protected open fun isExactValue(value: BasicValue) =
|
||||
value is ProgressionIteratorBasicValue ||
|
||||
value is CleanBoxedValue ||
|
||||
value is BoxedBasicValue ||
|
||||
value.type != null && isProgressionClass(value.type.internalName)
|
||||
|
||||
override fun merge(v: BasicValue, w: BasicValue) =
|
||||
when {
|
||||
v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE ->
|
||||
v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE -> {
|
||||
StrictBasicValue.UNINITIALIZED_VALUE
|
||||
v is BoxedBasicValue && w is BoxedBasicValue -> {
|
||||
onMergeSuccess(v, w)
|
||||
when {
|
||||
v is TaintedBoxedValue -> v
|
||||
w is TaintedBoxedValue -> w
|
||||
v.type != w.type -> v.taint()
|
||||
else -> v
|
||||
}
|
||||
}
|
||||
v is BoxedBasicValue ->
|
||||
v.taint()
|
||||
w is BoxedBasicValue ->
|
||||
w.taint()
|
||||
else ->
|
||||
v is BoxedBasicValue && v.typeEquals(w) -> {
|
||||
onMergeSuccess(v, w as BoxedBasicValue)
|
||||
v
|
||||
}
|
||||
else -> {
|
||||
if (v is BoxedBasicValue) {
|
||||
onMergeFail(v)
|
||||
}
|
||||
if (w is BoxedBasicValue) {
|
||||
onMergeFail(w)
|
||||
}
|
||||
super.merge(v, w)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun onNewBoxedValue(value: BoxedBasicValue) {}
|
||||
@@ -208,5 +197,7 @@ private fun isProgressionClass(internalClassName: String) =
|
||||
RangeCodegenUtil.isRangeOrProgression(buildFqNameByInternal(internalClassName))
|
||||
|
||||
private fun getValuesTypeOfProgressionClass(progressionClassInternalName: String) =
|
||||
RangeCodegenUtil.getPrimitiveRangeOrProgressionElementType(buildFqNameByInternal(progressionClassInternalName))
|
||||
?.typeName?.asString() ?: error("type should be not null")
|
||||
RangeCodegenUtil.getPrimitiveRangeOrProgressionElementType(buildFqNameByInternal(progressionClassInternalName))?.let {
|
||||
type ->
|
||||
type.typeName.asString()
|
||||
} ?: error("type should be not null")
|
||||
|
||||
@@ -22,25 +22,25 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
public class RedundantBoxedValuesCollection implements Iterable<BoxedValueDescriptor> {
|
||||
private final Set<BoxedValueDescriptor> safeToDeleteValues = new HashSet<BoxedValueDescriptor>();
|
||||
public class RedundantBoxedValuesCollection implements Iterable<BoxedBasicValue> {
|
||||
private final Set<BoxedBasicValue> safeToDeleteValues = new HashSet<BoxedBasicValue>();
|
||||
|
||||
public void add(@NotNull BoxedValueDescriptor descriptor) {
|
||||
safeToDeleteValues.add(descriptor);
|
||||
public void add(@NotNull BoxedBasicValue value) {
|
||||
safeToDeleteValues.add(value);
|
||||
}
|
||||
|
||||
public void remove(@NotNull BoxedValueDescriptor descriptor) {
|
||||
if (safeToDeleteValues.contains(descriptor)) {
|
||||
safeToDeleteValues.remove(descriptor);
|
||||
descriptor.markAsUnsafeToRemove();
|
||||
public void remove(@NotNull BoxedBasicValue value) {
|
||||
if (safeToDeleteValues.contains(value)) {
|
||||
safeToDeleteValues.remove(value);
|
||||
value.markAsUnsafeToRemove();
|
||||
|
||||
for (BoxedValueDescriptor mergedValueDescriptor : descriptor.getMergedWith()) {
|
||||
remove(mergedValueDescriptor);
|
||||
for (BoxedBasicValue mergedValue : value.getMergedWith()) {
|
||||
remove(mergedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void merge(@NotNull BoxedValueDescriptor v, @NotNull BoxedValueDescriptor w) {
|
||||
public void merge(@NotNull BoxedBasicValue v, @NotNull BoxedBasicValue w) {
|
||||
v.addMergedWith(w);
|
||||
w.addMergedWith(v);
|
||||
|
||||
@@ -59,7 +59,7 @@ public class RedundantBoxedValuesCollection implements Iterable<BoxedValueDescri
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<BoxedValueDescriptor> iterator() {
|
||||
public Iterator<BoxedBasicValue> iterator() {
|
||||
return safeToDeleteValues.iterator();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,12 +23,30 @@ import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnList
|
||||
import org.jetbrains.org.objectweb.asm.tree.TypeInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.VarInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
|
||||
internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterpreter(insnList) {
|
||||
|
||||
val candidatesBoxedValues = RedundantBoxedValuesCollection()
|
||||
|
||||
@Throws(AnalyzerException::class)
|
||||
override fun binaryOperation(insn: AbstractInsnNode, value1: BasicValue, value2: BasicValue): BasicValue? {
|
||||
processOperationWithBoxedValue(value1, insn)
|
||||
processOperationWithBoxedValue(value2, insn)
|
||||
|
||||
return super.binaryOperation(insn, value1, value2)
|
||||
}
|
||||
|
||||
@Throws(AnalyzerException::class)
|
||||
override fun ternaryOperation(insn: AbstractInsnNode, value1: BasicValue, value2: BasicValue, value3: BasicValue): BasicValue? {
|
||||
// in a valid code only aastore could happen with boxed value
|
||||
processOperationWithBoxedValue(value3, insn)
|
||||
|
||||
return super.ternaryOperation(insn, value1, value2, value3)
|
||||
}
|
||||
|
||||
@Throws(AnalyzerException::class)
|
||||
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? {
|
||||
if ((insn.opcode == Opcodes.CHECKCAST || insn.opcode == Opcodes.INSTANCEOF) && value is BoxedBasicValue) {
|
||||
val typeInsn = insn as TypeInsnNode
|
||||
@@ -43,23 +61,10 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete
|
||||
return super.unaryOperation(insn, value)
|
||||
}
|
||||
|
||||
override fun binaryOperation(insn: AbstractInsnNode, value1: BasicValue, value2: BasicValue): BasicValue? {
|
||||
processOperationWithBoxedValue(value1, insn)
|
||||
processOperationWithBoxedValue(value2, insn)
|
||||
|
||||
return super.binaryOperation(insn, value1, value2)
|
||||
}
|
||||
|
||||
override fun ternaryOperation(insn: AbstractInsnNode, value1: BasicValue, value2: BasicValue, value3: BasicValue): BasicValue? {
|
||||
// in a valid code only aastore could happen with boxed value
|
||||
processOperationWithBoxedValue(value3, insn)
|
||||
|
||||
return super.ternaryOperation(insn, value1, value2, value3)
|
||||
}
|
||||
|
||||
@Throws(AnalyzerException::class)
|
||||
override fun copyOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue {
|
||||
if (value is BoxedBasicValue && insn.opcode == Opcodes.ASTORE) {
|
||||
value.descriptor.addVariableIndex((insn as VarInsnNode).`var`)
|
||||
if (value is BoxedBasicValue && insn.opcode === Opcodes.ASTORE) {
|
||||
value.addVariableIndex((insn as VarInsnNode).`var`)
|
||||
}
|
||||
|
||||
processOperationWithBoxedValue(value, insn)
|
||||
@@ -72,15 +77,15 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete
|
||||
}
|
||||
|
||||
override fun onNewBoxedValue(value: BoxedBasicValue) {
|
||||
candidatesBoxedValues.add(value.descriptor)
|
||||
candidatesBoxedValues.add(value)
|
||||
}
|
||||
|
||||
override fun onUnboxing(insn: AbstractInsnNode, value: BoxedBasicValue, resultType: Type) {
|
||||
value.descriptor.run {
|
||||
if (unboxedType == resultType)
|
||||
addAssociatedInsn(value, insn)
|
||||
else
|
||||
addUnboxingWithCastTo(insn, resultType)
|
||||
if (value.primitiveType == resultType) {
|
||||
addAssociatedInsn(value, insn)
|
||||
}
|
||||
else {
|
||||
value.addUnboxingWithCastTo(insn, resultType)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,13 +98,11 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete
|
||||
}
|
||||
|
||||
override fun onMergeSuccess(v: BoxedBasicValue, w: BoxedBasicValue) {
|
||||
candidatesBoxedValues.merge(v.descriptor, w.descriptor)
|
||||
candidatesBoxedValues.merge(v, w)
|
||||
}
|
||||
|
||||
private fun processOperationWithBoxedValue(value: BasicValue?, insnNode: AbstractInsnNode) {
|
||||
if (value is BoxedBasicValue) {
|
||||
checkUsedValue(value)
|
||||
|
||||
if (!PERMITTED_OPERATIONS_OPCODES.contains(insnNode.opcode)) {
|
||||
markValueAsDirty(value)
|
||||
}
|
||||
@@ -110,7 +113,7 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete
|
||||
}
|
||||
|
||||
private fun markValueAsDirty(value: BoxedBasicValue) {
|
||||
candidatesBoxedValues.remove(value.descriptor)
|
||||
candidatesBoxedValues.remove(value)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -124,15 +127,17 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete
|
||||
when (targetInternalName) {
|
||||
Type.getInternalName(Any::class.java) ->
|
||||
true
|
||||
Type.getInternalName(Number::class.java) ->
|
||||
PRIMITIVE_TYPES_SORTS_WITH_WRAPPER_EXTENDS_NUMBER.contains(value.descriptor.unboxedType.sort)
|
||||
Type.getInternalName(Number::class.java) -> {
|
||||
PRIMITIVE_TYPES_SORTS_WITH_WRAPPER_EXTENDS_NUMBER.contains(
|
||||
value.primitiveType.sort)
|
||||
}
|
||||
else ->
|
||||
value.type.internalName == targetInternalName
|
||||
value.type.internalName.equals(targetInternalName)
|
||||
}
|
||||
|
||||
private fun addAssociatedInsn(value: BoxedBasicValue, insn: AbstractInsnNode) {
|
||||
value.descriptor.run {
|
||||
if (isSafeToRemove) addInsn(insn)
|
||||
if (value.isSafeToRemove) {
|
||||
value.addInsn(insn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.boxing;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
@@ -36,8 +38,9 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
@Override
|
||||
public void transform(@NotNull String internalClassName, @NotNull MethodNode node) {
|
||||
RedundantBoxingInterpreter interpreter = new RedundantBoxingInterpreter(node.instructions);
|
||||
Frame<BasicValue>[] frames = analyze(internalClassName, node, interpreter);
|
||||
|
||||
Frame<BasicValue>[] frames = analyze(
|
||||
internalClassName, node, interpreter
|
||||
);
|
||||
interpretPopInstructionsForBoxedValues(interpreter, node, frames);
|
||||
|
||||
RedundantBoxedValuesCollection valuesToOptimize = interpreter.getCandidatesBoxedValues();
|
||||
@@ -96,25 +99,32 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<BasicValue> variableValues = getValuesStoredOrLoadedToVariable(localVariableNode, node, frames);
|
||||
List<BasicValue> usedValues = getValuesStoredOrLoadedToVariable(localVariableNode, node, frames);
|
||||
|
||||
Collection<BasicValue> boxed = CollectionsKt.filter(variableValues, new Function1<BasicValue, Boolean>() {
|
||||
Collection<BasicValue> boxed = Collections2.filter(usedValues, new Predicate<BasicValue>() {
|
||||
@Override
|
||||
public Boolean invoke(BasicValue value) {
|
||||
return value instanceof BoxedBasicValue;
|
||||
public boolean apply(BasicValue input) {
|
||||
return input instanceof BoxedBasicValue;
|
||||
}
|
||||
});
|
||||
|
||||
if (boxed.isEmpty()) continue;
|
||||
|
||||
BoxedValueDescriptor firstBoxed = ((BoxedBasicValue) boxed.iterator().next()).getDescriptor();
|
||||
if (isUnsafeToRemoveBoxingForConnectedValues(variableValues, firstBoxed.getUnboxedType())) {
|
||||
for (BasicValue value : variableValues) {
|
||||
if (!(value instanceof BoxedBasicValue)) continue;
|
||||
final BoxedBasicValue firstBoxed = (BoxedBasicValue) boxed.iterator().next();
|
||||
|
||||
BoxedValueDescriptor descriptor = ((BoxedBasicValue) value).getDescriptor();
|
||||
if (descriptor.isSafeToRemove()) {
|
||||
values.remove(descriptor);
|
||||
if (CollectionsKt.any(usedValues, new Function1<BasicValue, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(BasicValue input) {
|
||||
if (input == StrictBasicValue.UNINITIALIZED_VALUE) return false;
|
||||
return input == null ||
|
||||
!(input instanceof BoxedBasicValue) ||
|
||||
!((BoxedBasicValue) input).isSafeToRemove() ||
|
||||
!((BoxedBasicValue) input).getPrimitiveType().equals(firstBoxed.getPrimitiveType());
|
||||
}
|
||||
})) {
|
||||
for (BasicValue value : usedValues) {
|
||||
if (value instanceof BoxedBasicValue && ((BoxedBasicValue) value).isSafeToRemove()) {
|
||||
values.remove((BoxedBasicValue) value);
|
||||
needToRepeat = true;
|
||||
}
|
||||
}
|
||||
@@ -124,20 +134,6 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
return needToRepeat;
|
||||
}
|
||||
|
||||
private static boolean isUnsafeToRemoveBoxingForConnectedValues(List<BasicValue> usedValues, final Type unboxedType) {
|
||||
return CollectionsKt.any(usedValues, new Function1<BasicValue, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(BasicValue input) {
|
||||
if (input == StrictBasicValue.UNINITIALIZED_VALUE) return false;
|
||||
if (!(input instanceof BoxedBasicValue)) return true;
|
||||
|
||||
BoxedValueDescriptor descriptor = ((BoxedBasicValue) input).getDescriptor();
|
||||
return !descriptor.isSafeToRemove() ||
|
||||
!(descriptor.getUnboxedType().equals(unboxedType));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void adaptLocalVariableTableForBoxedValues(@NotNull MethodNode node, @NotNull Frame<BasicValue>[] frames) {
|
||||
for (LocalVariableNode localVariableNode : node.localVariables) {
|
||||
if (Type.getType(localVariableNode.desc).getSort() != Type.OBJECT) {
|
||||
@@ -145,11 +141,8 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
}
|
||||
|
||||
for (BasicValue value : getValuesStoredOrLoadedToVariable(localVariableNode, node, frames)) {
|
||||
if (!(value instanceof BoxedBasicValue)) continue;
|
||||
|
||||
BoxedValueDescriptor descriptor = ((BoxedBasicValue) value).getDescriptor();
|
||||
if (!descriptor.isSafeToRemove()) continue;
|
||||
localVariableNode.desc = descriptor.getUnboxedType().getDescriptor();
|
||||
if (value == null || !(value instanceof BoxedBasicValue) || !((BoxedBasicValue) value).isSafeToRemove()) continue;
|
||||
localVariableNode.desc = ((BoxedBasicValue) value).getPrimitiveType().getDescriptor();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,9 +193,9 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
@NotNull
|
||||
private static int[] buildVariablesRemapping(@NotNull RedundantBoxedValuesCollection values, @NotNull MethodNode node) {
|
||||
Set<Integer> doubleSizedVars = new HashSet<Integer>();
|
||||
for (BoxedValueDescriptor valueDescriptor : values) {
|
||||
if (valueDescriptor.isDoubleSize()) {
|
||||
doubleSizedVars.addAll(valueDescriptor.getVariablesIndexes());
|
||||
for (BoxedBasicValue value : values) {
|
||||
if (value.getPrimitiveType().getSize() == 2) {
|
||||
doubleSizedVars.addAll(value.getVariablesIndexes());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,12 +233,12 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
@NotNull MethodNode node,
|
||||
@NotNull RedundantBoxedValuesCollection values
|
||||
) {
|
||||
for (BoxedValueDescriptor value : values) {
|
||||
for (BoxedBasicValue value : values) {
|
||||
adaptInstructionsForBoxedValue(node, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void adaptInstructionsForBoxedValue(@NotNull MethodNode node, @NotNull BoxedValueDescriptor value) {
|
||||
private static void adaptInstructionsForBoxedValue(@NotNull MethodNode node, @NotNull BoxedBasicValue value) {
|
||||
adaptBoxingInstruction(node, value);
|
||||
|
||||
for (Pair<AbstractInsnNode, Type> cast : value.getUnboxingWithCastInsns()) {
|
||||
@@ -257,7 +250,7 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
private static void adaptBoxingInstruction(@NotNull MethodNode node, @NotNull BoxedValueDescriptor value) {
|
||||
private static void adaptBoxingInstruction(@NotNull MethodNode node, @NotNull BoxedBasicValue value) {
|
||||
if (!value.isFromProgressionIterator()) {
|
||||
node.instructions.remove(value.getBoxingInsn());
|
||||
}
|
||||
@@ -287,12 +280,12 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
|
||||
private static void adaptCastInstruction(
|
||||
@NotNull MethodNode node,
|
||||
@NotNull BoxedValueDescriptor value,
|
||||
@NotNull BoxedBasicValue value,
|
||||
@NotNull Pair<AbstractInsnNode, Type> castWithType
|
||||
) {
|
||||
AbstractInsnNode castInsn = castWithType.getFirst();
|
||||
MethodNode castInsnsListener = new MethodNode(Opcodes.ASM5);
|
||||
new InstructionAdapter(castInsnsListener).cast(value.getUnboxedType(), castWithType.getSecond());
|
||||
new InstructionAdapter(castInsnsListener).cast(value.getPrimitiveType(), castWithType.getSecond());
|
||||
|
||||
for (AbstractInsnNode insn : castInsnsListener.instructions.toArray()) {
|
||||
node.instructions.insertBefore(castInsn, insn);
|
||||
@@ -302,7 +295,7 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
}
|
||||
|
||||
private static void adaptInstruction(
|
||||
@NotNull MethodNode node, @NotNull AbstractInsnNode insn, @NotNull BoxedValueDescriptor value
|
||||
@NotNull MethodNode node, @NotNull AbstractInsnNode insn, @NotNull BoxedBasicValue value
|
||||
) {
|
||||
boolean isDoubleSize = value.isDoubleSize();
|
||||
|
||||
@@ -329,7 +322,7 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
node.instructions.set(
|
||||
insn,
|
||||
new VarInsnNode(
|
||||
value.getUnboxedType().getOpcode(intVarOpcode),
|
||||
value.getPrimitiveType().getOpcode(intVarOpcode),
|
||||
((VarInsnNode) insn).var
|
||||
)
|
||||
);
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.codegen.signature;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil;
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmDescriptorTypeWriter;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
|
||||
@@ -58,7 +57,7 @@ public class JvmSignatureWriter extends JvmDescriptorTypeWriter<Type> {
|
||||
return;
|
||||
case Type.ARRAY:
|
||||
writeArrayType();
|
||||
writeAsmType(AsmUtil.correctElementType(asmType));
|
||||
writeAsmType(asmType.getElementType());
|
||||
writeArrayEnd();
|
||||
return;
|
||||
default:
|
||||
|
||||
@@ -41,10 +41,12 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.BindingTraceFilter
|
||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import java.io.File
|
||||
|
||||
@@ -92,7 +94,6 @@ class GenerationState @JvmOverloads constructor(
|
||||
val incrementalCacheForThisTarget: IncrementalCache?
|
||||
val packagesWithObsoleteParts: Set<FqName>
|
||||
val obsoleteMultifileClasses: List<FqName>
|
||||
val deserializationConfiguration: DeserializationConfiguration = CompilerDeserializationConfiguration(configuration)
|
||||
|
||||
init {
|
||||
val icComponents = configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS)
|
||||
@@ -166,7 +167,7 @@ class GenerationState @JvmOverloads constructor(
|
||||
|
||||
val generateParametersMetadata: Boolean = configuration.getBoolean(JVMConfigurationKeys.PARAMETERS_METADATA)
|
||||
|
||||
val languageVersionSettings = configuration.languageVersionSettings
|
||||
val languageVersionSettings = configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, LanguageVersionSettingsImpl.DEFAULT)
|
||||
val shouldInlineConstVals = languageVersionSettings.supportsFeature(LanguageFeature.InlineConstVals)
|
||||
|
||||
init {
|
||||
|
||||
@@ -958,7 +958,7 @@ public class KotlinTypeMapper {
|
||||
|
||||
if (!(descriptor instanceof ConstructorDescriptor) &&
|
||||
descriptor.getVisibility() == Visibilities.INTERNAL &&
|
||||
!descriptor.getAnnotations().hasAnnotation(KotlinBuiltIns.FQ_NAMES.publishedApi)) {
|
||||
!DescriptorUtilsKt.isPublishedApi(descriptor)) {
|
||||
return name + "$" + NameUtils.sanitizeAsJavaIdentifier(moduleName);
|
||||
}
|
||||
|
||||
@@ -1154,13 +1154,13 @@ public class KotlinTypeMapper {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getDefaultDescriptor(
|
||||
@NotNull Method method,
|
||||
@Nullable String dispatchReceiverDescriptor,
|
||||
@NotNull CallableDescriptor callableDescriptor
|
||||
) {
|
||||
private static String getDefaultDescriptor(@NotNull Method method, @Nullable String dispatchReceiverDescriptor, boolean isExtension) {
|
||||
String descriptor = method.getDescriptor();
|
||||
int maskArgumentsCount = (callableDescriptor.getValueParameters().size() + Integer.SIZE - 1) / Integer.SIZE;
|
||||
int argumentsCount = Type.getArgumentTypes(descriptor).length;
|
||||
if (isExtension) {
|
||||
argumentsCount--;
|
||||
}
|
||||
int maskArgumentsCount = (argumentsCount + Integer.SIZE - 1) / Integer.SIZE;
|
||||
String additionalArgs = StringUtil.repeat(Type.INT_TYPE.getDescriptor(), maskArgumentsCount);
|
||||
additionalArgs += (isConstructor(method) ? DEFAULT_CONSTRUCTOR_MARKER : OBJECT_TYPE).getDescriptor();
|
||||
String result = descriptor.replace(")", additionalArgs + ")");
|
||||
@@ -1186,7 +1186,7 @@ public class KotlinTypeMapper {
|
||||
String descriptor = getDefaultDescriptor(
|
||||
jvmSignature,
|
||||
isStaticMethod(kind, functionDescriptor) || isConstructor ? null : ownerType.getDescriptor(),
|
||||
CodegenUtilKt.unwrapFrontendVersion(functionDescriptor)
|
||||
functionDescriptor.getExtensionReceiverParameter() != null
|
||||
);
|
||||
|
||||
return new Method(isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, descriptor);
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.KotlinCompilerVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion
|
||||
import org.jetbrains.kotlin.load.kotlin.DeserializedDescriptorResolver
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.org.objectweb.asm.AnnotationVisitor
|
||||
@@ -37,7 +37,7 @@ fun writeKotlinMetadata(
|
||||
av.visit(JvmAnnotationNames.BYTECODE_VERSION_FIELD_NAME, JvmBytecodeBinaryVersion.INSTANCE.toArray())
|
||||
av.visit(JvmAnnotationNames.KIND_FIELD_NAME, kind.id)
|
||||
var flags = extraFlags
|
||||
if (KotlinCompilerVersion.isPreRelease() && state.languageVersionSettings.languageVersion == LanguageVersion.LATEST) {
|
||||
if (DeserializedDescriptorResolver.IS_PRE_RELEASE && state.languageVersionSettings.languageVersion == LanguageVersion.LATEST) {
|
||||
flags = flags or JvmAnnotationNames.METADATA_PRE_RELEASE_FLAG
|
||||
}
|
||||
if (flags != 0) {
|
||||
|
||||
@@ -63,9 +63,6 @@ public abstract class CommonCompilerArguments implements Serializable {
|
||||
@ValueDescription("<count>")
|
||||
public String repeat;
|
||||
|
||||
@Argument(value = "Xskip-metadata-version-check", description = "Load classes with bad metadata version anyway (incl. pre-release classes)")
|
||||
public boolean skipMetadataVersionCheck;
|
||||
|
||||
@Argument(value = "Xallow-kotlin-package", description = "Allow compiling code in package 'kotlin'")
|
||||
public boolean allowKotlinPackage;
|
||||
|
||||
@@ -79,6 +76,9 @@ public abstract class CommonCompilerArguments implements Serializable {
|
||||
@Argument(value = "Xno-check-impl", description = "Do not check presence of 'impl' modifier in multi-platform projects")
|
||||
public boolean noCheckImpl;
|
||||
|
||||
@Argument(value = "Xskip-java-check", description = "Do not warn when running the compiler under Java 6 or 7")
|
||||
public boolean noJavaVersionWarning;
|
||||
|
||||
@Argument(value = "Xcoroutines=warn")
|
||||
public boolean coroutinesWarn;
|
||||
|
||||
|
||||
@@ -94,6 +94,9 @@ public class K2JVMCompilerArguments extends CommonCompilerArguments {
|
||||
@Argument(value = "Xmultifile-parts-inherit", description = "Compile multifile classes as a hierarchy of parts and facade")
|
||||
public boolean inheritMultifileParts;
|
||||
|
||||
@Argument(value = "Xskip-metadata-version-check", description = "Load classes with bad metadata version anyway (incl. pre-release classes)")
|
||||
public boolean skipMetadataVersionCheck;
|
||||
|
||||
@Argument(value = "Xskip-runtime-version-check", description = "Allow Kotlin runtime libraries of incompatible versions in the classpath")
|
||||
public boolean skipRuntimeVersionCheck;
|
||||
|
||||
|
||||
@@ -23,8 +23,6 @@ import java.util.EnumSet;
|
||||
public enum CompilerMessageSeverity {
|
||||
EXCEPTION,
|
||||
ERROR,
|
||||
// Unlike a normal warning, a strong warning is not discarded when there are compilation errors.
|
||||
// Use it for problems related to configuration, not the diagnostics
|
||||
STRONG_WARNING,
|
||||
WARNING,
|
||||
INFO,
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.cli.common.repl
|
||||
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
|
||||
open class AggregatedReplStateHistory<T1, T2>(val history1: IReplStageHistory<T1>, val history2: IReplStageHistory<T2>, override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock())
|
||||
: IReplStageHistory<Pair<T1, T2>>, AbstractList<ReplHistoryRecord<Pair<T1, T2>>>()
|
||||
{
|
||||
override val size: Int
|
||||
get() = minOf(history1.size, history2.size)
|
||||
|
||||
override fun push(id: ILineId, item: Pair<T1, T2>) {
|
||||
lock.write {
|
||||
assertSameSize()
|
||||
history1.push(id, item.first)
|
||||
history2.push(id, item.second)
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(index: Int): ReplHistoryRecord<Pair<T1, T2>> = lock.read {
|
||||
assertSameSize()
|
||||
val r1 = history1[index]
|
||||
val r2 = history2[index]
|
||||
assertSameId(r1, r2)
|
||||
ReplHistoryRecord(r1.id, r1.item to r2.item)
|
||||
}
|
||||
|
||||
override fun pop(): ReplHistoryRecord<Pair<T1, T2>>? = lock.write {
|
||||
assertSameSize()
|
||||
val r1 = history1.pop()
|
||||
val r2 = history2.pop()
|
||||
if (r1 == null && r2 == null) return null
|
||||
if (r1 == null || r2 == null) throw IllegalStateException("Aggregated history mismatch: $r1 vs $r2")
|
||||
assertSameId(r1, r2)
|
||||
ReplHistoryRecord(r1.id, r1.item to r2.item)
|
||||
}
|
||||
|
||||
override fun resetTo(id: ILineId): Iterable<ILineId> = lock.write {
|
||||
assertSameSize()
|
||||
val i1 = history1.resetTo(id).toList()
|
||||
val i2 = history2.resetTo(id).toList()
|
||||
if (i1 != i2) throw IllegalStateException("Aggregated history resetted lines mismatch: $i1 != $i2")
|
||||
i1
|
||||
}
|
||||
|
||||
private fun assertSameSize() {
|
||||
if (history1.size != history2.size) throw IllegalStateException("Aggregated history sizes mismatch: ${history1.size} != ${history2.size}")
|
||||
}
|
||||
|
||||
private fun assertSameId(r1: ReplHistoryRecord<T1>, r2: ReplHistoryRecord<T2>) {
|
||||
if (r1.id != r2.id) throw IllegalStateException("Aggregated history mismatch: ${r1.id} != ${r2.id}")
|
||||
}
|
||||
}
|
||||
|
||||
open class AggregatedReplStageState<T1, T2>(val state1: IReplStageState<T1>, val state2: IReplStageState<T2>, final override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock())
|
||||
: IReplStageState<Pair<T1, T2>>
|
||||
{
|
||||
override val history: IReplStageHistory<Pair<T1, T2>> = AggregatedReplStateHistory(state1.history, state2.history, lock)
|
||||
|
||||
override fun <StateT : IReplStageState<*>> asState(target: Class<out StateT>): StateT =
|
||||
when {
|
||||
target.isAssignableFrom(state1::class.java) -> state1 as StateT
|
||||
target.isAssignableFrom(state2::class.java) -> state2 as StateT
|
||||
else -> super.asState(target)
|
||||
}
|
||||
|
||||
override fun getNextLineNo() = state1.getNextLineNo()
|
||||
|
||||
override val currentGeneration: Int get() = state1.currentGeneration
|
||||
}
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.cli.common.repl
|
||||
|
||||
import java.io.Serializable
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.write
|
||||
|
||||
data class LineId(override val no: Int, override val generation: Int, private val codeHash: Int) : ILineId, Serializable {
|
||||
|
||||
constructor(codeLine: ReplCodeLine): this(codeLine.no, codeLine.generation, codeLine.code.hashCode())
|
||||
|
||||
override fun compareTo(other: ILineId): Int = (other as? LineId)?.let {
|
||||
no.compareTo(it.no).takeIf { it != 0 }
|
||||
?: generation.compareTo(it.generation).takeIf { it != 0 }
|
||||
?: codeHash.compareTo(it.codeHash)
|
||||
} ?: -1 // TODO: check if it doesn't break something
|
||||
|
||||
companion object {
|
||||
private val serialVersionUID: Long = 8328353000L
|
||||
}
|
||||
}
|
||||
|
||||
open class BasicReplStageHistory<T>(override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()) : IReplStageHistory<T>, ArrayList<ReplHistoryRecord<T>>() {
|
||||
|
||||
val currentGeneration = AtomicInteger(REPL_CODE_LINE_FIRST_GEN)
|
||||
|
||||
override fun push(id: ILineId, item: T) {
|
||||
lock.write {
|
||||
add(ReplHistoryRecord(id, item))
|
||||
}
|
||||
}
|
||||
|
||||
override fun pop(): ReplHistoryRecord<T>? = lock.write { if (isEmpty()) null else removeAt(lastIndex) }
|
||||
|
||||
override fun resetTo(id: ILineId): Iterable<ILineId> {
|
||||
lock.write {
|
||||
val idx = indexOfFirst { it.id == id }
|
||||
if (idx < 0) throw java.util.NoSuchElementException("Cannot rest to inexistent line ${id.no}")
|
||||
if (idx < lastIndex) {
|
||||
val removed = asSequence().drop(idx + 1).map { it.id }.toList()
|
||||
removeRange(idx + 1, size)
|
||||
currentGeneration.incrementAndGet()
|
||||
return removed
|
||||
}
|
||||
else return emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class BasicReplStageState<HistoryItemT>(override final val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()): IReplStageState<HistoryItemT> {
|
||||
|
||||
override val currentGeneration: Int get() = history.currentGeneration.get()
|
||||
|
||||
override val history: BasicReplStageHistory<HistoryItemT> = BasicReplStageHistory(lock)
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.cli.common.repl
|
||||
|
||||
import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
|
||||
open class GenericReplEvaluatorState(baseClasspath: Iterable<File>, baseClassloader: ClassLoader?, override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock())
|
||||
: IReplStageState<EvalClassWithInstanceAndLoader>
|
||||
{
|
||||
override val history: IReplStageHistory<EvalClassWithInstanceAndLoader> = BasicReplStageHistory(lock)
|
||||
|
||||
override val currentGeneration: Int get() = (history as BasicReplStageHistory<*>).currentGeneration.get()
|
||||
|
||||
val topClassLoader: ReplClassLoader = makeReplClassLoader(baseClassloader, baseClasspath)
|
||||
|
||||
val currentClasspath: List<File> get() = lock.read {
|
||||
history.peek()?.item?.classLoader?.listAllUrlsAsFiles()
|
||||
?: topClassLoader.listAllUrlsAsFiles()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun makeReplClassLoader(baseClassloader: ClassLoader?, baseClasspath: Iterable<File>) =
|
||||
ReplClassLoader(URLClassLoader(baseClasspath.map { it.toURI().toURL() }.toTypedArray(), baseClassloader))
|
||||
@@ -22,37 +22,27 @@ import kotlin.concurrent.write
|
||||
|
||||
class GenericReplCompilingEvaluator(val compiler: ReplCompiler,
|
||||
baseClasspath: Iterable<File>,
|
||||
baseClassloader: ClassLoader? = Thread.currentThread().contextClassLoader,
|
||||
private val fallbackScriptArgs: ScriptArgsWithTypes? = null,
|
||||
repeatingMode: ReplRepeatingMode = ReplRepeatingMode.REPEAT_ONLY_MOST_RECENT
|
||||
baseClassloader: ClassLoader?,
|
||||
protected val fallbackScriptArgs: ScriptArgsWithTypes? = null,
|
||||
repeatingMode: ReplRepeatingMode = ReplRepeatingMode.REPEAT_ONLY_MOST_RECENT,
|
||||
protected val stateLock: ReentrantReadWriteLock = ReentrantReadWriteLock()
|
||||
) : ReplFullEvaluator {
|
||||
val evaluator = GenericReplEvaluator(baseClasspath, baseClassloader, fallbackScriptArgs, repeatingMode)
|
||||
val evaluator = GenericReplEvaluator(baseClasspath, baseClassloader, fallbackScriptArgs, repeatingMode, stateLock)
|
||||
|
||||
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = AggregatedReplStageState(compiler.createState(lock), evaluator.createState(lock), lock)
|
||||
|
||||
override fun compileAndEval(state: IReplStageState<*>, codeLine: ReplCodeLine, scriptArgs: ScriptArgsWithTypes?, invokeWrapper: InvokeWrapper?): ReplEvalResult {
|
||||
return state.lock.write {
|
||||
val aggregatedState = state.asState(AggregatedReplStageState::class.java)
|
||||
val compiled = compiler.compile(state, codeLine)
|
||||
override fun compileAndEval(codeLine: ReplCodeLine, scriptArgs: ScriptArgsWithTypes?, verifyHistory: List<ReplCodeLine>?, invokeWrapper: InvokeWrapper?): ReplEvalResult {
|
||||
return stateLock.write {
|
||||
val compiled = compiler.compile(codeLine, verifyHistory)
|
||||
when (compiled) {
|
||||
is ReplCompileResult.Error -> ReplEvalResult.Error.CompileTime(compiled.message, compiled.location)
|
||||
is ReplCompileResult.Incomplete -> ReplEvalResult.Incomplete()
|
||||
is ReplCompileResult.Error -> ReplEvalResult.Error.CompileTime(compiled.compiledHistory, compiled.message, compiled.location)
|
||||
is ReplCompileResult.HistoryMismatch -> ReplEvalResult.HistoryMismatch(compiled.compiledHistory, compiled.lineNo)
|
||||
is ReplCompileResult.Incomplete -> ReplEvalResult.Incomplete(compiled.compiledHistory)
|
||||
is ReplCompileResult.CompiledClasses -> {
|
||||
val result = eval(state, compiled, scriptArgs, invokeWrapper)
|
||||
val result = eval(compiled, scriptArgs, invokeWrapper)
|
||||
when (result) {
|
||||
is ReplEvalResult.Error,
|
||||
is ReplEvalResult.HistoryMismatch,
|
||||
is ReplEvalResult.Incomplete -> {
|
||||
aggregatedState.apply {
|
||||
lock.write {
|
||||
if (state1.history.size > state2.history.size) {
|
||||
state2.history.peek()?.let {
|
||||
state1.history.resetTo(it.id)
|
||||
}
|
||||
assert(state1.history.size == state2.history.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
result.completedEvalHistory.lastOrNull()?.let { compiler.resetToLine(it) }
|
||||
result
|
||||
}
|
||||
is ReplEvalResult.ValueResult,
|
||||
@@ -66,25 +56,49 @@ class GenericReplCompilingEvaluator(val compiler: ReplCompiler,
|
||||
}
|
||||
}
|
||||
|
||||
override fun eval(state: IReplStageState<*>, compileResult: ReplCompileResult.CompiledClasses, scriptArgs: ScriptArgsWithTypes?, invokeWrapper: InvokeWrapper?): ReplEvalResult =
|
||||
evaluator.eval(state, compileResult, scriptArgs, invokeWrapper)
|
||||
override fun resetToLine(lineNumber: Int): List<ReplCodeLine> {
|
||||
stateLock.write {
|
||||
val removedCompiledLines = compiler.resetToLine(lineNumber)
|
||||
val removedEvaluatorLines = evaluator.resetToLine(lineNumber)
|
||||
|
||||
override fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult = compiler.check(state, codeLine)
|
||||
removedCompiledLines.zip(removedEvaluatorLines).forEach {
|
||||
if (it.first != it.second) {
|
||||
throw IllegalStateException("History mismatch when resetting lines")
|
||||
}
|
||||
}
|
||||
|
||||
override fun compileToEvaluable(state: IReplStageState<*>, codeLine: ReplCodeLine, defaultScriptArgs: ScriptArgsWithTypes?): Pair<ReplCompileResult, Evaluable?> {
|
||||
val compiled = compiler.compile(state, codeLine)
|
||||
return removedCompiledLines
|
||||
}
|
||||
}
|
||||
|
||||
override fun resetToLine(line: ReplCodeLine): List<ReplCodeLine> = resetToLine(line.no)
|
||||
|
||||
override val lastEvaluatedScripts: List<EvalHistoryType> get() = evaluator.lastEvaluatedScripts
|
||||
override val history: List<ReplCodeLine> get() = evaluator.history
|
||||
override val currentClasspath: List<File> get() = evaluator.currentClasspath
|
||||
|
||||
override val compiledHistory: List<ReplCodeLine> get() = compiler.history
|
||||
override val evaluatedHistory: List<ReplCodeLine> get() = evaluator.history
|
||||
|
||||
override fun eval(compileResult: ReplCompileResult.CompiledClasses, scriptArgs: ScriptArgsWithTypes?, invokeWrapper: InvokeWrapper?): ReplEvalResult =
|
||||
evaluator.eval(compileResult, scriptArgs, invokeWrapper)
|
||||
|
||||
override fun check(codeLine: ReplCodeLine): ReplCheckResult = compiler.check(codeLine)
|
||||
|
||||
override fun compileToEvaluable(codeLine: ReplCodeLine, defaultScriptArgs: ScriptArgsWithTypes?, verifyHistory: List<ReplCodeLine>?): Pair<ReplCompileResult, Evaluable?> {
|
||||
val compiled = compiler.compile(codeLine, verifyHistory)
|
||||
return when (compiled) {
|
||||
// TODO: seems usafe when delayed evaluation may happen after some more compileAndEval calls on the same state; check and fix or protect
|
||||
is ReplCompileResult.CompiledClasses -> Pair(compiled, DelayedEvaluation(state, compiled, evaluator, defaultScriptArgs ?: fallbackScriptArgs))
|
||||
is ReplCompileResult.CompiledClasses -> Pair(compiled, DelayedEvaluation(compiled, stateLock, evaluator, defaultScriptArgs ?: fallbackScriptArgs))
|
||||
else -> Pair(compiled, null)
|
||||
}
|
||||
}
|
||||
|
||||
class DelayedEvaluation(private val state: IReplStageState<*>,
|
||||
override val compiledCode: ReplCompileResult.CompiledClasses,
|
||||
class DelayedEvaluation(override val compiledCode: ReplCompileResult.CompiledClasses,
|
||||
private val stateLock: ReentrantReadWriteLock,
|
||||
private val evaluator: ReplEvaluator,
|
||||
private val defaultScriptArgs: ScriptArgsWithTypes?) : Evaluable {
|
||||
override fun eval(scriptArgs: ScriptArgsWithTypes?, invokeWrapper: InvokeWrapper?): ReplEvalResult =
|
||||
evaluator.eval(state, compiledCode, scriptArgs ?: defaultScriptArgs, invokeWrapper)
|
||||
override fun eval(scriptArgs: ScriptArgsWithTypes?, invokeWrapper: InvokeWrapper?): ReplEvalResult {
|
||||
return stateLock.write { evaluator.eval(compiledCode, scriptArgs ?: defaultScriptArgs, invokeWrapper) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,55 +18,144 @@ package org.jetbrains.kotlin.cli.common.repl
|
||||
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
|
||||
open class GenericReplEvaluator(val baseClasspath: Iterable<File>,
|
||||
val baseClassloader: ClassLoader? = Thread.currentThread().contextClassLoader,
|
||||
open class GenericReplEvaluator(baseClasspath: Iterable<File>,
|
||||
baseClassloader: ClassLoader?,
|
||||
protected val fallbackScriptArgs: ScriptArgsWithTypes? = null,
|
||||
protected val repeatingMode: ReplRepeatingMode = ReplRepeatingMode.REPEAT_ONLY_MOST_RECENT
|
||||
protected val repeatingMode: ReplRepeatingMode = ReplRepeatingMode.REPEAT_ONLY_MOST_RECENT,
|
||||
protected val stateLock: ReentrantReadWriteLock = ReentrantReadWriteLock()
|
||||
) : ReplEvaluator {
|
||||
|
||||
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = GenericReplEvaluatorState(baseClasspath, baseClassloader, lock)
|
||||
private val topClassLoader: ReplClassLoader = makeReplClassLoader(baseClassloader, baseClasspath)
|
||||
|
||||
override fun eval(state: IReplStageState<*>,
|
||||
compileResult: ReplCompileResult.CompiledClasses,
|
||||
private val evaluatedHistory = ReplHistory<EvalClassWithInstanceAndLoader>()
|
||||
|
||||
override fun resetToLine(lineNumber: Int): List<ReplCodeLine> {
|
||||
return stateLock.write {
|
||||
evaluatedHistory.resetToLine(lineNumber)
|
||||
}.map { it.first }
|
||||
}
|
||||
|
||||
override val history: List<ReplCodeLine> get() = stateLock.read { evaluatedHistory.copySources() }
|
||||
|
||||
override val currentClasspath: List<File> get() = stateLock.read {
|
||||
evaluatedHistory.copyValues().lastOrNull()?.classLoader?.listAllUrlsAsFiles()
|
||||
?: topClassLoader.listAllUrlsAsFiles()
|
||||
}
|
||||
|
||||
private class HistoryActions(val effectiveHistory: List<EvalClassWithInstanceAndLoader>,
|
||||
val verify: (compareHistory: SourceList?) -> Int?,
|
||||
val addPlaceholder: (line: CompiledReplCodeLine, value: EvalClassWithInstanceAndLoader) -> Unit,
|
||||
val removePlaceholder: (line: CompiledReplCodeLine) -> Boolean,
|
||||
val addFinal: (line: CompiledReplCodeLine, value: EvalClassWithInstanceAndLoader) -> Unit,
|
||||
val processClasses: (compileResult: ReplCompileResult.CompiledClasses) -> Pair<ClassLoader, Class<out Any>>)
|
||||
|
||||
private fun prependClassLoaderWithNewClasses(effectiveHistory: List<EvalClassWithInstanceAndLoader>, compileResult: ReplCompileResult.CompiledClasses): Pair<ClassLoader, Class<out Any>> {
|
||||
return stateLock.write {
|
||||
var mainLineClassName: String? = null
|
||||
val classLoader = makeReplClassLoader(effectiveHistory.lastOrNull()?.classLoader ?: topClassLoader, compileResult.classpathAddendum)
|
||||
fun classNameFromPath(path: String) = JvmClassName.byInternalName(path.removeSuffix(".class"))
|
||||
fun compiledClassesNames() = compileResult.classes.map { classNameFromPath(it.path).internalName.replace('/', '.') }
|
||||
val expectedClassName = compileResult.generatedClassname
|
||||
compileResult.classes.filter { it.path.endsWith(".class") }
|
||||
.forEach {
|
||||
val className = classNameFromPath(it.path)
|
||||
if (className.internalName == expectedClassName || className.internalName.endsWith("/$expectedClassName")) {
|
||||
mainLineClassName = className.internalName.replace('/', '.')
|
||||
}
|
||||
classLoader.addClass(className, it.bytes)
|
||||
}
|
||||
|
||||
val scriptClass = try {
|
||||
classLoader.loadClass(mainLineClassName!!)
|
||||
}
|
||||
catch (t: Throwable) {
|
||||
throw Exception("Error loading class $mainLineClassName: known classes: ${compiledClassesNames()}", t)
|
||||
}
|
||||
Pair(classLoader, scriptClass)
|
||||
}
|
||||
}
|
||||
|
||||
override fun eval(compileResult: ReplCompileResult.CompiledClasses,
|
||||
scriptArgs: ScriptArgsWithTypes?,
|
||||
invokeWrapper: InvokeWrapper?): ReplEvalResult {
|
||||
state.lock.write {
|
||||
val evalState = state.asState(GenericReplEvaluatorState::class.java)
|
||||
val historyActor = when (repeatingMode) {
|
||||
ReplRepeatingMode.NONE -> HistoryActionsForNoRepeat(evalState)
|
||||
stateLock.write {
|
||||
val verifyHistory = compileResult.compiledHistory.dropLast(1)
|
||||
val defaultHistoryActor = HistoryActions(
|
||||
effectiveHistory = evaluatedHistory.copyValues(),
|
||||
verify = { line -> evaluatedHistory.firstMismatchingHistory(line) },
|
||||
addPlaceholder = { line, value -> evaluatedHistory.add(line, value) },
|
||||
removePlaceholder = { line -> evaluatedHistory.removeLast(line) },
|
||||
addFinal = { line, value -> evaluatedHistory.add(line, value) },
|
||||
processClasses = { compiled ->
|
||||
prependClassLoaderWithNewClasses(evaluatedHistory.copyValues(), compiled)
|
||||
})
|
||||
|
||||
val historyActor: HistoryActions = when (repeatingMode) {
|
||||
ReplRepeatingMode.NONE -> defaultHistoryActor
|
||||
ReplRepeatingMode.REPEAT_ONLY_MOST_RECENT -> {
|
||||
val lastItem = evalState.history.peek()
|
||||
if (lastItem == null || lastItem.id != compileResult.lineId) {
|
||||
HistoryActionsForNoRepeat(evalState)
|
||||
val lastItem = evaluatedHistory.lastItem()
|
||||
if (lastItem == null || lastItem.first.source != compileResult.compiledCodeLine.source) {
|
||||
defaultHistoryActor
|
||||
}
|
||||
else {
|
||||
HistoryActionsForRepeatRecentOnly(evalState)
|
||||
val trimmedHistory = ReplHistory(evaluatedHistory.copyAll().dropLast(1))
|
||||
HistoryActions(
|
||||
effectiveHistory = trimmedHistory.copyValues(),
|
||||
verify = { trimmedHistory.firstMismatchingHistory(it) },
|
||||
addPlaceholder = { _, _ -> NO_ACTION() },
|
||||
removePlaceholder = { NO_ACTION_THAT_RETURNS(true) },
|
||||
addFinal = { line, value ->
|
||||
evaluatedHistory.removeLast(line)
|
||||
evaluatedHistory.add(line, value)
|
||||
},
|
||||
processClasses = { _ ->
|
||||
Pair(lastItem.second.classLoader, lastItem.second.klass.java)
|
||||
})
|
||||
}
|
||||
}
|
||||
ReplRepeatingMode.REPEAT_ANY_PREVIOUS -> {
|
||||
val matchingItem = evalState.history.firstOrNull { it.id == compileResult.lineId }
|
||||
if (matchingItem == null) {
|
||||
HistoryActionsForNoRepeat(evalState)
|
||||
if (evaluatedHistory.isEmpty() || !evaluatedHistory.contains(compileResult.compiledCodeLine.source)) {
|
||||
defaultHistoryActor
|
||||
}
|
||||
else {
|
||||
HistoryActionsForRepeatAny(evalState, matchingItem)
|
||||
val historyCopy = evaluatedHistory.copyAll()
|
||||
val matchingItem = historyCopy.first { it.first.source == compileResult.compiledCodeLine.source }
|
||||
val trimmedHistory = ReplHistory(evaluatedHistory.copyAll().takeWhile { it != matchingItem })
|
||||
HistoryActions(
|
||||
effectiveHistory = trimmedHistory.copyValues(),
|
||||
verify = { trimmedHistory.firstMismatchingHistory(it) },
|
||||
addPlaceholder = { _, _ -> NO_ACTION() },
|
||||
removePlaceholder = { NO_ACTION_THAT_RETURNS(true) },
|
||||
addFinal = { line, value ->
|
||||
val extraLines = evaluatedHistory.resetToLine(line)
|
||||
evaluatedHistory.removeLast(line)
|
||||
evaluatedHistory.add(line, value)
|
||||
extraLines.forEach {
|
||||
evaluatedHistory.add(it.first, it.second)
|
||||
}
|
||||
},
|
||||
processClasses = { _ ->
|
||||
Pair(matchingItem.second.classLoader, matchingItem.second.klass.java)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val firstMismatch = historyActor.firstMismatch(compileResult.previousLines.asSequence())
|
||||
val firstMismatch = historyActor.verify(verifyHistory)
|
||||
if (firstMismatch != null) {
|
||||
return@eval ReplEvalResult.HistoryMismatch(firstMismatch.first?.id?.no ?: firstMismatch.second?.no ?: -1 /* means error? */)
|
||||
return@eval ReplEvalResult.HistoryMismatch(evaluatedHistory.copySources(), firstMismatch)
|
||||
}
|
||||
|
||||
val (classLoader, scriptClass) = try {
|
||||
historyActor.processClasses(compileResult)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
return@eval ReplEvalResult.Error.Runtime(e.message ?: "unknown", e)
|
||||
return@eval ReplEvalResult.Error.Runtime(evaluatedHistory.copySources(), e.message ?: "unknown", e)
|
||||
}
|
||||
|
||||
val currentScriptArgs = scriptArgs ?: fallbackScriptArgs
|
||||
@@ -81,7 +170,7 @@ open class GenericReplEvaluator(val baseClasspath: Iterable<File>,
|
||||
// TODO: try/catch ?
|
||||
val scriptInstanceConstructor = scriptClass.getConstructor(*constructorParams)
|
||||
|
||||
historyActor.addPlaceholder(compileResult.lineId, EvalClassWithInstanceAndLoader(scriptClass.kotlin, null, classLoader, invokeWrapper))
|
||||
historyActor.addPlaceholder(compileResult.compiledCodeLine, EvalClassWithInstanceAndLoader(scriptClass.kotlin, null, classLoader, invokeWrapper))
|
||||
|
||||
val scriptInstance =
|
||||
try {
|
||||
@@ -89,113 +178,33 @@ open class GenericReplEvaluator(val baseClasspath: Iterable<File>,
|
||||
else scriptInstanceConstructor.newInstance(*constructorArgs)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
historyActor.removePlaceholder(compileResult.lineId)
|
||||
historyActor.removePlaceholder(compileResult.compiledCodeLine)
|
||||
|
||||
// ignore everything in the stack trace until this constructor call
|
||||
return@eval ReplEvalResult.Error.Runtime(renderReplStackTrace(e.cause!!, startFromMethodName = "${scriptClass.name}.<init>"), e as? Exception)
|
||||
return@eval ReplEvalResult.Error.Runtime(evaluatedHistory.copySources(),
|
||||
renderReplStackTrace(e.cause!!, startFromMethodName = "${scriptClass.name}.<init>"), e as? Exception)
|
||||
}
|
||||
|
||||
historyActor.removePlaceholder(compileResult.lineId)
|
||||
historyActor.addFinal(compileResult.lineId, EvalClassWithInstanceAndLoader(scriptClass.kotlin, scriptInstance, classLoader, invokeWrapper))
|
||||
historyActor.removePlaceholder(compileResult.compiledCodeLine)
|
||||
historyActor.addFinal(compileResult.compiledCodeLine, EvalClassWithInstanceAndLoader(scriptClass.kotlin, scriptInstance, classLoader, invokeWrapper))
|
||||
|
||||
val resultField = scriptClass.getDeclaredField(SCRIPT_RESULT_FIELD_NAME).apply { isAccessible = true }
|
||||
val resultValue: Any? = resultField.get(scriptInstance)
|
||||
|
||||
return if (compileResult.hasResult) ReplEvalResult.ValueResult(resultValue)
|
||||
else ReplEvalResult.UnitResult()
|
||||
return if (compileResult.hasResult) ReplEvalResult.ValueResult(evaluatedHistory.copySources(), resultValue)
|
||||
else ReplEvalResult.UnitResult(evaluatedHistory.copySources())
|
||||
}
|
||||
}
|
||||
|
||||
override val lastEvaluatedScripts: List<EvalHistoryType> get() {
|
||||
return stateLock.read { evaluatedHistory.copyAll() }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val SCRIPT_RESULT_FIELD_NAME = "\$\$result"
|
||||
}
|
||||
|
||||
private fun makeReplClassLoader(baseClassloader: ClassLoader?, baseClasspath: Iterable<File>) =
|
||||
ReplClassLoader(URLClassLoader(baseClasspath.map { it.toURI().toURL() }.toTypedArray(), baseClassloader))
|
||||
}
|
||||
|
||||
private open class HistoryActionsForNoRepeat(val state: GenericReplEvaluatorState) {
|
||||
|
||||
open val effectiveHistory: List<EvalClassWithInstanceAndLoader> get() = state.history.map { it.item }
|
||||
|
||||
open fun firstMismatch(other: Sequence<ILineId>): Pair<ReplHistoryRecord<EvalClassWithInstanceAndLoader>?, ILineId?>? = state.history.firstMismatch(other)
|
||||
|
||||
open fun addPlaceholder(lineId: ILineId, value: EvalClassWithInstanceAndLoader) { state.history.push(lineId, value) }
|
||||
|
||||
open fun removePlaceholder(lineId: ILineId): Boolean = state.history.verifiedPop(lineId) != null
|
||||
|
||||
open fun addFinal(lineId: ILineId, value: EvalClassWithInstanceAndLoader) { state.history.push(lineId, value) }
|
||||
|
||||
open fun processClasses(compileResult: ReplCompileResult.CompiledClasses): Pair<ClassLoader, Class<out Any>> = prependClassLoaderWithNewClasses(effectiveHistory, compileResult)
|
||||
|
||||
private fun prependClassLoaderWithNewClasses(effectiveHistory: List<EvalClassWithInstanceAndLoader>,
|
||||
compileResult: ReplCompileResult.CompiledClasses
|
||||
): Pair<ClassLoader, Class<out Any>> {
|
||||
var mainLineClassName: String? = null
|
||||
val classLoader = makeReplClassLoader(effectiveHistory.lastOrNull()?.classLoader ?: state.topClassLoader, compileResult.classpathAddendum)
|
||||
fun classNameFromPath(path: String) = JvmClassName.byInternalName(path.removeSuffix(".class"))
|
||||
fun compiledClassesNames() = compileResult.classes.map { classNameFromPath(it.path).internalName.replace('/', '.') }
|
||||
val expectedClassName = compileResult.mainClassName
|
||||
compileResult.classes.filter { it.path.endsWith(".class") }
|
||||
.forEach {
|
||||
val className = classNameFromPath(it.path)
|
||||
if (className.internalName == expectedClassName || className.internalName.endsWith("/$expectedClassName")) {
|
||||
mainLineClassName = className.internalName.replace('/', '.')
|
||||
}
|
||||
classLoader.addClass(className, it.bytes)
|
||||
}
|
||||
|
||||
val scriptClass = try {
|
||||
classLoader.loadClass(mainLineClassName!!)
|
||||
}
|
||||
catch (t: Throwable) {
|
||||
throw Exception("Error loading class $mainLineClassName: known classes: ${compiledClassesNames()}", t)
|
||||
}
|
||||
return Pair(classLoader, scriptClass)
|
||||
}
|
||||
}
|
||||
|
||||
private open class HistoryActionsForRepeatRecentOnly(state: GenericReplEvaluatorState) : HistoryActionsForNoRepeat(state) {
|
||||
|
||||
val currentLast = state.history.peek()!!
|
||||
|
||||
override val effectiveHistory: List<EvalClassWithInstanceAndLoader> get() = super.effectiveHistory.dropLast(1)
|
||||
|
||||
override fun firstMismatch(other: Sequence<ILineId>): Pair<ReplHistoryRecord<EvalClassWithInstanceAndLoader>?, ILineId?>? =
|
||||
state.history.firstMismatchFiltered(other) { it.id != currentLast.id }
|
||||
|
||||
override fun addPlaceholder(lineId: ILineId, value: EvalClassWithInstanceAndLoader) {}
|
||||
|
||||
override fun removePlaceholder(lineId: ILineId): Boolean = true
|
||||
|
||||
override fun addFinal(lineId: ILineId, value: EvalClassWithInstanceAndLoader) {
|
||||
state.history.pop()
|
||||
state.history.push(lineId, value)
|
||||
}
|
||||
|
||||
override fun processClasses(compileResult: ReplCompileResult.CompiledClasses): Pair<ClassLoader, Class<out Any>> =
|
||||
currentLast.item.classLoader to currentLast.item.klass.java
|
||||
}
|
||||
|
||||
private open class HistoryActionsForRepeatAny(state: GenericReplEvaluatorState, val matchingLine: ReplHistoryRecord<EvalClassWithInstanceAndLoader>): HistoryActionsForNoRepeat(state) {
|
||||
|
||||
override val effectiveHistory: List<EvalClassWithInstanceAndLoader> get() = state.history.takeWhile { it.id != matchingLine.id }.map { it.item }
|
||||
|
||||
override fun firstMismatch(other: Sequence<ILineId>): Pair<ReplHistoryRecord<EvalClassWithInstanceAndLoader>?, ILineId?>? =
|
||||
state.history.firstMismatchWhile(other) { it.id != matchingLine.id }
|
||||
|
||||
override fun addPlaceholder(lineId: ILineId, value: EvalClassWithInstanceAndLoader) {}
|
||||
|
||||
override fun removePlaceholder(lineId: ILineId): Boolean = true
|
||||
|
||||
override fun addFinal(lineId: ILineId, value: EvalClassWithInstanceAndLoader) {
|
||||
val extraLines = state.history.takeLastWhile { it.id == matchingLine.id }
|
||||
state.history.resetTo(lineId)
|
||||
state.history.pop()
|
||||
state.history.push(lineId, value)
|
||||
extraLines.forEach {
|
||||
state.history.push(it.id, it.item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processClasses(compileResult: ReplCompileResult.CompiledClasses): Pair<ClassLoader, Class<out Any>> =
|
||||
matchingLine.item.classLoader to matchingLine.item.klass.java
|
||||
}
|
||||
|
||||
@@ -29,11 +29,10 @@ import kotlin.reflect.full.safeCast
|
||||
@Suppress("unused") // used externally (kotlin.script.utils)
|
||||
interface KotlinJsr223JvmInvocableScriptEngine : Invocable {
|
||||
|
||||
val state: IReplStageState<*> // The Invokable interface do not allow Context/Bindings substitution, so state is supplied via property
|
||||
val replScriptEvaluator: ReplEvaluatorExposedInternalHistory
|
||||
|
||||
private fun prioritizedHistory(receiverClass: KClass<*>?, receiverInstance: Any?): List<EvalClassWithInstanceAndLoader> {
|
||||
val evalState = state.asState(GenericReplEvaluatorState::class.java)
|
||||
return evalState.history.map { it.item }.filter { it.instance != null }.reversed().ensureNotEmpty("no script ").let { history ->
|
||||
return replScriptEvaluator.lastEvaluatedScripts.map { it.second }.filter { it.instance != null }.reversed().ensureNotEmpty("no script ").let { history ->
|
||||
if (receiverInstance != null) {
|
||||
val receiverKlass = receiverClass ?: receiverInstance.javaClass.kotlin
|
||||
val receiverInHistory = history.find { it.instance == receiverInstance } ?:
|
||||
@@ -60,10 +59,10 @@ interface KotlinJsr223JvmInvocableScriptEngine : Invocable {
|
||||
private fun invokeImpl(prioritizedCallOrder: List<EvalClassWithInstanceAndLoader>, name: String, args: Array<out Any?>): Any? {
|
||||
// TODO: cache the method lookups?
|
||||
|
||||
val (fn, mapping, invokeWrapper) = prioritizedCallOrder.asSequence().map { (klass, instance, _, invokeWrapper) ->
|
||||
val candidates = klass.functions.filter { it.name == name }
|
||||
candidates.findMapping(listOf(instance) + args)?.let {
|
||||
Triple(it.first, it.second, invokeWrapper)
|
||||
val (fn, mapping, invokeWrapper) = prioritizedCallOrder.asSequence().map { attempt ->
|
||||
val candidates = attempt.klass.functions.filter { it.name == name }
|
||||
candidates.findMapping(listOf<Any?>(attempt.instance) + args)?.let {
|
||||
Triple(it.first, it.second, attempt.invokeWrapper)
|
||||
}
|
||||
}.filterNotNull().firstOrNull() ?: throw NoSuchMethodException("no suitable function '$name' found")
|
||||
|
||||
@@ -95,7 +94,7 @@ interface KotlinJsr223JvmInvocableScriptEngine : Invocable {
|
||||
}
|
||||
|
||||
private fun <T : Any> proxyInterface(thiz: Any?, clasz: Class<T>?): T? {
|
||||
if (state.history.size == 0) throw IllegalStateException("no script")
|
||||
replScriptEvaluator.lastEvaluatedScripts.ensureNotEmpty("no script")
|
||||
val priority = prioritizedHistory(thiz?.javaClass?.kotlin, thiz)
|
||||
|
||||
if (clasz == null) throw IllegalArgumentException("class object cannot be null")
|
||||
@@ -110,6 +109,33 @@ interface KotlinJsr223JvmInvocableScriptEngine : Invocable {
|
||||
}
|
||||
}
|
||||
|
||||
private fun invokeImpl(prioritizedCallOrder: List<EvalClassWithInstanceAndLoader>, name: String, args: Array<out Any?>): Any? {
|
||||
// TODO: cache the method lookups?
|
||||
|
||||
val (fn, mapping, invokeWrapper) = prioritizedCallOrder.asSequence().map { attempt ->
|
||||
val candidates = attempt.klass.functions.filter { it.name == name }
|
||||
candidates.findMapping(listOf<Any?>(attempt.instance) + args)?.let {
|
||||
Triple(it.first, it.second, attempt.invokeWrapper)
|
||||
}
|
||||
}.filterNotNull().firstOrNull() ?: throw NoSuchMethodException("no suitable function '$name' found")
|
||||
|
||||
val res = try {
|
||||
if (invokeWrapper != null) {
|
||||
invokeWrapper.invoke {
|
||||
fn.callBy(mapping)
|
||||
}
|
||||
}
|
||||
else {
|
||||
fn.callBy(mapping)
|
||||
}
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
// ignore everything in the stack trace until this constructor call
|
||||
throw ScriptException(renderReplStackTrace(e.cause!!, startFromMethodName = fn.name))
|
||||
}
|
||||
return if (fn.returnType.classifier == Unit::class) Unit else res
|
||||
}
|
||||
|
||||
private fun Iterable<KFunction<*>>.findMapping(args: List<Any?>): Pair<KFunction<*>, Map<KParameter, Any?>>? {
|
||||
for (fn in this) {
|
||||
val mapping = tryCreateCallableMapping(fn, args)
|
||||
|
||||
@@ -18,16 +18,26 @@ package org.jetbrains.kotlin.cli.common.repl
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||
import java.io.Reader
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import javax.script.*
|
||||
|
||||
const val KOTLIN_SCRIPT_STATE_BINDINGS_KEY = "kotlin.script.state"
|
||||
const val KOTLIN_SCRIPT_ENGINE_BINDINGS_KEY = "kotlin.script.engine"
|
||||
val KOTLIN_SCRIPT_HISTORY_BINDINGS_KEY = "kotlin.script.history"
|
||||
val KOTLIN_SCRIPT_LINE_NUMBER_BINDINGS_KEY = "kotlin.script.line.number"
|
||||
|
||||
// TODO consider additional error handling
|
||||
var Bindings.kotlinScriptHistory: MutableList<ReplCodeLine>
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
get() = getOrPut(KOTLIN_SCRIPT_HISTORY_BINDINGS_KEY, { arrayListOf<ReplCodeLine>() }) as MutableList<ReplCodeLine>
|
||||
set(v) { put(KOTLIN_SCRIPT_HISTORY_BINDINGS_KEY, v) }
|
||||
|
||||
val Bindings.kotlinScriptLineNumber: AtomicInteger
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
get() = getOrPut(KOTLIN_SCRIPT_LINE_NUMBER_BINDINGS_KEY, { AtomicInteger(0) }) as AtomicInteger
|
||||
|
||||
abstract class KotlinJsr223JvmScriptEngineBase(protected val myFactory: ScriptEngineFactory) : AbstractScriptEngine(), ScriptEngine, Compilable {
|
||||
|
||||
protected abstract val replCompiler: ReplCompiler
|
||||
protected abstract val replEvaluator: ReplFullEvaluator
|
||||
protected abstract val replCompiler: ReplCompileAction
|
||||
protected abstract val replScriptEvaluator: ReplFullEvaluator
|
||||
|
||||
override fun eval(script: String, context: ScriptContext): Any? = compileAndEval(script, context)
|
||||
|
||||
@@ -37,29 +47,25 @@ abstract class KotlinJsr223JvmScriptEngineBase(protected val myFactory: ScriptEn
|
||||
|
||||
override fun compile(script: Reader): CompiledScript = compile(script.readText(), getContext())
|
||||
|
||||
override fun createBindings(): Bindings = SimpleBindings().apply { put(KOTLIN_SCRIPT_ENGINE_BINDINGS_KEY, this) }
|
||||
override fun createBindings(): Bindings = SimpleBindings()
|
||||
|
||||
override fun getFactory(): ScriptEngineFactory = myFactory
|
||||
|
||||
// the parameter could be used in the future when we decide to keep state completely in the context and solve appropriate problems (now e.g. replCompiler keeps separate state)
|
||||
fun nextCodeLine(context: ScriptContext, code: String) = getCurrentState(context).let { ReplCodeLine(it.getNextLineNo(), it.currentGeneration, code) }
|
||||
fun nextCodeLine(@Suppress("UNUSED_PARAMETER") context: ScriptContext, code: String) = ReplCodeLine(this.context.getBindings(ScriptContext.ENGINE_SCOPE).kotlinScriptLineNumber.incrementAndGet(), code)
|
||||
|
||||
protected abstract fun createState(lock: ReentrantReadWriteLock = ReentrantReadWriteLock()): IReplStageState<*>
|
||||
private fun getCurrentHistory(@Suppress("UNUSED_PARAMETER") context: ScriptContext) = this.context.getBindings(ScriptContext.ENGINE_SCOPE).kotlinScriptHistory
|
||||
|
||||
protected fun getCurrentState(context: ScriptContext) =
|
||||
context.getBindings(ScriptContext.ENGINE_SCOPE)
|
||||
.getOrPut(KOTLIN_SCRIPT_STATE_BINDINGS_KEY, {
|
||||
// TODO: check why createBinding is not called on creating default context, so the engine is not set
|
||||
context.getBindings(ScriptContext.ENGINE_SCOPE).put(KOTLIN_SCRIPT_ENGINE_BINDINGS_KEY, this@KotlinJsr223JvmScriptEngineBase)
|
||||
createState()
|
||||
}) as IReplStageState<*>
|
||||
private fun setContextHistory(@Suppress("UNUSED_PARAMETER") context: ScriptContext, history: ArrayList<ReplCodeLine>) {
|
||||
this.context.getBindings(ScriptContext.ENGINE_SCOPE).kotlinScriptHistory = history
|
||||
}
|
||||
|
||||
open fun overrideScriptArgs(context: ScriptContext): ScriptArgsWithTypes? = null
|
||||
|
||||
open fun compileAndEval(script: String, context: ScriptContext): Any? {
|
||||
val codeLine = nextCodeLine(context, script)
|
||||
val state = getCurrentState(context)
|
||||
val result = replEvaluator.compileAndEval(state, codeLine, scriptArgs = overrideScriptArgs(context))
|
||||
val history = getCurrentHistory(context)
|
||||
val result = replScriptEvaluator.compileAndEval(codeLine, scriptArgs = overrideScriptArgs(context), verifyHistory = history)
|
||||
val ret = when (result) {
|
||||
is ReplEvalResult.ValueResult -> result.value
|
||||
is ReplEvalResult.UnitResult -> null
|
||||
@@ -67,26 +73,29 @@ abstract class KotlinJsr223JvmScriptEngineBase(protected val myFactory: ScriptEn
|
||||
is ReplEvalResult.Incomplete -> throw ScriptException("error: incomplete code")
|
||||
is ReplEvalResult.HistoryMismatch -> throw ScriptException("Repl history mismatch at line: ${result.lineNo}")
|
||||
}
|
||||
setContextHistory(context, ArrayList(result.completedEvalHistory))
|
||||
return ret
|
||||
}
|
||||
|
||||
open fun compile(script: String, context: ScriptContext): CompiledScript {
|
||||
val codeLine = nextCodeLine(context, script)
|
||||
val state = getCurrentState(context)
|
||||
val history = getCurrentHistory(context)
|
||||
|
||||
val result = replCompiler.compile(state, codeLine)
|
||||
val result = replCompiler.compile(codeLine, history)
|
||||
val compiled = when (result) {
|
||||
is ReplCompileResult.Error -> throw ScriptException("Error${result.locationString()}: ${result.message}")
|
||||
is ReplCompileResult.Incomplete -> throw ScriptException("error: incomplete code")
|
||||
is ReplCompileResult.HistoryMismatch -> throw ScriptException("Repl history mismatch at line: ${result.lineNo}")
|
||||
is ReplCompileResult.CompiledClasses -> result
|
||||
}
|
||||
// TODO: check if it is ok to keep compiled history in the same place as compiledEval one
|
||||
setContextHistory(context, ArrayList(result.compiledHistory))
|
||||
return CompiledKotlinScript(this, codeLine, compiled)
|
||||
}
|
||||
|
||||
open fun eval(compiledScript: CompiledKotlinScript, context: ScriptContext): Any? {
|
||||
val state = getCurrentState(context)
|
||||
val result = try {
|
||||
replEvaluator.eval(state, compiledScript.compiledData, scriptArgs = overrideScriptArgs(context))
|
||||
replScriptEvaluator.eval(compiledScript.compiledData, scriptArgs = overrideScriptArgs(context))
|
||||
}
|
||||
catch (e: Exception) {
|
||||
throw ScriptException(e)
|
||||
@@ -99,6 +108,7 @@ abstract class KotlinJsr223JvmScriptEngineBase(protected val myFactory: ScriptEn
|
||||
is ReplEvalResult.Incomplete -> throw ScriptException("error: incomplete code")
|
||||
is ReplEvalResult.HistoryMismatch -> throw ScriptException("Repl history mismatch at line: ${result.lineNo}")
|
||||
}
|
||||
setContextHistory(context, ArrayList(result.completedEvalHistory))
|
||||
return ret
|
||||
}
|
||||
|
||||
|
||||
@@ -20,13 +20,9 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
import java.util.*
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
const val REPL_CODE_LINE_FIRST_NO = 1
|
||||
const val REPL_CODE_LINE_FIRST_GEN = 1
|
||||
|
||||
data class ReplCodeLine(val no: Int, val generation: Int, val code: String) : Serializable {
|
||||
data class ReplCodeLine(val no: Int, val code: String) : Serializable {
|
||||
companion object {
|
||||
private val serialVersionUID: Long = 8228357578L
|
||||
}
|
||||
@@ -47,14 +43,9 @@ data class CompiledClassData(val path: String, val bytes: ByteArray) : Serializa
|
||||
}
|
||||
}
|
||||
|
||||
interface CreateReplStageStateAction {
|
||||
fun createState(lock: ReentrantReadWriteLock = ReentrantReadWriteLock()): IReplStageState<*>
|
||||
}
|
||||
|
||||
// --- check
|
||||
|
||||
interface ReplCheckAction {
|
||||
fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult
|
||||
fun check(codeLine: ReplCodeLine): ReplCheckResult
|
||||
}
|
||||
|
||||
sealed class ReplCheckResult : Serializable {
|
||||
@@ -72,24 +63,40 @@ sealed class ReplCheckResult : Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
// --- compile
|
||||
interface ReplResettableCodeLine {
|
||||
fun resetToLine(lineNumber: Int): List<ReplCodeLine>
|
||||
|
||||
interface ReplCompileAction {
|
||||
fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult
|
||||
fun resetToLine(line: ReplCodeLine): List<ReplCodeLine> = resetToLine(line.no)
|
||||
}
|
||||
|
||||
sealed class ReplCompileResult : Serializable {
|
||||
class CompiledClasses(val lineId: LineId,
|
||||
val previousLines: List<ILineId>,
|
||||
val mainClassName: String,
|
||||
interface ReplCodeLineHistory {
|
||||
val history: List<ReplCodeLine>
|
||||
}
|
||||
|
||||
interface ReplCombinedHistory {
|
||||
val compiledHistory: List<ReplCodeLine>
|
||||
val evaluatedHistory: List<ReplCodeLine>
|
||||
}
|
||||
|
||||
interface ReplCompileAction {
|
||||
fun compile(codeLine: ReplCodeLine, verifyHistory: List<ReplCodeLine>? = null): ReplCompileResult
|
||||
}
|
||||
|
||||
sealed class ReplCompileResult(val compiledHistory: List<ReplCodeLine>) : Serializable {
|
||||
class CompiledClasses(compiledHistory: List<ReplCodeLine>,
|
||||
val compiledCodeLine: CompiledReplCodeLine,
|
||||
val generatedClassname: String,
|
||||
val classes: List<CompiledClassData>,
|
||||
val hasResult: Boolean,
|
||||
val classpathAddendum: List<File>) : ReplCompileResult()
|
||||
val classpathAddendum: List<File>) : ReplCompileResult(compiledHistory)
|
||||
|
||||
class Incomplete : ReplCompileResult()
|
||||
class Incomplete(compiledHistory: List<ReplCodeLine>) : ReplCompileResult(compiledHistory)
|
||||
|
||||
class Error(val message: String,
|
||||
val location: CompilerMessageLocation = CompilerMessageLocation.NO_LOCATION) : ReplCompileResult() {
|
||||
class HistoryMismatch(compiledHistory: List<ReplCodeLine>, val lineNo: Int) : ReplCompileResult(compiledHistory)
|
||||
|
||||
class Error(compiledHistory: List<ReplCodeLine>,
|
||||
val message: String,
|
||||
val location: CompilerMessageLocation = CompilerMessageLocation.NO_LOCATION) : ReplCompileResult(compiledHistory) {
|
||||
override fun toString(): String = "Error(message = \"$message\""
|
||||
}
|
||||
|
||||
@@ -98,35 +105,43 @@ sealed class ReplCompileResult : Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
interface ReplCompiler : ReplCompileAction, ReplCheckAction, CreateReplStageStateAction
|
||||
interface ReplCompiler : ReplResettableCodeLine, ReplCodeLineHistory, ReplCompileAction, ReplCheckAction
|
||||
|
||||
// --- eval
|
||||
typealias EvalHistoryType = Pair<CompiledReplCodeLine, EvalClassWithInstanceAndLoader>
|
||||
|
||||
interface ReplEvaluatorExposedInternalHistory {
|
||||
val lastEvaluatedScripts: List<EvalHistoryType>
|
||||
}
|
||||
|
||||
interface ReplClasspath {
|
||||
val currentClasspath: List<File>
|
||||
}
|
||||
|
||||
data class EvalClassWithInstanceAndLoader(val klass: KClass<*>, val instance: Any?, val classLoader: ClassLoader, val invokeWrapper: InvokeWrapper?)
|
||||
|
||||
interface ReplEvalAction {
|
||||
fun eval(state: IReplStageState<*>,
|
||||
compileResult: ReplCompileResult.CompiledClasses,
|
||||
fun eval(compileResult: ReplCompileResult.CompiledClasses,
|
||||
scriptArgs: ScriptArgsWithTypes? = null,
|
||||
invokeWrapper: InvokeWrapper? = null): ReplEvalResult
|
||||
}
|
||||
|
||||
sealed class ReplEvalResult : Serializable {
|
||||
class ValueResult(val value: Any?) : ReplEvalResult() {
|
||||
sealed class ReplEvalResult(val completedEvalHistory: List<ReplCodeLine>) : Serializable {
|
||||
class ValueResult(completedEvalHistory: List<ReplCodeLine>, val value: Any?) : ReplEvalResult(completedEvalHistory) {
|
||||
override fun toString(): String = "Result: $value"
|
||||
}
|
||||
|
||||
class UnitResult : ReplEvalResult()
|
||||
class UnitResult(completedEvalHistory: List<ReplCodeLine>) : ReplEvalResult(completedEvalHistory)
|
||||
|
||||
class Incomplete : ReplEvalResult()
|
||||
class Incomplete(completedEvalHistory: List<ReplCodeLine>) : ReplEvalResult(completedEvalHistory)
|
||||
|
||||
class HistoryMismatch(val lineNo: Int) : ReplEvalResult()
|
||||
class HistoryMismatch(completedEvalHistory: List<ReplCodeLine>, val lineNo: Int) : ReplEvalResult(completedEvalHistory)
|
||||
|
||||
sealed class Error(val message: String) : ReplEvalResult() {
|
||||
class Runtime(message: String, val cause: Exception? = null) : Error(message)
|
||||
sealed class Error(completedEvalHistory: List<ReplCodeLine>, val message: String) : ReplEvalResult(completedEvalHistory) {
|
||||
class Runtime(completedEvalHistory: List<ReplCodeLine>, message: String, val cause: Exception? = null) : Error(completedEvalHistory, message)
|
||||
|
||||
class CompileTime(message: String,
|
||||
val location: CompilerMessageLocation = CompilerMessageLocation.NO_LOCATION) : Error(message)
|
||||
class CompileTime(completedEvalHistory: List<ReplCodeLine>,
|
||||
message: String,
|
||||
val location: CompilerMessageLocation = CompilerMessageLocation.NO_LOCATION) : Error(completedEvalHistory, message)
|
||||
|
||||
override fun toString(): String = "${this::class.simpleName}Error(message = \"$message\""
|
||||
}
|
||||
@@ -136,44 +151,43 @@ sealed class ReplEvalResult : Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
interface ReplEvaluator : ReplEvalAction, CreateReplStageStateAction
|
||||
|
||||
// --- compileAdnEval
|
||||
interface ReplEvaluator : ReplResettableCodeLine, ReplCodeLineHistory, ReplEvaluatorExposedInternalHistory, ReplEvalAction, ReplClasspath
|
||||
|
||||
interface ReplAtomicEvalAction {
|
||||
fun compileAndEval(state: IReplStageState<*>,
|
||||
codeLine: ReplCodeLine,
|
||||
fun compileAndEval(codeLine: ReplCodeLine,
|
||||
scriptArgs: ScriptArgsWithTypes? = null,
|
||||
verifyHistory: List<ReplCodeLine>? = null,
|
||||
invokeWrapper: InvokeWrapper? = null): ReplEvalResult
|
||||
}
|
||||
|
||||
interface ReplAtomicEvaluator : ReplAtomicEvalAction, ReplCheckAction
|
||||
interface ReplAtomicEvaluator : ReplResettableCodeLine, ReplCombinedHistory, ReplEvaluatorExposedInternalHistory, ReplAtomicEvalAction, ReplCheckAction, ReplClasspath
|
||||
|
||||
interface ReplDelayedEvalAction {
|
||||
fun compileToEvaluable(state: IReplStageState<*>,
|
||||
codeLine: ReplCodeLine,
|
||||
defaultScriptArgs: ScriptArgsWithTypes? = null): Pair<ReplCompileResult, Evaluable?>
|
||||
fun compileToEvaluable(codeLine: ReplCodeLine, defaultScriptArgs: ScriptArgsWithTypes? = null, verifyHistory: List<ReplCodeLine>?): Pair<ReplCompileResult, Evaluable?>
|
||||
}
|
||||
|
||||
// other
|
||||
|
||||
interface Evaluable {
|
||||
val compiledCode: ReplCompileResult.CompiledClasses
|
||||
fun eval(scriptArgs: ScriptArgsWithTypes? = null, invokeWrapper: InvokeWrapper? = null): ReplEvalResult
|
||||
}
|
||||
|
||||
interface ReplFullEvaluator : ReplEvaluator, ReplAtomicEvaluator, ReplDelayedEvalAction
|
||||
interface ReplFullEvaluator : ReplEvaluator, ReplAtomicEvaluator, ReplDelayedEvalAction, ReplCombinedHistory
|
||||
|
||||
/**
|
||||
* Keep args and arg types together, so as a whole they are present or absent
|
||||
*/
|
||||
class ScriptArgsWithTypes(val scriptArgs: Array<out Any?>, val scriptArgsTypes: Array<out KClass<out Any>>) : Serializable {
|
||||
init { assert(scriptArgs.size == scriptArgsTypes.size) }
|
||||
companion object {
|
||||
private val serialVersionUID: Long = 8529357500L
|
||||
}
|
||||
}
|
||||
|
||||
interface ScriptTemplateEmptyArgsProvider {
|
||||
val defaultEmptyArgs: ScriptArgsWithTypes?
|
||||
}
|
||||
|
||||
class SimpleScriptTemplateEmptyArgsProvider(override val defaultEmptyArgs: ScriptArgsWithTypes? = null) : ScriptTemplateEmptyArgsProvider
|
||||
|
||||
enum class ReplRepeatingMode {
|
||||
NONE,
|
||||
REPEAT_ONLY_MOST_RECENT,
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.cli.common.repl
|
||||
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
|
||||
|
||||
interface ILineId : Comparable<ILineId> {
|
||||
val no: Int
|
||||
val generation: Int
|
||||
}
|
||||
|
||||
data class ReplHistoryRecord<out T> (val id: ILineId, val item: T)
|
||||
|
||||
interface IReplStageHistory<T> : List<ReplHistoryRecord<T>> {
|
||||
|
||||
fun peek(): ReplHistoryRecord<T>? = lock.read { lastOrNull() }
|
||||
|
||||
fun push(id: ILineId, item: T)
|
||||
|
||||
fun pop(): ReplHistoryRecord<T>?
|
||||
|
||||
fun verifiedPop(id: ILineId): ReplHistoryRecord<T>? = lock.write {
|
||||
if (lastOrNull()?.id == id) pop()
|
||||
else null
|
||||
}
|
||||
|
||||
fun resetTo(id: ILineId): Iterable<ILineId>
|
||||
|
||||
val lock: ReentrantReadWriteLock
|
||||
}
|
||||
|
||||
interface IReplStageState<T> {
|
||||
val history: IReplStageHistory<T>
|
||||
|
||||
val lock: ReentrantReadWriteLock
|
||||
|
||||
val currentGeneration: Int
|
||||
|
||||
fun getNextLineNo(): Int = history.peek()?.id?.no?.let { it + 1 } ?: REPL_CODE_LINE_FIRST_NO // TODO: it should be more robust downstream (e.g. use atomic)
|
||||
|
||||
fun <StateT : IReplStageState<*>> asState(target: Class<out StateT>): StateT =
|
||||
if (target.isAssignableFrom(this::class.java)) this as StateT
|
||||
else throw IllegalArgumentException("$this is not an expected instance of IReplStageState")
|
||||
}
|
||||
|
||||
|
||||
fun <T> IReplStageHistory<T>.firstMismatch(other: Sequence<ILineId>): Pair<ReplHistoryRecord<T>?, ILineId?>? =
|
||||
lock.read {
|
||||
iterator().asSequence().zip(other.asSequence()).firstOrNull { it.first.id != it.second }?.let { it.first to it.second }
|
||||
}
|
||||
|
||||
fun<T> IReplStageHistory<T>.firstMismatchFiltered(other: Sequence<ILineId>, predicate: (ReplHistoryRecord<T>) -> Boolean): Pair<ReplHistoryRecord<T>?, ILineId?>? =
|
||||
lock.read {
|
||||
iterator().asSequence().filter(predicate).zip(other.asSequence()).firstOrNull { it.first.id != it.second }?.let { it.first to it.second }
|
||||
}
|
||||
|
||||
fun<T> IReplStageHistory<T>.firstMismatchWhile(other: Sequence<ILineId>, predicate: (ReplHistoryRecord<T>) -> Boolean): Pair<ReplHistoryRecord<T>?, ILineId?>? =
|
||||
lock.read {
|
||||
iterator().asSequence().takeWhile(predicate).zip(other.asSequence()).firstOrNull { it.first.id != it.second }?.let { it.first to it.second }
|
||||
}
|
||||
|
||||
@@ -20,13 +20,13 @@ import com.google.common.base.Throwables
|
||||
import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
|
||||
fun makeScriptBaseName(codeLine: ReplCodeLine) =
|
||||
"Line_${codeLine.no}${if (codeLine.generation > REPL_CODE_LINE_FIRST_GEN) "_gen_${codeLine.generation}" else ""}"
|
||||
fun makeScriptBaseName(codeLine: ReplCodeLine, generation: Long) =
|
||||
"Line_${codeLine.no}${if (generation > 1) "_gen_$generation" else ""}"
|
||||
|
||||
fun renderReplStackTrace(cause: Throwable, startFromMethodName: String): String {
|
||||
val newTrace = arrayListOf<StackTraceElement>()
|
||||
var skip = true
|
||||
for ((_, element) in cause.stackTrace.withIndex().reversed()) {
|
||||
for ((i, element) in cause.stackTrace.withIndex().reversed()) {
|
||||
if ("${element.className}.${element.methodName}" == startFromMethodName) {
|
||||
skip = false
|
||||
}
|
||||
@@ -43,6 +43,10 @@ fun renderReplStackTrace(cause: Throwable, startFromMethodName: String): String
|
||||
return Throwables.getStackTraceAsString(cause)
|
||||
}
|
||||
|
||||
fun NO_ACTION(): Unit = Unit
|
||||
fun <T> NO_ACTION_THAT_RETURNS(v: T): T = v
|
||||
|
||||
|
||||
internal fun ClassLoader.listAllUrlsAsFiles(): List<File> {
|
||||
val parents = generateSequence(this) { loader -> loader.parent }.filterIsInstance(URLClassLoader::class.java)
|
||||
return parents.fold(emptyList<File>()) { accum, loader ->
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.utils.StringsKt;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -155,6 +156,7 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
|
||||
}
|
||||
|
||||
reportUnknownExtraFlags(messageCollector, arguments);
|
||||
reportUnsupportedJavaVersion(messageCollector, arguments);
|
||||
|
||||
GroupingMessageCollector groupingCollector = new GroupingMessageCollector(messageCollector);
|
||||
|
||||
@@ -232,8 +234,6 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
|
||||
configuration.put(CLIConfigurationKeys.COMPILER_JAR_LOCATOR, locator);
|
||||
}
|
||||
|
||||
configuration.put(CommonConfigurationKeys.SKIP_METADATA_VERSION_CHECK, arguments.skipMetadataVersionCheck);
|
||||
|
||||
setupLanguageVersionSettings(configuration, arguments);
|
||||
}
|
||||
|
||||
@@ -275,8 +275,8 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
|
||||
extraLanguageFeatures.add(coroutinesApplicabilityLevel);
|
||||
}
|
||||
|
||||
CommonConfigurationKeysKt.setLanguageVersionSettings(
|
||||
configuration,
|
||||
configuration.put(
|
||||
CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS,
|
||||
new LanguageVersionSettingsImpl(
|
||||
languageVersion,
|
||||
ApiVersion.createByLanguageVersion(apiVersion),
|
||||
@@ -288,19 +288,19 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
|
||||
|
||||
@Nullable
|
||||
private static LanguageFeature chooseCoroutinesApplicabilityLevel(
|
||||
@NotNull CompilerConfiguration configuration,
|
||||
@NotNull CommonCompilerArguments arguments
|
||||
) {
|
||||
if (arguments.coroutinesError && !arguments.coroutinesWarn && !arguments.coroutinesEnable) {
|
||||
@NotNull CompilerConfiguration configuration, @NotNull CommonCompilerArguments arguments) {
|
||||
if (!arguments.coroutinesEnable && !arguments.coroutinesError && !arguments.coroutinesWarn) {
|
||||
return LanguageFeature.WarnOnCoroutines;
|
||||
}
|
||||
else if (arguments.coroutinesError && !arguments.coroutinesWarn && !arguments.coroutinesEnable) {
|
||||
return LanguageFeature.ErrorOnCoroutines;
|
||||
}
|
||||
else if (arguments.coroutinesWarn && !arguments.coroutinesError && !arguments.coroutinesEnable) {
|
||||
return LanguageFeature.WarnOnCoroutines;
|
||||
}
|
||||
else if (arguments.coroutinesEnable && !arguments.coroutinesWarn && !arguments.coroutinesError) {
|
||||
return LanguageFeature.DoNotWarnOnCoroutines;
|
||||
}
|
||||
else if (!arguments.coroutinesEnable && !arguments.coroutinesError) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
String message = "The -Xcoroutines can only have one value";
|
||||
configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(
|
||||
CompilerMessageSeverity.ERROR, message, CompilerMessageLocation.NO_LOCATION
|
||||
@@ -350,6 +350,16 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
|
||||
}
|
||||
}
|
||||
|
||||
private void reportUnsupportedJavaVersion(MessageCollector collector, A arguments) {
|
||||
if (!SystemInfo.isJavaVersionAtLeast("1.8") && !arguments.noJavaVersionWarning) {
|
||||
collector.report(
|
||||
CompilerMessageSeverity.STRONG_WARNING,
|
||||
"Running the Kotlin compiler under Java 6 or 7 is unsupported and will no longer be possible in a future update.",
|
||||
CompilerMessageLocation.NO_LOCATION
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected abstract ExitCode doExecute(
|
||||
@NotNull A arguments,
|
||||
|
||||
@@ -39,8 +39,10 @@ class Usage {
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
String usage = fieldUsage(field, extraHelp);
|
||||
if (usage != null) {
|
||||
if (usage.contains("Xcoroutines")) {
|
||||
if (coroutinesUsagePrinted) continue;
|
||||
boolean coroutinesUsage = usage.contains("Xcoroutines");
|
||||
if (coroutinesUsage && coroutinesUsagePrinted) {
|
||||
continue;
|
||||
} else if (coroutinesUsage) {
|
||||
coroutinesUsagePrinted = true;
|
||||
}
|
||||
target.println(usage);
|
||||
@@ -87,7 +89,6 @@ class Usage {
|
||||
if (isXCoroutinesKey) {
|
||||
sb.append(" ");
|
||||
sb.append(coroutinesKeyDescription);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
int width = OPTION_NAME_PADDING_WIDTH - 1;
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.cli.jvm
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.cli.common.CLICompiler
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
@@ -31,16 +32,19 @@ import java.util.jar.Manifest
|
||||
object JvmRuntimeVersionsConsistencyChecker {
|
||||
private val LOG = Logger.getInstance(JvmRuntimeVersionsConsistencyChecker::class.java)
|
||||
|
||||
private fun <T> T?.assertNotNull(lazyMessage: () -> String): T =
|
||||
this ?: lazyMessage().let { message ->
|
||||
LOG.error(message)
|
||||
throw AssertionError(message)
|
||||
}
|
||||
private fun fatal(message: String): Nothing {
|
||||
LOG.error(message)
|
||||
throw AssertionError(message)
|
||||
}
|
||||
|
||||
private fun <T> T?.assertNotNull(message: () -> String): T =
|
||||
if (this == null) fatal(message()) else this
|
||||
|
||||
private const val META_INF = "META-INF"
|
||||
private const val MANIFEST_MF = "$META_INF/MANIFEST.MF"
|
||||
|
||||
private const val MANIFEST_KOTLIN_VERSION_ATTRIBUTE = "manifest.impl.attribute.kotlin.version"
|
||||
private const val MANIFEST_KOTLIN_VERSION_VALUE = "manifest.impl.value.kotlin.version"
|
||||
private const val MANIFEST_KOTLIN_RUNTIME_COMPONENT = "manifest.impl.attribute.kotlin.runtime.component"
|
||||
private const val MANIFEST_KOTLIN_RUNTIME_COMPONENT_CORE = "manifest.impl.value.kotlin.runtime.component.core"
|
||||
private const val MANIFEST_KOTLIN_RUNTIME_COMPONENT_MAIN = "manifest.impl.value.kotlin.runtime.component.main"
|
||||
@@ -53,6 +57,8 @@ object JvmRuntimeVersionsConsistencyChecker {
|
||||
)
|
||||
|
||||
private val KOTLIN_VERSION_ATTRIBUTE: String
|
||||
private val CURRENT_COMPILER_VERSION: MavenComparableVersion
|
||||
|
||||
private val KOTLIN_RUNTIME_COMPONENT_ATTRIBUTE: String
|
||||
private val KOTLIN_RUNTIME_COMPONENT_CORE: String
|
||||
private val KOTLIN_RUNTIME_COMPONENT_MAIN: String
|
||||
@@ -70,6 +76,18 @@ object JvmRuntimeVersionsConsistencyChecker {
|
||||
|
||||
KOTLIN_VERSION_ATTRIBUTE = manifestProperties.getProperty(MANIFEST_KOTLIN_VERSION_ATTRIBUTE)
|
||||
.assertNotNull { "$MANIFEST_KOTLIN_VERSION_ATTRIBUTE not found in kotlinManifest.properties" }
|
||||
|
||||
CURRENT_COMPILER_VERSION = run {
|
||||
val kotlinVersionString = manifestProperties.getProperty(MANIFEST_KOTLIN_VERSION_VALUE)
|
||||
.assertNotNull { "$MANIFEST_KOTLIN_VERSION_VALUE not found in kotlinManifest.properties" }
|
||||
|
||||
MavenComparableVersion(kotlinVersionString)
|
||||
}
|
||||
|
||||
if (CURRENT_COMPILER_VERSION != ApiVersion.LATEST.version) {
|
||||
fatal("Kotlin compiler version $CURRENT_COMPILER_VERSION in kotlinManifest.properties doesn't match ${ApiVersion.LATEST}")
|
||||
}
|
||||
|
||||
KOTLIN_RUNTIME_COMPONENT_ATTRIBUTE = manifestProperties.getProperty(MANIFEST_KOTLIN_RUNTIME_COMPONENT)
|
||||
.assertNotNull { "$MANIFEST_KOTLIN_RUNTIME_COMPONENT not found in kotlinManifest.properties" }
|
||||
KOTLIN_RUNTIME_COMPONENT_CORE = manifestProperties.getProperty(MANIFEST_KOTLIN_RUNTIME_COMPONENT_CORE)
|
||||
@@ -100,8 +118,8 @@ object JvmRuntimeVersionsConsistencyChecker {
|
||||
val runtimeJarsInfo = collectRuntimeJarsInfo(classpathJarRoots)
|
||||
if (runtimeJarsInfo.jars.isEmpty()) return
|
||||
|
||||
val languageVersionSettings = configuration.languageVersionSettings
|
||||
val apiVersion = languageVersionSettings.apiVersion.version
|
||||
val languageVersionSettings = configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS)
|
||||
val apiVersion = languageVersionSettings?.apiVersion?.version ?: CURRENT_COMPILER_VERSION
|
||||
|
||||
val consistency = checkCompilerClasspathConsistency(messageCollector, apiVersion, runtimeJarsInfo)
|
||||
if (consistency is ClasspathConsistency.InconsistentWithApiVersion) {
|
||||
@@ -119,20 +137,29 @@ object JvmRuntimeVersionsConsistencyChecker {
|
||||
|
||||
val actualApi = ApiVersion.parse(actualRuntimeVersion.toString())
|
||||
if (actualApi != null) {
|
||||
val inferredApiVersion =
|
||||
if (@Suppress("DEPRECATION") languageVersionSettings.isApiVersionExplicit)
|
||||
languageVersionSettings.apiVersion
|
||||
else
|
||||
minOf(languageVersionSettings.apiVersion, actualApi)
|
||||
val newSettings = if (languageVersionSettings == null) {
|
||||
LanguageVersionSettingsImpl(
|
||||
LanguageVersionSettingsImpl.DEFAULT.languageVersion,
|
||||
actualApi,
|
||||
listOf(LanguageFeature.WarnOnCoroutines)
|
||||
)
|
||||
}
|
||||
else {
|
||||
val inferredApiVersion =
|
||||
if (@Suppress("DEPRECATION") languageVersionSettings.isApiVersionExplicit)
|
||||
languageVersionSettings.apiVersion
|
||||
else
|
||||
minOf(languageVersionSettings.apiVersion, actualApi)
|
||||
|
||||
// "minOf" is needed in case when API version was inferred from language version and it's older than actualApi.
|
||||
// For example, in "kotlinc-1.2 -language-version 1.0 -cp kotlin-runtime-1.1.jar" we should still infer API = 1.0
|
||||
val newSettings = LanguageVersionSettingsImpl(
|
||||
languageVersionSettings.languageVersion,
|
||||
inferredApiVersion,
|
||||
languageVersionSettings.additionalFeatures,
|
||||
isApiVersionExplicit = false
|
||||
)
|
||||
// "minOf" is needed in case when API version was inferred from language version and it's older than actualApi.
|
||||
// For example, in "kotlinc-1.2 -language-version 1.0 -cp kotlin-runtime-1.1.jar" we should still infer API = 1.0
|
||||
LanguageVersionSettingsImpl(
|
||||
languageVersionSettings.languageVersion,
|
||||
inferredApiVersion,
|
||||
languageVersionSettings.additionalFeatures,
|
||||
isApiVersionExplicit = false
|
||||
)
|
||||
}
|
||||
|
||||
messageCollector.issue(null, "Old runtime has been found in the classpath. " +
|
||||
"Initial language version settings: $languageVersionSettings. " +
|
||||
@@ -201,10 +228,10 @@ object JvmRuntimeVersionsConsistencyChecker {
|
||||
}
|
||||
|
||||
private fun checkNotNewerThanCompiler(messageCollector: MessageCollector, jar: KotlinLibraryFile): Boolean {
|
||||
if (jar.version > ApiVersion.LATEST.version) {
|
||||
if (jar.version > CURRENT_COMPILER_VERSION) {
|
||||
messageCollector.issue(
|
||||
jar.file,
|
||||
"Runtime JAR file has version ${jar.version} which is newer than compiler version ${ApiVersion.LATEST.version}",
|
||||
"Runtime JAR file has version ${jar.version} which is newer than compiler version $CURRENT_COMPILER_VERSION",
|
||||
CompilerMessageSeverity.ERROR
|
||||
)
|
||||
return true
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.compiler.plugin.PluginCliOptionProcessingException
|
||||
import org.jetbrains.kotlin.compiler.plugin.cliPluginUsageString
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
|
||||
import org.jetbrains.kotlin.script.StandardScriptDefinition
|
||||
@@ -113,6 +114,10 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
return ExitCode.OK
|
||||
}
|
||||
|
||||
if (arguments.skipMetadataVersionCheck) {
|
||||
JvmMetadataVersion.skipCheck = true
|
||||
}
|
||||
|
||||
if (arguments.includeRuntime) {
|
||||
configuration.put(JVMConfigurationKeys.INCLUDE_RUNTIME, true)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.descriptors.PackagePartProvider
|
||||
import org.jetbrains.kotlin.load.kotlin.ModuleMapping
|
||||
import org.jetbrains.kotlin.load.kotlin.PackageParts
|
||||
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
|
||||
import java.io.EOFException
|
||||
|
||||
class JvmPackagePartProvider(
|
||||
@@ -33,8 +32,6 @@ class JvmPackagePartProvider(
|
||||
) : PackagePartProvider {
|
||||
private data class ModuleMappingInfo(val root: VirtualFile, val mapping: ModuleMapping)
|
||||
|
||||
private val deserializationConfiguration = CompilerDeserializationConfiguration(env.configuration)
|
||||
|
||||
private val notLoadedRoots by lazy(LazyThreadSafetyMode.NONE) {
|
||||
env.configuration.getList(JVMConfigurationKeys.CONTENT_ROOTS)
|
||||
.filterIsInstance<JvmClasspathRoot>()
|
||||
@@ -99,7 +96,7 @@ class JvmPackagePartProvider(
|
||||
val moduleFiles = metaInf.children.filter { it.name.endsWith(ModuleMapping.MAPPING_FILE_EXT) }
|
||||
for (moduleFile in moduleFiles) {
|
||||
val mapping = try {
|
||||
ModuleMapping.create(moduleFile.contentsToByteArray(), moduleFile.toString(), deserializationConfiguration)
|
||||
ModuleMapping.create(moduleFile.contentsToByteArray(), moduleFile.toString())
|
||||
}
|
||||
catch (e: EOFException) {
|
||||
throw RuntimeException("Error on reading package parts for '$packageFqName' package in '$moduleFile', " +
|
||||
|
||||
@@ -67,8 +67,7 @@ import org.jetbrains.kotlin.cli.common.CliModuleVisibilityManagerImpl
|
||||
import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.STRONG_WARNING
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
|
||||
import org.jetbrains.kotlin.cli.common.toBooleanLenient
|
||||
import org.jetbrains.kotlin.cli.jvm.JvmRuntimeVersionsConsistencyChecker
|
||||
import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.cli.jvm.repl
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.cli.jvm.repl.messages.DiagnosticMessageHolder
|
||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.script.KotlinScriptExternalDependencies
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
|
||||
class ReplCompilerStageHistory(private val state: GenericReplCompilerState) : BasicReplStageHistory<ScriptDescriptor>(state.lock) {
|
||||
|
||||
override fun resetTo(id: ILineId): Iterable<ILineId> {
|
||||
val removedCompiledLines = super.resetTo(id)
|
||||
val removedAnalyzedLines = state.analyzerEngine.resetToLine(id.no)
|
||||
|
||||
removedCompiledLines.zip(removedAnalyzedLines).forEach {
|
||||
if (it.first != LineId(it.second)) {
|
||||
throw IllegalStateException("History mismatch when resetting lines: ${it.first.no} != ${it.second}")
|
||||
}
|
||||
}
|
||||
return removedCompiledLines
|
||||
}
|
||||
}
|
||||
|
||||
abstract class GenericReplCheckerState: IReplStageState<ScriptDescriptor> {
|
||||
|
||||
// "line" - is the unit of evaluation here, could in fact consists of several character lines
|
||||
class LineState(
|
||||
val codeLine: ReplCodeLine,
|
||||
val psiFile: KtFile,
|
||||
val errorHolder: DiagnosticMessageHolder)
|
||||
|
||||
var lastLineState: LineState? = null // for transferring state to the compiler in most typical case
|
||||
}
|
||||
|
||||
class GenericReplCompilerState(environment: KotlinCoreEnvironment, override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()) : IReplStageState<ScriptDescriptor>, GenericReplCheckerState() {
|
||||
|
||||
override val history = ReplCompilerStageHistory(this)
|
||||
|
||||
override val currentGeneration: Int get() = (history as BasicReplStageHistory<*>).currentGeneration.get()
|
||||
|
||||
val analyzerEngine = ReplCodeAnalyzer(environment)
|
||||
|
||||
var lastDependencies: KotlinScriptExternalDependencies? = null
|
||||
}
|
||||
@@ -22,31 +22,66 @@ import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import java.io.File
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
|
||||
// TODO: remove if unused after switching old repl to the new infrastruct
|
||||
open class GenericRepl protected constructor(
|
||||
disposable: Disposable,
|
||||
scriptDefinition: KotlinScriptDefinition,
|
||||
compilerConfiguration: CompilerConfiguration,
|
||||
messageCollector: MessageCollector,
|
||||
baseClassloader: ClassLoader?,
|
||||
protected val fallbackScriptArgs: ScriptArgsWithTypes? = null,
|
||||
protected val repeatingMode: ReplRepeatingMode = ReplRepeatingMode.NONE
|
||||
protected val fallbackScriptArgs: ScriptArgsWithTypes?,
|
||||
protected val repeatingMode: ReplRepeatingMode = ReplRepeatingMode.NONE,
|
||||
protected val stateLock: ReentrantReadWriteLock
|
||||
) : ReplCompiler, ReplEvaluator, ReplAtomicEvaluator {
|
||||
constructor (
|
||||
disposable: Disposable,
|
||||
scriptDefinition: KotlinScriptDefinition,
|
||||
compilerConfiguration: CompilerConfiguration,
|
||||
messageCollector: MessageCollector,
|
||||
baseClassloader: ClassLoader?,
|
||||
fallbackScriptArgs: ScriptArgsWithTypes? = null
|
||||
) : this(disposable, scriptDefinition, compilerConfiguration, messageCollector, baseClassloader, fallbackScriptArgs, stateLock = ReentrantReadWriteLock())
|
||||
|
||||
protected val compiler: ReplCompiler by lazy { GenericReplCompiler(disposable, scriptDefinition, compilerConfiguration, messageCollector) }
|
||||
protected val evaluator: ReplFullEvaluator by lazy { GenericReplCompilingEvaluator(compiler, compilerConfiguration.jvmClasspathRoots, baseClassloader, fallbackScriptArgs, repeatingMode) }
|
||||
protected val compiler: ReplCompiler by lazy { GenericReplCompiler(disposable, scriptDefinition, compilerConfiguration, messageCollector, stateLock) }
|
||||
protected val evaluator: ReplFullEvaluator by lazy { GenericReplCompilingEvaluator(compiler, compilerConfiguration.jvmClasspathRoots, baseClassloader, fallbackScriptArgs, repeatingMode, stateLock) }
|
||||
protected var codeLineNumber = AtomicInteger(0)
|
||||
|
||||
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = AggregatedReplStageState(compiler.createState(lock), evaluator.createState(lock), lock)
|
||||
override fun resetToLine(lineNumber: Int): List<ReplCodeLine> {
|
||||
return evaluator.resetToLine(lineNumber)
|
||||
}
|
||||
|
||||
override fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult = compiler.check(state, codeLine)
|
||||
override fun resetToLine(line: ReplCodeLine): List<ReplCodeLine> {
|
||||
return evaluator.resetToLine(line)
|
||||
}
|
||||
|
||||
override fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult = compiler.compile(state, codeLine)
|
||||
override val history: List<ReplCodeLine> get() = evaluator.history
|
||||
override val compiledHistory: List<ReplCodeLine> get() = compiler.history
|
||||
override val evaluatedHistory: List<ReplCodeLine> get() = evaluator.history
|
||||
|
||||
override fun eval(state: IReplStageState<*>, compileResult: ReplCompileResult.CompiledClasses, scriptArgs: ScriptArgsWithTypes?, invokeWrapper: InvokeWrapper?): ReplEvalResult =
|
||||
evaluator.eval(state, compileResult, scriptArgs, invokeWrapper)
|
||||
override val currentClasspath: List<File>
|
||||
get() = evaluator.currentClasspath
|
||||
|
||||
override fun compileAndEval(state: IReplStageState<*>, codeLine: ReplCodeLine, scriptArgs: ScriptArgsWithTypes?, invokeWrapper: InvokeWrapper?): ReplEvalResult =
|
||||
evaluator.compileAndEval(state, codeLine, scriptArgs, invokeWrapper)
|
||||
override val lastEvaluatedScripts: List<EvalHistoryType>
|
||||
get() = evaluator.lastEvaluatedScripts
|
||||
|
||||
override fun check(codeLine: ReplCodeLine): ReplCheckResult {
|
||||
return compiler.check(codeLine)
|
||||
}
|
||||
|
||||
override fun compile(codeLine: ReplCodeLine, verifyHistory: List<ReplCodeLine>?): ReplCompileResult {
|
||||
return compiler.compile(codeLine, verifyHistory)
|
||||
}
|
||||
|
||||
override fun eval(compileResult: ReplCompileResult.CompiledClasses, scriptArgs: ScriptArgsWithTypes?, invokeWrapper: InvokeWrapper?): ReplEvalResult {
|
||||
return evaluator.eval(compileResult, scriptArgs, invokeWrapper)
|
||||
}
|
||||
|
||||
override fun compileAndEval(codeLine: ReplCodeLine, scriptArgs: ScriptArgsWithTypes?, verifyHistory: List<ReplCodeLine>?, invokeWrapper: InvokeWrapper?): ReplEvalResult {
|
||||
return evaluator.compileAndEval(codeLine, scriptArgs, verifyHistory, invokeWrapper)
|
||||
}
|
||||
|
||||
fun nextCodeLine(code: String) = ReplCodeLine(codeLineNumber.incrementAndGet(), code)
|
||||
}
|
||||
@@ -21,6 +21,7 @@ package org.jetbrains.kotlin.cli.jvm.repl
|
||||
import org.jetbrains.kotlin.cli.common.repl.CompiledReplCodeLine
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplHistory
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplResettableCodeLine
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
@@ -42,18 +43,23 @@ import org.jetbrains.kotlin.resolve.scopes.ImportingScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.replaceImportingScopes
|
||||
import org.jetbrains.kotlin.script.ScriptPriorities
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
|
||||
class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
|
||||
|
||||
class GenericReplAnalyzer(environment: KotlinCoreEnvironment,
|
||||
protected val stateLock: ReentrantReadWriteLock = ReentrantReadWriteLock()) : ReplResettableCodeLine {
|
||||
private val topDownAnalysisContext: TopDownAnalysisContext
|
||||
private val topDownAnalyzer: LazyTopDownAnalyzer
|
||||
private val resolveSession: ResolveSession
|
||||
private val scriptDeclarationFactory: ScriptMutableDeclarationProviderFactory
|
||||
private val replState = ResettableAnalyzerState()
|
||||
private val replState = ResettableReplState()
|
||||
|
||||
val module: ModuleDescriptorImpl
|
||||
get() = stateLock.read { field }
|
||||
|
||||
val trace: BindingTraceContext = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace()
|
||||
get() = stateLock.read { field }
|
||||
|
||||
init {
|
||||
// Module source scope is empty because all binary classes are in the dependency module, and all source classes are guaranteed
|
||||
@@ -88,15 +94,21 @@ class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
|
||||
}
|
||||
}
|
||||
|
||||
fun resetToLine(lineNumber: Int): List<ReplCodeLine> = replState.resetToLine(lineNumber)
|
||||
override fun resetToLine(lineNumber: Int): List<ReplCodeLine> {
|
||||
return stateLock.write { replState.resetToLine(lineNumber) }
|
||||
}
|
||||
|
||||
override fun resetToLine(line: ReplCodeLine): List<ReplCodeLine> = resetToLine(line.no)
|
||||
|
||||
fun analyzeReplLine(psiFile: KtFile, codeLine: ReplCodeLine): ReplLineAnalysisResult {
|
||||
topDownAnalysisContext.scripts.clear()
|
||||
trace.clearDiagnostics()
|
||||
return stateLock.write {
|
||||
topDownAnalysisContext.scripts.clear()
|
||||
trace.clearDiagnostics()
|
||||
|
||||
psiFile.script!!.putUserData(ScriptPriorities.PRIORITY_KEY, codeLine.no)
|
||||
psiFile.script!!.putUserData(ScriptPriorities.PRIORITY_KEY, codeLine.no)
|
||||
|
||||
return doAnalyze(psiFile, codeLine)
|
||||
doAnalyze(psiFile, codeLine)
|
||||
}
|
||||
}
|
||||
|
||||
private fun doAnalyze(linePsi: KtFile, codeLine: ReplCodeLine): ReplLineAnalysisResult {
|
||||
@@ -167,8 +179,7 @@ class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
|
||||
}
|
||||
|
||||
// TODO: merge with org.jetbrains.kotlin.resolve.repl.ReplState when switching to new REPL infrastruct everywhere
|
||||
// TODO: review it's place in the extracted state infrastruct (now the analyzer itself is a part of the state
|
||||
class ResettableAnalyzerState {
|
||||
class ResettableReplState {
|
||||
private val successfulLines = ReplHistory<LineInfo.SuccessfulLine>()
|
||||
private val submittedLines = hashMapOf<KtFile, LineInfo>()
|
||||
|
||||
@@ -178,6 +189,8 @@ class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
|
||||
return removed.map { it.first }
|
||||
}
|
||||
|
||||
fun resetToLine(line: ReplCodeLine): List<ReplCodeLine> = resetToLine(line.no)
|
||||
|
||||
fun submitLine(ktFile: KtFile, codeLine: ReplCodeLine) {
|
||||
val line = LineInfo.SubmittedLine(ktFile, successfulLines.lastValue())
|
||||
submittedLines[ktFile] = line
|
||||
@@ -26,9 +26,12 @@ import com.intellij.testFramework.LightVirtualFile
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCheckResult
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
|
||||
import org.jetbrains.kotlin.cli.common.repl.makeScriptBaseName
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.cli.jvm.repl.messages.DiagnosticMessageHolder
|
||||
import org.jetbrains.kotlin.cli.jvm.repl.messages.ReplTerminalDiagnosticMessageHolder
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
@@ -37,6 +40,8 @@ import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
|
||||
const val KOTLIN_REPL_JVM_TARGET_PROPERTY = "kotlin.repl.jvm.target"
|
||||
@@ -45,9 +50,9 @@ open class GenericReplChecker(
|
||||
disposable: Disposable,
|
||||
val scriptDefinition: KotlinScriptDefinition,
|
||||
val compilerConfiguration: CompilerConfiguration,
|
||||
messageCollector: MessageCollector
|
||||
) : ReplCheckAction {
|
||||
|
||||
messageCollector: MessageCollector,
|
||||
protected val stateLock: ReentrantReadWriteLock = ReentrantReadWriteLock()
|
||||
) {
|
||||
internal val environment = run {
|
||||
compilerConfiguration.apply {
|
||||
add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition)
|
||||
@@ -65,12 +70,21 @@ open class GenericReplChecker(
|
||||
|
||||
private val psiFileFactory: PsiFileFactoryImpl = PsiFileFactory.getInstance(environment.project) as PsiFileFactoryImpl
|
||||
|
||||
internal fun createDiagnosticHolder() = ReplTerminalDiagnosticMessageHolder()
|
||||
// "line" - is the unit of evaluation here, could in fact consists of several character lines
|
||||
internal class LineState(
|
||||
val codeLine: ReplCodeLine,
|
||||
val psiFile: KtFile,
|
||||
val errorHolder: DiagnosticMessageHolder)
|
||||
|
||||
override fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult {
|
||||
state.lock.write {
|
||||
val checkerState = state.asState(GenericReplCheckerState::class.java)
|
||||
val scriptFileName = makeScriptBaseName(codeLine)
|
||||
private var _lineState: LineState? = null
|
||||
|
||||
internal val lineState: LineState? get() = stateLock.read { _lineState }
|
||||
|
||||
fun createDiagnosticHolder() = ReplTerminalDiagnosticMessageHolder()
|
||||
|
||||
fun check(codeLine: ReplCodeLine, generation: Long): ReplCheckResult {
|
||||
stateLock.write {
|
||||
val scriptFileName = makeScriptBaseName(codeLine, generation)
|
||||
val virtualFile =
|
||||
LightVirtualFile("$scriptFileName${KotlinParserDefinition.STD_SCRIPT_EXT}", KotlinLanguage.INSTANCE, StringUtil.convertLineSeparators(codeLine.code)).apply {
|
||||
charset = CharsetToolkit.UTF8_CHARSET
|
||||
@@ -83,7 +97,7 @@ open class GenericReplChecker(
|
||||
val syntaxErrorReport = AnalyzerWithCompilerReport.reportSyntaxErrors(psiFile, errorHolder)
|
||||
|
||||
if (!syntaxErrorReport.isHasErrors) {
|
||||
checkerState.lastLineState = GenericReplCheckerState.LineState(codeLine, psiFile, errorHolder)
|
||||
_lineState = LineState(codeLine, psiFile, errorHolder)
|
||||
}
|
||||
|
||||
return when {
|
||||
|
||||
@@ -26,82 +26,115 @@ import org.jetbrains.kotlin.codegen.ClassBuilderFactories
|
||||
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.script.KotlinScriptExternalDependencies
|
||||
import java.io.File
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
|
||||
// WARNING: not thread safe, assuming external synchronization
|
||||
|
||||
open class GenericReplCompiler(disposable: Disposable,
|
||||
protected val scriptDefinition: KotlinScriptDefinition,
|
||||
protected val compilerConfiguration: CompilerConfiguration,
|
||||
messageCollector: MessageCollector
|
||||
) : ReplCompiler {
|
||||
messageCollector: MessageCollector,
|
||||
protected val stateLock: ReentrantReadWriteLock = ReentrantReadWriteLock()) : ReplCompiler {
|
||||
private val checker = GenericReplChecker(disposable, scriptDefinition, compilerConfiguration, messageCollector, stateLock)
|
||||
|
||||
private val checker = GenericReplChecker(disposable, scriptDefinition, compilerConfiguration, messageCollector)
|
||||
private val analyzerEngine = GenericReplAnalyzer(checker.environment, stateLock)
|
||||
|
||||
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = GenericReplCompilerState(checker.environment, lock)
|
||||
private var lastDependencies: KotlinScriptExternalDependencies? = null
|
||||
|
||||
override fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult = checker.check(state, codeLine)
|
||||
private val descriptorsHistory = ReplHistory<ScriptDescriptor>()
|
||||
|
||||
override fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult {
|
||||
state.lock.write {
|
||||
val compilerState = state.asState(GenericReplCompilerState::class.java)
|
||||
private val generation = AtomicLong(1)
|
||||
|
||||
override fun resetToLine(lineNumber: Int): List<ReplCodeLine> {
|
||||
return stateLock.write {
|
||||
generation.incrementAndGet()
|
||||
val removedCompiledLines = descriptorsHistory.resetToLine(lineNumber)
|
||||
val removedAnalyzedLines = analyzerEngine.resetToLine(lineNumber)
|
||||
|
||||
removedCompiledLines.zip(removedAnalyzedLines).forEach {
|
||||
if (it.first.first != it.second) {
|
||||
throw IllegalStateException("History mismatch when resetting lines")
|
||||
}
|
||||
}
|
||||
|
||||
removedCompiledLines
|
||||
}.map { it.first }
|
||||
}
|
||||
|
||||
override val history: List<ReplCodeLine> get() = stateLock.read { descriptorsHistory.copySources() }
|
||||
|
||||
override fun check(codeLine: ReplCodeLine): ReplCheckResult = stateLock.read {
|
||||
return checker.check(codeLine, generation.get())
|
||||
}
|
||||
|
||||
override fun compile(codeLine: ReplCodeLine, verifyHistory: List<ReplCodeLine>?): ReplCompileResult {
|
||||
stateLock.write {
|
||||
val firstMismatch = descriptorsHistory.firstMismatchingHistory(verifyHistory)
|
||||
if (firstMismatch != null) {
|
||||
return@compile ReplCompileResult.HistoryMismatch(descriptorsHistory.copySources(), firstMismatch)
|
||||
}
|
||||
|
||||
val currentGeneration = generation.get()
|
||||
|
||||
val (psiFile, errorHolder) = run {
|
||||
if (compilerState.lastLineState == null || compilerState.lastLineState!!.codeLine != codeLine) {
|
||||
val res = checker.check(state, codeLine)
|
||||
if (checker.lineState == null || checker.lineState!!.codeLine != codeLine) {
|
||||
val res = checker.check(codeLine, currentGeneration)
|
||||
when (res) {
|
||||
is ReplCheckResult.Incomplete -> return@compile ReplCompileResult.Incomplete()
|
||||
is ReplCheckResult.Error -> return@compile ReplCompileResult.Error(res.message, res.location)
|
||||
is ReplCheckResult.Incomplete -> return@compile ReplCompileResult.Incomplete(descriptorsHistory.copySources())
|
||||
is ReplCheckResult.Error -> return@compile ReplCompileResult.Error(descriptorsHistory.copySources(), res.message, res.location)
|
||||
is ReplCheckResult.Ok -> {} // continue
|
||||
}
|
||||
}
|
||||
Pair(compilerState.lastLineState!!.psiFile, compilerState.lastLineState!!.errorHolder)
|
||||
Pair(checker.lineState!!.psiFile, checker.lineState!!.errorHolder)
|
||||
}
|
||||
|
||||
val newDependencies = scriptDefinition.getDependenciesFor(psiFile, checker.environment.project, compilerState.lastDependencies)
|
||||
val newDependencies = scriptDefinition.getDependenciesFor(psiFile, checker.environment.project, lastDependencies)
|
||||
var classpathAddendum: List<File>? = null
|
||||
if (compilerState.lastDependencies != newDependencies) {
|
||||
compilerState.lastDependencies = newDependencies
|
||||
if (lastDependencies != newDependencies) {
|
||||
lastDependencies = newDependencies
|
||||
classpathAddendum = newDependencies?.let { checker.environment.updateClasspath(it.classpath.map(::JvmClasspathRoot)) }
|
||||
}
|
||||
|
||||
val analysisResult = compilerState.analyzerEngine.analyzeReplLine(psiFile, codeLine)
|
||||
val analysisResult = analyzerEngine.analyzeReplLine(psiFile, codeLine)
|
||||
AnalyzerWithCompilerReport.reportDiagnostics(analysisResult.diagnostics, errorHolder)
|
||||
val scriptDescriptor = when (analysisResult) {
|
||||
is ReplCodeAnalyzer.ReplLineAnalysisResult.WithErrors -> return ReplCompileResult.Error(errorHolder.renderedDiagnostics)
|
||||
is ReplCodeAnalyzer.ReplLineAnalysisResult.Successful -> analysisResult.scriptDescriptor
|
||||
is GenericReplAnalyzer.ReplLineAnalysisResult.WithErrors -> return ReplCompileResult.Error(descriptorsHistory.copySources(), errorHolder.renderedDiagnostics)
|
||||
is GenericReplAnalyzer.ReplLineAnalysisResult.Successful -> analysisResult.scriptDescriptor
|
||||
else -> error("Unexpected result ${analysisResult.javaClass}")
|
||||
}
|
||||
|
||||
val generationState = GenerationState(
|
||||
val state = GenerationState(
|
||||
psiFile.project,
|
||||
ClassBuilderFactories.binaries(false),
|
||||
compilerState.analyzerEngine.module,
|
||||
compilerState.analyzerEngine.trace.bindingContext,
|
||||
analyzerEngine.module,
|
||||
analyzerEngine.trace.bindingContext,
|
||||
listOf(psiFile),
|
||||
compilerConfiguration
|
||||
)
|
||||
generationState.replSpecific.scriptResultFieldName = SCRIPT_RESULT_FIELD_NAME
|
||||
generationState.replSpecific.earlierScriptsForReplInterpreter = compilerState.history.map { it.item }
|
||||
generationState.beforeCompile()
|
||||
state.replSpecific.scriptResultFieldName = SCRIPT_RESULT_FIELD_NAME
|
||||
state.replSpecific.earlierScriptsForReplInterpreter = descriptorsHistory.copyValues()
|
||||
state.beforeCompile()
|
||||
KotlinCodegenFacade.generatePackage(
|
||||
generationState,
|
||||
psiFile.script!!.containingKtFile.packageFqName,
|
||||
setOf(psiFile.script!!.containingKtFile),
|
||||
state,
|
||||
psiFile.script!!.getContainingKtFile().packageFqName,
|
||||
setOf(psiFile.script!!.getContainingKtFile()),
|
||||
org.jetbrains.kotlin.codegen.CompilationErrorHandler.THROW_EXCEPTION)
|
||||
|
||||
val generatedClassname = makeScriptBaseName(codeLine)
|
||||
compilerState.history.push(LineId(codeLine), scriptDescriptor)
|
||||
val generatedClassname = makeScriptBaseName(codeLine, currentGeneration)
|
||||
val compiledCodeLine = CompiledReplCodeLine(generatedClassname, codeLine)
|
||||
descriptorsHistory.add(compiledCodeLine, scriptDescriptor)
|
||||
|
||||
return ReplCompileResult.CompiledClasses(LineId(codeLine),
|
||||
compilerState.history.map { it.id },
|
||||
return ReplCompileResult.CompiledClasses(descriptorsHistory.copySources(),
|
||||
compiledCodeLine,
|
||||
generatedClassname,
|
||||
generationState.factory.asList().map { CompiledClassData(it.relativePath, it.asByteArray()) },
|
||||
generationState.replSpecific.hasResult,
|
||||
classpathAddendum ?: emptyList())
|
||||
state.factory.asList().map { CompiledClassData(it.relativePath, it.asByteArray()) },
|
||||
state.replSpecific.hasResult,
|
||||
classpathAddendum ?: emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ class ReplInterpreter(
|
||||
}
|
||||
|
||||
private val psiFileFactory: PsiFileFactoryImpl = PsiFileFactory.getInstance(environment.project) as PsiFileFactoryImpl
|
||||
private val analyzerEngine = ReplCodeAnalyzer(environment)
|
||||
private val analyzerEngine = GenericReplAnalyzer(environment)
|
||||
|
||||
fun eval(line: String): LineResult {
|
||||
++lineNumber
|
||||
@@ -98,11 +98,11 @@ class ReplInterpreter(
|
||||
return LineResult.Error.CompileTime(errorHolder.renderedDiagnostics)
|
||||
}
|
||||
|
||||
val analysisResult = analyzerEngine.analyzeReplLine(psiFile, ReplCodeLine(lineNumber, 0, "fake line"))
|
||||
val analysisResult = analyzerEngine.analyzeReplLine(psiFile, ReplCodeLine(lineNumber, "fake line"))
|
||||
AnalyzerWithCompilerReport.reportDiagnostics(analysisResult.diagnostics, errorHolder)
|
||||
val scriptDescriptor = when (analysisResult) {
|
||||
is ReplCodeAnalyzer.ReplLineAnalysisResult.WithErrors -> return LineResult.Error.CompileTime(errorHolder.renderedDiagnostics)
|
||||
is ReplCodeAnalyzer.ReplLineAnalysisResult.Successful -> analysisResult.scriptDescriptor
|
||||
is GenericReplAnalyzer.ReplLineAnalysisResult.WithErrors -> return LineResult.Error.CompileTime(errorHolder.renderedDiagnostics)
|
||||
is GenericReplAnalyzer.ReplLineAnalysisResult.Successful -> analysisResult.scriptDescriptor
|
||||
else -> error("Unexpected result ${analysisResult.javaClass}")
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ class ReplInterpreter(
|
||||
private fun renderStackTrace(cause: Throwable, startFromMethodName: String): String {
|
||||
val newTrace = arrayListOf<StackTraceElement>()
|
||||
var skip = true
|
||||
for ((_, element) in cause.stackTrace.withIndex().reversed()) {
|
||||
for ((i, element) in cause.stackTrace.withIndex().reversed()) {
|
||||
if ("${element.className}.${element.methodName}" == startFromMethodName) {
|
||||
skip = false
|
||||
}
|
||||
@@ -214,8 +214,8 @@ class ReplInterpreter(
|
||||
state.beforeCompile()
|
||||
KotlinCodegenFacade.generatePackage(
|
||||
state,
|
||||
script.containingKtFile.packageFqName,
|
||||
setOf(script.containingKtFile),
|
||||
script.getContainingKtFile().packageFqName,
|
||||
setOf(script.getContainingKtFile()),
|
||||
errorHandler
|
||||
)
|
||||
}
|
||||
|
||||
@@ -80,10 +80,9 @@ open class CompilerCallbackServicesFacadeServer(
|
||||
|
||||
override fun lookupTracker_isDoNothing(): Boolean = lookupTracker_isDoNothing
|
||||
|
||||
override fun compilationCanceledStatus_checkCanceled(): Void? {
|
||||
override fun compilationCanceledStatus_checkCanceled() {
|
||||
try {
|
||||
compilationCanceledStatus!!.checkCanceled()
|
||||
return null
|
||||
}
|
||||
catch (e: Exception) {
|
||||
// avoid passing exceptions that may have different serialVersionUID on across rmi border
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.daemon.client
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.daemon.common.CompileService
|
||||
import org.jetbrains.kotlin.daemon.common.RemoteOperationsTracer
|
||||
import org.jetbrains.kotlin.daemon.common.SOCKET_ANY_FREE_PORT
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
// TODO: reduce number of ports used then SOCKET_ANY_FREE_PORT is passed (same problem with other calls)
|
||||
|
||||
open class KotlinRemoteReplClientBase(
|
||||
protected val compileService: CompileService,
|
||||
clientAliveFlagFile: File?,
|
||||
targetPlatform: CompileService.TargetPlatform,
|
||||
templateClasspath: List<File>,
|
||||
templateClassName: String,
|
||||
scriptArgs: Array<out Any?>? = null,
|
||||
scriptArgsTypes: Array<out Class<out Any>>? = null,
|
||||
compilerMessagesOutputStream: OutputStream = System.err,
|
||||
evalOutputStream: OutputStream? = null,
|
||||
evalErrorStream: OutputStream? = null,
|
||||
evalInputStream: InputStream? = null,
|
||||
port: Int = SOCKET_ANY_FREE_PORT,
|
||||
operationsTracer: RemoteOperationsTracer? = null
|
||||
) {
|
||||
|
||||
val sessionId = compileService.leaseReplSession(
|
||||
clientAliveFlagFile?.absolutePath,
|
||||
targetPlatform,
|
||||
CompilerCallbackServicesFacadeServer(port = port),
|
||||
templateClasspath,
|
||||
templateClassName,
|
||||
scriptArgs,
|
||||
scriptArgsTypes,
|
||||
RemoteOutputStreamServer(compilerMessagesOutputStream, port),
|
||||
evalOutputStream?.let { RemoteOutputStreamServer(it, port) },
|
||||
evalErrorStream?.let { RemoteOutputStreamServer(it, port) },
|
||||
evalInputStream?.let { RemoteInputStreamServer(it, port) },
|
||||
operationsTracer
|
||||
).get()
|
||||
|
||||
// dispose should be called at the end of the repl lifetime to free daemon repl session and appropriate resources
|
||||
open fun dispose() {
|
||||
try {
|
||||
compileService.releaseReplSession(sessionId)
|
||||
}
|
||||
catch (ex: java.rmi.RemoteException) {
|
||||
// assuming that communication failed and daemon most likely is already down
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinRemoteReplCompiler(
|
||||
compileService: CompileService,
|
||||
clientAliveFlagFile: File?,
|
||||
targetPlatform: CompileService.TargetPlatform,
|
||||
templateClasspath: List<File>,
|
||||
templateClassName: String,
|
||||
compilerMessagesOutputStream: OutputStream,
|
||||
port: Int = SOCKET_ANY_FREE_PORT,
|
||||
operationsTracer: RemoteOperationsTracer? = null
|
||||
) : KotlinRemoteReplClientBase(
|
||||
compileService = compileService,
|
||||
clientAliveFlagFile = clientAliveFlagFile,
|
||||
targetPlatform = targetPlatform,
|
||||
templateClasspath = templateClasspath,
|
||||
templateClassName = templateClassName,
|
||||
compilerMessagesOutputStream = compilerMessagesOutputStream,
|
||||
evalOutputStream = null,
|
||||
evalErrorStream = null,
|
||||
evalInputStream = null,
|
||||
port = port,
|
||||
operationsTracer = operationsTracer
|
||||
), ReplCompiler, ReplCheckAction {
|
||||
override fun resetToLine(lineNumber: Int): List<ReplCodeLine> {
|
||||
return emptyList() // TODO: not implemented, no current need
|
||||
}
|
||||
|
||||
override val history: List<ReplCodeLine>
|
||||
get() = emptyList() // TODO: not implemented, no current need
|
||||
|
||||
override fun check(codeLine: ReplCodeLine): ReplCheckResult {
|
||||
return compileService.remoteReplLineCheck(sessionId, codeLine).get()
|
||||
}
|
||||
|
||||
override fun compile(codeLine: ReplCodeLine, verifyHistory: List<ReplCodeLine>?): ReplCompileResult {
|
||||
return compileService.remoteReplLineCompile(sessionId, codeLine, verifyHistory).get()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: consider removing daemon eval completely - it is not required now and has questionable security. This will simplify daemon interface as well
|
||||
class KotlinRemoteReplEvaluator(
|
||||
compileService: CompileService,
|
||||
clientAliveFlagFile: File?,
|
||||
targetPlatform: CompileService.TargetPlatform,
|
||||
templateClasspath: List<File>,
|
||||
templateClassName: String,
|
||||
scriptArgs: Array<out Any?>? = null,
|
||||
scriptArgsTypes: Array<out Class<out Any>>? = null,
|
||||
compilerMessagesOutputStream: OutputStream,
|
||||
evalOutputStream: OutputStream?,
|
||||
evalErrorStream: OutputStream?,
|
||||
evalInputStream: InputStream?,
|
||||
port: Int = SOCKET_ANY_FREE_PORT,
|
||||
operationsTracer: RemoteOperationsTracer? = null
|
||||
) : KotlinRemoteReplClientBase(
|
||||
compileService = compileService,
|
||||
clientAliveFlagFile = clientAliveFlagFile,
|
||||
targetPlatform = targetPlatform,
|
||||
templateClasspath = templateClasspath,
|
||||
templateClassName = templateClassName,
|
||||
scriptArgs = scriptArgs,
|
||||
scriptArgsTypes = scriptArgsTypes,
|
||||
compilerMessagesOutputStream = compilerMessagesOutputStream,
|
||||
evalOutputStream = evalOutputStream,
|
||||
evalErrorStream = evalErrorStream,
|
||||
evalInputStream = evalInputStream,
|
||||
port = port,
|
||||
operationsTracer = operationsTracer
|
||||
), ReplAtomicEvalAction, ReplEvaluatorExposedInternalHistory, ReplCheckAction {
|
||||
|
||||
override val lastEvaluatedScripts: List<EvalHistoryType> = emptyList() // not implemented, no need so far
|
||||
|
||||
// TODO: invokeWrapper is ignored here, and in the daemon the session wrapper is used instead; So consider to make it per call (avoid performance penalties though)
|
||||
// TODO: scriptArgs are ignored here, they should be passed through
|
||||
override fun compileAndEval(codeLine: ReplCodeLine,
|
||||
scriptArgs: ScriptArgsWithTypes?,
|
||||
verifyHistory: List<ReplCodeLine>?,
|
||||
invokeWrapper: InvokeWrapper?): ReplEvalResult {
|
||||
return compileService.remoteReplLineEval(sessionId, codeLine, verifyHistory).get()
|
||||
}
|
||||
|
||||
override fun check(codeLine: ReplCodeLine): ReplCheckResult {
|
||||
return compileService.remoteReplLineCheck(sessionId, codeLine).get()
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.daemon.client
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.daemon.common.*
|
||||
import java.io.File
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
|
||||
// TODO: reduce number of ports used then SOCKET_ANY_FREE_PORT is passed (same problem with other calls)
|
||||
|
||||
open class KotlinRemoteReplCompilerClient(
|
||||
protected val compileService: CompileService,
|
||||
clientAliveFlagFile: File?,
|
||||
targetPlatform: CompileService.TargetPlatform,
|
||||
args: Array<out String>,
|
||||
messageCollector: MessageCollector,
|
||||
templateClasspath: List<File>,
|
||||
templateClassName: String,
|
||||
port: Int = SOCKET_ANY_FREE_PORT
|
||||
) : ReplCompiler {
|
||||
val services = BasicCompilerServicesWithResultsFacadeServer(messageCollector, null, port)
|
||||
|
||||
val sessionId = compileService.leaseReplSession(
|
||||
clientAliveFlagFile?.absolutePath,
|
||||
args,
|
||||
CompilationOptions(
|
||||
CompilerMode.NON_INCREMENTAL_COMPILER,
|
||||
targetPlatform,
|
||||
arrayOf(ReportCategory.COMPILER_MESSAGE.code, ReportCategory.DAEMON_MESSAGE.code, ReportCategory.EXCEPTION.code, ReportCategory.OUTPUT_MESSAGE.code),
|
||||
ReportSeverity.INFO.code,
|
||||
emptyArray()),
|
||||
services,
|
||||
templateClasspath,
|
||||
templateClassName
|
||||
).get()
|
||||
|
||||
// dispose should be called at the end of the repl lifetime to free daemon repl session and appropriate resources
|
||||
open fun dispose() {
|
||||
try {
|
||||
compileService.releaseReplSession(sessionId)
|
||||
}
|
||||
catch (ex: java.rmi.RemoteException) {
|
||||
// assuming that communication failed and daemon most likely is already down
|
||||
}
|
||||
}
|
||||
|
||||
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> =
|
||||
RemoteReplCompilerState(compileService.replCreateState(sessionId).get(), lock)
|
||||
|
||||
override fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult =
|
||||
compileService.replCheck(sessionId, state.asState(RemoteReplCompilerState::class.java).replStateFacade.getId(), codeLine).get()
|
||||
|
||||
override fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult =
|
||||
compileService.replCompile(sessionId, state.asState(RemoteReplCompilerState::class.java).replStateFacade.getId(), codeLine).get()
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.daemon.client
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.daemon.common.ReplStateFacade
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
|
||||
// NOTE: the lock is local
|
||||
// TODO: verify that locla lock doesn't lead to any synch problems
|
||||
class RemoteReplCompilerStateHistory(private val state: RemoteReplCompilerState) : IReplStageHistory<Unit>, AbstractList<ReplHistoryRecord<Unit>>() {
|
||||
override val size: Int
|
||||
get() = state.replStateFacade.getHistorySize()
|
||||
|
||||
override fun get(index: Int): ReplHistoryRecord<Unit> = ReplHistoryRecord(state.replStateFacade.historyGet(index), Unit)
|
||||
|
||||
override fun push(id: ILineId, item: Unit) {
|
||||
throw NotImplementedError("push to remote history is not supported")
|
||||
}
|
||||
|
||||
override fun pop(): ReplHistoryRecord<Unit>? {
|
||||
throw NotImplementedError("pop from remote history is not supported")
|
||||
}
|
||||
|
||||
override fun resetTo(id: ILineId): Iterable<ILineId> = state.replStateFacade.historyResetTo(id).apply {
|
||||
if (isNotEmpty()) {
|
||||
currentGeneration.incrementAndGet()
|
||||
}
|
||||
}
|
||||
|
||||
val currentGeneration = AtomicInteger(REPL_CODE_LINE_FIRST_GEN)
|
||||
|
||||
override val lock: ReentrantReadWriteLock get() = state.lock
|
||||
}
|
||||
|
||||
class RemoteReplCompilerState(internal val replStateFacade: ReplStateFacade, override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()) : IReplStageState<Unit> {
|
||||
|
||||
override val currentGeneration: Int get() = (history as RemoteReplCompilerStateHistory).currentGeneration.get()
|
||||
|
||||
override val history: IReplStageHistory<Unit> = RemoteReplCompilerStateHistory(this)
|
||||
}
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.daemon.common
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCheckResult
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
import java.rmi.Remote
|
||||
@@ -35,6 +38,8 @@ interface CompileService : Remote {
|
||||
METADATA
|
||||
}
|
||||
|
||||
|
||||
|
||||
companion object {
|
||||
val NO_SESSION: Int = 0
|
||||
}
|
||||
@@ -102,7 +107,6 @@ interface CompileService : Remote {
|
||||
|
||||
// TODO: consider adding async version of shutdown and release
|
||||
|
||||
@Deprecated("The usages should be replaced with `compile` method", ReplaceWith("compile"))
|
||||
@Throws(RemoteException::class)
|
||||
fun remoteCompile(
|
||||
sessionId: Int,
|
||||
@@ -115,7 +119,6 @@ interface CompileService : Remote {
|
||||
operationsTracer: RemoteOperationsTracer?
|
||||
): CallResult<Int>
|
||||
|
||||
@Deprecated("The usages should be replaced with `compile` method", ReplaceWith("compile"))
|
||||
@Throws(RemoteException::class)
|
||||
fun remoteIncrementalCompile(
|
||||
sessionId: Int,
|
||||
@@ -140,7 +143,6 @@ interface CompileService : Remote {
|
||||
@Throws(RemoteException::class)
|
||||
fun clearJarCache()
|
||||
|
||||
@Deprecated("The usages should be replaced with other `leaseReplSession` method", ReplaceWith("leaseReplSession"))
|
||||
@Throws(RemoteException::class)
|
||||
fun leaseReplSession(
|
||||
aliveFlagPath: String?,
|
||||
@@ -160,14 +162,12 @@ interface CompileService : Remote {
|
||||
@Throws(RemoteException::class)
|
||||
fun releaseReplSession(sessionId: Int): CallResult<Nothing>
|
||||
|
||||
@Deprecated("The usages should be replaced with `replCheck` method", ReplaceWith("replCheck"))
|
||||
@Throws(RemoteException::class)
|
||||
fun remoteReplLineCheck(
|
||||
sessionId: Int,
|
||||
codeLine: ReplCodeLine
|
||||
): CallResult<ReplCheckResult>
|
||||
|
||||
@Deprecated("The usages should be replaced with `replCompile` method", ReplaceWith("replCompile"))
|
||||
@Throws(RemoteException::class)
|
||||
fun remoteReplLineCompile(
|
||||
sessionId: Int,
|
||||
@@ -175,38 +175,10 @@ interface CompileService : Remote {
|
||||
history: List<ReplCodeLine>?
|
||||
): CallResult<ReplCompileResult>
|
||||
|
||||
@Deprecated("Evaluation on daemon is not supported")
|
||||
@Throws(RemoteException::class)
|
||||
fun remoteReplLineEval(
|
||||
sessionId: Int,
|
||||
codeLine: ReplCodeLine,
|
||||
history: List<ReplCodeLine>?
|
||||
): CallResult<ReplEvalResult>
|
||||
|
||||
@Throws(RemoteException::class)
|
||||
fun leaseReplSession(
|
||||
aliveFlagPath: String?,
|
||||
compilerArguments: Array<out String>,
|
||||
compilationOptions: CompilationOptions,
|
||||
servicesFacade: CompilerServicesFacadeBase,
|
||||
templateClasspath: List<File>,
|
||||
templateClassName: String
|
||||
): CallResult<Int>
|
||||
|
||||
@Throws(RemoteException::class)
|
||||
fun replCreateState(sessionId: Int): CallResult<ReplStateFacade>
|
||||
|
||||
@Throws(RemoteException::class)
|
||||
fun replCheck(
|
||||
sessionId: Int,
|
||||
replStateId: Int,
|
||||
codeLine: ReplCodeLine
|
||||
): CallResult<ReplCheckResult>
|
||||
|
||||
@Throws(RemoteException::class)
|
||||
fun replCompile(
|
||||
sessionId: Int,
|
||||
replStateId: Int,
|
||||
codeLine: ReplCodeLine
|
||||
): CallResult<ReplCompileResult>
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import java.rmi.RemoteException
|
||||
* the reason for having common facade is attempt to reduce number of connections between client and daemon
|
||||
* Note: non-standard naming convention used to denote combining several entities in one facade - prefix <entityName>_ is used for every function belonging to the entity
|
||||
*/
|
||||
@Deprecated("The usages should be replaced with `compile` method and `CompilerServicesFacadeBase` implementations", ReplaceWith("CompilerServicesFacadeBase"))
|
||||
interface CompilerCallbackServicesFacade : Remote {
|
||||
|
||||
@Throws(RemoteException::class)
|
||||
@@ -81,7 +80,7 @@ interface CompilerCallbackServicesFacade : Remote {
|
||||
// ----------------------------------------------------
|
||||
// CompilationCanceledStatus
|
||||
@Throws(RemoteException::class, RmiFriendlyCompilationCanceledException::class)
|
||||
fun compilationCanceledStatus_checkCanceled(): Void?
|
||||
fun compilationCanceledStatus_checkCanceled(): Unit
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.daemon.common
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.repl.ILineId
|
||||
import java.rmi.Remote
|
||||
import java.rmi.RemoteException
|
||||
|
||||
interface ReplStateFacade : Remote {
|
||||
|
||||
@Throws(RemoteException::class)
|
||||
fun getId(): Int
|
||||
|
||||
@Throws(RemoteException::class)
|
||||
fun getHistorySize(): Int
|
||||
|
||||
@Throws(RemoteException::class)
|
||||
fun historyGet(index: Int): ILineId
|
||||
|
||||
@Throws(RemoteException::class)
|
||||
fun historyResetTo(id: ILineId): List<ILineId>
|
||||
}
|
||||
@@ -63,6 +63,7 @@ import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import java.util.logging.Level
|
||||
import java.util.logging.Logger
|
||||
import kotlin.comparisons.compareByDescending
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.schedule
|
||||
import kotlin.concurrent.write
|
||||
@@ -101,7 +102,6 @@ class CompileServiceImpl(
|
||||
val timer: Timer,
|
||||
val onShutdown: () -> Unit
|
||||
) : CompileService {
|
||||
|
||||
init {
|
||||
System.setProperty(KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY, "true")
|
||||
}
|
||||
@@ -133,13 +133,24 @@ class CompileServiceImpl(
|
||||
private val lock = ReentrantReadWriteLock()
|
||||
private val sessions: MutableMap<Int, ClientOrSessionProxy<Any>> = hashMapOf()
|
||||
private val sessionsIdCounter = AtomicInteger(0)
|
||||
private val internalRng = Random()
|
||||
|
||||
fun<T: Any> leaseSession(session: ClientOrSessionProxy<T>): Int = lock.write {
|
||||
val newId = getValidId(sessionsIdCounter) {
|
||||
it != CompileService.NO_SESSION && !sessions.containsKey(it)
|
||||
fun<T: Any> leaseSession(session: ClientOrSessionProxy<T>): Int {
|
||||
// fighting hypothetical integer wrapping
|
||||
var newId = sessionsIdCounter.incrementAndGet()
|
||||
for (attempt in 1..100) {
|
||||
if (newId != CompileService.NO_SESSION) {
|
||||
lock.write {
|
||||
if (!sessions.containsKey(newId)) {
|
||||
sessions.put(newId, session)
|
||||
return newId
|
||||
}
|
||||
}
|
||||
}
|
||||
// assuming wrap, jumping to random number to reduce probability of further clashes
|
||||
newId = sessionsIdCounter.addAndGet(internalRng.nextInt())
|
||||
}
|
||||
sessions.put(newId, session)
|
||||
newId
|
||||
throw IllegalStateException("Invalid state or algorithm error")
|
||||
}
|
||||
|
||||
fun isEmpty(): Boolean = lock.read { sessions.isEmpty() }
|
||||
@@ -256,7 +267,7 @@ class CompileServiceImpl(
|
||||
ifAlive { CompileService.CallResult.Good(usedMemory(withGC = true)) }
|
||||
|
||||
override fun shutdown(): CompileService.CallResult<Nothing> = ifAliveExclusive(minAliveness = Aliveness.LastSession, ignoreCompilerChanged = true) {
|
||||
shutdownWithDelay()
|
||||
shutdownImpl()
|
||||
CompileService.CallResult.Ok()
|
||||
}
|
||||
|
||||
@@ -461,10 +472,9 @@ class CompileServiceImpl(
|
||||
CompileService.CallResult.Error("Sorry, only JVM target platform is supported now")
|
||||
else {
|
||||
val disposable = Disposer.newDisposable()
|
||||
val compilerMessagesStream = PrintStream(BufferedOutputStream(RemoteOutputStreamClient(compilerMessagesOutputStream, DummyProfiler()), REMOTE_STREAM_BUFFER_SIZE))
|
||||
val messageCollector = KeepFirstErrorMessageCollector(compilerMessagesStream)
|
||||
val repl = KotlinJvmReplService(disposable, port, templateClasspath, templateClassName,
|
||||
messageCollector, operationsTracer)
|
||||
val repl = KotlinJvmReplService(disposable, templateClasspath, templateClassName,
|
||||
scriptArgs?.let { ScriptArgsWithTypes(it, scriptArgsTypes?.map { it.kotlin }?.toTypedArray() ?: emptyArray()) },
|
||||
compilerMessagesOutputStream, operationsTracer)
|
||||
val sessionId = state.sessions.leaseSession(ClientOrSessionProxy(aliveFlagPath, repl, disposable))
|
||||
|
||||
CompileService.CallResult.Good(sessionId)
|
||||
@@ -477,14 +487,14 @@ class CompileServiceImpl(
|
||||
override fun remoteReplLineCheck(sessionId: Int, codeLine: ReplCodeLine): CompileService.CallResult<ReplCheckResult> =
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
withValidRepl(sessionId) {
|
||||
CompileService.CallResult.Good(check(codeLine))
|
||||
check(codeLine)
|
||||
}
|
||||
}
|
||||
|
||||
override fun remoteReplLineCompile(sessionId: Int, codeLine: ReplCodeLine, history: List<ReplCodeLine>?): CompileService.CallResult<ReplCompileResult> =
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
withValidRepl(sessionId) {
|
||||
CompileService.CallResult.Good(compile(codeLine, history))
|
||||
compile(codeLine, history)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,56 +503,12 @@ class CompileServiceImpl(
|
||||
codeLine: ReplCodeLine,
|
||||
history: List<ReplCodeLine>?
|
||||
): CompileService.CallResult<ReplEvalResult> =
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
CompileService.CallResult.Error("Eval on daemon is not supported")
|
||||
}
|
||||
|
||||
override fun leaseReplSession(aliveFlagPath: String?,
|
||||
compilerArguments: Array<out String>,
|
||||
compilationOptions: CompilationOptions,
|
||||
servicesFacade: CompilerServicesFacadeBase,
|
||||
templateClasspath: List<File>,
|
||||
templateClassName: String
|
||||
): CompileService.CallResult<Int> = ifAlive(minAliveness = Aliveness.Alive) {
|
||||
if (compilationOptions.targetPlatform != CompileService.TargetPlatform.JVM)
|
||||
CompileService.CallResult.Error("Sorry, only JVM target platform is supported now")
|
||||
else {
|
||||
val disposable = Disposer.newDisposable()
|
||||
val messageCollector = CompileServicesFacadeMessageCollector(servicesFacade, compilationOptions)
|
||||
val repl = KotlinJvmReplService(disposable, port, templateClasspath, templateClassName,
|
||||
messageCollector, null)
|
||||
val sessionId = state.sessions.leaseSession(ClientOrSessionProxy(aliveFlagPath, repl, disposable))
|
||||
|
||||
CompileService.CallResult.Good(sessionId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun replCreateState(sessionId: Int): CompileService.CallResult<ReplStateFacade> =
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
withValidRepl(sessionId) {
|
||||
CompileService.CallResult.Good(createRemoteState(port))
|
||||
compileAndEval(codeLine, verifyHistory = history)
|
||||
}
|
||||
}
|
||||
|
||||
override fun replCheck(sessionId: Int, replStateId: Int, codeLine: ReplCodeLine): CompileService.CallResult<ReplCheckResult> =
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
withValidRepl(sessionId) {
|
||||
withValidReplState(replStateId) { state ->
|
||||
check(state, codeLine)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun replCompile(sessionId: Int, replStateId: Int, codeLine: ReplCodeLine): CompileService.CallResult<ReplCompileResult> =
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
withValidRepl(sessionId) {
|
||||
withValidReplState(replStateId) { state ->
|
||||
compile(state, codeLine)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// internal implementation stuff
|
||||
|
||||
// TODO: consider matching compilerId coming from outside with actual one
|
||||
@@ -603,7 +569,7 @@ class CompileServiceImpl(
|
||||
|
||||
// 3. check if in graceful shutdown state and all sessions are closed
|
||||
if (shutdownCondition({ state.alive.get() == Aliveness.LastSession.ordinal && state.sessions.isEmpty() }, "All sessions finished, shutting down")) {
|
||||
shutdownWithDelay()
|
||||
shutdown()
|
||||
shuttingDown = true
|
||||
}
|
||||
|
||||
@@ -629,7 +595,7 @@ class CompileServiceImpl(
|
||||
// TODO: could be too expensive anyway, consider removing this check
|
||||
shutdownCondition({ classpathWatcher.isChanged }, "Compiler changed"))
|
||||
{
|
||||
scheduleShutdown(true)
|
||||
shutdown()
|
||||
shuttingDown = true
|
||||
}
|
||||
|
||||
@@ -745,7 +711,7 @@ class CompileServiceImpl(
|
||||
operationsTracer: RemoteOperationsTracer?,
|
||||
body: (PrintStream, EventManager, Profiler) -> ExitCode): CompileService.CallResult<Int> =
|
||||
ifAlive {
|
||||
withValidClientOrSessionProxy(sessionId) { _ ->
|
||||
withValidClientOrSessionProxy(sessionId) { session ->
|
||||
operationsTracer?.before("compile")
|
||||
val rpcProfiler = if (daemonOptions.reportPerf) WallAndThreadTotalProfiler() else DummyProfiler()
|
||||
val eventManger = EventManagerImpl()
|
||||
@@ -775,7 +741,7 @@ class CompileServiceImpl(
|
||||
tracer: RemoteOperationsTracer?,
|
||||
body: (EventManager, Profiler) -> ExitCode): CompileService.CallResult<Int> =
|
||||
ifAlive {
|
||||
withValidClientOrSessionProxy(sessionId) { _ ->
|
||||
withValidClientOrSessionProxy(sessionId) { session ->
|
||||
tracer?.before("compile")
|
||||
val rpcProfiler = if (daemonOptions.reportPerf) WallAndThreadTotalProfiler() else DummyProfiler()
|
||||
val eventManger = EventManagerImpl()
|
||||
@@ -895,6 +861,7 @@ class CompileServiceImpl(
|
||||
finally {
|
||||
_lastUsedSeconds = nowSeconds()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private inline fun<R> withValidRepl(sessionId: Int, body: KotlinJvmReplService.() -> R): CompileService.CallResult<R> =
|
||||
@@ -903,12 +870,4 @@ class CompileServiceImpl(
|
||||
CompileService.CallResult.Good(it.body())
|
||||
} ?: CompileService.CallResult.Error("Not a REPL session $sessionId")
|
||||
}
|
||||
|
||||
@JvmName("withValidRepl1")
|
||||
private inline fun<R> withValidRepl(sessionId: Int, body: KotlinJvmReplService.() -> CompileService.CallResult<R>): CompileService.CallResult<R> =
|
||||
withValidClientOrSessionProxy(sessionId) { session ->
|
||||
(session?.data as? KotlinJvmReplService?)?.let {
|
||||
it.body()
|
||||
} ?: CompileService.CallResult.Error("Not a REPL session $sessionId")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import kotlin.concurrent.schedule
|
||||
|
||||
val DAEMON_PERIODIC_CHECK_INTERVAL_MS = 1000L
|
||||
|
||||
|
||||
class LogStream(name: String) : OutputStream() {
|
||||
|
||||
val log by lazy { Logger.getLogger(name) }
|
||||
@@ -156,6 +157,8 @@ object KotlinCompileDaemon {
|
||||
println(COMPILE_DAEMON_IS_READY_MESSAGE)
|
||||
log.info("daemon is listening on port: $port")
|
||||
|
||||
log.info("daemon is listening on port: $port")
|
||||
|
||||
// this supposed to stop redirected streams reader(s) on the client side and prevent some situations with hanging threads, but doesn't work reliably
|
||||
// TODO: implement more reliable scheme
|
||||
System.out.close()
|
||||
|
||||
@@ -20,40 +20,58 @@ import com.intellij.openapi.Disposable
|
||||
import org.jetbrains.kotlin.cli.common.messages.*
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
|
||||
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
|
||||
import org.jetbrains.kotlin.cli.jvm.repl.GenericReplCompiler
|
||||
import org.jetbrains.kotlin.cli.jvm.repl.GenericReplCompilerState
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.daemon.common.CompileService
|
||||
import org.jetbrains.kotlin.daemon.common.DummyProfiler
|
||||
import org.jetbrains.kotlin.daemon.common.RemoteOperationsTracer
|
||||
import org.jetbrains.kotlin.daemon.common.RemoteOutputStream
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.File
|
||||
import java.io.PrintStream
|
||||
import java.net.URLClassLoader
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
|
||||
open class KotlinJvmReplService(
|
||||
disposable: Disposable,
|
||||
val portForServers: Int,
|
||||
templateClasspath: List<File>,
|
||||
templateClassName: String,
|
||||
protected val messageCollector: MessageCollector,
|
||||
@Deprecated("drop it")
|
||||
protected val fallbackScriptArgs: ScriptArgsWithTypes?,
|
||||
compilerOutputStreamProxy: RemoteOutputStream,
|
||||
protected val operationsTracer: RemoteOperationsTracer?
|
||||
) : ReplCompileAction, ReplCheckAction, CreateReplStageStateAction {
|
||||
) : ReplCompileAction, ReplAtomicEvalAction, ReplCheckAction, ReplEvaluatorExposedInternalHistory {
|
||||
protected val compilerMessagesStream = PrintStream(BufferedOutputStream(RemoteOutputStreamClient(compilerOutputStreamProxy, DummyProfiler()), REMOTE_STREAM_BUFFER_SIZE))
|
||||
|
||||
protected class KeepFirstErrorMessageCollector(compilerMessagesStream: PrintStream) : MessageCollector {
|
||||
|
||||
private val innerCollector = PrintingMessageCollector(compilerMessagesStream, MessageRenderer.WITHOUT_PATHS, false)
|
||||
|
||||
internal var firstErrorMessage: String? = null
|
||||
internal var firstErrorLocation: CompilerMessageLocation? = null
|
||||
|
||||
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) {
|
||||
if (firstErrorMessage == null && severity.isError) {
|
||||
firstErrorMessage = message
|
||||
firstErrorLocation = location
|
||||
}
|
||||
innerCollector.report(severity, message, location)
|
||||
}
|
||||
|
||||
override fun hasErrors(): Boolean = innerCollector.hasErrors()
|
||||
override fun clear() {
|
||||
innerCollector.clear()
|
||||
}
|
||||
}
|
||||
protected val messageCollector = KeepFirstErrorMessageCollector(compilerMessagesStream)
|
||||
|
||||
protected val configuration = CompilerConfiguration().apply {
|
||||
addJvmClasspathRoots(PathUtil.getJdkClassesRoots())
|
||||
addJvmClasspathRoots(PathUtil.getKotlinPathsForCompiler().let { listOf(it.runtimePath, it.reflectPath, it.scriptRuntimePath) })
|
||||
addJvmClasspathRoots(templateClasspath)
|
||||
put(CommonConfigurationKeys.MODULE_NAME, "kotlin-script")
|
||||
put(CommonConfigurationKeys.SKIP_METADATA_VERSION_CHECK, true)
|
||||
}
|
||||
|
||||
protected fun makeScriptDefinition(templateClasspath: List<File>, templateClassName: String): KotlinScriptDefinition? {
|
||||
@@ -89,92 +107,49 @@ open class KotlinJvmReplService(
|
||||
else GenericReplCompiler(disposable, scriptDef, configuration, messageCollector)
|
||||
}
|
||||
|
||||
protected val statesLock = ReentrantReadWriteLock()
|
||||
// TODO: consider using values here for session cleanup
|
||||
protected val states = WeakHashMap<RemoteReplStateFacadeServer, Boolean>() // used as (missing) WeakHashSet
|
||||
protected val stateIdCounter = AtomicInteger()
|
||||
@Deprecated("remove after removal state-less check/compile/eval methods")
|
||||
protected val defaultStateFacade: RemoteReplStateFacadeServer by lazy { createRemoteState() }
|
||||
private val replEvaluator: ReplFullEvaluator? by lazy {
|
||||
replCompiler?.let { compiler ->
|
||||
GenericReplCompilingEvaluator(compiler, configuration.jvmClasspathRoots, null, fallbackScriptArgs, ReplRepeatingMode.NONE)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> =
|
||||
replCompiler?.createState(lock) ?: throw IllegalStateException("repl compiler is not initialized properly")
|
||||
override val lastEvaluatedScripts: List<EvalHistoryType> get() = replEvaluator?.lastEvaluatedScripts ?: emptyList()
|
||||
|
||||
override fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult {
|
||||
override fun check(codeLine: ReplCodeLine): ReplCheckResult {
|
||||
operationsTracer?.before("check")
|
||||
try {
|
||||
return replCompiler?.check(state, codeLine)
|
||||
?: ReplCheckResult.Error("Initialization error", CompilerMessageLocation.NO_LOCATION)
|
||||
return replCompiler?.check(codeLine)
|
||||
?: ReplCheckResult.Error(messageCollector.firstErrorMessage ?: "Unknown error",
|
||||
messageCollector.firstErrorLocation ?: CompilerMessageLocation.NO_LOCATION)
|
||||
}
|
||||
finally {
|
||||
operationsTracer?.after("check")
|
||||
}
|
||||
}
|
||||
|
||||
override fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult {
|
||||
override fun compile(codeLine: ReplCodeLine, verifyHistory: List<ReplCodeLine>?): ReplCompileResult {
|
||||
operationsTracer?.before("compile")
|
||||
try {
|
||||
return replCompiler?.compile(state, codeLine)
|
||||
?: ReplCompileResult.Error("Initialization error", CompilerMessageLocation.NO_LOCATION)
|
||||
return replCompiler?.compile(codeLine, verifyHistory)
|
||||
?: ReplCompileResult.Error(verifyHistory ?: emptyList(),
|
||||
messageCollector.firstErrorMessage ?: "Unknown error",
|
||||
messageCollector.firstErrorLocation ?: CompilerMessageLocation.NO_LOCATION)
|
||||
}
|
||||
finally {
|
||||
operationsTracer?.after("compile")
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Use check(state, line) instead")
|
||||
fun check(codeLine: ReplCodeLine): ReplCheckResult = check(defaultStateFacade.state, codeLine)
|
||||
|
||||
@Deprecated("Use compile(state, line) instead")
|
||||
fun compile(codeLine: ReplCodeLine, verifyHistory: List<ReplCodeLine>?): ReplCompileResult = compile(defaultStateFacade.state, codeLine)
|
||||
|
||||
fun createRemoteState(port: Int = portForServers): RemoteReplStateFacadeServer = statesLock.write {
|
||||
val id = getValidId(stateIdCounter) { id -> states.none { it.key.getId() == id} }
|
||||
val stateFacade = RemoteReplStateFacadeServer(id, createState().asState(GenericReplCompilerState::class.java), port)
|
||||
states.put(stateFacade, true)
|
||||
stateFacade
|
||||
}
|
||||
|
||||
fun<R> withValidReplState(stateId: Int, body: (IReplStageState<*>) -> R): CompileService.CallResult<R> = statesLock.read {
|
||||
states.keys.firstOrNull { it.getId() == stateId }?.let {
|
||||
CompileService.CallResult.Good(body(it.state))
|
||||
override fun compileAndEval(codeLine: ReplCodeLine, scriptArgs: ScriptArgsWithTypes?, verifyHistory: List<ReplCodeLine>?, invokeWrapper: InvokeWrapper?): ReplEvalResult {
|
||||
operationsTracer?.before("eval")
|
||||
try {
|
||||
return replEvaluator?.compileAndEval(codeLine, scriptArgs ?: fallbackScriptArgs, verifyHistory, invokeWrapper)
|
||||
?: ReplEvalResult.Error.CompileTime(verifyHistory ?: replEvaluator?.history ?: emptyList(),
|
||||
messageCollector.firstErrorMessage ?: "Unknown error",
|
||||
messageCollector.firstErrorLocation ?: CompilerMessageLocation.NO_LOCATION)
|
||||
}
|
||||
?: CompileService.CallResult.Error("No REPL state with id $stateId found")
|
||||
}
|
||||
}
|
||||
|
||||
internal class KeepFirstErrorMessageCollector(compilerMessagesStream: PrintStream) : MessageCollector {
|
||||
|
||||
private val innerCollector = PrintingMessageCollector(compilerMessagesStream, MessageRenderer.WITHOUT_PATHS, false)
|
||||
|
||||
internal var firstErrorMessage: String? = null
|
||||
internal var firstErrorLocation: CompilerMessageLocation? = null
|
||||
|
||||
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) {
|
||||
if (firstErrorMessage == null && severity.isError) {
|
||||
firstErrorMessage = message
|
||||
firstErrorLocation = location
|
||||
finally {
|
||||
operationsTracer?.after("eval")
|
||||
}
|
||||
innerCollector.report(severity, message, location)
|
||||
}
|
||||
|
||||
override fun hasErrors(): Boolean = innerCollector.hasErrors()
|
||||
override fun clear() {
|
||||
innerCollector.clear()
|
||||
}
|
||||
}
|
||||
|
||||
internal val internalRng = Random()
|
||||
|
||||
inline internal fun getValidId(counter: AtomicInteger, check: (Int) -> Boolean): Int {
|
||||
// fighting hypothetical integer wrapping
|
||||
var newId = counter.incrementAndGet()
|
||||
var attemptsLeft = 100
|
||||
while (!check(newId)) {
|
||||
attemptsLeft -= 1
|
||||
if (attemptsLeft <= 0)
|
||||
throw IllegalStateException("Invalid state or algorithm error")
|
||||
// assuming wrap, jumping to random number to reduce probability of further clashes
|
||||
newId = counter.addAndGet(internalRng.nextInt())
|
||||
}
|
||||
return newId
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.daemon
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.repl.ILineId
|
||||
import org.jetbrains.kotlin.cli.jvm.repl.GenericReplCompilerState
|
||||
import org.jetbrains.kotlin.daemon.common.LoopbackNetworkInterface
|
||||
import org.jetbrains.kotlin.daemon.common.ReplStateFacade
|
||||
import org.jetbrains.kotlin.daemon.common.SOCKET_ANY_FREE_PORT
|
||||
import java.rmi.server.UnicastRemoteObject
|
||||
|
||||
class RemoteReplStateFacadeServer(val _id: Int,
|
||||
val state: GenericReplCompilerState,
|
||||
port: Int = SOCKET_ANY_FREE_PORT
|
||||
) : ReplStateFacade,
|
||||
UnicastRemoteObject(port, LoopbackNetworkInterface.clientLoopbackSocketFactory, LoopbackNetworkInterface.serverLoopbackSocketFactory)
|
||||
{
|
||||
override fun getId(): Int = _id
|
||||
|
||||
override fun getHistorySize(): Int = state.history.size
|
||||
|
||||
override fun historyGet(index: Int): ILineId = state.history[index].id
|
||||
|
||||
override fun historyResetTo(id: ILineId): List<ILineId> = state.history.resetTo(id).toList()
|
||||
}
|
||||
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.context.LazyResolveToken
|
||||
import org.jetbrains.kotlin.context.ModuleContext
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackagePartProvider
|
||||
import org.jetbrains.kotlin.frontend.di.configureCommon
|
||||
import org.jetbrains.kotlin.frontend.di.configureModule
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.load.java.InternalFlexibleTypeTransformer
|
||||
@@ -47,10 +46,11 @@ import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer
|
||||
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
|
||||
|
||||
private fun StorageComponentContainer.configureJavaTopDownAnalysis(
|
||||
fun StorageComponentContainer.configureJavaTopDownAnalysis(
|
||||
moduleContentScope: GlobalSearchScope,
|
||||
project: Project,
|
||||
lookupTracker: LookupTracker
|
||||
lookupTracker: LookupTracker,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
useInstance(moduleContentScope)
|
||||
useInstance(lookupTracker)
|
||||
@@ -75,6 +75,7 @@ private fun StorageComponentContainer.configureJavaTopDownAnalysis(
|
||||
useImpl<JavaSourceElementFactoryImpl>()
|
||||
useInstance(InternalFlexibleTypeTransformer)
|
||||
|
||||
useInstance(languageVersionSettings)
|
||||
useImpl<CompilerDeserializationConfiguration>()
|
||||
}
|
||||
|
||||
@@ -87,19 +88,19 @@ fun createContainerForLazyResolveWithJava(
|
||||
targetEnvironment: TargetEnvironment,
|
||||
lookupTracker: LookupTracker,
|
||||
packagePartProvider: PackagePartProvider,
|
||||
compilerConfiguration: CompilerConfiguration,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
useBuiltInsProvider: Boolean,
|
||||
useLazyResolve: Boolean
|
||||
useLazyResolve: Boolean,
|
||||
compilerConfiguration: CompilerConfiguration
|
||||
): StorageComponentContainer = createContainer("LazyResolveWithJava", JvmPlatform) {
|
||||
configureModule(moduleContext, JvmPlatform, bindingTrace)
|
||||
configureJavaTopDownAnalysis(moduleContentScope, moduleContext.project, lookupTracker)
|
||||
configureJavaTopDownAnalysis(moduleContentScope, moduleContext.project, lookupTracker, languageVersionSettings)
|
||||
|
||||
useInstance(compilerConfiguration)
|
||||
useInstance(packagePartProvider)
|
||||
useInstance(moduleClassResolver)
|
||||
useInstance(declarationProviderFactory)
|
||||
|
||||
configureCommon(compilerConfiguration)
|
||||
|
||||
if (useBuiltInsProvider) {
|
||||
useInstance((moduleContext.module.builtIns as JvmBuiltIns).settings)
|
||||
useImpl<JvmBuiltInsPackageFragmentProvider>()
|
||||
@@ -122,17 +123,18 @@ fun createContainerForTopDownAnalyzerForJvm(
|
||||
moduleContentScope: GlobalSearchScope,
|
||||
lookupTracker: LookupTracker,
|
||||
packagePartProvider: PackagePartProvider,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
moduleClassResolver: ModuleClassResolver,
|
||||
compilerConfiguration: CompilerConfiguration
|
||||
): ComponentProvider = createContainerForLazyResolveWithJava(
|
||||
moduleContext, bindingTrace, declarationProviderFactory, moduleContentScope, moduleClassResolver,
|
||||
CompilerEnvironment, lookupTracker, packagePartProvider, compilerConfiguration,
|
||||
useBuiltInsProvider = true, useLazyResolve = false
|
||||
CompilerEnvironment, lookupTracker, packagePartProvider, languageVersionSettings,
|
||||
useBuiltInsProvider = true, useLazyResolve = false, compilerConfiguration = compilerConfiguration
|
||||
)
|
||||
|
||||
|
||||
fun ComponentProvider.initJvmBuiltInsForTopDownAnalysis() {
|
||||
get<JvmBuiltIns>().initialize(get<ModuleDescriptor>(), get<LanguageVersionSettings>())
|
||||
fun ComponentProvider.initJvmBuiltInsForTopDownAnalysis(module: ModuleDescriptor, languageVersionSettings: LanguageVersionSettings) {
|
||||
get<JvmBuiltIns>().initialize(module, languageVersionSettings)
|
||||
}
|
||||
|
||||
internal fun JvmBuiltIns.initialize(module: ModuleDescriptor, languageVersionSettings: LanguageVersionSettings) {
|
||||
|
||||
@@ -143,9 +143,8 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadClassAnnotations(@NotNull final AnnotationVisitor annotationVisitor, @Nullable byte[] cachedContents) {
|
||||
byte[] fileContents = cachedContents != null ? cachedContents : getFileContents();
|
||||
new ClassReader(fileContents).accept(new ClassVisitor(ASM5) {
|
||||
public void loadClassAnnotations(@NotNull final AnnotationVisitor annotationVisitor) {
|
||||
new ClassReader(getFileContents()).accept(new ClassVisitor(ASM5) {
|
||||
@Override
|
||||
public org.jetbrains.org.objectweb.asm.AnnotationVisitor visitAnnotation(@NotNull String desc, boolean visible) {
|
||||
return convertAnnotationVisitor(annotationVisitor, desc, innerClasses);
|
||||
@@ -216,9 +215,8 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMembers(@NotNull final MemberVisitor memberVisitor, @Nullable byte[] cachedContents) {
|
||||
byte[] fileContents = cachedContents != null ? cachedContents : getFileContents();
|
||||
new ClassReader(fileContents).accept(new ClassVisitor(ASM5) {
|
||||
public void visitMembers(@NotNull final MemberVisitor memberVisitor) {
|
||||
new ClassReader(getFileContents()).accept(new ClassVisitor(ASM5) {
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, @NotNull String name, @NotNull String desc, String signature, Object value) {
|
||||
final AnnotationVisitor v = memberVisitor.visitField(Name.identifier(name), desc, value);
|
||||
|
||||
@@ -19,19 +19,18 @@ package org.jetbrains.kotlin.load.kotlin.incremental
|
||||
import org.jetbrains.kotlin.descriptors.PackagePartProvider
|
||||
import org.jetbrains.kotlin.load.kotlin.ModuleMapping
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
||||
import org.jetbrains.kotlin.modules.TargetId
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
internal class IncrementalPackagePartProvider(
|
||||
internal class IncrementalPackagePartProvider private constructor(
|
||||
private val parent: PackagePartProvider,
|
||||
incrementalCaches: List<IncrementalCache>,
|
||||
storageManager: StorageManager
|
||||
) : PackagePartProvider {
|
||||
lateinit var deserializationConfiguration: DeserializationConfiguration
|
||||
|
||||
private val moduleMappings = storageManager.createLazyValue {
|
||||
incrementalCaches.map { cache ->
|
||||
ModuleMapping.create(cache.getModuleMappingData(), "<incremental>", deserializationConfiguration)
|
||||
ModuleMapping.create(cache.getModuleMappingData(), "<incremental>")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,4 +41,19 @@ internal class IncrementalPackagePartProvider(
|
||||
|
||||
// TODO
|
||||
override fun findMetadataPackageParts(packageFqName: String): List<String> = TODO()
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun create(
|
||||
parent: PackagePartProvider,
|
||||
targets: List<TargetId>?,
|
||||
incrementalCompilationComponents: IncrementalCompilationComponents?,
|
||||
storageManager: StorageManager
|
||||
): PackagePartProvider {
|
||||
if (targets == null || incrementalCompilationComponents == null) return parent
|
||||
|
||||
val incrementalCaches = targets.map { incrementalCompilationComponents.getIncrementalCache(it) }
|
||||
return IncrementalPackagePartProvider(parent, incrementalCaches, storageManager)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.analyzer.*
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.container.get
|
||||
import org.jetbrains.kotlin.context.ModuleContext
|
||||
import org.jetbrains.kotlin.descriptors.PackagePartProvider
|
||||
@@ -82,20 +81,15 @@ object JvmAnalyzerFacade : AnalyzerFacade<JvmPlatformParameters>() {
|
||||
resolverForModule.componentProvider.get<JavaDescriptorResolver>()
|
||||
}
|
||||
|
||||
val configuration = CompilerConfiguration().apply {
|
||||
val languageSettingsProvider = LanguageSettingsProvider.getInstance(project)
|
||||
languageVersionSettings = languageSettingsProvider.getLanguageVersionSettings(moduleInfo, project)
|
||||
|
||||
val platform = languageSettingsProvider.getTargetPlatform(moduleInfo)
|
||||
if (platform is JvmTarget) {
|
||||
put(JVMConfigurationKeys.JVM_TARGET, platform)
|
||||
}
|
||||
|
||||
isReadOnly = true
|
||||
}
|
||||
|
||||
val languageSettingsProvider = LanguageSettingsProvider.getInstance(project)
|
||||
val trace = CodeAnalyzerInitializer.getInstance(project).createTrace()
|
||||
|
||||
//TODO: need to propagate full CompilerConfiguration to frontend
|
||||
val compilerConfiguration = CompilerConfiguration()
|
||||
val platform = languageSettingsProvider.getTargetPlatform(moduleInfo)
|
||||
if (platform is JvmTarget) {
|
||||
compilerConfiguration.put(JVMConfigurationKeys.JVM_TARGET, platform)
|
||||
}
|
||||
compilerConfiguration.isReadOnly = true
|
||||
val container = createContainerForLazyResolveWithJava(
|
||||
moduleContext,
|
||||
trace,
|
||||
@@ -105,9 +99,10 @@ object JvmAnalyzerFacade : AnalyzerFacade<JvmPlatformParameters>() {
|
||||
targetEnvironment,
|
||||
LookupTracker.DO_NOTHING,
|
||||
packagePartProvider,
|
||||
configuration,
|
||||
languageSettingsProvider.getLanguageVersionSettings(moduleInfo, project),
|
||||
useBuiltInsProvider = false, // TODO: load built-ins from module dependencies in IDE
|
||||
useLazyResolve = true
|
||||
useLazyResolve = true,
|
||||
compilerConfiguration = compilerConfiguration
|
||||
)
|
||||
|
||||
StorageComponentContainerContributor.getInstances(project).forEach { it.onContainerComposed(container, moduleInfo) }
|
||||
|
||||
@@ -24,9 +24,10 @@ import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.builtins.JvmBuiltInsPackageFragmentProvider
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||
import org.jetbrains.kotlin.container.ComponentProvider
|
||||
import org.jetbrains.kotlin.container.get
|
||||
import org.jetbrains.kotlin.context.ContextForNewModule
|
||||
@@ -62,7 +63,6 @@ import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtens
|
||||
import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import java.util.*
|
||||
|
||||
@@ -135,10 +135,13 @@ object TopDownAnalyzerFacadeForJVM {
|
||||
val sourceScope = if (separateModules) sourceModuleSearchScope else GlobalSearchScope.allScope(project)
|
||||
val moduleClassResolver = SourceOrBinaryModuleClassResolver(sourceScope)
|
||||
|
||||
val languageVersionSettings =
|
||||
configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, LanguageVersionSettingsImpl.DEFAULT)
|
||||
|
||||
val optionalBuiltInsModule =
|
||||
if (configuration.getBoolean(JVMConfigurationKeys.ADD_BUILT_INS_FROM_COMPILER_TO_DEPENDENCIES)) {
|
||||
if (createBuiltInsFromModule)
|
||||
JvmBuiltIns(storageManager).apply { initialize(module, configuration.languageVersionSettings) }.builtInsModule
|
||||
JvmBuiltIns(storageManager).apply { initialize(module, languageVersionSettings) }.builtInsModule
|
||||
else module.builtIns.builtInsModule
|
||||
}
|
||||
else null
|
||||
@@ -154,7 +157,7 @@ object TopDownAnalyzerFacadeForJVM {
|
||||
|
||||
val dependenciesContainer = createContainerForTopDownAnalyzerForJvm(
|
||||
dependenciesContext, trace, DeclarationProviderFactory.EMPTY, dependencyScope, lookupTracker,
|
||||
packagePartProvider(dependencyScope), moduleClassResolver, configuration
|
||||
packagePartProvider(dependencyScope), languageVersionSettings, moduleClassResolver, configuration
|
||||
)
|
||||
|
||||
StorageComponentContainerContributor.getInstances(project).forEach { it.onContainerComposed(dependenciesContainer, null) }
|
||||
@@ -170,22 +173,18 @@ object TopDownAnalyzerFacadeForJVM {
|
||||
}
|
||||
else null
|
||||
|
||||
val partProvider = packagePartProvider(sourceScope).let { fragment ->
|
||||
if (targetIds == null || incrementalComponents == null) fragment
|
||||
else IncrementalPackagePartProvider(fragment, targetIds.map(incrementalComponents::getIncrementalCache), storageManager)
|
||||
}
|
||||
|
||||
// Note that it's necessary to create container for sources _after_ creation of container for dependencies because
|
||||
// CliLightClassGenerationSupport#initialize is invoked when container is created, so only the last module descriptor is going
|
||||
// to be stored in CliLightClassGenerationSupport, and it better be the source one (otherwise light classes would not be found)
|
||||
// TODO: get rid of duplicate invocation of CodeAnalyzerInitializer#initialize, or refactor CliLightClassGenerationSupport
|
||||
val container = createContainerForTopDownAnalyzerForJvm(
|
||||
moduleContext, trace, declarationProviderFactory(storageManager, files), sourceScope, lookupTracker,
|
||||
partProvider, moduleClassResolver, configuration
|
||||
IncrementalPackagePartProvider.create(
|
||||
packagePartProvider(sourceScope), targetIds, incrementalComponents, storageManager
|
||||
),
|
||||
languageVersionSettings, moduleClassResolver, configuration
|
||||
).apply {
|
||||
initJvmBuiltInsForTopDownAnalysis()
|
||||
(partProvider as? IncrementalPackagePartProvider)?.deserializationConfiguration = get<DeserializationConfiguration>()
|
||||
|
||||
initJvmBuiltInsForTopDownAnalysis(module, languageVersionSettings)
|
||||
StorageComponentContainerContributor.getInstances(project).forEach { it.onContainerComposed(this, null) }
|
||||
}
|
||||
|
||||
@@ -254,7 +253,7 @@ object TopDownAnalyzerFacadeForJVM {
|
||||
fun createContextWithSealedModule(project: Project, configuration: CompilerConfiguration): MutableModuleContext =
|
||||
createModuleContext(project, configuration, false).apply {
|
||||
setDependencies(module, module.builtIns.builtInsModule)
|
||||
(module.builtIns as JvmBuiltIns).initialize(module, configuration.languageVersionSettings)
|
||||
(module.builtIns as JvmBuiltIns).initialize(module, configuration.get(LANGUAGE_VERSION_SETTINGS, LanguageVersionSettingsImpl.DEFAULT))
|
||||
}
|
||||
|
||||
private fun createModuleContext(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -49,7 +49,6 @@ object JvmPlatformConfigurator : PlatformConfigurator(
|
||||
|
||||
additionalCallCheckers = listOf(
|
||||
JavaAnnotationCallChecker(),
|
||||
InterfaceDefaultMethodCallChecker(),
|
||||
JavaClassOnCompanionChecker(),
|
||||
ProtectedInSuperClassCompanionCallChecker(),
|
||||
UnsupportedSyntheticCallableReferenceChecker(),
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScope
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.findCorrespondingSupertype
|
||||
import java.util.*
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
@@ -58,10 +59,8 @@ class SamAdapterFunctionsScope(
|
||||
override fun getSyntheticMemberFunctions(receiverTypes: Collection<KotlinType>, name: Name, location: LookupLocation): Collection<FunctionDescriptor> {
|
||||
var result: SmartList<FunctionDescriptor>? = null
|
||||
for (type in receiverTypes) {
|
||||
val substitutorForType by lazy { buildMemberScopeSubstitutorForType(type) }
|
||||
|
||||
for (function in type.memberScope.getContributedFunctions(name, location)) {
|
||||
val extension = extensionForFunction(function.original)?.substitute(substitutorForType)
|
||||
val extension = extensionForFunction(function.original)?.substituteForReceiverType(type)
|
||||
if (extension != null) {
|
||||
if (result == null) {
|
||||
result = SmartList()
|
||||
@@ -77,15 +76,24 @@ class SamAdapterFunctionsScope(
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildMemberScopeSubstitutorForType(type: KotlinType) =
|
||||
TypeConstructorSubstitution.create(type).wrapWithCapturingSubstitution(needApproximation = true).buildSubstitutor()
|
||||
private fun FunctionDescriptor.substituteForReceiverType(receiverType: KotlinType): FunctionDescriptor? {
|
||||
val containingClass = containingDeclaration as? ClassDescriptor ?: return null
|
||||
val correspondingSupertype = findCorrespondingSupertype(receiverType, containingClass.defaultType) ?: return null
|
||||
|
||||
return substitute(
|
||||
TypeConstructorSubstitution
|
||||
.create(correspondingSupertype)
|
||||
.wrapWithCapturingSubstitution(needApproximation = true)
|
||||
.buildSubstitutor()
|
||||
)
|
||||
}
|
||||
|
||||
override fun getSyntheticMemberFunctions(receiverTypes: Collection<KotlinType>): Collection<FunctionDescriptor> {
|
||||
return receiverTypes.flatMapTo(LinkedHashSet<FunctionDescriptor>()) { type ->
|
||||
type.memberScope.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS)
|
||||
.filterIsInstance<FunctionDescriptor>()
|
||||
.mapNotNull {
|
||||
extensionForFunction(it.original)?.substitute(buildMemberScopeSubstitutorForType(type))
|
||||
extensionForFunction(it.original)?.substituteForReceiverType(type)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,10 +167,13 @@ class SamAdapterFunctionsScope(
|
||||
}
|
||||
}
|
||||
|
||||
override fun newCopyBuilder(substitutor: TypeSubstitutor): CopyConfiguration =
|
||||
super.newCopyBuilder(substitutor).setOriginal(this.original)
|
||||
|
||||
override fun doSubstitute(configuration: CopyConfiguration): FunctionDescriptor? {
|
||||
val descriptor = super.doSubstitute(configuration) as MyFunctionDescriptor? ?: return null
|
||||
val original = configuration.original
|
||||
?: throw UnsupportedOperationException("doSubstitute with no original should not be called for synthetic extension")
|
||||
?: throw UnsupportedOperationException("doSubstitute with no original should not be called for synthetic extension $this")
|
||||
|
||||
original as MyFunctionDescriptor
|
||||
assert(original.original == original) { "original in doSubstitute should have no other original" }
|
||||
|
||||
@@ -19,7 +19,10 @@ package org.jetbrains.kotlin.analyzer.common
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.analyzer.*
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||
import org.jetbrains.kotlin.container.StorageComponentContainer
|
||||
import org.jetbrains.kotlin.container.get
|
||||
import org.jetbrains.kotlin.container.useImpl
|
||||
@@ -31,7 +34,6 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackagePartProvider
|
||||
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.frontend.di.configureCommon
|
||||
import org.jetbrains.kotlin.frontend.di.configureModule
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.load.kotlin.MetadataFinderFactory
|
||||
@@ -49,11 +51,9 @@ import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragmen
|
||||
* See [TargetPlatform.Default]
|
||||
*/
|
||||
object DefaultAnalyzerFacade : AnalyzerFacade<PlatformAnalysisParameters>() {
|
||||
private val compilerConfiguration = CompilerConfiguration().apply {
|
||||
languageVersionSettings = LanguageVersionSettingsImpl(
|
||||
LanguageVersion.LATEST, ApiVersion.LATEST, setOf(LanguageFeature.MultiPlatformProjects)
|
||||
)
|
||||
}
|
||||
private val languageVersionSettings = LanguageVersionSettingsImpl(
|
||||
LanguageVersion.LATEST, ApiVersion.LATEST, setOf(LanguageFeature.MultiPlatformProjects)
|
||||
)
|
||||
|
||||
private class SourceModuleInfo(
|
||||
override val name: Name,
|
||||
@@ -135,7 +135,7 @@ object DefaultAnalyzerFacade : AnalyzerFacade<PlatformAnalysisParameters>() {
|
||||
useImpl<ResolveSession>()
|
||||
useImpl<LazyTopDownAnalyzer>()
|
||||
useImpl<FileScopeProviderImpl>()
|
||||
configureCommon(compilerConfiguration)
|
||||
useInstance(languageVersionSettings)
|
||||
useImpl<CompilerDeserializationConfiguration>()
|
||||
useInstance(packagePartProvider)
|
||||
useInstance(declarationProviderFactory)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.config;
|
||||
|
||||
public class CommonConfigurationKeys {
|
||||
private CommonConfigurationKeys() {
|
||||
}
|
||||
|
||||
public static final CompilerConfigurationKey<LanguageVersionSettings> LANGUAGE_VERSION_SETTINGS =
|
||||
CompilerConfigurationKey.create("language version settings");
|
||||
|
||||
public static final CompilerConfigurationKey<Boolean> DISABLE_INLINE =
|
||||
CompilerConfigurationKey.create("disable inline");
|
||||
|
||||
public static final CompilerConfigurationKey<String> MODULE_NAME =
|
||||
CompilerConfigurationKey.create("module name");
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.config
|
||||
|
||||
object CommonConfigurationKeys {
|
||||
@JvmField
|
||||
val LANGUAGE_VERSION_SETTINGS = CompilerConfigurationKey<LanguageVersionSettings>("language version settings")
|
||||
|
||||
@JvmField
|
||||
val SKIP_METADATA_VERSION_CHECK = CompilerConfigurationKey<Boolean>("skip metadata version check")
|
||||
|
||||
@JvmField
|
||||
val DISABLE_INLINE = CompilerConfigurationKey<Boolean>("disable inline")
|
||||
|
||||
@JvmField
|
||||
val MODULE_NAME = CompilerConfigurationKey<String>("module name")
|
||||
}
|
||||
|
||||
var CompilerConfiguration.languageVersionSettings: LanguageVersionSettings
|
||||
get() = get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, LanguageVersionSettingsImpl.DEFAULT)
|
||||
set(value) = put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, value)
|
||||
@@ -23,11 +23,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class CompilerConfigurationKey<T> {
|
||||
Key<T> ideaKey;
|
||||
|
||||
public CompilerConfigurationKey(@NotNull @NonNls String name) {
|
||||
private CompilerConfigurationKey(@NotNull @NonNls String name) {
|
||||
ideaKey = Key.create(name);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T> CompilerConfigurationKey<T> create(@NotNull @NonNls String name) {
|
||||
return new CompilerConfigurationKey<T>(name);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -790,8 +790,6 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtConstantExpression> WRONG_LONG_SUFFIX = DiagnosticFactory0.create(ERROR, LONG_LITERAL_SUFFIX);
|
||||
DiagnosticFactory0<KtConstantExpression> INT_LITERAL_OUT_OF_RANGE = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtConstantExpression> FLOAT_LITERAL_OUT_OF_RANGE = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtConstantExpression> FLOAT_LITERAL_CONFORMS_INFINITY = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<KtConstantExpression> FLOAT_LITERAL_CONFORMS_ZERO = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory2<KtConstantExpression, String, KotlinType> CONSTANT_EXPECTED_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR);
|
||||
DiagnosticFactory0<KtConstantExpression> INCORRECT_CHARACTER_LITERAL = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtConstantExpression> EMPTY_CHARACTER_LITERAL = DiagnosticFactory0.create(ERROR);
|
||||
@@ -892,7 +890,6 @@ public interface Errors {
|
||||
|
||||
DiagnosticFactory1<PsiElement, ClassDescriptor> INACCESSIBLE_OUTER_CLASS_EXPRESSION = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory0<KtClass> NESTED_CLASS_NOT_ALLOWED = DiagnosticFactory0.create(ERROR, DECLARATION_NAME);
|
||||
DiagnosticFactory0<KtObjectDeclaration> NESTED_OBJECT_NOT_ALLOWED = DiagnosticFactory0.create(ERROR, DECLARATION_NAME);
|
||||
|
||||
//Inline and inlinable parameters
|
||||
DiagnosticFactory2<KtElement, DeclarationDescriptor, DeclarationDescriptor> NON_PUBLIC_CALL_FROM_PUBLIC_INLINE = DiagnosticFactory2.create(ERROR, CALL_ELEMENT);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -437,7 +437,6 @@ public class DefaultErrorMessages {
|
||||
|
||||
MAP.put(INACCESSIBLE_OUTER_CLASS_EXPRESSION, "Expression is inaccessible from a nested class ''{0}'', use ''inner'' keyword to make the class inner", NAME);
|
||||
MAP.put(NESTED_CLASS_NOT_ALLOWED, "Nested class is not allowed here, use 'inner' keyword to make the class inner");
|
||||
MAP.put(NESTED_OBJECT_NOT_ALLOWED, "Objects inside inner classes are prohibited");
|
||||
|
||||
MAP.put(HAS_NEXT_MISSING, "hasNext() cannot be called on iterator() of type ''{0}''", RENDER_TYPE);
|
||||
MAP.put(HAS_NEXT_FUNCTION_AMBIGUITY, "hasNext() is ambiguous for iterator() of type ''{0}''", RENDER_TYPE);
|
||||
@@ -535,8 +534,6 @@ public class DefaultErrorMessages {
|
||||
MAP.put(INT_LITERAL_OUT_OF_RANGE, "The value is out of range");
|
||||
MAP.put(WRONG_LONG_SUFFIX, "Use 'L' instead of 'l'");
|
||||
MAP.put(FLOAT_LITERAL_OUT_OF_RANGE, "The value is out of range");
|
||||
MAP.put(FLOAT_LITERAL_CONFORMS_INFINITY, "Floating point number conforms to infinity");
|
||||
MAP.put(FLOAT_LITERAL_CONFORMS_ZERO, "Floating point number conforms to zero");
|
||||
MAP.put(INCORRECT_CHARACTER_LITERAL, "Incorrect character literal");
|
||||
MAP.put(EMPTY_CHARACTER_LITERAL, "Empty character literal");
|
||||
MAP.put(ILLEGAL_UNDERSCORE, "Illegal underscore");
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package org.jetbrains.kotlin.frontend.di
|
||||
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.container.StorageComponentContainer
|
||||
import org.jetbrains.kotlin.container.get
|
||||
import org.jetbrains.kotlin.container.useImpl
|
||||
@@ -26,11 +26,9 @@ import org.jetbrains.kotlin.context.LazyResolveToken
|
||||
import org.jetbrains.kotlin.context.ModuleContext
|
||||
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.lazy.*
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.types.expressions.DeclarationScopeProviderForLocalClassifierAnalyzer
|
||||
import org.jetbrains.kotlin.types.expressions.LocalClassDescriptorHolder
|
||||
import org.jetbrains.kotlin.types.expressions.LocalLazyDeclarationResolver
|
||||
@@ -66,17 +64,12 @@ fun StorageComponentContainer.configureModule(
|
||||
useInstance(trace)
|
||||
}
|
||||
|
||||
fun StorageComponentContainer.configureCommon(configuration: CompilerConfiguration) {
|
||||
useInstance(configuration)
|
||||
useInstance(configuration.languageVersionSettings)
|
||||
}
|
||||
|
||||
fun createContainerForBodyResolve(
|
||||
moduleContext: ModuleContext,
|
||||
bindingTrace: BindingTrace,
|
||||
platform: TargetPlatform,
|
||||
statementFilter: StatementFilter,
|
||||
compilerConfiguration: CompilerConfiguration
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): StorageComponentContainer = createContainer("BodyResolve", platform) {
|
||||
configureModule(moduleContext, platform, bindingTrace)
|
||||
|
||||
@@ -84,7 +77,7 @@ fun createContainerForBodyResolve(
|
||||
|
||||
useInstance(LookupTracker.DO_NOTHING)
|
||||
useInstance(BodyResolveCache.ThrowException)
|
||||
configureCommon(compilerConfiguration)
|
||||
useInstance(languageVersionSettings)
|
||||
|
||||
useImpl<BodyResolver>()
|
||||
}
|
||||
@@ -95,7 +88,7 @@ fun createContainerForLazyBodyResolve(
|
||||
bindingTrace: BindingTrace,
|
||||
platform: TargetPlatform,
|
||||
bodyResolveCache: BodyResolveCache,
|
||||
compilerConfiguration: CompilerConfiguration
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): StorageComponentContainer = createContainer("LazyBodyResolve", platform) {
|
||||
configureModule(moduleContext, platform, bindingTrace)
|
||||
|
||||
@@ -103,7 +96,7 @@ fun createContainerForLazyBodyResolve(
|
||||
useInstance(kotlinCodeAnalyzer)
|
||||
useInstance(kotlinCodeAnalyzer.fileScopeProvider)
|
||||
useInstance(bodyResolveCache)
|
||||
configureCommon(compilerConfiguration)
|
||||
useInstance(languageVersionSettings)
|
||||
useImpl<LazyTopDownAnalyzer>()
|
||||
useImpl<BasicAbsentDescriptorHandler>()
|
||||
}
|
||||
@@ -113,7 +106,7 @@ fun createContainerForLazyLocalClassifierAnalyzer(
|
||||
bindingTrace: BindingTrace,
|
||||
platform: TargetPlatform,
|
||||
lookupTracker: LookupTracker,
|
||||
compilerConfiguration: CompilerConfiguration,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
statementFilter: StatementFilter,
|
||||
localClassDescriptorHolder: LocalClassDescriptorHolder
|
||||
): StorageComponentContainer = createContainer("LocalClassifierAnalyzer", platform) {
|
||||
@@ -133,7 +126,7 @@ fun createContainerForLazyLocalClassifierAnalyzer(
|
||||
useImpl<DeclarationScopeProviderForLocalClassifierAnalyzer>()
|
||||
useImpl<LocalLazyDeclarationResolver>()
|
||||
|
||||
configureCommon(compilerConfiguration)
|
||||
useInstance(languageVersionSettings)
|
||||
useInstance(statementFilter)
|
||||
}
|
||||
|
||||
@@ -143,14 +136,15 @@ fun createContainerForLazyResolve(
|
||||
bindingTrace: BindingTrace,
|
||||
platform: TargetPlatform,
|
||||
targetEnvironment: TargetEnvironment,
|
||||
compilerConfiguration: CompilerConfiguration
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): StorageComponentContainer = createContainer("LazyResolve", platform) {
|
||||
configureModule(moduleContext, platform, bindingTrace)
|
||||
|
||||
useInstance(declarationProviderFactory)
|
||||
useInstance(LookupTracker.DO_NOTHING)
|
||||
|
||||
configureCommon(compilerConfiguration)
|
||||
useInstance(languageVersionSettings)
|
||||
//TODO: need to propagate full CompilerConfiguration to frontend
|
||||
useInstance(CompilerConfiguration.EMPTY)
|
||||
|
||||
useImpl<FileScopeProviderImpl>()
|
||||
useImpl<CompilerDeserializationConfiguration>()
|
||||
@@ -160,12 +154,14 @@ fun createContainerForLazyResolve(
|
||||
useImpl<ResolveSession>()
|
||||
}
|
||||
|
||||
fun createLazyResolveSession(moduleContext: ModuleContext, files: Collection<KtFile>): ResolveSession =
|
||||
createContainerForLazyResolve(
|
||||
moduleContext,
|
||||
FileBasedDeclarationProviderFactory(moduleContext.storageManager, files),
|
||||
BindingTraceContext(),
|
||||
TargetPlatform.Default,
|
||||
CompilerEnvironment,
|
||||
CompilerConfiguration.EMPTY
|
||||
).get<ResolveSession>()
|
||||
@JvmOverloads
|
||||
fun createLazyResolveSession(
|
||||
moduleContext: ModuleContext,
|
||||
declarationProviderFactory: DeclarationProviderFactory,
|
||||
bindingTrace: BindingTrace,
|
||||
platform: TargetPlatform,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
targetEnvironment: TargetEnvironment = CompilerEnvironment
|
||||
): ResolveSession = createContainerForLazyResolve(
|
||||
moduleContext, declarationProviderFactory, bindingTrace, platform, targetEnvironment, languageVersionSettings
|
||||
).get<ResolveSession>()
|
||||
|
||||
@@ -311,12 +311,6 @@ private fun findFirstLeafWhollyInRange(file: PsiFile, range: TextRange): PsiElem
|
||||
return if (elementRange.endOffset <= range.endOffset) element else null
|
||||
}
|
||||
|
||||
val PsiElement.textRangeWithoutComments: TextRange
|
||||
get() {
|
||||
val firstNonCommentChild = children.firstOrNull { it !is PsiWhiteSpace && it !is PsiComment } ?: return textRange
|
||||
return TextRange(firstNonCommentChild.startOffset, endOffset)
|
||||
}
|
||||
|
||||
// ---------------------------------- Debug/logging ----------------------------------------------------------------------------------------
|
||||
|
||||
fun PsiElement.getElementTextWithContext(): String {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
* Copyright 2010-2015 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.
|
||||
@@ -56,8 +56,7 @@ public class CompileTimeConstantUtils {
|
||||
"kotlin.charArrayOf",
|
||||
"kotlin.shortArrayOf",
|
||||
"kotlin.byteArrayOf",
|
||||
"kotlin.booleanArrayOf",
|
||||
"kotlin.emptyArray"
|
||||
"kotlin.booleanArrayOf"
|
||||
);
|
||||
|
||||
public static void checkConstructorParametersType(@NotNull List<KtParameter> parameters, @NotNull BindingTrace trace) {
|
||||
@@ -111,7 +110,7 @@ public class CompileTimeConstantUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isArrayFunctionCall(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
public static boolean isArrayMethodCall(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
return ARRAY_CALL_NAMES.contains(DescriptorUtils.getFqName(resolvedCall.getCandidateDescriptor()).asString());
|
||||
}
|
||||
|
||||
|
||||
@@ -16,14 +16,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
|
||||
class CompilerDeserializationConfiguration(configuration: CompilerConfiguration) : DeserializationConfiguration {
|
||||
override val typeAliasesAllowed = configuration.languageVersionSettings.supportsFeature(LanguageFeature.TypeAliases)
|
||||
|
||||
override val skipMetadataVersionCheck = configuration.getBoolean(CommonConfigurationKeys.SKIP_METADATA_VERSION_CHECK)
|
||||
class CompilerDeserializationConfiguration(private val languageVersionSettings: LanguageVersionSettings) : DeserializationConfiguration {
|
||||
override val typeAliasesAllowed: Boolean
|
||||
get() = languageVersionSettings.supportsFeature(LanguageFeature.TypeAliases)
|
||||
}
|
||||
|
||||
@@ -334,15 +334,15 @@ public class DescriptorResolver {
|
||||
public List<VariableDescriptor> invoke() {
|
||||
assert owner.getDispatchReceiverParameter() == null
|
||||
: "Destructuring declarations are only be parsed for lambdas, and they must not have a dispatch receiver";
|
||||
LexicalScope scopeForDestructuring =
|
||||
ScopeUtilsKt.createScopeForDestructuring(scope, owner.getExtensionReceiverParameter());
|
||||
LexicalScope scopeWithReceiver =
|
||||
ScopeUtilsKt.addImplicitReceiver(scope, owner.getExtensionReceiverParameter());
|
||||
|
||||
List<VariableDescriptor> result =
|
||||
destructuringDeclarationResolver.resolveLocalVariablesFromDestructuringDeclaration(
|
||||
scope,
|
||||
destructuringDeclaration, new TransientReceiver(type), /* initializer = */ null,
|
||||
ExpressionTypingContext.newContext(
|
||||
trace, scopeForDestructuring, DataFlowInfoFactory.EMPTY, TypeUtils.NO_EXPECTED_TYPE
|
||||
trace, scopeWithReceiver, DataFlowInfoFactory.EMPTY, TypeUtils.NO_EXPECTED_TYPE
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.BaseImportingScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||
|
||||
class LazyExplicitImportScope(
|
||||
private val packageOrClassDescriptor: DeclarationDescriptor,
|
||||
private val packageFragmentForVisibilityCheck: PackageFragmentDescriptor?,
|
||||
private val declaredName: Name,
|
||||
private val aliasName: Name,
|
||||
private val storeReferences: (Collection<DeclarationDescriptor>) -> Unit
|
||||
): BaseImportingScope(null) {
|
||||
|
||||
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? {
|
||||
if (name != aliasName) return null
|
||||
|
||||
return when (packageOrClassDescriptor) {
|
||||
is PackageViewDescriptor -> packageOrClassDescriptor.memberScope.getContributedClassifier(declaredName, location)
|
||||
is ClassDescriptor -> packageOrClassDescriptor.unsubstitutedInnerClassesScope.getContributedClassifier(declaredName, location)
|
||||
else -> throw IllegalStateException("Should be class or package: $packageOrClassDescriptor")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<FunctionDescriptor> {
|
||||
if (name != aliasName) return emptyList()
|
||||
|
||||
return collectCallableMemberDescriptors(location, MemberScope::getContributedFunctions)
|
||||
}
|
||||
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<VariableDescriptor> {
|
||||
if (name != aliasName) return emptyList()
|
||||
|
||||
return collectCallableMemberDescriptors(location, MemberScope::getContributedVariables)
|
||||
}
|
||||
|
||||
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
|
||||
val descriptors = SmartList<DeclarationDescriptor>()
|
||||
descriptors.addIfNotNull(getContributedClassifier(aliasName, NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS))
|
||||
descriptors.addAll(getContributedFunctions(aliasName, NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS))
|
||||
descriptors.addAll(getContributedVariables(aliasName, NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS))
|
||||
|
||||
return descriptors
|
||||
}
|
||||
|
||||
override fun printStructure(p: Printer) {
|
||||
p.println(javaClass.simpleName, ": ", aliasName)
|
||||
}
|
||||
|
||||
// should be called only once
|
||||
internal fun storeReferencesToDescriptors() = getContributedDescriptors().apply(storeReferences)
|
||||
|
||||
private fun <D : CallableMemberDescriptor> collectCallableMemberDescriptors(
|
||||
location: LookupLocation,
|
||||
getDescriptors: MemberScope.(Name, LookupLocation) -> Collection<D>
|
||||
): Collection<D> {
|
||||
val descriptors = SmartList<D>()
|
||||
|
||||
when (packageOrClassDescriptor) {
|
||||
is PackageViewDescriptor -> {
|
||||
val packageScope = packageOrClassDescriptor.memberScope
|
||||
descriptors.addAll(packageScope.getDescriptors(declaredName, location))
|
||||
}
|
||||
|
||||
is ClassDescriptor -> {
|
||||
val staticClassScope = packageOrClassDescriptor.staticScope
|
||||
descriptors.addAll(staticClassScope.getDescriptors(declaredName, location))
|
||||
|
||||
if (packageOrClassDescriptor.kind == ClassKind.OBJECT) {
|
||||
descriptors.addAll(
|
||||
packageOrClassDescriptor.unsubstitutedMemberScope.getDescriptors(declaredName, location)
|
||||
.mapNotNull { it.asImportedFromObjectIfPossible() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
else -> throw IllegalStateException("Should be class or package: $packageOrClassDescriptor")
|
||||
}
|
||||
|
||||
return descriptors.choseOnlyVisibleOrAll()
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun <D : CallableMemberDescriptor> D.asImportedFromObjectIfPossible(): D? = when (this) {
|
||||
is PropertyDescriptor -> asImportedFromObject() as D
|
||||
is FunctionDescriptor -> asImportedFromObject() as D
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun <D : CallableMemberDescriptor> Collection<D>.choseOnlyVisibleOrAll() =
|
||||
filter { isVisible(it, packageFragmentForVisibilityCheck, position = QualifierPosition.IMPORT) }.
|
||||
check { it.isNotEmpty() } ?: this
|
||||
}
|
||||
@@ -36,7 +36,6 @@ import org.jetbrains.kotlin.resolve.checkers.UnderscoreChecker;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.diagnostics.Errors.NESTED_CLASS_NOT_ALLOWED;
|
||||
import static org.jetbrains.kotlin.diagnostics.Errors.NESTED_OBJECT_NOT_ALLOWED;
|
||||
import static org.jetbrains.kotlin.lexer.KtTokens.*;
|
||||
import static org.jetbrains.kotlin.psi.KtStubbedPsiUtil.getContainingDeclaration;
|
||||
|
||||
@@ -220,20 +219,10 @@ public class ModifiersChecker {
|
||||
|
||||
public void checkModifiersForDeclaration(@NotNull KtDeclaration modifierListOwner, @NotNull MemberDescriptor descriptor) {
|
||||
checkNestedClassAllowed(modifierListOwner, descriptor);
|
||||
checkObjectInsideInnerClass(modifierListOwner, descriptor);
|
||||
checkTypeParametersModifiers(modifierListOwner);
|
||||
checkModifierListCommon(modifierListOwner, descriptor);
|
||||
}
|
||||
|
||||
private void checkObjectInsideInnerClass(@NotNull KtDeclaration modifierListOwner, @NotNull MemberDescriptor descriptor) {
|
||||
if (modifierListOwner instanceof KtObjectDeclaration) {
|
||||
KtObjectDeclaration ktObject = (KtObjectDeclaration) modifierListOwner;
|
||||
if (!ktObject.isLocal() && isIllegalNestedClass(descriptor)) {
|
||||
trace.report(NESTED_OBJECT_NOT_ALLOWED.on(ktObject));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkModifierListCommon(@NotNull KtDeclaration modifierListOwner, @NotNull DeclarationDescriptor descriptor) {
|
||||
AnnotationUseSiteTargetChecker.INSTANCE.check(modifierListOwner, descriptor, trace);
|
||||
runDeclarationCheckers(modifierListOwner, descriptor);
|
||||
|
||||
@@ -54,22 +54,23 @@ object ModifierCheckerCore {
|
||||
COMPATIBLE_FOR_CLASSES_ONLY
|
||||
}
|
||||
|
||||
private val defaultVisibilityTargets = EnumSet.of(CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
|
||||
private val defaultVisibilityTargets = EnumSet.of(CLASS_ONLY, OBJECT, INTERFACE, INNER_CLASS, ENUM_CLASS, ANNOTATION_CLASS,
|
||||
MEMBER_FUNCTION, TOP_LEVEL_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER,
|
||||
MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, CONSTRUCTOR, TYPEALIAS)
|
||||
|
||||
val possibleTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>(
|
||||
ENUM_KEYWORD to EnumSet.of(ENUM_CLASS),
|
||||
ABSTRACT_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
OPEN_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
FINAL_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS, OBJECT, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
SEALED_KEYWORD to EnumSet.of(CLASS_ONLY),
|
||||
INNER_KEYWORD to EnumSet.of(CLASS_ONLY),
|
||||
ABSTRACT_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INNER_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
OPEN_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INNER_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
FINAL_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INNER_CLASS, ENUM_CLASS, OBJECT, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
SEALED_KEYWORD to EnumSet.of(CLASS_ONLY, INNER_CLASS),
|
||||
// We should have also CLASS_ONLY here because INNER_CLASS is not always perfectly identified
|
||||
INNER_KEYWORD to EnumSet.of(CLASS_ONLY, INNER_CLASS),
|
||||
OVERRIDE_KEYWORD to EnumSet.of(MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
PRIVATE_KEYWORD to defaultVisibilityTargets,
|
||||
PUBLIC_KEYWORD to defaultVisibilityTargets,
|
||||
INTERNAL_KEYWORD to defaultVisibilityTargets,
|
||||
PROTECTED_KEYWORD to EnumSet.of(CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
|
||||
PROTECTED_KEYWORD to EnumSet.of(CLASS_ONLY, OBJECT, INTERFACE, INNER_CLASS, ENUM_CLASS, ANNOTATION_CLASS,
|
||||
MEMBER_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, MEMBER_PROPERTY, CONSTRUCTOR, TYPEALIAS),
|
||||
IN_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
|
||||
OUT_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
|
||||
@@ -77,7 +78,7 @@ object ModifierCheckerCore {
|
||||
VARARG_KEYWORD to EnumSet.of(VALUE_PARAMETER, PROPERTY_PARAMETER),
|
||||
COMPANION_KEYWORD to EnumSet.of(OBJECT),
|
||||
LATEINIT_KEYWORD to EnumSet.of(MEMBER_PROPERTY),
|
||||
DATA_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS),
|
||||
DATA_KEYWORD to EnumSet.of(CLASS_ONLY, INNER_CLASS, LOCAL_CLASS),
|
||||
INLINE_KEYWORD to EnumSet.of(FUNCTION, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER),
|
||||
NOINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
|
||||
TAILREC_KEYWORD to EnumSet.of(FUNCTION),
|
||||
@@ -88,8 +89,8 @@ object ModifierCheckerCore {
|
||||
CONST_KEYWORD to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY),
|
||||
OPERATOR_KEYWORD to EnumSet.of(FUNCTION),
|
||||
INFIX_KEYWORD to EnumSet.of(FUNCTION),
|
||||
HEADER_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY_WITHOUT_FIELD_OR_DELEGATE, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
|
||||
IMPL_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, MEMBER_FUNCTION, TOP_LEVEL_PROPERTY, MEMBER_PROPERTY, CONSTRUCTOR, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS, TYPEALIAS)
|
||||
HEADER_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY_WITHOUT_FIELD_OR_DELEGATE, CLASS_ONLY, OBJECT, INTERFACE, INNER_CLASS, ENUM_CLASS, ANNOTATION_CLASS),
|
||||
IMPL_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, MEMBER_FUNCTION, TOP_LEVEL_PROPERTY, MEMBER_PROPERTY, CONSTRUCTOR, CLASS_ONLY, OBJECT, INTERFACE, INNER_CLASS, ENUM_CLASS, ANNOTATION_CLASS, TYPEALIAS)
|
||||
)
|
||||
|
||||
val featureDependencies = mapOf(
|
||||
@@ -103,8 +104,8 @@ object ModifierCheckerCore {
|
||||
LanguageFeature.Coroutines to LanguageFeature.ErrorOnCoroutines
|
||||
)
|
||||
|
||||
val noWarningOnFeature = mapOf(
|
||||
LanguageFeature.Coroutines to LanguageFeature.DoNotWarnOnCoroutines
|
||||
val warningOnFeature = mapOf(
|
||||
LanguageFeature.Coroutines to LanguageFeature.WarnOnCoroutines
|
||||
)
|
||||
|
||||
val featureDependenciesTargets = mapOf(
|
||||
@@ -120,16 +121,16 @@ object ModifierCheckerCore {
|
||||
)
|
||||
|
||||
val possibleParentTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>(
|
||||
INNER_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS),
|
||||
OVERRIDE_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL,
|
||||
INNER_KEYWORD to EnumSet.of(CLASS_ONLY, INNER_CLASS, LOCAL_CLASS, ENUM_CLASS),
|
||||
OVERRIDE_KEYWORD to EnumSet.of(CLASS_ONLY, INNER_CLASS, LOCAL_CLASS, OBJECT, OBJECT_LITERAL,
|
||||
INTERFACE, ENUM_CLASS, ENUM_ENTRY),
|
||||
PROTECTED_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS, COMPANION_OBJECT),
|
||||
INTERNAL_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL,
|
||||
PROTECTED_KEYWORD to EnumSet.of(CLASS_ONLY, INNER_CLASS, LOCAL_CLASS, ENUM_CLASS, COMPANION_OBJECT),
|
||||
INTERNAL_KEYWORD to EnumSet.of(CLASS_ONLY, INNER_CLASS, LOCAL_CLASS, OBJECT, OBJECT_LITERAL,
|
||||
ENUM_CLASS, ENUM_ENTRY, FILE),
|
||||
PRIVATE_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL,
|
||||
PRIVATE_KEYWORD to EnumSet.of(CLASS_ONLY, INNER_CLASS, LOCAL_CLASS, OBJECT, OBJECT_LITERAL,
|
||||
INTERFACE, ENUM_CLASS, ENUM_ENTRY, FILE),
|
||||
COMPANION_KEYWORD to EnumSet.of(CLASS_ONLY, ENUM_CLASS, INTERFACE),
|
||||
FINAL_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL,
|
||||
FINAL_KEYWORD to EnumSet.of(CLASS_ONLY, INNER_CLASS, LOCAL_CLASS, OBJECT, OBJECT_LITERAL,
|
||||
ENUM_CLASS, ENUM_ENTRY, ANNOTATION_CLASS, FILE)
|
||||
)
|
||||
|
||||
@@ -168,13 +169,6 @@ object ModifierCheckerCore {
|
||||
result += compatibilityForClassesRegister(PRIVATE_KEYWORD, ABSTRACT_KEYWORD)
|
||||
|
||||
result += incompatibilityRegister(CROSSINLINE_KEYWORD, NOINLINE_KEYWORD)
|
||||
|
||||
// 1. subclasses contained inside a sealed class can not be instantiated, because their constructors needs
|
||||
// an instance of an outer sealed (effectively abstract) class
|
||||
// 2. subclasses of a non-top-level sealed class must be declared inside the class
|
||||
// (see the KEEP https://github.com/Kotlin/KEEP/blob/master/proposals/sealed-class-inheritance.md)
|
||||
result += incompatibilityRegister(SEALED_KEYWORD, INNER_KEYWORD)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -299,8 +293,8 @@ object ModifierCheckerCore {
|
||||
return false
|
||||
}
|
||||
|
||||
val pairedNoWarningFeature = noWarningOnFeature[dependency]
|
||||
if (pairedNoWarningFeature != null && !languageVersionSettings.supportsFeature(pairedNoWarningFeature)) {
|
||||
val pairedWarningFeature = warningOnFeature[dependency]
|
||||
if (pairedWarningFeature != null && languageVersionSettings.supportsFeature(pairedWarningFeature)) {
|
||||
trace.report(Errors.EXPERIMENTAL_FEATURE_WARNING.on(node.psi, diagnosticData))
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
|
||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
|
||||
import org.jetbrains.kotlin.types.expressions.isWithoutValueArguments
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||
|
||||
class QualifiedExpressionResolver {
|
||||
@@ -106,7 +107,7 @@ class QualifiedExpressionResolver {
|
||||
val lastPart = qualifierPartList.last()
|
||||
val classifier = when (qualifier) {
|
||||
is PackageViewDescriptor -> qualifier.memberScope.getContributedClassifier(lastPart.name, lastPart.location)
|
||||
is ClassDescriptor -> {
|
||||
is ClassDescriptor -> {
|
||||
val descriptor = qualifier.unsubstitutedInnerClassesScope.getContributedClassifier(lastPart.name, lastPart.location)
|
||||
checkNotEnumEntry(descriptor, trace, lastPart.expression)
|
||||
descriptor
|
||||
@@ -206,7 +207,7 @@ class QualifiedExpressionResolver {
|
||||
path: List<QualifierPart>,
|
||||
lastPart: QualifierPart,
|
||||
packageFragmentForVisibilityCheck: PackageFragmentDescriptor?
|
||||
): ImportingScope? {
|
||||
): SingleImportScope? {
|
||||
val aliasName = KtPsiUtil.getAliasName(importDirective)
|
||||
if (aliasName == null) {
|
||||
// import kotlin.
|
||||
@@ -214,23 +215,63 @@ class QualifiedExpressionResolver {
|
||||
return null
|
||||
}
|
||||
|
||||
val resolvedDescriptor = resolveToPackageOrClass(
|
||||
val packageOrClassDescriptor = resolveToPackageOrClass(
|
||||
path.subList(0, path.size - 1), moduleDescriptor, trace,
|
||||
packageFragmentForVisibilityCheck, scopeForFirstPart = null, position = QualifierPosition.IMPORT
|
||||
) ?: return null
|
||||
|
||||
val packageOrClassDescriptor = (resolvedDescriptor as? TypeAliasDescriptor)?.let { it.classDescriptor ?: return null } ?: resolvedDescriptor
|
||||
|
||||
return LazyExplicitImportScope(packageOrClassDescriptor, packageFragmentForVisibilityCheck, lastPart.name, aliasName) {
|
||||
candidates ->
|
||||
|
||||
if (candidates.isNotEmpty()) {
|
||||
storeResult(trace, lastPart.expression, candidates, packageFragmentForVisibilityCheck, position = QualifierPosition.IMPORT, isQualifier = false)
|
||||
}
|
||||
else {
|
||||
tryResolveDescriptorsWhichCannotBeImported(trace, moduleDescriptor, packageOrClassDescriptor, lastPart)
|
||||
}
|
||||
val candidates = collectCandidateDescriptors(lastPart, packageOrClassDescriptor)
|
||||
if (candidates.isNotEmpty()) {
|
||||
storeResult(trace, lastPart.expression, candidates, packageFragmentForVisibilityCheck, position = QualifierPosition.IMPORT, isQualifier = false)
|
||||
}
|
||||
else {
|
||||
tryResolveDescriptorsWhichCannotBeImported(trace, moduleDescriptor, packageOrClassDescriptor, lastPart)
|
||||
return null
|
||||
}
|
||||
|
||||
val importedDescriptors = candidates.filter { isVisible(it, packageFragmentForVisibilityCheck, position = QualifierPosition.IMPORT) }.
|
||||
check { it.isNotEmpty() } ?: candidates
|
||||
|
||||
return SingleImportScope(aliasName, importedDescriptors)
|
||||
}
|
||||
|
||||
private fun collectCandidateDescriptors(lastPart: QualifierPart, packageOrClassDescriptor: DeclarationDescriptor): SmartList<DeclarationDescriptor> {
|
||||
val descriptors = SmartList<DeclarationDescriptor>()
|
||||
|
||||
val lastName = lastPart.name
|
||||
val location = lastPart.location
|
||||
when (packageOrClassDescriptor) {
|
||||
is PackageViewDescriptor -> {
|
||||
val packageScope = packageOrClassDescriptor.memberScope
|
||||
descriptors.addIfNotNull(packageScope.getContributedClassifier(lastName, location))
|
||||
descriptors.addAll(packageScope.getContributedVariables(lastName, location))
|
||||
descriptors.addAll(packageScope.getContributedFunctions(lastName, location))
|
||||
}
|
||||
|
||||
is ClassDescriptor -> {
|
||||
descriptors.addIfNotNull(
|
||||
packageOrClassDescriptor.unsubstitutedInnerClassesScope.getContributedClassifier(lastName, location)
|
||||
)
|
||||
val staticClassScope = packageOrClassDescriptor.staticScope
|
||||
descriptors.addAll(staticClassScope.getContributedFunctions(lastName, location))
|
||||
descriptors.addAll(staticClassScope.getContributedVariables(lastName, location))
|
||||
|
||||
if (packageOrClassDescriptor.kind == ClassKind.OBJECT) {
|
||||
descriptors.addAll(
|
||||
packageOrClassDescriptor.unsubstitutedMemberScope.getContributedFunctions(lastName, location)
|
||||
.map { it.asImportedFromObject() }
|
||||
)
|
||||
descriptors.addAll(
|
||||
packageOrClassDescriptor.unsubstitutedMemberScope.getContributedVariables(lastName, location)
|
||||
.filterIsInstance<PropertyDescriptor>()
|
||||
.map { it.asImportedFromObject() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
else -> throw IllegalStateException("Should be class or package: $packageOrClassDescriptor")
|
||||
}
|
||||
return descriptors
|
||||
}
|
||||
|
||||
private fun tryResolveDescriptorsWhichCannotBeImported(
|
||||
@@ -303,6 +344,9 @@ class QualifiedExpressionResolver {
|
||||
val location = KotlinLookupLocation(expression)
|
||||
}
|
||||
|
||||
private enum class QualifierPosition {
|
||||
PACKAGE_HEADER, IMPORT, TYPE, EXPRESSION
|
||||
}
|
||||
|
||||
private fun resolveToPackageOrClass(
|
||||
path: List<QualifierPart>,
|
||||
@@ -359,7 +403,7 @@ class QualifiedExpressionResolver {
|
||||
moduleDescriptor.quickResolveToPackage(path, trace, position)
|
||||
|
||||
var currentDescriptor: DeclarationDescriptor? = prefixDescriptor
|
||||
for (qualifierPartIndex in nextIndexAfterPrefix..path.size - 1) {
|
||||
for (qualifierPartIndex in nextIndexAfterPrefix .. path.size - 1) {
|
||||
val qualifierPart = path[qualifierPartIndex]
|
||||
|
||||
val nextPackageOrClassDescriptor =
|
||||
@@ -455,7 +499,7 @@ class QualifiedExpressionResolver {
|
||||
)
|
||||
|
||||
if (result == null) return QualifiedExpressionResolveResult.UNRESOLVED
|
||||
return when (index) {
|
||||
return when(index) {
|
||||
path.size -> QualifiedExpressionResolveResult(result, null)
|
||||
path.size - 1 -> QualifiedExpressionResolveResult(result, path[index].name)
|
||||
else -> QualifiedExpressionResolveResult.UNRESOLVED
|
||||
@@ -596,12 +640,12 @@ class QualifiedExpressionResolver {
|
||||
|
||||
if (descriptor is DeclarationDescriptorWithVisibility) {
|
||||
val fromToCheck =
|
||||
if (shouldBeVisibleFrom is PackageFragmentDescriptor && shouldBeVisibleFrom.source == SourceElement.NO_SOURCE && referenceExpression.containingFile !is DummyHolder) {
|
||||
PackageFragmentWithCustomSource(shouldBeVisibleFrom, KotlinSourceElement(referenceExpression.getContainingKtFile()))
|
||||
}
|
||||
else {
|
||||
shouldBeVisibleFrom
|
||||
}
|
||||
if (shouldBeVisibleFrom is PackageFragmentDescriptor && shouldBeVisibleFrom.source == SourceElement.NO_SOURCE && referenceExpression.containingFile !is DummyHolder) {
|
||||
PackageFragmentWithCustomSource(shouldBeVisibleFrom, KotlinSourceElement(referenceExpression.getContainingKtFile()))
|
||||
}
|
||||
else {
|
||||
shouldBeVisibleFrom
|
||||
}
|
||||
if (!isVisible(descriptor, fromToCheck, position)) {
|
||||
trace.report(Errors.INVISIBLE_REFERENCE.on(referenceExpression, descriptor, descriptor.visibility, descriptor))
|
||||
}
|
||||
@@ -627,25 +671,21 @@ class QualifiedExpressionResolver {
|
||||
|
||||
return qualifier
|
||||
}
|
||||
}
|
||||
|
||||
internal fun isVisible(
|
||||
descriptor: DeclarationDescriptor,
|
||||
shouldBeVisibleFrom: DeclarationDescriptor?,
|
||||
position: QualifierPosition
|
||||
): Boolean {
|
||||
if (descriptor !is DeclarationDescriptorWithVisibility || shouldBeVisibleFrom == null) return true
|
||||
private fun isVisible(
|
||||
descriptor: DeclarationDescriptor,
|
||||
shouldBeVisibleFrom: DeclarationDescriptor?,
|
||||
position: QualifierPosition
|
||||
): Boolean {
|
||||
if (descriptor !is DeclarationDescriptorWithVisibility || shouldBeVisibleFrom == null) return true
|
||||
|
||||
val visibility = descriptor.visibility
|
||||
if (position == QualifierPosition.IMPORT) {
|
||||
if (Visibilities.isPrivate(visibility)) return false
|
||||
if (!visibility.mustCheckInImports()) return true
|
||||
val visibility = descriptor.visibility
|
||||
if (position == QualifierPosition.IMPORT) {
|
||||
if (Visibilities.isPrivate(visibility)) return false
|
||||
if (!visibility.mustCheckInImports()) return true
|
||||
}
|
||||
return Visibilities.isVisibleIgnoringReceiver(descriptor, shouldBeVisibleFrom)
|
||||
}
|
||||
return Visibilities.isVisibleIgnoringReceiver(descriptor, shouldBeVisibleFrom)
|
||||
}
|
||||
|
||||
internal enum class QualifierPosition {
|
||||
PACKAGE_HEADER, IMPORT, TYPE, EXPRESSION
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.BaseImportingScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
|
||||
class SingleImportScope(private val aliasName: Name, private val descriptors: Collection<DeclarationDescriptor>) : BaseImportingScope(null) {
|
||||
override fun getContributedClassifier(name: Name, location: LookupLocation)
|
||||
= if (name == aliasName) descriptors.filterIsInstance<ClassifierDescriptor>().singleOrNull() else null
|
||||
|
||||
override fun getContributedPackage(name: Name)
|
||||
= if (name == aliasName) descriptors.filterIsInstance<PackageViewDescriptor>().singleOrNull() else null
|
||||
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation)
|
||||
= if (name == aliasName) descriptors.filterIsInstance<VariableDescriptor>() else emptyList()
|
||||
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation)
|
||||
= if (name == aliasName) descriptors.filterIsInstance<FunctionDescriptor>() else emptyList()
|
||||
|
||||
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean)
|
||||
= descriptors
|
||||
|
||||
override fun printStructure(p: Printer) {
|
||||
p.println(javaClass.simpleName, ": ", aliasName)
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,7 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer
|
||||
import org.jetbrains.kotlin.types.expressions.FakeCallResolver
|
||||
import java.util.*
|
||||
|
||||
class CallCompleter(
|
||||
@@ -61,6 +62,7 @@ class CallCompleter(
|
||||
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||
private val callCheckers: Iterable<CallChecker>,
|
||||
private val builtIns: KotlinBuiltIns,
|
||||
private val fakeCallResolver: FakeCallResolver,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val compilerConfiguration: CompilerConfiguration
|
||||
) {
|
||||
@@ -84,7 +86,7 @@ class CallCompleter(
|
||||
temporaryTrace.commit()
|
||||
}
|
||||
|
||||
if (resolvedCall != null && context.trace.wantsDiagnostics()) {
|
||||
if (resolvedCall != null) {
|
||||
val calleeExpression = if (resolvedCall is VariableAsFunctionResolvedCall)
|
||||
resolvedCall.variableCall.call.calleeExpression
|
||||
else
|
||||
@@ -93,12 +95,10 @@ class CallCompleter(
|
||||
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
|
||||
else resolvedCall.call.callElement
|
||||
|
||||
val callCheckerContext = CallCheckerContext(context, languageVersionSettings, compilerConfiguration)
|
||||
for (callChecker in callCheckers) {
|
||||
callChecker.check(resolvedCall, reportOn, callCheckerContext)
|
||||
|
||||
if (resolvedCall is VariableAsFunctionResolvedCall) {
|
||||
callChecker.check(resolvedCall.variableCall, reportOn, callCheckerContext)
|
||||
if (context.trace.wantsDiagnostics()) {
|
||||
val callCheckerContext = CallCheckerContext(context, languageVersionSettings, compilerConfiguration)
|
||||
for (callChecker in callCheckers) {
|
||||
callChecker.check(resolvedCall, reportOn, callCheckerContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.coroutines.hasSuspendFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
@@ -41,8 +42,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
object CoroutineSuspendCallChecker : CallChecker {
|
||||
private val ALLOWED_SCOPE_KINDS = setOf(LexicalScopeKind.FUNCTION_INNER_SCOPE, LexicalScopeKind.FUNCTION_HEADER_FOR_DESTRUCTURING)
|
||||
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
val descriptor = resolvedCall.candidateDescriptor as? FunctionDescriptor ?: return
|
||||
if (!descriptor.isSuspend) return
|
||||
@@ -50,7 +49,7 @@ object CoroutineSuspendCallChecker : CallChecker {
|
||||
val enclosingSuspendFunction =
|
||||
context.scope
|
||||
.parentsWithSelf.firstOrNull {
|
||||
it is LexicalScope && it.kind in ALLOWED_SCOPE_KINDS &&
|
||||
it is LexicalScope && it.kind == LexicalScopeKind.FUNCTION_INNER_SCOPE &&
|
||||
it.ownerDescriptor.safeAs<FunctionDescriptor>()?.isSuspend == true
|
||||
}?.cast<LexicalScope>()?.ownerDescriptor?.cast<FunctionDescriptor>()
|
||||
|
||||
@@ -96,7 +95,7 @@ fun checkCoroutinesFeature(languageVersionSettings: LanguageVersionSettings, dia
|
||||
else if (languageVersionSettings.supportsFeature(LanguageFeature.ErrorOnCoroutines)) {
|
||||
diagnosticHolder.report(Errors.EXPERIMENTAL_FEATURE_ERROR.on(reportOn, diagnosticData))
|
||||
}
|
||||
else if (!languageVersionSettings.supportsFeature(LanguageFeature.DoNotWarnOnCoroutines)) {
|
||||
else if (languageVersionSettings.supportsFeature(LanguageFeature.WarnOnCoroutines)) {
|
||||
diagnosticHolder.report(Errors.EXPERIMENTAL_FEATURE_WARNING.on(reportOn, diagnosticData))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,15 +56,11 @@ import javax.inject.Inject
|
||||
|
||||
class TypeTemplate(
|
||||
val typeVariable: TypeVariable,
|
||||
val coroutineInferenceData: CoroutineInferenceData,
|
||||
nullable: Boolean = true
|
||||
) : FlexibleType(
|
||||
typeVariable.originalTypeParameter.builtIns.nothingType,
|
||||
typeVariable.originalTypeParameter.builtIns.anyType.makeNullableAsSpecified(nullable)
|
||||
) {
|
||||
val coroutineInferenceData: CoroutineInferenceData
|
||||
) : FlexibleType(typeVariable.originalTypeParameter.builtIns.nothingType, typeVariable.originalTypeParameter.builtIns.nullableAnyType) {
|
||||
override fun replaceAnnotations(newAnnotations: Annotations) = this
|
||||
|
||||
override fun makeNullableAsSpecified(newNullability: Boolean) = TypeTemplate(typeVariable, coroutineInferenceData, newNullability)
|
||||
override fun makeNullableAsSpecified(newNullability: Boolean) = this
|
||||
|
||||
override val delegate: SimpleType
|
||||
get() = upperBound
|
||||
|
||||
@@ -17,15 +17,13 @@
|
||||
package org.jetbrains.kotlin.resolve.calls.resolvedCallUtil
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtCallElement
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.psi.KtThisExpression
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCast
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
@@ -76,16 +74,29 @@ fun ResolvedCall<*>.getExplicitReceiverValue(): ReceiverValue? {
|
||||
}
|
||||
}
|
||||
|
||||
fun ResolvedCall<*>.getImplicitReceiverValue(): ImplicitReceiver? =
|
||||
getImplicitReceivers().firstOrNull() as? ImplicitReceiver
|
||||
fun ResolvedCall<*>.getImplicitReceiverValue(): ImplicitReceiver? {
|
||||
return when (explicitReceiverKind) {
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER -> extensionReceiver ?: dispatchReceiver
|
||||
ExplicitReceiverKind.DISPATCH_RECEIVER -> extensionReceiver
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER -> dispatchReceiver
|
||||
else -> null
|
||||
} as? ImplicitReceiver
|
||||
}
|
||||
|
||||
fun ResolvedCall<*>.getImplicitReceivers(): Collection<ReceiverValue> =
|
||||
when (explicitReceiverKind) {
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER -> listOfNotNull(extensionReceiver, dispatchReceiver)
|
||||
ExplicitReceiverKind.DISPATCH_RECEIVER -> listOfNotNull(extensionReceiver)
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER -> listOfNotNull(dispatchReceiver)
|
||||
ExplicitReceiverKind.BOTH_RECEIVERS -> emptyList()
|
||||
}
|
||||
fun ResolvedCall<*>.getImplicitReceivers(): Collection<ReceiverValue> {
|
||||
if (this is VariableAsFunctionResolvedCall) {
|
||||
val receivers = variableCall.getImplicitReceivers() + functionCall.getImplicitReceivers()
|
||||
assert(receivers.size <= 3) { "There are ${receivers.size} for $this call" }
|
||||
return receivers
|
||||
}
|
||||
|
||||
return when (explicitReceiverKind) {
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER -> listOfNotNull(dispatchReceiver, extensionReceiver)
|
||||
ExplicitReceiverKind.DISPATCH_RECEIVER -> listOfNotNull(extensionReceiver)
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER -> listOfNotNull(dispatchReceiver)
|
||||
ExplicitReceiverKind.BOTH_RECEIVERS -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun ResolvedCall<*>.hasSafeNullableReceiver(context: CallResolutionContext<*>): Boolean {
|
||||
if (!call.isSafeCall()) return false
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user