mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-05-14 00:21:34 +00:00
Compare commits
215 Commits
build-1.6.
...
ssa/native
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99b395b0fa | ||
|
|
0c5bf63844 | ||
|
|
fd7c4c0c2d | ||
|
|
4a62466671 | ||
|
|
47d0211370 | ||
|
|
5819959cce | ||
|
|
1cd321a90f | ||
|
|
16f41bd80c | ||
|
|
8ab546ba51 | ||
|
|
a5e59e09ee | ||
|
|
6d7eb2bd21 | ||
|
|
21f7e16ee6 | ||
|
|
fb1eac0985 | ||
|
|
0a6e51e47f | ||
|
|
f37d880964 | ||
|
|
301f446433 | ||
|
|
a8077aebb0 | ||
|
|
753ba99b04 | ||
|
|
a0553f4dfd | ||
|
|
c3a327e118 | ||
|
|
1a5552bef8 | ||
|
|
6660c9b26b | ||
|
|
ab158a53c3 | ||
|
|
1cdbbad367 | ||
|
|
5e87d753b7 | ||
|
|
a7cc275c7d | ||
|
|
12d694de46 | ||
|
|
16f0ba8e46 | ||
|
|
49c412b022 | ||
|
|
6ea2dea28e | ||
|
|
e7a08b14e3 | ||
|
|
7e1c776376 | ||
|
|
4049cf94b1 | ||
|
|
da72f26d94 | ||
|
|
e18c3517a9 | ||
|
|
cd08dc49a0 | ||
|
|
4edc1239ac | ||
|
|
af12d61388 | ||
|
|
3cd43dced4 | ||
|
|
a17a61341b | ||
|
|
68f14fdd87 | ||
|
|
5a26e79b08 | ||
|
|
b77dc4136b | ||
|
|
64ebddcbc6 | ||
|
|
68e7476765 | ||
|
|
1e95717b8d | ||
|
|
f64a0efa8b | ||
|
|
26ede5d885 | ||
|
|
9fb41b6334 | ||
|
|
367db345a8 | ||
|
|
dda9bb93f6 | ||
|
|
3d4e861f05 | ||
|
|
6c246738a5 | ||
|
|
dff392f2cd | ||
|
|
1857096071 | ||
|
|
50a343f91e | ||
|
|
cdfe8d60a4 | ||
|
|
0c35a3b699 | ||
|
|
486c6b3c15 | ||
|
|
ebb340fe68 | ||
|
|
8d764fa50e | ||
|
|
0fb398d45e | ||
|
|
f2ffead881 | ||
|
|
2c1c24c042 | ||
|
|
cd6384eb20 | ||
|
|
e85940a1ac | ||
|
|
ed0e3b0fed | ||
|
|
f8503ba1bf | ||
|
|
55663a0fb1 | ||
|
|
32c51cbb45 | ||
|
|
15c41b2610 | ||
|
|
edd2ca775b | ||
|
|
5096e8c5c4 | ||
|
|
7a99f9ff2e | ||
|
|
9be941def2 | ||
|
|
9acdcc7590 | ||
|
|
bf362abb57 | ||
|
|
6b18f33f92 | ||
|
|
b01c13a4df | ||
|
|
ec90649854 | ||
|
|
d88a665fa8 | ||
|
|
2f2e608502 | ||
|
|
492b8acf93 | ||
|
|
69fe7e66a5 | ||
|
|
1808f14677 | ||
|
|
ac2dffa74e | ||
|
|
a630273af2 | ||
|
|
bc9b2fd78b | ||
|
|
23b315446f | ||
|
|
b85a796492 | ||
|
|
f9607292b5 | ||
|
|
b46a42be33 | ||
|
|
7bddc2a815 | ||
|
|
4e4d36f85a | ||
|
|
a21d281c19 | ||
|
|
a04913a197 | ||
|
|
73a8b4544a | ||
|
|
b617aca8ee | ||
|
|
ca98417a0c | ||
|
|
b1bcbaf48f | ||
|
|
f6413c41a0 | ||
|
|
2e2edf398c | ||
|
|
8e32bbbe90 | ||
|
|
23c438aa03 | ||
|
|
63d1e195e0 | ||
|
|
9e0ba8c3d2 | ||
|
|
c56b6455f1 | ||
|
|
9b9a529b7f | ||
|
|
d346953de9 | ||
|
|
1679da45ab | ||
|
|
db12a96e54 | ||
|
|
39c6be86cb | ||
|
|
06d3c6f233 | ||
|
|
e75ca75e3e | ||
|
|
94af3adb4b | ||
|
|
1b98723b3f | ||
|
|
d124239025 | ||
|
|
dd3eb53904 | ||
|
|
3acb96e474 | ||
|
|
c57302abba | ||
|
|
1338675833 | ||
|
|
06001fc091 | ||
|
|
d3905fd763 | ||
|
|
3ec9599bc4 | ||
|
|
445e5122c1 | ||
|
|
ebe96ec79a | ||
|
|
a8f7bf5fbc | ||
|
|
2e3b576342 | ||
|
|
aef45f0997 | ||
|
|
d7f5015faa | ||
|
|
cd487efbe9 | ||
|
|
623b289616 | ||
|
|
58110709f3 | ||
|
|
28c473074c | ||
|
|
cd26ef2bb5 | ||
|
|
608b88996a | ||
|
|
1760befa37 | ||
|
|
81ce59cf48 | ||
|
|
e159392d22 | ||
|
|
5455800de4 | ||
|
|
747cc7d55d | ||
|
|
784273ac5b | ||
|
|
493fdbd418 | ||
|
|
8ad368e990 | ||
|
|
40d19b50c5 | ||
|
|
bfcd954dd3 | ||
|
|
b8330deefa | ||
|
|
5ec19c2417 | ||
|
|
1a1f6b0c0b | ||
|
|
017448e359 | ||
|
|
d3ddeef67f | ||
|
|
b3dbca7ea6 | ||
|
|
06ee84f809 | ||
|
|
5b9ce7e823 | ||
|
|
280c445783 | ||
|
|
bcf6202863 | ||
|
|
45d31fdba2 | ||
|
|
3bc0eaff59 | ||
|
|
0d1380c232 | ||
|
|
2ca3adbcb2 | ||
|
|
c19598c2fc | ||
|
|
9736cc162b | ||
|
|
fd92b851a2 | ||
|
|
1c678be0d3 | ||
|
|
cfc4e715e4 | ||
|
|
c1fb40a436 | ||
|
|
672b972b38 | ||
|
|
ac387b1f26 | ||
|
|
2c31d2e67d | ||
|
|
8c51c3c5c3 | ||
|
|
512a851c65 | ||
|
|
85a2a3255d | ||
|
|
cdc0f36859 | ||
|
|
33251f6d50 | ||
|
|
5873511f64 | ||
|
|
e2e0358505 | ||
|
|
1607a8231a | ||
|
|
927723c766 | ||
|
|
cc531149e5 | ||
|
|
eb94167ff2 | ||
|
|
170184dce4 | ||
|
|
206457d9ff | ||
|
|
7e04bb4bf1 | ||
|
|
766857881a | ||
|
|
2f0f88062a | ||
|
|
a28138eb72 | ||
|
|
b6c3132614 | ||
|
|
627af332b1 | ||
|
|
e6af3ff6a8 | ||
|
|
a70fc99130 | ||
|
|
22d202e657 | ||
|
|
755f847ab9 | ||
|
|
3c9dcdbbee | ||
|
|
8a812996dd | ||
|
|
1d913a6bf0 | ||
|
|
3b8cb4b00d | ||
|
|
13cf9329b2 | ||
|
|
7e71bd8f1c | ||
|
|
307de0be89 | ||
|
|
eccbf38061 | ||
|
|
fb801bdc33 | ||
|
|
54957ead5c | ||
|
|
1d2d1f9e8d | ||
|
|
afacff326d | ||
|
|
cb37a05b79 | ||
|
|
e64f7ffb98 | ||
|
|
75c76e2b57 | ||
|
|
f7f51cf38e | ||
|
|
4396482fed | ||
|
|
46a0c4be4b | ||
|
|
fba480875f | ||
|
|
edc134ef2d | ||
|
|
ba8f2e6bf3 | ||
|
|
c1afb6354b | ||
|
|
d670743a2f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -68,3 +68,4 @@ distTmp/
|
||||
outTmp/
|
||||
/test.output
|
||||
/kotlin-native/dist
|
||||
kotlin-ide/
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.build.GeneratedJvmClass
|
||||
import org.jetbrains.kotlin.incremental.storage.*
|
||||
import org.jetbrains.kotlin.inline.inlineFunctionsJvmNames
|
||||
import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.JvmPackagePartProto
|
||||
@@ -113,7 +114,7 @@ open class IncrementalJvmCache(
|
||||
}
|
||||
|
||||
open fun saveFileToCache(generatedClass: GeneratedJvmClass, changesCollector: ChangesCollector) {
|
||||
saveClassToCache(KotlinClassInfo(generatedClass.outputClass), generatedClass.sourceFiles, changesCollector)
|
||||
saveClassToCache(KotlinClassInfo.createFrom(generatedClass.outputClass), generatedClass.sourceFiles, changesCollector)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -612,16 +613,6 @@ class KotlinClassInfo private constructor(
|
||||
val inlineFunctionsMap: LinkedHashMap<String, Long>
|
||||
) {
|
||||
|
||||
constructor(kotlinClass: LocalFileKotlinClass) : this(
|
||||
kotlinClass.classId,
|
||||
kotlinClass.classHeader.kind,
|
||||
kotlinClass.classHeader.data,
|
||||
kotlinClass.classHeader.strings,
|
||||
kotlinClass.classHeader.multifileClassName,
|
||||
getConstantsMap(kotlinClass.fileContents),
|
||||
getInlineFunctionsMap(kotlinClass.classHeader, kotlinClass.fileContents)
|
||||
)
|
||||
|
||||
val className: JvmClassName by lazy { JvmClassName.byClassId(classId) }
|
||||
|
||||
fun scopeFqName(companion: Boolean = false) = when (classKind) {
|
||||
@@ -630,6 +621,36 @@ class KotlinClassInfo private constructor(
|
||||
}
|
||||
else -> className.packageFqName
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun createFrom(kotlinClass: LocalFileKotlinClass): KotlinClassInfo {
|
||||
return KotlinClassInfo(
|
||||
kotlinClass.classId,
|
||||
kotlinClass.classHeader.kind,
|
||||
kotlinClass.classHeader.data,
|
||||
kotlinClass.classHeader.strings,
|
||||
kotlinClass.classHeader.multifileClassName,
|
||||
getConstantsMap(kotlinClass.fileContents),
|
||||
getInlineFunctionsMap(kotlinClass.classHeader, kotlinClass.fileContents)
|
||||
)
|
||||
}
|
||||
|
||||
/** Creates [KotlinClassInfo] from the given classContents, or returns `null` if the class is not a kotlinc-generated class. */
|
||||
fun tryCreateFrom(classContents: ByteArray): KotlinClassInfo? {
|
||||
return FileBasedKotlinClass.create(classContents) { classId, _, classHeader, _ ->
|
||||
KotlinClassInfo(
|
||||
classId,
|
||||
classHeader.kind,
|
||||
classHeader.data,
|
||||
classHeader.strings,
|
||||
classHeader.multifileClassName,
|
||||
getConstantsMap(classContents),
|
||||
getInlineFunctionsMap(classHeader, classContents)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConstantsMap(bytes: ByteArray): LinkedHashMap<String, Any> {
|
||||
@@ -694,4 +715,4 @@ private fun getInlineFunctionsMap(header: KotlinClassHeader, bytes: ByteArray):
|
||||
}, 0)
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ extra["versions.kotlinx-collections-immutable-jvm"] = immutablesVersion
|
||||
extra["versions.ktor-network"] = "1.0.1"
|
||||
|
||||
if (!project.hasProperty("versions.kotlin-native")) {
|
||||
extra["versions.kotlin-native"] = "1.6.0-dev-1728"
|
||||
extra["versions.kotlin-native"] = "1.6.0-dev-2972"
|
||||
}
|
||||
|
||||
val useJvmFir by extra(project.kotlinBuildProperties.useFir)
|
||||
@@ -315,15 +315,7 @@ extra["compilerArtifactsForIde"] = listOf(
|
||||
|
||||
// TODO: fix remaining warnings and remove this property.
|
||||
extra["tasksWithWarnings"] = listOf(
|
||||
":kotlin-stdlib:compileTestKotlin",
|
||||
":kotlin-stdlib-jdk7:compileTestKotlin",
|
||||
":kotlin-stdlib-jdk8:compileTestKotlin",
|
||||
":plugins:uast-kotlin-base:compileKotlin",
|
||||
":plugins:uast-kotlin-base:compileTestKotlin",
|
||||
":plugins:uast-kotlin:compileKotlin",
|
||||
":plugins:uast-kotlin:compileTestKotlin",
|
||||
":plugins:uast-kotlin-fir:compileKotlin",
|
||||
":plugins:uast-kotlin-fir:compileTestKotlin"
|
||||
":kotlin-gradle-plugin:compileKotlin"
|
||||
)
|
||||
|
||||
val tasksWithWarnings: List<String> by extra
|
||||
@@ -482,15 +474,10 @@ allprojects {
|
||||
}
|
||||
|
||||
if (!kotlinBuildProperties.disableWerror) {
|
||||
// For compiler and stdlib, allWarningsAsErrors is configured in the corresponding "root" projects
|
||||
// (compiler/build.gradle.kts and libraries/commonConfiguration.gradle).
|
||||
val projectsWithWarningsAsErrors = listOf("core", "plugins").map { File(it).absoluteFile }
|
||||
if (projectsWithWarningsAsErrors.any(projectDir::startsWith)) {
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile> {
|
||||
if (path !in tasksWithWarnings) {
|
||||
kotlinOptions {
|
||||
allWarningsAsErrors = true
|
||||
}
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile> {
|
||||
if (path !in tasksWithWarnings) {
|
||||
kotlinOptions {
|
||||
allWarningsAsErrors = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,6 @@ val jpsStandalone by configurations.creating
|
||||
val jpsStandaloneForIde by configurations.creating
|
||||
val intellijCore by configurations.creating
|
||||
val intellijCoreForIde by configurations.creating
|
||||
val nodeJSPlugin by configurations.creating
|
||||
|
||||
/**
|
||||
* Special repository for annotations.jar required for idea runtime only.
|
||||
|
||||
@@ -82,8 +82,6 @@ fun Project.intellijCoreDep() = "kotlin.build:intellij-core:${rootProject.extra[
|
||||
|
||||
fun Project.jpsStandalone() = "kotlin.build:jps-standalone:${rootProject.extra["versions.intellijSdk"]}"
|
||||
|
||||
fun Project.nodeJSPlugin() = "kotlin.build:NodeJS:${rootProject.extra["versions.idea.NodeJS"]}"
|
||||
|
||||
fun Project.jpsBuildTest() = "com.jetbrains.intellij.idea:jps-build-test:${rootProject.extra["versions.intellijSdk"]}"
|
||||
|
||||
fun Project.kotlinxCollectionsImmutable() = "org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:${rootProject.extra["versions.kotlinx-collections-immutable"]}"
|
||||
|
||||
@@ -5,21 +5,15 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.coroutinesIntrinsicsPackageFqName
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.isTopLevelInPackage
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
val COROUTINE_SUSPENDED_NAME = Name.identifier("COROUTINE_SUSPENDED")
|
||||
|
||||
fun FunctionDescriptor.isBuiltInIntercepted(languageVersionSettings: LanguageVersionSettings): Boolean =
|
||||
!languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines) &&
|
||||
isTopLevelInPackage("intercepted", languageVersionSettings.coroutinesIntrinsicsPackageFqName().asString())
|
||||
|
||||
fun FunctionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings: LanguageVersionSettings): Boolean =
|
||||
fun FunctionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(): Boolean =
|
||||
isTopLevelInPackage(
|
||||
"suspendCoroutineUninterceptedOrReturn",
|
||||
languageVersionSettings.coroutinesIntrinsicsPackageFqName().asString()
|
||||
StandardNames.COROUTINES_INTRINSICS_PACKAGE_FQ_NAME.asString()
|
||||
)
|
||||
|
||||
@@ -475,7 +475,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
|
||||
List<Type> superCtorArgTypes = new ArrayList<>();
|
||||
if (superClassAsmType.equals(LAMBDA) || functionReferenceTarget != null ||
|
||||
CoroutineCodegenUtilKt.isCoroutineSuperClass(state.getLanguageVersionSettings(), superClassAsmType.getInternalName())
|
||||
CoroutineCodegenUtilKt.isCoroutineSuperClass(superClassAsmType.getInternalName())
|
||||
) {
|
||||
iv.iconst(CodegenUtilKt.getArity(funDescriptor));
|
||||
superCtorArgTypes.add(Type.INT_TYPE);
|
||||
|
||||
@@ -89,7 +89,6 @@ import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor;
|
||||
import org.jetbrains.kotlin.types.*;
|
||||
import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContextImpl;
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS;
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker;
|
||||
import org.jetbrains.kotlin.types.model.TypeParameterMarker;
|
||||
import org.jetbrains.kotlin.types.typesApproximation.CapturedTypeApproximationKt;
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions;
|
||||
@@ -1288,11 +1287,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
@NotNull
|
||||
private static CallableDescriptor unwrapOriginalReceiverOwnerForSuspendLambda(@NotNull MethodContext context) {
|
||||
FunctionDescriptor originalForDoResume =
|
||||
context.getFunctionDescriptor().getUserData(CoroutineCodegenUtilKt.INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME);
|
||||
FunctionDescriptor originalForInvokeSuspend =
|
||||
context.getFunctionDescriptor().getUserData(CoroutineCodegenUtilKt.INITIAL_SUSPEND_DESCRIPTOR_FOR_INVOKE_SUSPEND);
|
||||
|
||||
if (originalForDoResume != null) {
|
||||
return originalForDoResume;
|
||||
if (originalForInvokeSuspend != null) {
|
||||
return originalForInvokeSuspend;
|
||||
}
|
||||
|
||||
if (context.getFunctionDescriptor().isSuspend()) {
|
||||
@@ -2617,26 +2616,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
? coroutineInstanceValueForSuspensionPoint
|
||||
: getContinuationParameterFromEnclosingSuspendFunction(resolvedCall);
|
||||
|
||||
if (coroutineInstanceValue != null && needsExperimentalCoroutinesWrapper(resolvedCall.getCandidateDescriptor())) {
|
||||
StackValue releaseContinuation = coroutineInstanceValue;
|
||||
coroutineInstanceValue = new StackValue(CoroutineCodegenUtilKt.EXPERIMENTAL_CONTINUATION_ASM_TYPE) {
|
||||
@Override
|
||||
public void putSelector(
|
||||
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v
|
||||
) {
|
||||
releaseContinuation.put(CoroutineCodegenUtilKt.RELEASE_CONTINUATION_ASM_TYPE, v);
|
||||
invokeCoroutineMigrationMethod(
|
||||
v,
|
||||
"toExperimentalContinuation",
|
||||
Type.getMethodDescriptor(
|
||||
CoroutineCodegenUtilKt.EXPERIMENTAL_CONTINUATION_ASM_TYPE,
|
||||
CoroutineCodegenUtilKt.RELEASE_CONTINUATION_ASM_TYPE
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
tempVariables.put(continuationExpression, coroutineInstanceValue);
|
||||
}
|
||||
|
||||
@@ -2774,7 +2753,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
SuspensionPointKind suspensionPointKind =
|
||||
CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall, this, state.getLanguageVersionSettings());
|
||||
CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall, this);
|
||||
boolean maybeSuspensionPoint = suspensionPointKind != SuspensionPointKind.NEVER && !insideCallableReference();
|
||||
boolean isConstructor = resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor;
|
||||
if (!(callableMethod instanceof IntrinsicWithSpecialReceiver)) {
|
||||
@@ -2833,7 +2812,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
KotlinType unboxedInlineClass = CoroutineCodegenUtilKt.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass(
|
||||
(FunctionDescriptor) resolvedCall.getResultingDescriptor(), typeMapper);
|
||||
if (unboxedInlineClass != null) {
|
||||
CoroutineCodegenUtilKt.generateCoroutineSuspendedCheck(v, state.getLanguageVersionSettings());
|
||||
CoroutineCodegenUtilKt.generateCoroutineSuspendedCheck(v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2948,7 +2927,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
FunctionDescriptor original =
|
||||
CoroutineCodegenUtilKt.getOriginalSuspendFunctionView(
|
||||
unwrapInitialSignatureDescriptor(DescriptorUtils.unwrapFakeOverride((FunctionDescriptor) descriptor.getOriginal())),
|
||||
bindingContext, state
|
||||
bindingContext
|
||||
);
|
||||
|
||||
FunctionDescriptor functionDescriptor =
|
||||
@@ -5243,7 +5222,7 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
}
|
||||
|
||||
CodegenUtilKt.generateAsCast(
|
||||
v, rightKotlinType, boxedRightType, safeAs, state.getLanguageVersionSettings(), state.getUnifiedNullChecks()
|
||||
v, rightKotlinType, boxedRightType, safeAs, state.getUnifiedNullChecks()
|
||||
);
|
||||
|
||||
return Unit.INSTANCE;
|
||||
@@ -5297,7 +5276,7 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
return null;
|
||||
}
|
||||
|
||||
CodegenUtilKt.generateIsCheck(v, rhsKotlinType, type, state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines));
|
||||
CodegenUtilKt.generateIsCheck(v, rhsKotlinType, type);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -481,8 +481,7 @@ public class FunctionCodegen {
|
||||
}
|
||||
|
||||
if (!functionDescriptor.isExternal()) {
|
||||
generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy, memberCodegen, state.getJvmDefaultMode(),
|
||||
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines));
|
||||
generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy, memberCodegen, state.getJvmDefaultMode());
|
||||
}
|
||||
else if (staticInCompanionObject) {
|
||||
// native @JvmStatic foo() in companion object should delegate to the static native function moved to the outer class
|
||||
@@ -583,8 +582,7 @@ public class FunctionCodegen {
|
||||
@NotNull JvmMethodSignature signature,
|
||||
@NotNull FunctionGenerationStrategy strategy,
|
||||
@NotNull MemberCodegen<?> parentCodegen,
|
||||
@NotNull JvmDefaultMode jvmDefaultMode,
|
||||
boolean isReleaseCoroutines
|
||||
@NotNull JvmDefaultMode jvmDefaultMode
|
||||
) {
|
||||
mv.visitCode();
|
||||
|
||||
@@ -594,8 +592,7 @@ public class FunctionCodegen {
|
||||
KotlinTypeMapper typeMapper = parentCodegen.typeMapper;
|
||||
if (BuiltinSpecialBridgesUtil.shouldHaveTypeSafeBarrier(functionDescriptor, typeMapper::mapAsmMethod)) {
|
||||
generateTypeCheckBarrierIfNeeded(
|
||||
new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), null, typeMapper,
|
||||
isReleaseCoroutines);
|
||||
new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), null, typeMapper);
|
||||
}
|
||||
|
||||
Label methodEntry = null;
|
||||
@@ -1430,8 +1427,7 @@ public class FunctionCodegen {
|
||||
MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv);
|
||||
|
||||
if (delegateTo.getArgumentTypes().length > 0 && isSpecialBridge) {
|
||||
generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes(), typeMapper,
|
||||
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines));
|
||||
generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes(), typeMapper);
|
||||
}
|
||||
|
||||
iv.load(0, OBJECT_TYPE);
|
||||
@@ -1477,8 +1473,7 @@ public class FunctionCodegen {
|
||||
@NotNull FunctionDescriptor descriptor,
|
||||
@NotNull Type returnType,
|
||||
@Nullable Type[] delegateParameterTypes,
|
||||
@NotNull KotlinTypeMapper typeMapper,
|
||||
boolean isReleaseCoroutines
|
||||
@NotNull KotlinTypeMapper typeMapper
|
||||
) {
|
||||
BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription typeSafeBarrierDescription =
|
||||
BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor);
|
||||
@@ -1512,7 +1507,7 @@ public class FunctionCodegen {
|
||||
} else {
|
||||
targetBoxedType = boxType(delegateParameterTypes[i]);
|
||||
}
|
||||
CodegenUtilKt.generateIsCheck(iv, kotlinType, targetBoxedType, isReleaseCoroutines);
|
||||
CodegenUtilKt.generateIsCheck(iv, kotlinType, targetBoxedType);
|
||||
iv.ifeq(defaultBranch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.builtins.StandardNames.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME
|
||||
import org.jetbrains.kotlin.builtins.createFunctionType
|
||||
import org.jetbrains.kotlin.codegen.coroutines.coroutinesJvmInternalPackageFqName
|
||||
import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
|
||||
import org.jetbrains.kotlin.codegen.coroutines.isSuspendLambdaOrLocalFunction
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
||||
@@ -33,8 +32,7 @@ class JvmRuntimeTypes(
|
||||
private val generateOptimizedCallableReferenceSuperClasses: Boolean
|
||||
) {
|
||||
private val kotlinJvmInternalPackage = MutablePackageFragmentDescriptor(module, FqName("kotlin.jvm.internal"))
|
||||
private val kotlinCoroutinesJvmInternalPackage =
|
||||
MutablePackageFragmentDescriptor(module, languageVersionSettings.coroutinesJvmInternalPackageFqName())
|
||||
private val kotlinCoroutinesJvmInternalPackage = MutablePackageFragmentDescriptor(module, COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME)
|
||||
|
||||
private fun internal(className: String, packageFragment: PackageFragmentDescriptor = kotlinJvmInternalPackage): Lazy<ClassDescriptor> =
|
||||
lazy { createClass(packageFragment, className) }
|
||||
@@ -53,24 +51,16 @@ class JvmRuntimeTypes(
|
||||
private val localVariableReference: ClassDescriptor by internal("LocalVariableReference")
|
||||
private val mutableLocalVariableReference: ClassDescriptor by internal("MutableLocalVariableReference")
|
||||
|
||||
private val coroutineImpl: ClassDescriptor by internal("CoroutineImpl", kotlinCoroutinesJvmInternalPackage)
|
||||
private val continuationImpl: ClassDescriptor by coroutinesInternal("ContinuationImpl")
|
||||
private val restrictedContinuationImpl: ClassDescriptor by coroutinesInternal("RestrictedContinuationImpl")
|
||||
private val suspendLambda: ClassDescriptor by coroutinesInternal("SuspendLambda")
|
||||
private val restrictedSuspendLambda: ClassDescriptor by coroutinesInternal("RestrictedSuspendLambda")
|
||||
|
||||
private val suspendFunctionInterface: ClassDescriptor? by lazy {
|
||||
if (languageVersionSettings.isReleaseCoroutines())
|
||||
createClass(kotlinCoroutinesJvmInternalPackage, "SuspendFunction", ClassKind.INTERFACE)
|
||||
else null
|
||||
createClass(kotlinCoroutinesJvmInternalPackage, "SuspendFunction", ClassKind.INTERFACE)
|
||||
}
|
||||
|
||||
private fun createCoroutineSuperClass(className: String): ClassDescriptor {
|
||||
return if (languageVersionSettings.isReleaseCoroutines())
|
||||
createClass(kotlinCoroutinesJvmInternalPackage, className)
|
||||
else
|
||||
coroutineImpl
|
||||
}
|
||||
private fun createCoroutineSuperClass(className: String): ClassDescriptor = createClass(kotlinCoroutinesJvmInternalPackage, className)
|
||||
|
||||
private val propertyReferences: List<ClassDescriptor> by propertyClasses("PropertyReference", "")
|
||||
private val mutablePropertyReferences: List<ClassDescriptor> by propertyClasses("MutablePropertyReference", "")
|
||||
@@ -94,7 +84,7 @@ class JvmRuntimeTypes(
|
||||
fun getSupertypesForClosure(descriptor: FunctionDescriptor): Collection<KotlinType> {
|
||||
val actualFunctionDescriptor =
|
||||
if (descriptor.isSuspend)
|
||||
getOrCreateJvmSuspendFunctionView(descriptor, languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines))
|
||||
getOrCreateJvmSuspendFunctionView(descriptor)
|
||||
else
|
||||
descriptor
|
||||
|
||||
@@ -118,7 +108,7 @@ class JvmRuntimeTypes(
|
||||
if (descriptor.isSuspend) {
|
||||
return mutableListOf<KotlinType>().apply {
|
||||
if (actualFunctionDescriptor.extensionReceiverParameter?.type
|
||||
?.isRestrictsSuspensionReceiver(languageVersionSettings) == true
|
||||
?.isRestrictsSuspensionReceiver() == true
|
||||
) {
|
||||
if (descriptor.isSuspendLambdaOrLocalFunction()) {
|
||||
add(restrictedSuspendLambda.defaultType)
|
||||
|
||||
@@ -477,7 +477,6 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
SimpleFunctionDescriptor jvmSuspendFunctionView =
|
||||
CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
|
||||
functionDescriptor,
|
||||
languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
|
||||
this.bindingContext
|
||||
);
|
||||
|
||||
@@ -714,54 +713,6 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
super.visitCallExpression(expression);
|
||||
checkSamCall(expression);
|
||||
checkCrossinlineCall(expression);
|
||||
recordSuspendFunctionTypeWrapperForArguments(expression);
|
||||
}
|
||||
|
||||
private void recordSuspendFunctionTypeWrapperForArguments(@NotNull KtCallExpression expression) {
|
||||
ResolvedCall<?> call = CallUtilKt.getResolvedCall(expression, bindingContext);
|
||||
if (call == null) return;
|
||||
|
||||
CallableDescriptor descriptor = call.getResultingDescriptor();
|
||||
if (!CodegenUtilKt.needsExperimentalCoroutinesWrapper(descriptor)) return;
|
||||
|
||||
List<ResolvedValueArgument> argumentsByIndex = call.getValueArgumentsByIndex();
|
||||
if (argumentsByIndex == null) return;
|
||||
|
||||
for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
|
||||
ResolvedValueArgument resolvedValueArgument = argumentsByIndex.get(parameter.getIndex());
|
||||
if (!(resolvedValueArgument instanceof ExpressionValueArgument)) continue;
|
||||
ValueArgument valueArgument = ((ExpressionValueArgument) resolvedValueArgument).getValueArgument();
|
||||
if (valueArgument == null) continue;
|
||||
KtExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||
if (argumentExpression == null) continue;
|
||||
|
||||
recordSuspendFunctionTypeWrapperForArgument(parameter, argumentExpression);
|
||||
}
|
||||
|
||||
ReceiverValue receiver = call.getExtensionReceiver();
|
||||
if (descriptor.getExtensionReceiverParameter() != null && receiver instanceof ExpressionReceiver) {
|
||||
recordSuspendFunctionTypeWrapperForArgument(
|
||||
descriptor.getExtensionReceiverParameter(),
|
||||
((ExpressionReceiver) receiver).getExpression()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void recordSuspendFunctionTypeWrapperForArgument(ParameterDescriptor parameter, KtExpression argumentExpression) {
|
||||
if (FunctionTypesKt.isSuspendFunctionTypeOrSubtype(parameter.getType())) {
|
||||
|
||||
// SuspendFunctionN type is mapped to is mapped to FunctionTypeN+1, but we also need to remove an argument for return type
|
||||
// So, it could be parameter.getType().getArguments().size() + 1 - 1
|
||||
int functionTypeArity = parameter.getType().getArguments().size();
|
||||
|
||||
Type functionType = Type.getObjectType(NUMBERED_FUNCTION_PREFIX + functionTypeArity);
|
||||
|
||||
bindingTrace.record(
|
||||
FUNCTION_TYPE_FOR_SUSPEND_WRAPPER,
|
||||
argumentExpression,
|
||||
functionType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCrossinlineCall(@NotNull KtCallExpression expression) {
|
||||
|
||||
@@ -13,15 +13,13 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.context.CodegenContext
|
||||
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext
|
||||
import org.jetbrains.kotlin.codegen.context.MultifileClassFacadeContext
|
||||
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_ASM_TYPE
|
||||
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
|
||||
import org.jetbrains.kotlin.codegen.inline.NUMBERED_FUNCTION_PREFIX
|
||||
import org.jetbrains.kotlin.codegen.inline.ReificationArgument
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
@@ -45,8 +43,6 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor.CoroutinesCompatibilityMode
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
|
||||
@@ -70,8 +66,7 @@ internal val JAVA_LANG_DEPRECATED = Type.getType(Deprecated::class.java).descrip
|
||||
fun generateIsCheck(
|
||||
v: InstructionAdapter,
|
||||
kotlinType: KotlinType,
|
||||
asmType: Type,
|
||||
isReleaseCoroutines: Boolean
|
||||
asmType: Type
|
||||
) {
|
||||
if (TypeUtils.isNullableType(kotlinType)) {
|
||||
val nope = Label()
|
||||
@@ -82,7 +77,7 @@ fun generateIsCheck(
|
||||
|
||||
ifnull(nope)
|
||||
|
||||
TypeIntrinsics.instanceOf(this, kotlinType, asmType, isReleaseCoroutines)
|
||||
TypeIntrinsics.instanceOf(this, kotlinType, asmType)
|
||||
|
||||
goTo(end)
|
||||
|
||||
@@ -93,7 +88,7 @@ fun generateIsCheck(
|
||||
mark(end)
|
||||
}
|
||||
} else {
|
||||
TypeIntrinsics.instanceOf(v, kotlinType, asmType, isReleaseCoroutines)
|
||||
TypeIntrinsics.instanceOf(v, kotlinType, asmType)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +97,6 @@ fun generateAsCast(
|
||||
kotlinType: KotlinType,
|
||||
asmType: Type,
|
||||
isSafe: Boolean,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
unifiedNullChecks: Boolean,
|
||||
) {
|
||||
if (!isSafe) {
|
||||
@@ -112,7 +106,7 @@ fun generateAsCast(
|
||||
} else {
|
||||
with(v) {
|
||||
dup()
|
||||
TypeIntrinsics.instanceOf(v, kotlinType, asmType, languageVersionSettings.isReleaseCoroutines())
|
||||
TypeIntrinsics.instanceOf(v, kotlinType, asmType)
|
||||
val ok = Label()
|
||||
ifne(ok)
|
||||
pop()
|
||||
@@ -444,14 +438,10 @@ fun KotlinType.isInlineClassTypeWithPrimitiveEquality(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
fun CallableDescriptor.needsExperimentalCoroutinesWrapper() =
|
||||
(this as? DeserializedMemberDescriptor)?.coroutinesExperimentalCompatibilityMode == CoroutinesCompatibilityMode.NEEDS_WRAPPER
|
||||
|
||||
fun recordCallLabelForLambdaArgument(declaration: KtFunctionLiteral, bindingTrace: BindingTrace) {
|
||||
val labelName = getCallLabelForLambdaArgument(declaration, bindingTrace.bindingContext) ?: return
|
||||
val functionDescriptor = bindingTrace[BindingContext.FUNCTION, declaration] ?: return
|
||||
bindingTrace.record(CodegenBinding.CALL_LABEL_FOR_LAMBDA_ARGUMENT, functionDescriptor, labelName)
|
||||
|
||||
}
|
||||
|
||||
fun getCallLabelForLambdaArgument(declaration: KtFunctionLiteral, bindingContext: BindingContext): String? {
|
||||
@@ -647,7 +637,7 @@ private fun generateLambdaForRunSuspend(
|
||||
}
|
||||
|
||||
visitVarInsn(ALOAD, 1)
|
||||
val continuationInternalName = state.languageVersionSettings.continuationAsmType().internalName
|
||||
val continuationInternalName = CONTINUATION_ASM_TYPE.internalName
|
||||
|
||||
visitTypeInsn(
|
||||
CHECKCAST,
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
package org.jetbrains.kotlin.codegen.context
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineUninterceptedOrReturn
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.codegen.OwnerKind
|
||||
import org.jetbrains.kotlin.codegen.binding.MutableClosure
|
||||
import org.jetbrains.kotlin.config.coroutinesPackageFqName
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.isTopLevelInPackage
|
||||
@@ -17,25 +17,26 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getParentResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
|
||||
class InlineLambdaContext(
|
||||
functionDescriptor: FunctionDescriptor,
|
||||
contextKind: OwnerKind,
|
||||
parentContext: CodegenContext<*>,
|
||||
closure: MutableClosure?,
|
||||
val isCrossInline: Boolean,
|
||||
private val isPropertyReference: Boolean
|
||||
functionDescriptor: FunctionDescriptor,
|
||||
contextKind: OwnerKind,
|
||||
parentContext: CodegenContext<*>,
|
||||
closure: MutableClosure?,
|
||||
val isCrossInline: Boolean,
|
||||
private val isPropertyReference: Boolean
|
||||
) : MethodContext(functionDescriptor, contextKind, parentContext, closure, false) {
|
||||
|
||||
override fun getFirstCrossInlineOrNonInlineContext(): CodegenContext<*> {
|
||||
if (isCrossInline && !isSuspendIntrinsicParameter()) return this
|
||||
|
||||
val parent = if (isPropertyReference) parentContext as? AnonymousClassContext else { parentContext as? ClosureContext } ?:
|
||||
throw AssertionError(
|
||||
"Parent of inlining lambda body should be " +
|
||||
"${if (isPropertyReference) "ClosureContext" else "AnonymousClassContext"}, but: $parentContext"
|
||||
)
|
||||
val parent = if (isPropertyReference) parentContext as? AnonymousClassContext else {
|
||||
parentContext as? ClosureContext
|
||||
} ?: throw AssertionError(
|
||||
"Parent of inlining lambda body should be " +
|
||||
"${if (isPropertyReference) "ClosureContext" else "AnonymousClassContext"}, but: $parentContext"
|
||||
)
|
||||
|
||||
val grandParent = parent.parentContext ?:
|
||||
throw AssertionError("Parent context of lambda class context should exist: $contextDescriptor")
|
||||
val grandParent =
|
||||
parent.parentContext ?: throw AssertionError("Parent context of lambda class context should exist: $contextDescriptor")
|
||||
return grandParent.firstCrossInlineOrNonInlineContext
|
||||
}
|
||||
|
||||
@@ -44,7 +45,7 @@ class InlineLambdaContext(
|
||||
if (contextDescriptor !is AnonymousFunctionDescriptor) return false
|
||||
val resolvedCall = (contextDescriptor.source.getPsi() as? KtElement).getParentResolvedCall(state.bindingContext) ?: return false
|
||||
val descriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return false
|
||||
return descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(state.languageVersionSettings)
|
||||
|| descriptor.isTopLevelInPackage("suspendCoroutine", state.languageVersionSettings.coroutinesPackageFqName().asString())
|
||||
return descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn()
|
||||
|| descriptor.isTopLevelInPackage("suspendCoroutine", StandardNames.COROUTINES_PACKAGE_FQ_NAME.asString())
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.coroutines
|
||||
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.isPrimitiveBoxing
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
@@ -15,10 +16,9 @@ import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import java.util.*
|
||||
|
||||
private val BOXING_CLASS_INTERNAL_NAME =
|
||||
RELEASE_COROUTINES_VERSION_SETTINGS.coroutinesJvmInternalPackageFqName().child(Name.identifier("Boxing")).topLevelClassInternalName()
|
||||
StandardNames.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("Boxing")).topLevelClassInternalName()
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
object ChangeBoxingMethodTransformer : MethodTransformer() {
|
||||
|
||||
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.codegen.coroutines
|
||||
|
||||
import com.intellij.util.ArrayUtil
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding.CAPTURES_CROSSINLINE_LAMBDA
|
||||
@@ -17,8 +18,6 @@ import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHO
|
||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
||||
@@ -41,7 +40,6 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
@@ -56,7 +54,7 @@ abstract class AbstractCoroutineCodegen(
|
||||
element: KtElement,
|
||||
closureContext: ClosureContext,
|
||||
classBuilder: ClassBuilder,
|
||||
private val userDataForDoResume: Map<out CallableDescriptor.UserDataKey<*>, *>? = null
|
||||
private val userDataForInvokeSuspend: Map<out CallableDescriptor.UserDataKey<*>, *>? = null
|
||||
) : ClosureCodegen(
|
||||
outerExpressionCodegen.state,
|
||||
element, null, closureContext, null,
|
||||
@@ -67,17 +65,10 @@ abstract class AbstractCoroutineCodegen(
|
||||
protected val languageVersionSettings = outerExpressionCodegen.state.languageVersionSettings
|
||||
|
||||
protected val methodToImplement =
|
||||
if (languageVersionSettings.isReleaseCoroutines())
|
||||
createImplMethod(
|
||||
INVOKE_SUSPEND_METHOD_NAME,
|
||||
SUSPEND_CALL_RESULT_NAME to classDescriptor.module.getResult(classDescriptor.builtIns.anyType)
|
||||
)
|
||||
else
|
||||
createImplMethod(
|
||||
DO_RESUME_METHOD_NAME,
|
||||
"data" to classDescriptor.builtIns.nullableAnyType,
|
||||
"throwable" to classDescriptor.builtIns.throwable.defaultType.makeNullable()
|
||||
)
|
||||
createImplMethod(
|
||||
INVOKE_SUSPEND_METHOD_NAME,
|
||||
SUSPEND_CALL_RESULT_NAME to classDescriptor.module.getResult(classDescriptor.builtIns.anyType)
|
||||
)
|
||||
|
||||
private fun createImplMethod(name: String, vararg parameters: Pair<String, KotlinType>) =
|
||||
SimpleFunctionDescriptorImpl.create(
|
||||
@@ -94,7 +85,7 @@ abstract class AbstractCoroutineCodegen(
|
||||
builtIns.nullableAnyType,
|
||||
Modality.FINAL,
|
||||
DescriptorVisibilities.PUBLIC,
|
||||
userDataForDoResume
|
||||
userDataForInvokeSuspend
|
||||
)
|
||||
}
|
||||
|
||||
@@ -109,7 +100,7 @@ abstract class AbstractCoroutineCodegen(
|
||||
|
||||
override fun generateConstructor(): Method {
|
||||
val args = calculateConstructorParameters(typeMapper, languageVersionSettings, closure, asmType)
|
||||
val argTypes = args.map { it.fieldType }.plus(languageVersionSettings.continuationAsmType()).toTypedArray()
|
||||
val argTypes = args.map { it.fieldType }.plus(CONTINUATION_ASM_TYPE).toTypedArray()
|
||||
|
||||
val constructor = Method("<init>", Type.VOID_TYPE, argTypes)
|
||||
val mv = v.newMethod(
|
||||
@@ -124,18 +115,17 @@ abstract class AbstractCoroutineCodegen(
|
||||
iv.generateClosureFieldsInitializationFromParameters(closure, args)
|
||||
|
||||
iv.load(0, AsmTypes.OBJECT_TYPE)
|
||||
val hasArityParameter = !languageVersionSettings.isReleaseCoroutines() || passArityToSuperClass
|
||||
if (hasArityParameter) {
|
||||
iv.iconst(if (passArityToSuperClass) funDescriptor.arity else 0)
|
||||
if (passArityToSuperClass) {
|
||||
iv.iconst(funDescriptor.arity)
|
||||
}
|
||||
|
||||
iv.load(argTypes.map { it.size }.sum(), AsmTypes.OBJECT_TYPE)
|
||||
|
||||
val parameters =
|
||||
if (hasArityParameter)
|
||||
listOf(Type.INT_TYPE, languageVersionSettings.continuationAsmType())
|
||||
if (passArityToSuperClass)
|
||||
listOf(Type.INT_TYPE, CONTINUATION_ASM_TYPE)
|
||||
else
|
||||
listOf(languageVersionSettings.continuationAsmType())
|
||||
listOf(CONTINUATION_ASM_TYPE)
|
||||
|
||||
val superClassConstructorDescriptor = Type.getMethodDescriptor(
|
||||
Type.VOID_TYPE,
|
||||
@@ -148,9 +138,7 @@ abstract class AbstractCoroutineCodegen(
|
||||
FunctionCodegen.endVisit(iv, "constructor", element)
|
||||
}
|
||||
|
||||
if (languageVersionSettings.isReleaseCoroutines()) {
|
||||
v.newField(JvmDeclarationOrigin.NO_ORIGIN, AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "label", "I", null, null)
|
||||
}
|
||||
v.newField(JvmDeclarationOrigin.NO_ORIGIN, AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "label", "I", null, null)
|
||||
|
||||
return constructor
|
||||
}
|
||||
@@ -167,7 +155,7 @@ class CoroutineCodegenForLambda private constructor(
|
||||
private val forInline: Boolean
|
||||
) : AbstractCoroutineCodegen(
|
||||
outerExpressionCodegen, element, closureContext, classBuilder,
|
||||
userDataForDoResume = mapOf(INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME to originalSuspendFunctionDescriptor)
|
||||
userDataForInvokeSuspend = mapOf(INITIAL_SUSPEND_DESCRIPTOR_FOR_INVOKE_SUSPEND to originalSuspendFunctionDescriptor)
|
||||
) {
|
||||
private val builtIns = funDescriptor.builtIns
|
||||
|
||||
@@ -215,8 +203,7 @@ class CoroutineCodegenForLambda private constructor(
|
||||
funDescriptor.typeParameters,
|
||||
funDescriptor.valueParameters,
|
||||
funDescriptor.module.getContinuationOfTypeOrAny(
|
||||
builtIns.unitType,
|
||||
state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
|
||||
builtIns.unitType
|
||||
),
|
||||
funDescriptor.modality,
|
||||
DescriptorVisibilities.PUBLIC
|
||||
@@ -231,14 +218,11 @@ class CoroutineCodegenForLambda private constructor(
|
||||
"too many arguments of create to have an erased signature: $argumentsNum: $typedCreate"
|
||||
}
|
||||
return typedCreate.module.resolveClassByFqName(
|
||||
languageVersionSettings.coroutinesJvmInternalPackageFqName().child(
|
||||
if (languageVersionSettings.isReleaseCoroutines())
|
||||
Name.identifier("BaseContinuationImpl")
|
||||
else
|
||||
Name.identifier("CoroutineImpl")
|
||||
StandardNames.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(
|
||||
Name.identifier("BaseContinuationImpl")
|
||||
),
|
||||
NoLookupLocation.FROM_BACKEND
|
||||
).sure { "BaseContinuationImpl or CoroutineImpl is not found" }.defaultType.memberScope
|
||||
).sure { "BaseContinuationImpl is not found" }.defaultType.memberScope
|
||||
.getContributedFunctions(typedCreate.name, NoLookupLocation.FROM_BACKEND)
|
||||
.find { it.valueParameters.size == argumentsNum }
|
||||
.sure { "erased parent of $typedCreate is not found" }
|
||||
@@ -365,7 +349,7 @@ class CoroutineCodegenForLambda private constructor(
|
||||
v.thisName,
|
||||
typeMapper.mapFunctionName(createCoroutineDescriptor, null),
|
||||
Type.getMethodDescriptor(
|
||||
languageVersionSettings.continuationAsmType(),
|
||||
CONTINUATION_ASM_TYPE,
|
||||
*createArgumentTypes.toTypedArray()
|
||||
),
|
||||
false
|
||||
@@ -373,11 +357,7 @@ class CoroutineCodegenForLambda private constructor(
|
||||
checkcast(Type.getObjectType(v.thisName))
|
||||
|
||||
// .doResume(Unit)
|
||||
if (languageVersionSettings.isReleaseCoroutines()) {
|
||||
invokeInvokeSuspendWithUnit(v.thisName)
|
||||
} else {
|
||||
invokeDoResumeWithUnit(v.thisName)
|
||||
}
|
||||
invokeInvokeSuspendWithUnit(v.thisName)
|
||||
areturn(AsmTypes.OBJECT_TYPE)
|
||||
}
|
||||
|
||||
@@ -540,15 +520,14 @@ class CoroutineCodegenForLambda private constructor(
|
||||
override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor {
|
||||
val stateMachineBuilder = CoroutineTransformerMethodVisitor(
|
||||
mv, access, name, desc, null, null,
|
||||
containingClassInternalName = v.thisName,
|
||||
obtainClassBuilderForCoroutineState = { v },
|
||||
isForNamedFunction = false,
|
||||
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||
disableTailCallOptimizationForFunctionReturningUnit = false,
|
||||
reportSuspensionPointInsideMonitor = { reportSuspensionPointInsideMonitor(element, state, it) },
|
||||
lineNumber = CodegenUtil.getLineNumberForElement(element, false) ?: 0,
|
||||
sourceFile = element.containingKtFile.name,
|
||||
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||
containingClassInternalName = v.thisName,
|
||||
isForNamedFunction = false,
|
||||
languageVersionSettings = languageVersionSettings,
|
||||
disableTailCallOptimizationForFunctionReturningUnit = false,
|
||||
useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS),
|
||||
initialVarsCountByType = varsCountByType
|
||||
)
|
||||
@@ -625,7 +604,7 @@ class CoroutineCodegenForNamedFunction private constructor(
|
||||
private val labelFieldStackValue by lazy {
|
||||
StackValue.field(
|
||||
FieldInfo.createForHiddenField(
|
||||
computeLabelOwner(languageVersionSettings, v.thisName),
|
||||
Type.getObjectType(v.thisName),
|
||||
Type.INT_TYPE,
|
||||
COROUTINE_LABEL_FIELD_NAME
|
||||
),
|
||||
@@ -647,44 +626,25 @@ class CoroutineCodegenForNamedFunction private constructor(
|
||||
}
|
||||
|
||||
override fun generateClosureBody() {
|
||||
generateResumeImpl()
|
||||
|
||||
if (!languageVersionSettings.isReleaseCoroutines()) {
|
||||
generateGetLabelMethod()
|
||||
generateSetLabelMethod()
|
||||
}
|
||||
generateInvokeSuspend()
|
||||
|
||||
v.newField(
|
||||
JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_SYNTHETIC or AsmUtil.NO_FLAG_PACKAGE_PRIVATE,
|
||||
languageVersionSettings.dataFieldName(), AsmTypes.OBJECT_TYPE.descriptor, null, null
|
||||
CONTINUATION_RESULT_FIELD_NAME, AsmTypes.OBJECT_TYPE.descriptor, null, null
|
||||
)
|
||||
|
||||
if (!languageVersionSettings.isReleaseCoroutines()) {
|
||||
v.newField(
|
||||
JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_SYNTHETIC or AsmUtil.NO_FLAG_PACKAGE_PRIVATE,
|
||||
EXCEPTION_FIELD_NAME, AsmTypes.JAVA_THROWABLE_TYPE.descriptor, null, null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateResumeImpl() {
|
||||
private fun generateInvokeSuspend() {
|
||||
functionCodegen.generateMethod(
|
||||
OtherOrigin(element),
|
||||
methodToImplement,
|
||||
object : FunctionGenerationStrategy.CodegenBased(state) {
|
||||
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
|
||||
StackValue.field(
|
||||
AsmTypes.OBJECT_TYPE, Type.getObjectType(v.thisName), languageVersionSettings.dataFieldName(), false,
|
||||
AsmTypes.OBJECT_TYPE, Type.getObjectType(v.thisName), CONTINUATION_RESULT_FIELD_NAME, false,
|
||||
StackValue.LOCAL_0
|
||||
).store(StackValue.local(1, AsmTypes.OBJECT_TYPE), codegen.v)
|
||||
|
||||
if (!languageVersionSettings.isReleaseCoroutines()) {
|
||||
StackValue.field(
|
||||
AsmTypes.JAVA_THROWABLE_TYPE, Type.getObjectType(v.thisName), EXCEPTION_FIELD_NAME, false,
|
||||
StackValue.LOCAL_0
|
||||
).store(StackValue.local(2, AsmTypes.JAVA_THROWABLE_TYPE), codegen.v)
|
||||
}
|
||||
|
||||
labelFieldStackValue.store(
|
||||
StackValue.operation(Type.INT_TYPE) {
|
||||
labelFieldStackValue.put(Type.INT_TYPE, it)
|
||||
@@ -736,7 +696,7 @@ class CoroutineCodegenForNamedFunction private constructor(
|
||||
with(codegen.v) {
|
||||
// We need to box the returned inline class in resume path.
|
||||
// But first, check for COROUTINE_SUSPENDED, since the function can return it
|
||||
generateCoroutineSuspendedCheck(languageVersionSettings)
|
||||
generateCoroutineSuspendedCheck()
|
||||
// Now we box the inline class
|
||||
StackValue.coerce(AsmTypes.OBJECT_TYPE, typeMapper.mapType(inlineClassToBoxInInvokeSuspend), this)
|
||||
StackValue.boxInlineClass(inlineClassToBoxInInvokeSuspend, this, typeMapper)
|
||||
|
||||
@@ -9,15 +9,10 @@ import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.inline.*
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.*
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
@@ -49,7 +44,6 @@ class CoroutineTransformerMethodVisitor(
|
||||
obtainClassBuilderForCoroutineState: () -> ClassBuilder,
|
||||
private val isForNamedFunction: Boolean,
|
||||
private val shouldPreserveClassInitialization: Boolean,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
// Since tail-call optimization of functions with Unit return type relies on ability of call-site to recognize them,
|
||||
// in order to ignore return value and push Unit, when we cannot ensure this ability, for example, when the function overrides function,
|
||||
// returning Any, we need to disable tail-call optimization for these functions.
|
||||
@@ -73,7 +67,6 @@ class CoroutineTransformerMethodVisitor(
|
||||
|
||||
private var continuationIndex = if (isForNamedFunction) -1 else 0
|
||||
private var dataIndex = if (isForNamedFunction) -1 else 1
|
||||
private var exceptionIndex = if (isForNamedFunction || languageVersionSettings.isReleaseCoroutines()) -1 else 2
|
||||
|
||||
override fun performTransformations(methodNode: MethodNode) {
|
||||
removeFakeContinuationConstructorCall(methodNode)
|
||||
@@ -89,9 +82,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
val suspensionPoints = collectSuspensionPoints(methodNode)
|
||||
RedundantLocalsEliminationMethodTransformer(suspensionPoints)
|
||||
.transform(containingClassInternalName, methodNode)
|
||||
if (languageVersionSettings.isReleaseCoroutines()) {
|
||||
ChangeBoxingMethodTransformer.transform(containingClassInternalName, methodNode)
|
||||
}
|
||||
ChangeBoxingMethodTransformer.transform(containingClassInternalName, methodNode)
|
||||
updateMaxStack(methodNode)
|
||||
|
||||
checkForSuspensionPointInsideMonitor(methodNode, suspensionPoints)
|
||||
@@ -105,7 +96,6 @@ class CoroutineTransformerMethodVisitor(
|
||||
}
|
||||
|
||||
val examiner = MethodNodeExaminer(
|
||||
languageVersionSettings,
|
||||
containingClassInternalName,
|
||||
methodNode,
|
||||
suspensionPoints,
|
||||
@@ -119,9 +109,6 @@ class CoroutineTransformerMethodVisitor(
|
||||
}
|
||||
|
||||
dataIndex = methodNode.maxLocals++
|
||||
if (!languageVersionSettings.isReleaseCoroutines()) {
|
||||
exceptionIndex = methodNode.maxLocals++
|
||||
}
|
||||
continuationIndex = methodNode.maxLocals++
|
||||
|
||||
prepareMethodNodePreludeForNamedFunction(methodNode)
|
||||
@@ -158,7 +145,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
insertBefore(
|
||||
actualCoroutineStart,
|
||||
insnListOf(
|
||||
*withInstructionAdapter { loadCoroutineSuspendedMarker(languageVersionSettings) }.toArray(),
|
||||
*withInstructionAdapter { loadCoroutineSuspendedMarker() }.toArray(),
|
||||
tableSwitchLabel,
|
||||
// Allow debugger to stop on enter into suspend function
|
||||
LineNumberNode(lineNumber, tableSwitchLabel),
|
||||
@@ -176,7 +163,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
)
|
||||
|
||||
insert(firstStateLabel, withInstructionAdapter {
|
||||
generateResumeWithExceptionCheck(languageVersionSettings.isReleaseCoroutines(), dataIndex, exceptionIndex)
|
||||
generateResumeWithExceptionCheck(dataIndex)
|
||||
})
|
||||
insert(last, defaultLabel)
|
||||
|
||||
@@ -192,11 +179,9 @@ class CoroutineTransformerMethodVisitor(
|
||||
dropUnboxInlineClassMarkers(methodNode, suspensionPoints)
|
||||
methodNode.removeEmptyCatchBlocks()
|
||||
|
||||
updateLvtAccordingToLiveness(methodNode, isForNamedFunction)
|
||||
updateLvtAccordingToLiveness(methodNode, isForNamedFunction, stateLabels)
|
||||
|
||||
if (languageVersionSettings.isReleaseCoroutines()) {
|
||||
writeDebugMetadata(methodNode, suspensionPointLineNumbers, spilledToVariableMapping)
|
||||
}
|
||||
writeDebugMetadata(methodNode, suspensionPointLineNumbers, spilledToVariableMapping)
|
||||
}
|
||||
|
||||
// When suspension point is inlined, it is in range of fake inliner variables.
|
||||
@@ -263,7 +248,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
methodNode.localVariables.add(
|
||||
LocalVariableNode(
|
||||
SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME,
|
||||
languageVersionSettings.continuationAsmType().descriptor,
|
||||
CONTINUATION_ASM_TYPE.descriptor,
|
||||
null,
|
||||
startLabel,
|
||||
endLabel,
|
||||
@@ -402,7 +387,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
methodNode.instructions.add(withInstructionAdapter { mark(endLabel) })
|
||||
methodNode.visitLocalVariable(
|
||||
CONTINUATION_VARIABLE_NAME,
|
||||
languageVersionSettings.continuationAsmType().descriptor,
|
||||
CONTINUATION_ASM_TYPE.descriptor,
|
||||
null,
|
||||
startLabel,
|
||||
endLabel,
|
||||
@@ -430,33 +415,17 @@ class CoroutineTransformerMethodVisitor(
|
||||
}
|
||||
|
||||
private fun InstructionAdapter.getLabel() {
|
||||
if (isForNamedFunction && !languageVersionSettings.isReleaseCoroutines())
|
||||
invokevirtual(
|
||||
classBuilderForCoroutineState.thisName,
|
||||
"getLabel",
|
||||
Type.getMethodDescriptor(Type.INT_TYPE),
|
||||
false
|
||||
)
|
||||
else
|
||||
getfield(
|
||||
computeLabelOwner(languageVersionSettings, classBuilderForCoroutineState.thisName).internalName,
|
||||
COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor
|
||||
)
|
||||
getfield(
|
||||
Type.getObjectType(classBuilderForCoroutineState.thisName).internalName,
|
||||
COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor
|
||||
)
|
||||
}
|
||||
|
||||
private fun InstructionAdapter.setLabel() {
|
||||
if (isForNamedFunction && !languageVersionSettings.isReleaseCoroutines())
|
||||
invokevirtual(
|
||||
classBuilderForCoroutineState.thisName,
|
||||
"setLabel",
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE),
|
||||
false
|
||||
)
|
||||
else
|
||||
putfield(
|
||||
computeLabelOwner(languageVersionSettings, classBuilderForCoroutineState.thisName).internalName,
|
||||
COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor
|
||||
)
|
||||
putfield(
|
||||
Type.getObjectType(classBuilderForCoroutineState.thisName).internalName,
|
||||
COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateMaxStack(methodNode: MethodNode) {
|
||||
@@ -534,8 +503,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
needDispatchReceiver,
|
||||
internalNameForDispatchReceiver,
|
||||
containingClassInternalName,
|
||||
classBuilderForCoroutineState,
|
||||
languageVersionSettings
|
||||
classBuilderForCoroutineState
|
||||
)
|
||||
|
||||
visitVarInsn(Opcodes.ASTORE, continuationIndex)
|
||||
@@ -543,19 +511,13 @@ class CoroutineTransformerMethodVisitor(
|
||||
visitLabel(afterCoroutineStateCreated)
|
||||
|
||||
visitVarInsn(Opcodes.ALOAD, continuationIndex)
|
||||
getfield(classBuilderForCoroutineState.thisName, languageVersionSettings.dataFieldName(), AsmTypes.OBJECT_TYPE.descriptor)
|
||||
getfield(classBuilderForCoroutineState.thisName, CONTINUATION_RESULT_FIELD_NAME, AsmTypes.OBJECT_TYPE.descriptor)
|
||||
visitVarInsn(Opcodes.ASTORE, dataIndex)
|
||||
|
||||
val resultStartLabel = Label()
|
||||
visitLabel(resultStartLabel)
|
||||
|
||||
addContinuationAndResultToLvt(methodNode, afterCoroutineStateCreated, resultStartLabel)
|
||||
|
||||
if (!languageVersionSettings.isReleaseCoroutines()) {
|
||||
visitVarInsn(Opcodes.ALOAD, continuationIndex)
|
||||
getfield(classBuilderForCoroutineState.thisName, EXCEPTION_FIELD_NAME, AsmTypes.JAVA_THROWABLE_TYPE.descriptor)
|
||||
visitVarInsn(Opcodes.ASTORE, exceptionIndex)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -692,7 +654,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
// k + 1 - data
|
||||
// k + 2 - exception
|
||||
for (slot in 0 until localsCount) {
|
||||
if (slot == continuationIndex || slot == dataIndex || slot == exceptionIndex) continue
|
||||
if (slot == continuationIndex || slot == dataIndex) continue
|
||||
val value = frame.getLocal(slot)
|
||||
if (value.type == null || !livenessFrame.isAlive(slot)) continue
|
||||
|
||||
@@ -992,7 +954,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
|
||||
insert(possibleTryCatchBlockStart, withInstructionAdapter {
|
||||
nop()
|
||||
generateResumeWithExceptionCheck(languageVersionSettings.isReleaseCoroutines(), dataIndex, exceptionIndex)
|
||||
generateResumeWithExceptionCheck(dataIndex)
|
||||
|
||||
// Load continuation argument just like suspending function returns it
|
||||
load(dataIndex, AsmTypes.OBJECT_TYPE)
|
||||
@@ -1118,8 +1080,7 @@ internal fun InstructionAdapter.generateContinuationConstructorCall(
|
||||
needDispatchReceiver: Boolean,
|
||||
internalNameForDispatchReceiver: String?,
|
||||
containingClassInternalName: String,
|
||||
classBuilderForCoroutineState: ClassBuilder,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
classBuilderForCoroutineState: ClassBuilder
|
||||
) {
|
||||
anew(objectTypeForState)
|
||||
dup()
|
||||
@@ -1128,8 +1089,7 @@ internal fun InstructionAdapter.generateContinuationConstructorCall(
|
||||
getParameterTypesIndicesForCoroutineConstructor(
|
||||
methodNode.desc,
|
||||
methodNode.access,
|
||||
needDispatchReceiver, internalNameForDispatchReceiver ?: containingClassInternalName,
|
||||
languageVersionSettings
|
||||
needDispatchReceiver, internalNameForDispatchReceiver ?: containingClassInternalName
|
||||
)
|
||||
for ((type, index) in parameterTypesAndIndices) {
|
||||
load(index, type)
|
||||
@@ -1149,22 +1109,11 @@ internal fun InstructionAdapter.generateContinuationConstructorCall(
|
||||
)
|
||||
}
|
||||
|
||||
private fun InstructionAdapter.generateResumeWithExceptionCheck(isReleaseCoroutines: Boolean, dataIndex: Int, exceptionIndex: Int) {
|
||||
private fun InstructionAdapter.generateResumeWithExceptionCheck(dataIndex: Int) {
|
||||
// Check if resumeWithException has been called
|
||||
|
||||
if (isReleaseCoroutines) {
|
||||
load(dataIndex, AsmTypes.OBJECT_TYPE)
|
||||
invokestatic("kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V", false)
|
||||
} else {
|
||||
load(exceptionIndex, AsmTypes.OBJECT_TYPE)
|
||||
dup()
|
||||
val noExceptionLabel = Label()
|
||||
ifnull(noExceptionLabel)
|
||||
athrow()
|
||||
|
||||
mark(noExceptionLabel)
|
||||
pop()
|
||||
}
|
||||
load(dataIndex, AsmTypes.OBJECT_TYPE)
|
||||
invokestatic("kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V", false)
|
||||
}
|
||||
|
||||
private fun Type.fieldNameForVar(index: Int) = descriptor.first() + "$" + index
|
||||
@@ -1235,16 +1184,15 @@ private fun getParameterTypesIndicesForCoroutineConstructor(
|
||||
desc: String,
|
||||
containingFunctionAccess: Int,
|
||||
needDispatchReceiver: Boolean,
|
||||
thisName: String,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
thisName: String
|
||||
): Collection<Pair<Type, Int>> {
|
||||
return mutableListOf<Pair<Type, Int>>().apply {
|
||||
if (needDispatchReceiver) {
|
||||
add(Type.getObjectType(thisName) to 0)
|
||||
}
|
||||
val continuationIndex =
|
||||
getAllParameterTypes(desc, !isStatic(containingFunctionAccess), thisName).dropLast(1).map(Type::getSize).sum()
|
||||
add(languageVersionSettings.continuationAsmType() to continuationIndex)
|
||||
getAllParameterTypes(desc, !isStatic(containingFunctionAccess), thisName).dropLast(1).sumOf(Type::getSize)
|
||||
add(CONTINUATION_ASM_TYPE to continuationIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1269,7 +1217,7 @@ private fun MethodNode.nodeTextWithLiveness(liveness: List<VariableLivenessFrame
|
||||
* This means, that function parameters do not longer span the whole function, including `this`.
|
||||
* This might and will break some bytecode processors, including old versions of R8. See KT-24510.
|
||||
*/
|
||||
private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction: Boolean) {
|
||||
private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction: Boolean, suspensionPoints: List<LabelNode>) {
|
||||
val liveness = analyzeLiveness(method)
|
||||
|
||||
fun List<LocalVariableNode>.findRecord(insnIndex: Int, variableIndex: Int): LocalVariableNode? {
|
||||
@@ -1288,8 +1236,8 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
|
||||
fun nextLabel(node: AbstractInsnNode?): LabelNode? {
|
||||
var current = node
|
||||
while (current != null) {
|
||||
if (current is LabelNode) return current as LabelNode
|
||||
current = current!!.next
|
||||
if (current is LabelNode) return current
|
||||
current = current.next
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -1346,33 +1294,17 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
|
||||
|
||||
// Attempt to extend existing local variable node corresponding to the record in
|
||||
// the original local variable table, if there is no back-edge
|
||||
val recordToExtend: LocalVariableNode? = oldLvtNodeToLatestNewLvtNode[lvtRecord]
|
||||
var recordExtended = false
|
||||
if (recordToExtend != null) {
|
||||
var hasBackEdgeOrStore = false
|
||||
var current: AbstractInsnNode? = recordToExtend.end
|
||||
while (current != null && current != endLabel) {
|
||||
if (current is JumpInsnNode) {
|
||||
if (method.instructions.indexOf((current as JumpInsnNode).label) < method.instructions.indexOf(current)) {
|
||||
hasBackEdgeOrStore = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (current!!.isStoreOperation() && (current as VarInsnNode).`var` == recordToExtend.index) {
|
||||
hasBackEdgeOrStore = true
|
||||
break
|
||||
}
|
||||
current = current!!.next
|
||||
}
|
||||
if (!hasBackEdgeOrStore) {
|
||||
recordToExtend.end = endLabel
|
||||
recordExtended = true
|
||||
}
|
||||
}
|
||||
if (!recordExtended) {
|
||||
val node = LocalVariableNode(lvtRecord.name, lvtRecord.desc, lvtRecord.signature, startLabel, endLabel, lvtRecord.index)
|
||||
method.localVariables.add(node)
|
||||
oldLvtNodeToLatestNewLvtNode[lvtRecord] = node
|
||||
val latest = oldLvtNodeToLatestNewLvtNode[lvtRecord]
|
||||
// if we can extend the previous range to where the local variable dies, we do not need a
|
||||
// new entry, we know we cannot extend it to the lvt.endOffset, if we could we would have
|
||||
// done so when we added it below.
|
||||
val extended = latest?.extendRecordIfPossible(method, suspensionPoints, lvtRecord.end) ?: false
|
||||
if (!extended) {
|
||||
val new = LocalVariableNode(lvtRecord.name, lvtRecord.desc, lvtRecord.signature, startLabel, endLabel, lvtRecord.index)
|
||||
oldLvtNodeToLatestNewLvtNode[lvtRecord] = new
|
||||
method.localVariables.add(new)
|
||||
// see if we can extend it all the way to the old end
|
||||
new.extendRecordIfPossible(method, suspensionPoints, lvtRecord.end)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1395,3 +1327,35 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We cannot extend a record if there is STORE instruction or a back-edge.
|
||||
* STORE instructions can signify a unspilling operation, in which case, the variable will become visible before it unspilled,
|
||||
* back-edges occur in loops.
|
||||
*
|
||||
* @return true if the range has been extended
|
||||
*/
|
||||
private fun LocalVariableNode.extendRecordIfPossible(
|
||||
method: MethodNode,
|
||||
suspensionPoints: List<LabelNode>,
|
||||
endLabel: LabelNode
|
||||
): Boolean {
|
||||
val nextSuspensionPointLabel = suspensionPoints.find { it in InsnSequence(end, endLabel) } ?: endLabel
|
||||
|
||||
var current: AbstractInsnNode? = end
|
||||
while (current != null && current != nextSuspensionPointLabel) {
|
||||
if (current is JumpInsnNode) {
|
||||
if (method.instructions.indexOf(current.label) < method.instructions.indexOf(current)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// TODO: HACK
|
||||
// TODO: Find correct label, which is OK to be used as end label.
|
||||
if (current.opcode == Opcodes.ARETURN && nextSuspensionPointLabel != endLabel) return false
|
||||
if (current.isStoreOperation() && (current as VarInsnNode).`var` == index) {
|
||||
return false
|
||||
}
|
||||
current = current.next
|
||||
}
|
||||
end = nextSuspensionPointLabel
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -88,18 +88,17 @@ class SuspendFunctionGenerationStrategy(
|
||||
return CoroutineTransformerMethodVisitor(
|
||||
mv, access, name, desc, null, null, containingClassInternalName, this::classBuilderForCoroutineState,
|
||||
isForNamedFunction = true,
|
||||
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||
disableTailCallOptimizationForFunctionReturningUnit = originalSuspendDescriptor.returnType?.isUnit() == true &&
|
||||
originalSuspendDescriptor.overriddenDescriptors.isNotEmpty() &&
|
||||
!originalSuspendDescriptor.allOverriddenFunctionsReturnUnit(),
|
||||
reportSuspensionPointInsideMonitor = { reportSuspensionPointInsideMonitor(declaration, state, it) },
|
||||
lineNumber = CodegenUtil.getLineNumberForElement(declaration, false) ?: 0,
|
||||
sourceFile = declaration.containingKtFile.name,
|
||||
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||
needDispatchReceiver = originalSuspendDescriptor.dispatchReceiverParameter != null,
|
||||
internalNameForDispatchReceiver = (originalSuspendDescriptor.containingDeclaration as? ClassDescriptor)?.let {
|
||||
if (it.isInlineClass()) state.typeMapper.mapType(it).internalName else null
|
||||
} ?: containingClassInternalNameOrNull(),
|
||||
languageVersionSettings = languageVersionSettings,
|
||||
disableTailCallOptimizationForFunctionReturningUnit = originalSuspendDescriptor.returnType?.isUnit() == true &&
|
||||
originalSuspendDescriptor.overriddenDescriptors.isNotEmpty() &&
|
||||
!originalSuspendDescriptor.allOverriddenFunctionsReturnUnit(),
|
||||
useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS)
|
||||
)
|
||||
}
|
||||
@@ -155,8 +154,7 @@ class SuspendFunctionGenerationStrategy(
|
||||
needDispatchReceiver,
|
||||
internalNameForDispatchReceiver,
|
||||
containingClassInternalName,
|
||||
classBuilderForCoroutineState,
|
||||
languageVersionSettings
|
||||
classBuilderForCoroutineState
|
||||
)
|
||||
addFakeContinuationConstructorCallMarker(this, false)
|
||||
pop() // Otherwise stack-transformation breaks
|
||||
|
||||
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.codegen.optimization.common.asSequence
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
@@ -27,7 +26,6 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
|
||||
internal class MethodNodeExaminer(
|
||||
val languageVersionSettings: LanguageVersionSettings,
|
||||
containingClassInternalName: String,
|
||||
val methodNode: MethodNode,
|
||||
suspensionPoints: List<SuspensionPoint>,
|
||||
@@ -116,7 +114,7 @@ internal class MethodNodeExaminer(
|
||||
val label = Label()
|
||||
methodNode.instructions.insertBefore(pop, withInstructionAdapter {
|
||||
dup()
|
||||
loadCoroutineSuspendedMarker(languageVersionSettings)
|
||||
loadCoroutineSuspendedMarker()
|
||||
ifacmpne(label)
|
||||
areturn(AsmTypes.OBJECT_TYPE)
|
||||
mark(label)
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.backend.common.COROUTINE_SUSPENDED_NAME
|
||||
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineUninterceptedOrReturn
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.builtins.StandardNames.COROUTINES_INTRINSICS_PACKAGE_FQ_NAME
|
||||
import org.jetbrains.kotlin.builtins.StandardNames.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME
|
||||
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalClassDescriptor
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
@@ -54,67 +56,27 @@ import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
const val COROUTINE_LABEL_FIELD_NAME = "label"
|
||||
const val SUSPEND_FUNCTION_CREATE_METHOD_NAME = "create"
|
||||
const val DO_RESUME_METHOD_NAME = "doResume"
|
||||
const val INVOKE_SUSPEND_METHOD_NAME = "invokeSuspend"
|
||||
const val EXCEPTION_FIELD_NAME = "exception"
|
||||
const val CONTINUATION_RESULT_FIELD_NAME = "result"
|
||||
|
||||
val RELEASE_COROUTINES_VERSION_SETTINGS = LanguageVersionSettingsImpl(LanguageVersion.KOTLIN_1_3, ApiVersion.KOTLIN_1_3)
|
||||
private const val GET_CONTEXT_METHOD_NAME = "getContext"
|
||||
|
||||
fun LanguageVersionSettings.isResumeImplMethodName(name: String) =
|
||||
if (isReleaseCoroutines())
|
||||
name == INVOKE_SUSPEND_METHOD_NAME
|
||||
else
|
||||
name == DO_RESUME_METHOD_NAME
|
||||
val DEBUG_METADATA_ANNOTATION_ASM_TYPE: Type =
|
||||
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("DebugMetadata")).topLevelClassAsmType()
|
||||
|
||||
fun LanguageVersionSettings.dataFieldName(): String = if (isReleaseCoroutines()) "result" else "data"
|
||||
fun coroutineContextAsmType(): Type =
|
||||
StandardNames.COROUTINES_PACKAGE_FQ_NAME.child(Name.identifier("CoroutineContext")).topLevelClassAsmType()
|
||||
|
||||
fun isResumeImplMethodNameFromAnyLanguageSettings(name: String) = name == INVOKE_SUSPEND_METHOD_NAME || name == DO_RESUME_METHOD_NAME
|
||||
|
||||
fun LanguageVersionSettings.coroutinesJvmInternalPackageFqName() =
|
||||
coroutinesPackageFqName().child(Name.identifier("jvm")).child(Name.identifier("internal"))
|
||||
|
||||
val DEBUG_METADATA_ANNOTATION_ASM_TYPE = RELEASE_COROUTINES_VERSION_SETTINGS.coroutinesJvmInternalPackageFqName()
|
||||
.child(Name.identifier("DebugMetadata")).topLevelClassAsmType()
|
||||
|
||||
fun LanguageVersionSettings.continuationAsmType() =
|
||||
continuationInterfaceFqName().topLevelClassAsmType()
|
||||
|
||||
fun continuationAsmTypes() = listOf(
|
||||
LanguageVersionSettingsImpl(LanguageVersion.KOTLIN_1_3, ApiVersion.KOTLIN_1_3).continuationAsmType(),
|
||||
LanguageVersionSettingsImpl(LanguageVersion.KOTLIN_1_2, ApiVersion.KOTLIN_1_2).continuationAsmType()
|
||||
)
|
||||
|
||||
fun LanguageVersionSettings.coroutineContextAsmType() =
|
||||
coroutinesPackageFqName().child(Name.identifier("CoroutineContext")).topLevelClassAsmType()
|
||||
|
||||
fun LanguageVersionSettings.isCoroutineSuperClass(internalName: String): Boolean {
|
||||
val coroutinesJvmInternalPackage = coroutinesJvmInternalPackageFqName()
|
||||
|
||||
return if (isReleaseCoroutines())
|
||||
coroutinesJvmInternalPackage.identifiedChild("ContinuationImpl") == internalName ||
|
||||
coroutinesJvmInternalPackage.identifiedChild("RestrictedContinuationImpl") == internalName ||
|
||||
coroutinesJvmInternalPackage.identifiedChild("SuspendLambda") == internalName ||
|
||||
coroutinesJvmInternalPackage.identifiedChild("RestrictedSuspendLambda") == internalName
|
||||
else
|
||||
coroutinesJvmInternalPackage.identifiedChild("CoroutineImpl") == internalName
|
||||
}
|
||||
fun String.isCoroutineSuperClass(): Boolean =
|
||||
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.identifiedChild("ContinuationImpl") == this ||
|
||||
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.identifiedChild("RestrictedContinuationImpl") == this ||
|
||||
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.identifiedChild("SuspendLambda") == this ||
|
||||
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.identifiedChild("RestrictedSuspendLambda") == this
|
||||
|
||||
private fun FqName.identifiedChild(name: String) = child(Name.identifier(name)).topLevelClassInternalName()
|
||||
|
||||
private fun LanguageVersionSettings.coroutinesIntrinsicsFileFacadeInternalName() =
|
||||
coroutinesIntrinsicsPackageFqName().child(Name.identifier("IntrinsicsKt")).topLevelClassAsmType()
|
||||
|
||||
private fun LanguageVersionSettings.internalCoroutineIntrinsicsOwnerInternalName() =
|
||||
coroutinesJvmInternalPackageFqName().child(Name.identifier("CoroutineIntrinsics")).topLevelClassInternalName()
|
||||
|
||||
fun computeLabelOwner(languageVersionSettings: LanguageVersionSettings, thisName: String): Type =
|
||||
if (languageVersionSettings.isReleaseCoroutines())
|
||||
Type.getObjectType(thisName)
|
||||
else
|
||||
languageVersionSettings.coroutinesJvmInternalPackageFqName().child(Name.identifier("CoroutineImpl")).topLevelClassAsmType()
|
||||
|
||||
private const val NORMALIZE_CONTINUATION_METHOD_NAME = "normalizeContinuation"
|
||||
private const val GET_CONTEXT_METHOD_NAME = "getContext"
|
||||
private val coroutinesIntrinsicsFileFacadeInternalName: Type =
|
||||
COROUTINES_INTRINSICS_PACKAGE_FQ_NAME.child(Name.identifier("IntrinsicsKt")).topLevelClassAsmType()
|
||||
|
||||
data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val fakeContinuationExpression: KtExpression)
|
||||
|
||||
@@ -122,7 +84,7 @@ data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val
|
||||
val INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION = object : CallableDescriptor.UserDataKey<FunctionDescriptor> {}
|
||||
|
||||
@JvmField
|
||||
val INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME = object : CallableDescriptor.UserDataKey<FunctionDescriptor> {}
|
||||
val INITIAL_SUSPEND_DESCRIPTOR_FOR_INVOKE_SUSPEND = object : CallableDescriptor.UserDataKey<FunctionDescriptor> {}
|
||||
|
||||
val CONTINUATION_PARAMETER_NAME = Name.identifier("continuation")
|
||||
|
||||
@@ -158,9 +120,9 @@ fun ResolvedCall<*>.replaceSuspensionFunctionWithRealDescriptor(
|
||||
val newCandidateDescriptor =
|
||||
when (function) {
|
||||
is FunctionImportedFromObject ->
|
||||
getOrCreateJvmSuspendFunctionView(function.callableFromObject, isReleaseCoroutines, bindingContext).asImportedFromObject()
|
||||
getOrCreateJvmSuspendFunctionView(function.callableFromObject, bindingContext).asImportedFromObject()
|
||||
is SimpleFunctionDescriptor ->
|
||||
getOrCreateJvmSuspendFunctionView(function, isReleaseCoroutines, bindingContext)
|
||||
getOrCreateJvmSuspendFunctionView(function, bindingContext)
|
||||
else ->
|
||||
throw AssertionError("Unexpected suspend function descriptor: $function")
|
||||
}
|
||||
@@ -223,10 +185,10 @@ private fun NewResolvedCallImpl<VariableDescriptor>.asDummyOldResolvedCall(bindi
|
||||
|
||||
enum class SuspensionPointKind { NEVER, NOT_INLINE, ALWAYS }
|
||||
|
||||
fun ResolvedCall<*>.isSuspensionPoint(codegen: ExpressionCodegen, languageVersionSettings: LanguageVersionSettings): SuspensionPointKind {
|
||||
fun ResolvedCall<*>.isSuspensionPoint(codegen: ExpressionCodegen): SuspensionPointKind {
|
||||
val functionDescriptor = resultingDescriptor as? FunctionDescriptor ?: return SuspensionPointKind.NEVER
|
||||
if (!functionDescriptor.unwrapInitialDescriptorForSuspendFunction().isSuspend) return SuspensionPointKind.NEVER
|
||||
if (functionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm(languageVersionSettings)) return SuspensionPointKind.ALWAYS
|
||||
if (functionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm()) return SuspensionPointKind.ALWAYS
|
||||
if (functionDescriptor.isInline) return SuspensionPointKind.NEVER
|
||||
|
||||
val isInlineLambda = this.safeAs<VariableAsFunctionResolvedCall>()
|
||||
@@ -242,7 +204,6 @@ fun CallableDescriptor.isSuspendFunctionNotSuspensionView(): Boolean {
|
||||
|
||||
fun <D : FunctionDescriptor> getOrCreateJvmSuspendFunctionView(function: D, state: GenerationState): D = getOrCreateJvmSuspendFunctionView(
|
||||
function,
|
||||
state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
|
||||
state.bindingContext
|
||||
)
|
||||
|
||||
@@ -252,7 +213,6 @@ fun <D : FunctionDescriptor> getOrCreateJvmSuspendFunctionView(function: D, stat
|
||||
@JvmOverloads
|
||||
fun <D : FunctionDescriptor> getOrCreateJvmSuspendFunctionView(
|
||||
function: D,
|
||||
isReleaseCoroutines: Boolean,
|
||||
bindingContext: BindingContext? = null
|
||||
): D {
|
||||
assert(function.isSuspend) {
|
||||
@@ -272,7 +232,7 @@ fun <D : FunctionDescriptor> getOrCreateJvmSuspendFunctionView(
|
||||
outType = if (function.containingDeclaration.safeAs<ClassDescriptor>()?.isBuiltinFunctionalClassDescriptor == true)
|
||||
function.builtIns.nullableAnyType
|
||||
else
|
||||
function.getContinuationParameterTypeOfSuspendFunction(isReleaseCoroutines),
|
||||
function.getContinuationParameterTypeOfSuspendFunction(),
|
||||
declaresDefaultValue = false, isCrossinline = false,
|
||||
isNoinline = false, varargElementType = null,
|
||||
source = SourceElement.NO_SOURCE
|
||||
@@ -309,8 +269,7 @@ fun <D : FunctionDescriptor> D.createCustomCopy(
|
||||
return result as D
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.getContinuationParameterTypeOfSuspendFunction(isReleaseCoroutines: Boolean) =
|
||||
module.getContinuationOfTypeOrAny(returnType!!, if (this.needsExperimentalCoroutinesWrapper()) false else isReleaseCoroutines)
|
||||
private fun FunctionDescriptor.getContinuationParameterTypeOfSuspendFunction() = module.getContinuationOfTypeOrAny(returnType!!)
|
||||
|
||||
fun ModuleDescriptor.getResult(kotlinType: KotlinType) =
|
||||
module.resolveTopLevelClass(
|
||||
@@ -323,44 +282,11 @@ fun ModuleDescriptor.getResult(kotlinType: KotlinType) =
|
||||
)
|
||||
} ?: ErrorUtils.createErrorType("For Result")
|
||||
|
||||
private fun MethodNode.invokeNormalizeContinuation(languageVersionSettings: LanguageVersionSettings) {
|
||||
visitMethodInsn(
|
||||
Opcodes.INVOKESTATIC,
|
||||
languageVersionSettings.internalCoroutineIntrinsicsOwnerInternalName(),
|
||||
NORMALIZE_CONTINUATION_METHOD_NAME,
|
||||
Type.getMethodDescriptor(languageVersionSettings.continuationAsmType(), languageVersionSettings.continuationAsmType()),
|
||||
false
|
||||
)
|
||||
}
|
||||
fun FunctionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm() =
|
||||
getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION)?.isBuiltInSuspendCoroutineUninterceptedOrReturn() == true
|
||||
|
||||
fun FunctionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm(languageVersionSettings: LanguageVersionSettings) =
|
||||
getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION)?.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) == true
|
||||
|
||||
fun createMethodNodeForIntercepted(languageVersionSettings: LanguageVersionSettings): MethodNode {
|
||||
val node =
|
||||
MethodNode(
|
||||
Opcodes.API_VERSION,
|
||||
Opcodes.ACC_STATIC,
|
||||
"fake",
|
||||
Type.getMethodDescriptor(languageVersionSettings.continuationAsmType(), languageVersionSettings.continuationAsmType()),
|
||||
null, null
|
||||
)
|
||||
|
||||
node.visitVarInsn(Opcodes.ALOAD, 0)
|
||||
|
||||
node.invokeNormalizeContinuation(languageVersionSettings)
|
||||
|
||||
node.visitInsn(Opcodes.ARETURN)
|
||||
node.visitMaxs(1, 1)
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
fun createMethodNodeForCoroutineContext(
|
||||
functionDescriptor: FunctionDescriptor,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): MethodNode {
|
||||
assert(functionDescriptor.isBuiltInCoroutineContext(languageVersionSettings)) {
|
||||
fun createMethodNodeForCoroutineContext(functionDescriptor: FunctionDescriptor): MethodNode {
|
||||
assert(functionDescriptor.isBuiltInCoroutineContext()) {
|
||||
"functionDescriptor must be kotlin.coroutines.intrinsics.coroutineContext property getter"
|
||||
}
|
||||
|
||||
@@ -369,7 +295,7 @@ fun createMethodNodeForCoroutineContext(
|
||||
Opcodes.API_VERSION,
|
||||
Opcodes.ACC_STATIC,
|
||||
"fake",
|
||||
Type.getMethodDescriptor(languageVersionSettings.coroutineContextAsmType()),
|
||||
Type.getMethodDescriptor(coroutineContextAsmType()),
|
||||
null, null
|
||||
)
|
||||
|
||||
@@ -377,20 +303,20 @@ fun createMethodNodeForCoroutineContext(
|
||||
|
||||
addFakeContinuationMarker(v)
|
||||
|
||||
v.invokeGetContext(languageVersionSettings)
|
||||
v.invokeGetContext()
|
||||
|
||||
node.visitMaxs(1, 1)
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
fun createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSettings: LanguageVersionSettings): MethodNode {
|
||||
fun createMethodNodeForSuspendCoroutineUninterceptedOrReturn(): MethodNode {
|
||||
val node =
|
||||
MethodNode(
|
||||
Opcodes.API_VERSION,
|
||||
Opcodes.ACC_STATIC,
|
||||
"fake",
|
||||
Type.getMethodDescriptor(OBJECT_TYPE, AsmTypes.FUNCTION1, languageVersionSettings.continuationAsmType()),
|
||||
Type.getMethodDescriptor(OBJECT_TYPE, AsmTypes.FUNCTION1, CONTINUATION_ASM_TYPE),
|
||||
null, null
|
||||
)
|
||||
|
||||
@@ -405,25 +331,22 @@ fun createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSett
|
||||
"($OBJECT_TYPE)$OBJECT_TYPE"
|
||||
)
|
||||
|
||||
if (languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)) {
|
||||
val elseLabel = Label()
|
||||
// if (result === COROUTINE_SUSPENDED) {
|
||||
dup()
|
||||
loadCoroutineSuspendedMarker(languageVersionSettings)
|
||||
ifacmpne(elseLabel)
|
||||
// DebugProbesKt.probeCoroutineSuspended(continuation)
|
||||
load(1, OBJECT_TYPE) // continuation
|
||||
checkcast(languageVersionSettings.continuationAsmType())
|
||||
invokestatic(
|
||||
languageVersionSettings.coroutinesJvmInternalPackageFqName().child(Name.identifier("DebugProbesKt"))
|
||||
.topLevelClassAsmType().internalName,
|
||||
"probeCoroutineSuspended",
|
||||
"(${languageVersionSettings.continuationAsmType()})V",
|
||||
false
|
||||
)
|
||||
// }
|
||||
mark(elseLabel)
|
||||
}
|
||||
val elseLabel = Label()
|
||||
// if (result === COROUTINE_SUSPENDED) {
|
||||
dup()
|
||||
loadCoroutineSuspendedMarker()
|
||||
ifacmpne(elseLabel)
|
||||
// DebugProbesKt.probeCoroutineSuspended(continuation)
|
||||
load(1, OBJECT_TYPE) // continuation
|
||||
checkcast(CONTINUATION_ASM_TYPE)
|
||||
invokestatic(
|
||||
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("DebugProbesKt")).topLevelClassAsmType().internalName,
|
||||
"probeCoroutineSuspended",
|
||||
"($CONTINUATION_ASM_TYPE)V",
|
||||
false
|
||||
)
|
||||
// }
|
||||
mark(elseLabel)
|
||||
}
|
||||
|
||||
node.visitInsn(Opcodes.ARETURN)
|
||||
@@ -433,13 +356,13 @@ fun createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSett
|
||||
}
|
||||
|
||||
|
||||
private fun InstructionAdapter.invokeGetContext(languageVersionSettings: LanguageVersionSettings) {
|
||||
private fun InstructionAdapter.invokeGetContext() {
|
||||
invokeinterface(
|
||||
languageVersionSettings.continuationAsmType().internalName,
|
||||
CONTINUATION_ASM_TYPE.internalName,
|
||||
GET_CONTEXT_METHOD_NAME,
|
||||
Type.getMethodDescriptor(languageVersionSettings.coroutineContextAsmType())
|
||||
Type.getMethodDescriptor(coroutineContextAsmType())
|
||||
)
|
||||
areturn(languageVersionSettings.coroutineContextAsmType())
|
||||
areturn(coroutineContextAsmType())
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@@ -447,15 +370,12 @@ fun <D : CallableDescriptor?> D.unwrapInitialDescriptorForSuspendFunction(): D =
|
||||
this.safeAs<SimpleFunctionDescriptor>()?.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) as D ?: this
|
||||
|
||||
|
||||
fun FunctionDescriptor.getOriginalSuspendFunctionView(bindingContext: BindingContext, isReleaseCoroutines: Boolean): FunctionDescriptor =
|
||||
fun FunctionDescriptor.getOriginalSuspendFunctionView(bindingContext: BindingContext): FunctionDescriptor =
|
||||
if (isSuspend)
|
||||
getOrCreateJvmSuspendFunctionView(unwrapInitialDescriptorForSuspendFunction().original, isReleaseCoroutines, bindingContext)
|
||||
getOrCreateJvmSuspendFunctionView(unwrapInitialDescriptorForSuspendFunction().original, bindingContext)
|
||||
else
|
||||
this
|
||||
|
||||
fun FunctionDescriptor.getOriginalSuspendFunctionView(bindingContext: BindingContext, state: GenerationState) =
|
||||
getOriginalSuspendFunctionView(bindingContext, state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines))
|
||||
|
||||
// For each suspend function, we have a corresponding JVM view function that has an extra continuation parameter,
|
||||
// and, more importantly, returns 'kotlin.Any' (so that it can return as a reference value or a special COROUTINE_SUSPENDED object).
|
||||
// This also causes boxing of primitives and inline class values.
|
||||
@@ -482,38 +402,24 @@ fun FunctionDescriptor.originalReturnTypeOfSuspendFunctionReturningUnboxedInline
|
||||
return originalReturnType
|
||||
}
|
||||
|
||||
fun InstructionAdapter.loadCoroutineSuspendedMarker(languageVersionSettings: LanguageVersionSettings) {
|
||||
fun InstructionAdapter.loadCoroutineSuspendedMarker() {
|
||||
invokestatic(
|
||||
languageVersionSettings.coroutinesIntrinsicsFileFacadeInternalName().internalName,
|
||||
coroutinesIntrinsicsFileFacadeInternalName.internalName,
|
||||
"get$COROUTINE_SUSPENDED_NAME",
|
||||
Type.getMethodDescriptor(OBJECT_TYPE),
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
fun InstructionAdapter.generateCoroutineSuspendedCheck(languageVersionSettings: LanguageVersionSettings) {
|
||||
fun InstructionAdapter.generateCoroutineSuspendedCheck() {
|
||||
dup()
|
||||
loadCoroutineSuspendedMarker(languageVersionSettings)
|
||||
loadCoroutineSuspendedMarker()
|
||||
val elseLabel = Label()
|
||||
ifacmpne(elseLabel)
|
||||
areturn(OBJECT_TYPE)
|
||||
mark(elseLabel)
|
||||
}
|
||||
|
||||
fun InstructionAdapter.invokeDoResumeWithUnit(thisName: String) {
|
||||
// .doResume(Unit, null)
|
||||
StackValue.putUnitInstance(this)
|
||||
|
||||
aconst(null)
|
||||
|
||||
invokevirtual(
|
||||
thisName,
|
||||
DO_RESUME_METHOD_NAME,
|
||||
Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE, AsmTypes.JAVA_THROWABLE_TYPE),
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
fun InstructionAdapter.invokeInvokeSuspendWithUnit(thisName: String) {
|
||||
StackValue.putUnitInstance(this)
|
||||
|
||||
@@ -537,18 +443,14 @@ fun FunctionDescriptor.isSuspendLambdaOrLocalFunction() = this.isSuspend && when
|
||||
}
|
||||
|
||||
fun FunctionDescriptor.isLocalSuspendFunctionNotSuspendLambda() = isSuspendLambdaOrLocalFunction() && this !is AnonymousFunctionDescriptor
|
||||
|
||||
@JvmField
|
||||
val EXPERIMENTAL_CONTINUATION_ASM_TYPE = StandardNames.CONTINUATION_INTERFACE_FQ_NAME_EXPERIMENTAL.topLevelClassAsmType()
|
||||
|
||||
@JvmField
|
||||
val RELEASE_CONTINUATION_ASM_TYPE = StandardNames.CONTINUATION_INTERFACE_FQ_NAME_RELEASE.topLevelClassAsmType()
|
||||
val CONTINUATION_ASM_TYPE = StandardNames.CONTINUATION_INTERFACE_FQ_NAME.topLevelClassAsmType()
|
||||
|
||||
fun FunctionDescriptor.isInvokeSuspendOfLambda(): Boolean {
|
||||
if (this !is SimpleFunctionDescriptor) return false
|
||||
if (valueParameters.size != 1 ||
|
||||
valueParameters[0].name.asString() != SUSPEND_CALL_RESULT_NAME ||
|
||||
name.asString() != "invokeSuspend"
|
||||
name.asString() != INVOKE_SUSPEND_METHOD_NAME
|
||||
) return false
|
||||
return containingDeclaration is SyntheticClassDescriptorForLambda
|
||||
}
|
||||
@@ -62,7 +62,7 @@ class AnonymousObjectTransformer(
|
||||
createClassReader().accept(object : ClassVisitor(Opcodes.API_VERSION, classBuilder.visitor) {
|
||||
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<String>) {
|
||||
classBuilder.defineClass(null, maxOf(version, state.classFileVersion), access, name, signature, superName, interfaces)
|
||||
if (languageVersionSettings.isCoroutineSuperClass(superName)) {
|
||||
if (superName.isCoroutineSuperClass()) {
|
||||
inliningContext.isContinuation = true
|
||||
}
|
||||
superClassName = superName
|
||||
|
||||
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.isMethodInsnWith
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.removeUnusedLocalVariables
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.updateMaxStack
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
|
||||
class InplaceArgumentsMethodTransformer : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
val methodContext = parseMethodOrNull(methodNode)
|
||||
if (methodContext != null) {
|
||||
if (methodContext.calls.isEmpty()) return
|
||||
|
||||
collectStartToEnd(methodContext)
|
||||
collectLvtEntryInstructions(methodContext)
|
||||
collectSuspensionPoints(methodContext)
|
||||
|
||||
transformMethod(methodContext)
|
||||
updateLvtEntriesForMovedInstructions(methodContext)
|
||||
|
||||
methodNode.removeUnusedLocalVariables()
|
||||
methodNode.updateMaxStack()
|
||||
}
|
||||
stripMarkers(methodNode)
|
||||
}
|
||||
|
||||
private class MethodContext(
|
||||
val methodNode: MethodNode,
|
||||
val calls: List<CallContext>
|
||||
) {
|
||||
val startArgToEndArg = HashMap<AbstractInsnNode, AbstractInsnNode>()
|
||||
val lvtEntryForInstruction = HashMap<AbstractInsnNode, LocalVariableNode>()
|
||||
val varInstructionMoved = HashMap<AbstractInsnNode, CallContext>()
|
||||
val suspensionJumpLabels = HashSet<LabelNode>()
|
||||
}
|
||||
|
||||
private class CallContext(
|
||||
val callStartMarker: AbstractInsnNode,
|
||||
val callEndMarker: AbstractInsnNode,
|
||||
val args: List<ArgContext>,
|
||||
val calls: List<CallContext>,
|
||||
val endLabel: LabelNode
|
||||
)
|
||||
|
||||
private class ArgContext(
|
||||
val argStartMarker: AbstractInsnNode,
|
||||
val argEndMarker: AbstractInsnNode,
|
||||
val calls: List<CallContext>,
|
||||
val storeInsn: VarInsnNode
|
||||
) {
|
||||
val loadOpcode = storeInsn.opcode - Opcodes.ISTORE + Opcodes.ILOAD
|
||||
|
||||
val varIndex = storeInsn.`var`
|
||||
}
|
||||
|
||||
private fun parseMethodOrNull(methodNode: MethodNode): MethodContext? {
|
||||
// We assume that the method body structure follows this grammar:
|
||||
// METHOD ::= insn* (CALL insn*)*
|
||||
// CALL ::= callStartMarker insn* (ARG insn*)* (CALL insn*)* callEndMarker
|
||||
// ARG ::= argStartMarker insn* (CALL insn*)* argEndMarker storeInsn
|
||||
|
||||
val iter = methodNode.instructions.iterator()
|
||||
val calls = ArrayList<CallContext>()
|
||||
try {
|
||||
while (iter.hasNext()) {
|
||||
val insn = iter.next()
|
||||
when {
|
||||
insn.isInplaceCallStartMarker() ->
|
||||
calls.add(parseCall(methodNode, insn, iter))
|
||||
insn.isInplaceCallEndMarker() || insn.isInplaceArgumentStartMarker() || insn.isInplaceArgumentEndMarker() ->
|
||||
throw ParseErrorException()
|
||||
}
|
||||
}
|
||||
} catch (e: ParseErrorException) {
|
||||
return null
|
||||
}
|
||||
return MethodContext(methodNode, calls)
|
||||
}
|
||||
|
||||
private fun parseCall(methodNode: MethodNode, start: AbstractInsnNode, iter: ListIterator<AbstractInsnNode>): CallContext {
|
||||
// CALL ::= callStartMarker insn* (ARG insn*)* (CALL insn*)* callEndMarker
|
||||
val args = ArrayList<ArgContext>()
|
||||
val calls = ArrayList<CallContext>()
|
||||
while (iter.hasNext()) {
|
||||
val insn = iter.next()
|
||||
when {
|
||||
insn.isInplaceCallStartMarker() ->
|
||||
calls.add(parseCall(methodNode, insn, iter))
|
||||
insn.isInplaceCallEndMarker() -> {
|
||||
val previous = insn.previous
|
||||
val endLabel =
|
||||
if (previous.type == AbstractInsnNode.LABEL)
|
||||
previous as LabelNode
|
||||
else
|
||||
LabelNode(Label()).also {
|
||||
// Make sure each call with inplace arguments has an endLabel
|
||||
// (we need it to update LVT after transformation).
|
||||
methodNode.instructions.insertBefore(insn, it)
|
||||
}
|
||||
return CallContext(start, insn, args, calls, endLabel)
|
||||
}
|
||||
insn.isInplaceArgumentStartMarker() ->
|
||||
args.add(parseArg(methodNode, insn, iter))
|
||||
insn.isInplaceArgumentEndMarker() ->
|
||||
throw ParseErrorException()
|
||||
}
|
||||
}
|
||||
// Reached instruction list end, didn't find inplace-call-end marker
|
||||
throw ParseErrorException()
|
||||
}
|
||||
|
||||
private fun parseArg(methodNode: MethodNode, start: AbstractInsnNode, iter: ListIterator<AbstractInsnNode>): ArgContext {
|
||||
// ARG ::= argStartMarker insn* (CALL insn*)* argEndMarker storeInsn
|
||||
val calls = ArrayList<CallContext>()
|
||||
while (iter.hasNext()) {
|
||||
val insn = iter.next()
|
||||
when {
|
||||
insn.isInplaceCallStartMarker() ->
|
||||
calls.add(parseCall(methodNode, insn, iter))
|
||||
insn.isInplaceArgumentEndMarker() -> {
|
||||
val next = insn.next
|
||||
if (next is VarInsnNode && next.opcode in Opcodes.ISTORE..Opcodes.ASTORE) {
|
||||
iter.next()
|
||||
return ArgContext(start, insn, calls, next)
|
||||
} else {
|
||||
throw ParseErrorException()
|
||||
}
|
||||
}
|
||||
insn.isInplaceCallEndMarker() || insn.isInplaceArgumentStartMarker() ->
|
||||
throw ParseErrorException()
|
||||
}
|
||||
}
|
||||
// Reached instruction list end, didn't find inplace-argument-end marker
|
||||
throw ParseErrorException()
|
||||
}
|
||||
|
||||
private class ParseErrorException : RuntimeException() {
|
||||
override fun fillInStackTrace(): Throwable = this
|
||||
}
|
||||
|
||||
private fun collectStartToEnd(methodContext: MethodContext) {
|
||||
for (call in methodContext.calls) {
|
||||
collectStartToEnd(methodContext, call)
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectStartToEnd(methodContext: MethodContext, callContext: CallContext) {
|
||||
for (arg in callContext.args) {
|
||||
collectStartToEnd(methodContext, arg)
|
||||
}
|
||||
for (call in callContext.calls) {
|
||||
collectStartToEnd(methodContext, call)
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectStartToEnd(methodContext: MethodContext, argContext: ArgContext) {
|
||||
methodContext.startArgToEndArg[argContext.argStartMarker] = argContext.argEndMarker
|
||||
for (call in argContext.calls) {
|
||||
collectStartToEnd(methodContext, call)
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectLvtEntryInstructions(methodContext: MethodContext) {
|
||||
val insnList = methodContext.methodNode.instructions
|
||||
val insnArray = insnList.toArray()
|
||||
for (lv in methodContext.methodNode.localVariables) {
|
||||
val lvStartIndex = insnList.indexOf(lv.start)
|
||||
val lvEndIndex = insnList.indexOf(lv.end)
|
||||
for (i in lvStartIndex until lvEndIndex) {
|
||||
val insn = insnArray[i]
|
||||
if (insn.opcode in Opcodes.ILOAD..Opcodes.ALOAD || insn.opcode in Opcodes.ISTORE..Opcodes.ASTORE) {
|
||||
if ((insn as VarInsnNode).`var` == lv.index) {
|
||||
methodContext.lvtEntryForInstruction[insn] = lv
|
||||
}
|
||||
} else if (insn.opcode == Opcodes.IINC) {
|
||||
if ((insn as IincInsnNode).`var` == lv.index) {
|
||||
methodContext.lvtEntryForInstruction[insn] = lv
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectSuspensionPoints(methodContext: MethodContext) {
|
||||
val insnList = methodContext.methodNode.instructions
|
||||
var insn = insnList.first
|
||||
while (
|
||||
!insn.isMethodInsnWith(Opcodes.INVOKESTATIC) {
|
||||
owner == "kotlin/coroutines/intrinsics/IntrinsicsKt" &&
|
||||
name == "getCOROUTINE_SUSPENDED" &&
|
||||
desc == "()Ljava/lang/Object;"
|
||||
}
|
||||
) {
|
||||
insn = insn.next ?: return
|
||||
}
|
||||
|
||||
// Find a first TABLESWITCH and record its jump destinations
|
||||
while (insn != null) {
|
||||
if (insn.opcode != Opcodes.TABLESWITCH || insn.previous.opcode != Opcodes.GETFIELD) {
|
||||
insn = insn.next
|
||||
continue
|
||||
}
|
||||
val getFiendInsn = insn.previous as FieldInsnNode
|
||||
if (getFiendInsn.name != "label" || getFiendInsn.desc != "I") {
|
||||
insn = insn.next
|
||||
continue
|
||||
}
|
||||
val tableSwitchInsn = insn as TableSwitchInsnNode
|
||||
methodContext.suspensionJumpLabels.addAll(tableSwitchInsn.labels)
|
||||
methodContext.suspensionJumpLabels.add(tableSwitchInsn.dflt)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformMethod(methodContext: MethodContext) {
|
||||
for (call in methodContext.calls) {
|
||||
transformCall(methodContext, call)
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformCall(methodContext: MethodContext, callContext: CallContext) {
|
||||
// Transform nested calls
|
||||
for (arg in callContext.args) {
|
||||
for (nestedCall in arg.calls) {
|
||||
transformCall(methodContext, nestedCall)
|
||||
}
|
||||
}
|
||||
for (call in callContext.calls) {
|
||||
transformCall(methodContext, call)
|
||||
}
|
||||
|
||||
// If an inplace argument contains a non-local jump,
|
||||
// moving such argument inside inline function body can interfere with stack normalization.
|
||||
// TODO investigate complex cases
|
||||
if (callContext.args.any { it.isUnsafeToMove(methodContext) }) {
|
||||
// Do not transform such call, just strip call and argument markers.
|
||||
val insnList = methodContext.methodNode.instructions
|
||||
for (arg in callContext.args) {
|
||||
insnList.remove(arg.argStartMarker)
|
||||
insnList.remove(arg.argEndMarker)
|
||||
}
|
||||
insnList.remove(callContext.callStartMarker)
|
||||
insnList.remove(callContext.callEndMarker)
|
||||
return
|
||||
}
|
||||
|
||||
moveInplaceArgumentsFromStoresToLoads(methodContext, callContext)
|
||||
}
|
||||
|
||||
private fun ArgContext.isUnsafeToMove(methodContext: MethodContext): Boolean {
|
||||
val argInsns = InsnSequence(this.argStartMarker, this.argEndMarker)
|
||||
val localLabels = argInsns.filterTo(HashSet()) { it is LabelNode }
|
||||
return argInsns.any { insn ->
|
||||
insn in methodContext.suspensionJumpLabels ||
|
||||
insn.opcode == Opcodes.GOTO && (insn as JumpInsnNode).label !in localLabels
|
||||
}
|
||||
}
|
||||
|
||||
private fun moveInplaceArgumentsFromStoresToLoads(methodContext: MethodContext, callContext: CallContext) {
|
||||
// Transform call
|
||||
val insnList = methodContext.methodNode.instructions
|
||||
val args = callContext.args.associateBy { it.varIndex }
|
||||
var argsProcessed = 0
|
||||
|
||||
var insn: AbstractInsnNode = callContext.callStartMarker
|
||||
while (insn != callContext.callEndMarker) {
|
||||
when {
|
||||
insn.isInplaceArgumentStartMarker() -> {
|
||||
// Skip argument body
|
||||
insn = methodContext.startArgToEndArg[insn]!!
|
||||
}
|
||||
|
||||
insn.opcode in Opcodes.ILOAD..Opcodes.ALOAD -> {
|
||||
// Load instruction
|
||||
val loadInsn = insn as VarInsnNode
|
||||
val varIndex = loadInsn.`var`
|
||||
val arg = args[varIndex]
|
||||
|
||||
if (arg == null || arg.loadOpcode != insn.opcode) {
|
||||
// Not an argument load
|
||||
insn = insn.next
|
||||
} else {
|
||||
// For each argument within this call we have
|
||||
// <inplaceArgStartMarker>
|
||||
// <argumentBody>
|
||||
// <inplaceArgEndMarker>
|
||||
// store [arg]
|
||||
// ...
|
||||
// load [arg]
|
||||
// Replace 'load [arg]' with '<argumentBody>', drop 'store [arg]' and argument markers.
|
||||
|
||||
var argInsn = arg.argStartMarker.next
|
||||
while (argInsn != arg.argEndMarker) {
|
||||
// If a LOAD/STORE/IINC instruction was moved,
|
||||
// record it so that we can update corresponding LVT entry if needed.
|
||||
// NB it's better to do so after all transformations, so that we don't recalculate node indices.
|
||||
if (argInsn.opcode in Opcodes.ILOAD..Opcodes.ALOAD ||
|
||||
argInsn.opcode in Opcodes.ISTORE..Opcodes.ASTORE ||
|
||||
argInsn.opcode == Opcodes.IINC
|
||||
) {
|
||||
methodContext.varInstructionMoved[argInsn] = callContext
|
||||
}
|
||||
|
||||
val argInsnNext = argInsn.next
|
||||
insnList.remove(argInsn)
|
||||
insnList.insertBefore(loadInsn, argInsn)
|
||||
argInsn = argInsnNext
|
||||
}
|
||||
|
||||
// Remove argument load and corresponding argument store instructions
|
||||
insnList.remove(arg.storeInsn)
|
||||
insn = loadInsn.next
|
||||
insnList.remove(loadInsn)
|
||||
|
||||
// Replace subsequent argument loads with DUP instructions of appropriate size
|
||||
while (insn.opcode == loadInsn.opcode && (insn as VarInsnNode).`var` == varIndex) {
|
||||
if (insn.opcode == Opcodes.LLOAD || insn.opcode == Opcodes.DLOAD) {
|
||||
insnList.insertBefore(insn, InsnNode(Opcodes.DUP2))
|
||||
} else {
|
||||
insnList.insertBefore(insn, InsnNode(Opcodes.DUP))
|
||||
}
|
||||
val next = insn.next
|
||||
insnList.remove(insn)
|
||||
insn = next
|
||||
}
|
||||
|
||||
// Remove argument markers
|
||||
insnList.remove(arg.argStartMarker)
|
||||
insnList.remove(arg.argEndMarker)
|
||||
|
||||
// If there are no more inplace arguments left to process, we are done
|
||||
++argsProcessed
|
||||
if (argsProcessed >= callContext.args.size)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
else ->
|
||||
insn = insn.next
|
||||
}
|
||||
}
|
||||
|
||||
// Remove call start and call end markers
|
||||
insnList.remove(callContext.callStartMarker)
|
||||
insnList.remove(callContext.callEndMarker)
|
||||
}
|
||||
|
||||
private fun updateLvtEntriesForMovedInstructions(methodContext: MethodContext) {
|
||||
val insnList = methodContext.methodNode.instructions
|
||||
for ((insn, callContext) in methodContext.varInstructionMoved.entries) {
|
||||
// Extend local variable interval to call end label if needed
|
||||
val lv = methodContext.lvtEntryForInstruction[insn] ?: continue
|
||||
val lvEndIndex = insnList.indexOf(lv.end)
|
||||
val endLabelIndex = insnList.indexOf(callContext.endLabel)
|
||||
if (endLabelIndex > lvEndIndex) {
|
||||
lv.end = callContext.endLabel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun stripMarkers(methodNode: MethodNode) {
|
||||
var insn = methodNode.instructions.first
|
||||
while (insn != null) {
|
||||
if (insn.isInplaceCallStartMarker() ||
|
||||
insn.isInplaceCallEndMarker() ||
|
||||
insn.isInplaceArgumentStartMarker() ||
|
||||
insn.isInplaceArgumentEndMarker()
|
||||
) {
|
||||
val next = insn.next
|
||||
methodNode.instructions.remove(insn)
|
||||
insn = next
|
||||
continue
|
||||
}
|
||||
insn = insn.next
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ class DefaultLambda(info: ExtractedDefaultLambda, sourceCompiler: SourceCompiler
|
||||
// TODO: suspend lambdas are their own continuations, so the body is pre-inlined into `invokeSuspend`
|
||||
// and thus can't be detangled from the state machine. To make them inlinable, this needs to be redesigned.
|
||||
// See `SuspendLambdaLowering`.
|
||||
require(!sourceCompiler.state.languageVersionSettings.isCoroutineSuperClass(superName)) {
|
||||
require(!superName.isCoroutineSuperClass()) {
|
||||
"suspend default lambda ${lambdaClassType.internalName} cannot be inlined; use a function reference instead"
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_ASM_TYPE
|
||||
import org.jetbrains.kotlin.codegen.inline.FieldRemapper.Companion.foldName
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.CoroutineTransformer
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.markNoinlineLambdaIfSuspend
|
||||
@@ -688,7 +688,7 @@ class MethodInliner(
|
||||
}
|
||||
|
||||
for ((index, param) in paramTypes.reversed().withIndex()) {
|
||||
if (param != languageVersionSettings.continuationAsmType() && param != OBJECT_TYPE) continue
|
||||
if (param != CONTINUATION_ASM_TYPE && param != OBJECT_TYPE) continue
|
||||
val sourceIndices = (frame.getStack(frame.stackSize - index - 1) as? Aload0BasicValue)?.indices ?: continue
|
||||
for (sourceIndex in sourceIndices) {
|
||||
val src = processingNode.instructions[sourceIndex]
|
||||
@@ -733,6 +733,7 @@ class MethodInliner(
|
||||
|
||||
private fun preprocessNodeBeforeInline(node: MethodNode, returnLabels: Map<String, Label?>) {
|
||||
try {
|
||||
InplaceArgumentsMethodTransformer().transform("fake", node)
|
||||
FixStackWithLabelNormalizationMethodTransformer().transform("fake", node)
|
||||
} catch (e: Throwable) {
|
||||
throw wrapException(e, node, "couldn't inline method call")
|
||||
|
||||
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -158,8 +157,7 @@ class PsiSourceCompilerForInline(
|
||||
}
|
||||
|
||||
FunctionCodegen.generateMethodBody(
|
||||
adapter, descriptor, context, jvmMethodSignature, strategy, parentCodegen, state.jvmDefaultMode,
|
||||
state.languageVersionSettings.isReleaseCoroutines()
|
||||
adapter, descriptor, context, jvmMethodSignature, strategy, parentCodegen, state.jvmDefaultMode
|
||||
)
|
||||
|
||||
if (isLambda) {
|
||||
@@ -235,7 +233,7 @@ class PsiSourceCompilerForInline(
|
||||
}
|
||||
|
||||
override fun compileInlineFunction(jvmSignature: JvmMethodSignature): SMAPAndMethodNode {
|
||||
generateInlineIntrinsic(state.languageVersionSettings, functionDescriptor, jvmSignature.asmMethod, codegen.typeSystem)?.let {
|
||||
generateInlineIntrinsic(functionDescriptor, jvmSignature.asmMethod, codegen.typeSystem)?.let {
|
||||
return it
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@ import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.intConstant
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -233,7 +231,7 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
|
||||
if (stubCheckcast !is TypeInsnNode) return false
|
||||
|
||||
val newMethodNode = MethodNode(Opcodes.API_VERSION)
|
||||
generateAsCast(InstructionAdapter(newMethodNode), kotlinType, asmType, safe, languageVersionSettings, unifiedNullChecks)
|
||||
generateAsCast(InstructionAdapter(newMethodNode), kotlinType, asmType, safe, unifiedNullChecks)
|
||||
|
||||
instructions.insert(insn, newMethodNode.instructions)
|
||||
// Keep stubCheckcast to avoid VerifyErrors on 1.8+ bytecode,
|
||||
@@ -257,7 +255,7 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
|
||||
if (stubInstanceOf !is TypeInsnNode) return false
|
||||
|
||||
val newMethodNode = MethodNode(Opcodes.API_VERSION)
|
||||
generateIsCheck(InstructionAdapter(newMethodNode), kotlinType, asmType, languageVersionSettings.isReleaseCoroutines())
|
||||
generateIsCheck(InstructionAdapter(newMethodNode), kotlinType, asmType)
|
||||
|
||||
instructions.insert(insn, newMethodNode.instructions)
|
||||
instructions.remove(stubInstanceOf)
|
||||
|
||||
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.codegen.inline.*
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
@@ -49,18 +48,16 @@ class CoroutineTransformer(
|
||||
fun suspendLambdaWithGeneratedStateMachine(node: MethodNode): Boolean =
|
||||
!isContinuationNotLambda() && isSuspendLambda(node) && isStateMachine(node)
|
||||
|
||||
private fun isContinuationNotLambda(): Boolean = inliningContext.isContinuation &&
|
||||
if (state.languageVersionSettings.isReleaseCoroutines()) superClassName.endsWith("ContinuationImpl")
|
||||
else methods.any { it.name == "getLabel" }
|
||||
private fun isContinuationNotLambda(): Boolean = inliningContext.isContinuation && superClassName.endsWith("ContinuationImpl")
|
||||
|
||||
private fun isStateMachine(node: MethodNode): Boolean =
|
||||
node.instructions.asSequence().any { insn -> insn is LdcInsnNode && insn.cst == ILLEGAL_STATE_ERROR_MESSAGE }
|
||||
|
||||
private fun isSuspendLambda(node: MethodNode) = isResumeImpl(node)
|
||||
private fun isSuspendLambda(node: MethodNode) = isInvokeSuspend(node)
|
||||
|
||||
fun newMethod(node: MethodNode): DeferredMethodVisitor {
|
||||
return when {
|
||||
isResumeImpl(node) -> {
|
||||
isInvokeSuspend(node) -> {
|
||||
assert(!isStateMachine(node)) {
|
||||
"Inlining/transforming state-machine"
|
||||
}
|
||||
@@ -71,9 +68,8 @@ class CoroutineTransformer(
|
||||
}
|
||||
}
|
||||
|
||||
private fun isResumeImpl(node: MethodNode): Boolean =
|
||||
state.languageVersionSettings.isResumeImplMethodName(node.name.removeSuffix(FOR_INLINE_SUFFIX)) &&
|
||||
inliningContext.isContinuation
|
||||
private fun isInvokeSuspend(node: MethodNode): Boolean =
|
||||
node.name.removeSuffix(FOR_INLINE_SUFFIX) == INVOKE_SUSPEND_METHOD_NAME && inliningContext.isContinuation
|
||||
|
||||
private fun isSuspendFunctionWithFakeConstructorCall(node: MethodNode): Boolean = findFakeContinuationConstructorClassName(node) != null
|
||||
|
||||
@@ -88,16 +84,15 @@ class CoroutineTransformer(
|
||||
val sourceCompilerForInline = inliningContext.root.sourceCompilerForInline
|
||||
val stateMachineBuilder = CoroutineTransformerMethodVisitor(
|
||||
createNewMethodFrom(node, name), node.access, name, node.desc, null, null,
|
||||
containingClassInternalName = classBuilder.thisName,
|
||||
obtainClassBuilderForCoroutineState = { classBuilder },
|
||||
isForNamedFunction = false,
|
||||
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||
disableTailCallOptimizationForFunctionReturningUnit = false,
|
||||
reportSuspensionPointInsideMonitor = { sourceCompilerForInline.reportSuspensionPointInsideMonitor(it) },
|
||||
// TODO: this linenumbers might not be correct and since they are used only for step-over, check them.
|
||||
lineNumber = inliningContext.callSiteInfo.lineNumber,
|
||||
sourceFile = inliningContext.callSiteInfo.file?.name ?: "",
|
||||
languageVersionSettings = state.languageVersionSettings,
|
||||
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||
containingClassInternalName = classBuilder.thisName,
|
||||
isForNamedFunction = false,
|
||||
disableTailCallOptimizationForFunctionReturningUnit = false,
|
||||
useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS)
|
||||
)
|
||||
|
||||
@@ -123,17 +118,16 @@ class CoroutineTransformer(
|
||||
val sourceCompilerForInline = inliningContext.root.sourceCompilerForInline
|
||||
val stateMachineBuilder = CoroutineTransformerMethodVisitor(
|
||||
createNewMethodFrom(node, name), node.access, name, node.desc, null, null,
|
||||
containingClassInternalName = classBuilder.thisName,
|
||||
obtainClassBuilderForCoroutineState = { (inliningContext as RegeneratedClassContext).continuationBuilders[continuationClassName]!! },
|
||||
isForNamedFunction = true,
|
||||
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||
disableTailCallOptimizationForFunctionReturningUnit = disableTailCallOptimization,
|
||||
reportSuspensionPointInsideMonitor = { sourceCompilerForInline.reportSuspensionPointInsideMonitor(it) },
|
||||
lineNumber = inliningContext.callSiteInfo.lineNumber,
|
||||
sourceFile = inliningContext.callSiteInfo.file?.name ?: "",
|
||||
languageVersionSettings = state.languageVersionSettings,
|
||||
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||
containingClassInternalName = classBuilder.thisName,
|
||||
isForNamedFunction = true,
|
||||
needDispatchReceiver = true,
|
||||
internalNameForDispatchReceiver = classBuilder.thisName,
|
||||
disableTailCallOptimizationForFunctionReturningUnit = disableTailCallOptimization,
|
||||
putContinuationParameterToLvt = !state.isIrBackend,
|
||||
useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS)
|
||||
)
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.nullCheck.isParameterCheckedForNull
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
|
||||
|
||||
fun canInlineArgumentsInPlace(methodNode: MethodNode): Boolean {
|
||||
// Usual inline functions are inlined in the following way:
|
||||
// <evaluate argument #1>
|
||||
// <store argument to an argument variable V1>
|
||||
// ...
|
||||
// <evaluate argument #N>
|
||||
// <store argument to an argument variable VN>
|
||||
// <inline function method body with parameter variables Pi remapped to argument variables Vi>
|
||||
// If an argument #k is already stored in a local variable W, this variable W is reused.
|
||||
// When inlining arguments in-place, we instead replace corresponding variable load instructions in the inline function method body
|
||||
// with bytecode for evaluating a given argument.
|
||||
// We can do so if such transformation keeps the evaluation order intact, possibly disregarding class initialization.
|
||||
//
|
||||
// This is true for many simple @InlineOnly functions from Kotlin standard library.
|
||||
// For example, bytecode for 'inline fun println(message: Any?)' is:
|
||||
// GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
|
||||
// ALOAD 0
|
||||
// INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
|
||||
// Basic inlining for 'println("Hello, world!")' would produce (skipping labels and line numbers):
|
||||
// // evaluate arguments, storing them to local variables
|
||||
// LDC "Hello, world!"
|
||||
// ASTORE 0
|
||||
// GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
|
||||
// ALOAD 0
|
||||
// INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
|
||||
// With argument "Hello, world!" inlined in-place it would be:
|
||||
// GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
|
||||
// LDC "Hello, world!"
|
||||
// INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
|
||||
// Such inlining is possible because we consider it OK to reorder 'GETSTATIC java/lang/System.out : Ljava/io/PrintStream;' instruction
|
||||
// with any argument evaluation instructions ('LDC "Hello, world!"' in this case).
|
||||
|
||||
val tcbStartLabels = methodNode.tryCatchBlocks.mapTo(HashSet()) { it.start }
|
||||
|
||||
val methodParameterTypes = Type.getArgumentTypes(methodNode.desc)
|
||||
|
||||
val jvmArgumentTypes = ArrayList<Type>(methodParameterTypes.size + 1)
|
||||
if (methodNode.access and Opcodes.ACC_STATIC == 0) {
|
||||
// Here we don't care much about the exact 'this' type,
|
||||
// it's only important to remember that variable slot #0 holds an object reference.
|
||||
jvmArgumentTypes.add(AsmTypes.OBJECT_TYPE)
|
||||
}
|
||||
jvmArgumentTypes.addAll(methodParameterTypes)
|
||||
|
||||
val argumentVarEnd = jvmArgumentTypes.sumOf { it.size }
|
||||
var expectedArgumentVar = 0
|
||||
var lastArgIndex = 0
|
||||
|
||||
var insn = methodNode.instructions.first
|
||||
|
||||
// During arguments evaluation, make sure that all arguments are loaded in expected order
|
||||
// and there are no unexpected side effects in-between.
|
||||
while (insn != null && expectedArgumentVar < argumentVarEnd) {
|
||||
// Entering a try-catch block before all arguments are loaded breaks evaluation order.
|
||||
if (insn in tcbStartLabels)
|
||||
return false
|
||||
|
||||
// Some instructions break evaluation order.
|
||||
if (insn.isProhibitedDuringArgumentsEvaluation())
|
||||
return false
|
||||
|
||||
// Allow a limited list of 'GETSTATIC <owner> <name> <desc>' instructions.
|
||||
if (insn.opcode == Opcodes.GETSTATIC) {
|
||||
val fieldInsn = insn as FieldInsnNode
|
||||
val fieldSignature = FieldSignature(fieldInsn.owner, fieldInsn.name, fieldInsn.desc)
|
||||
if (fieldSignature !in whitelistedStaticFields)
|
||||
return false
|
||||
}
|
||||
|
||||
// Writing to or incrementing an argument variable forbids in-place argument inlining.
|
||||
if (insn.opcode in Opcodes.ISTORE..Opcodes.ASTORE && (insn as VarInsnNode).`var` < argumentVarEnd)
|
||||
return false
|
||||
if (insn.opcode == Opcodes.IINC && (insn as IincInsnNode).`var` < argumentVarEnd)
|
||||
return false
|
||||
|
||||
// Analyze variable loads.
|
||||
if (insn.opcode in Opcodes.ILOAD..Opcodes.ALOAD) {
|
||||
// Skip parameter null check: 'aload x; ldc "..."; invokestatic <check>'
|
||||
if (insn.opcode == Opcodes.ALOAD && insn.isParameterCheckedForNull()) {
|
||||
// Go directly to the instruction after 'invokestatic <check>'
|
||||
insn = insn.next.next.next
|
||||
continue
|
||||
}
|
||||
|
||||
val varInsn = insn as VarInsnNode
|
||||
val varIndex = (varInsn).`var`
|
||||
if (varIndex == expectedArgumentVar) {
|
||||
// Expected argument variable loaded.
|
||||
expectedArgumentVar += jvmArgumentTypes[lastArgIndex].size
|
||||
++lastArgIndex
|
||||
// Skip a sequence of load instructions referring to the same argument variable
|
||||
// (such sequence is present in functions like 'Array.copyOf' and can be replaced with DUP instructions).
|
||||
do {
|
||||
insn = insn.next
|
||||
} while (insn != null && insn.opcode == varInsn.opcode && (insn as VarInsnNode).`var` == varIndex)
|
||||
continue
|
||||
} else if (varIndex < argumentVarEnd) {
|
||||
// Loaded an argument variable, but not an expected one => broken evaluation order
|
||||
return false
|
||||
} else {
|
||||
// It's OK to load any non-argument variable during argument evaluation.
|
||||
insn = insn.next
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Anything else is fine.
|
||||
insn = insn.next
|
||||
}
|
||||
|
||||
// Method body is over, but not all arguments were loaded on stack.
|
||||
if (expectedArgumentVar < argumentVarEnd)
|
||||
return false
|
||||
|
||||
// After arguments evaluation make sure that argument variables are no longer accessed
|
||||
// (we are not going to store anything to those variables anyway).
|
||||
while (insn != null) {
|
||||
if (insn.opcode in Opcodes.ILOAD..Opcodes.ALOAD || insn.opcode in Opcodes.ISTORE..Opcodes.ASTORE) {
|
||||
if ((insn as VarInsnNode).`var` < argumentVarEnd)
|
||||
return false
|
||||
} else if (insn.opcode == Opcodes.IINC) {
|
||||
if ((insn as IincInsnNode).`var` < argumentVarEnd)
|
||||
return false
|
||||
}
|
||||
insn = insn.next
|
||||
}
|
||||
|
||||
// Didn't encounter anything suspicious.
|
||||
return true
|
||||
}
|
||||
|
||||
internal data class FieldSignature(
|
||||
val owner: String,
|
||||
val name: String,
|
||||
val desc: String
|
||||
)
|
||||
|
||||
private val whitelistedStaticFields: Set<FieldSignature> =
|
||||
hashSetOf(
|
||||
FieldSignature("java/lang/System", "out", "Ljava/io/PrintStream;"),
|
||||
FieldSignature("kotlin/Result", "Companion", "Lkotlin/Result\$Companion;"),
|
||||
FieldSignature("kotlin/_Assertions", "ENABLED", "Z")
|
||||
)
|
||||
|
||||
private fun AbstractInsnNode.isProhibitedDuringArgumentsEvaluation() =
|
||||
opcode in opcodeProhibitedDuringArgumentsEvaluation.indices &&
|
||||
opcodeProhibitedDuringArgumentsEvaluation[opcode]
|
||||
|
||||
private val opcodeProhibitedDuringArgumentsEvaluation = BooleanArray(256).also { a ->
|
||||
// Any kind of jump during arguments evaluation is a hazard.
|
||||
// This includes all conditional jump instructions, switch instructions, return and throw instructions.
|
||||
// Very conservative, but enough for practical cases.
|
||||
for (i in Opcodes.IFEQ..Opcodes.RETURN) a[i] = true
|
||||
a[Opcodes.IFNULL] = true
|
||||
a[Opcodes.IFNONNULL] = true
|
||||
a[Opcodes.ATHROW] = true
|
||||
|
||||
// Instruction with non-trivial side effects is a hazard.
|
||||
// NB GETSTATIC is taken care of separately.
|
||||
a[Opcodes.PUTSTATIC] = true
|
||||
a[Opcodes.PUTFIELD] = true
|
||||
a[Opcodes.INVOKEVIRTUAL] = true
|
||||
a[Opcodes.INVOKESPECIAL] = true
|
||||
a[Opcodes.INVOKESTATIC] = true
|
||||
a[Opcodes.INVOKEINTERFACE] = true
|
||||
a[Opcodes.INVOKEDYNAMIC] = true
|
||||
a[Opcodes.MONITORENTER] = true
|
||||
a[Opcodes.MONITOREXIT] = true
|
||||
|
||||
// Integer division instructions can throw exception
|
||||
a[Opcodes.IDIV] = true
|
||||
a[Opcodes.LDIV] = true
|
||||
a[Opcodes.IREM] = true
|
||||
a[Opcodes.LREM] = true
|
||||
|
||||
// CHECKCAST can throw exception
|
||||
a[Opcodes.CHECKCAST] = true
|
||||
|
||||
// Array creation can throw exception (in case of negative array size)
|
||||
a[Opcodes.NEWARRAY] = true
|
||||
a[Opcodes.ANEWARRAY] = true
|
||||
a[Opcodes.MULTIANEWARRAY] = true
|
||||
|
||||
// Array access instructions can throw exception
|
||||
for (i in Opcodes.IALOAD..Opcodes.SALOAD) a[i] = true
|
||||
for (i in Opcodes.IASTORE..Opcodes.SASTORE) a[i] = true
|
||||
}
|
||||
|
||||
|
||||
private const val MARKER_INPLACE_CALL_START = "<INPLACE-CALL-START>"
|
||||
private const val MARKER_INPLACE_ARGUMENT_START = "<INPLACE-ARGUMENT-START>"
|
||||
private const val MARKER_INPLACE_ARGUMENT_END = "<INPLACE-ARGUMENT-END>"
|
||||
private const val MARKER_INPLACE_CALL_END = "<INPLACE-CALL-END>"
|
||||
|
||||
|
||||
private fun InstructionAdapter.addMarker(name: String) {
|
||||
visitMethodInsn(Opcodes.INVOKESTATIC, INLINE_MARKER_CLASS_NAME, name, "()V", false)
|
||||
}
|
||||
|
||||
fun InstructionAdapter.addInplaceCallStartMarker() = addMarker(MARKER_INPLACE_CALL_START)
|
||||
fun InstructionAdapter.addInplaceCallEndMarker() = addMarker(MARKER_INPLACE_CALL_END)
|
||||
fun InstructionAdapter.addInplaceArgumentStartMarker() = addMarker(MARKER_INPLACE_ARGUMENT_START)
|
||||
fun InstructionAdapter.addInplaceArgumentEndMarker() = addMarker(MARKER_INPLACE_ARGUMENT_END)
|
||||
|
||||
internal fun AbstractInsnNode.isInplaceCallStartMarker() = isInlineMarker(this, MARKER_INPLACE_CALL_START)
|
||||
internal fun AbstractInsnNode.isInplaceCallEndMarker() = isInlineMarker(this, MARKER_INPLACE_CALL_END)
|
||||
internal fun AbstractInsnNode.isInplaceArgumentStartMarker() = isInlineMarker(this, MARKER_INPLACE_ARGUMENT_START)
|
||||
internal fun AbstractInsnNode.isInplaceArgumentEndMarker() = isInlineMarker(this, MARKER_INPLACE_ARGUMENT_END)
|
||||
@@ -60,7 +60,7 @@ const val INLINE_FUN_VAR_SUFFIX = "\$iv"
|
||||
internal const val FIRST_FUN_LABEL = "$$$$\$ROOT$$$$$"
|
||||
internal const val SPECIAL_TRANSFORMATION_NAME = "\$special"
|
||||
const val INLINE_TRANSFORMATION_SUFFIX = "\$inlined"
|
||||
internal const val INLINE_CALL_TRANSFORMATION_SUFFIX = "$" + INLINE_TRANSFORMATION_SUFFIX
|
||||
internal const val INLINE_CALL_TRANSFORMATION_SUFFIX = "$$INLINE_TRANSFORMATION_SUFFIX"
|
||||
internal const val INLINE_FUN_THIS_0_SUFFIX = "\$inline_fun"
|
||||
internal const val DEFAULT_LAMBDA_FAKE_CALL = "$$\$DEFAULT_LAMBDA_FAKE_CALL$$$"
|
||||
internal const val CAPTURED_FIELD_FOLD_PREFIX = "$$$"
|
||||
@@ -68,11 +68,10 @@ internal const val CAPTURED_FIELD_FOLD_PREFIX = "$$$"
|
||||
private const val NON_LOCAL_RETURN = "$$$$\$NON_LOCAL_RETURN$$$$$"
|
||||
const val CAPTURED_FIELD_PREFIX = "$"
|
||||
private const val NON_CAPTURED_FIELD_PREFIX = "$$"
|
||||
private const val INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker"
|
||||
internal const val INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker"
|
||||
private const val INLINE_MARKER_BEFORE_METHOD_NAME = "beforeInlineCall"
|
||||
private const val INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall"
|
||||
private const val INLINE_MARKER_FINALLY_START = "finallyStart"
|
||||
|
||||
private const val INLINE_MARKER_FINALLY_END = "finallyEnd"
|
||||
private const val INLINE_MARKER_BEFORE_SUSPEND_ID = 0
|
||||
private const val INLINE_MARKER_AFTER_SUSPEND_ID = 1
|
||||
@@ -302,7 +301,7 @@ internal fun firstLabelInChain(node: LabelNode): LabelNode {
|
||||
internal fun areLabelsBeforeSameInsn(first: LabelNode, second: LabelNode): Boolean =
|
||||
firstLabelInChain(first) == firstLabelInChain(second)
|
||||
|
||||
internal val MethodNode?.nodeText: String
|
||||
val MethodNode?.nodeText: String
|
||||
get() {
|
||||
if (this == null) {
|
||||
return "Not generated"
|
||||
@@ -535,17 +534,15 @@ internal fun isInlineMarker(insn: AbstractInsnNode): Boolean {
|
||||
return isInlineMarker(insn, null)
|
||||
}
|
||||
|
||||
private fun isInlineMarker(insn: AbstractInsnNode, name: String?): Boolean {
|
||||
if (insn !is MethodInsnNode) {
|
||||
return false
|
||||
}
|
||||
internal fun isInlineMarker(insn: AbstractInsnNode, name: String?): Boolean {
|
||||
if (insn.opcode != Opcodes.INVOKESTATIC) return false
|
||||
|
||||
return insn.getOpcode() == Opcodes.INVOKESTATIC &&
|
||||
insn.owner == INLINE_MARKER_CLASS_NAME &&
|
||||
val methodInsn = insn as MethodInsnNode
|
||||
return methodInsn.owner == INLINE_MARKER_CLASS_NAME &&
|
||||
if (name != null)
|
||||
insn.name == name
|
||||
methodInsn.name == name
|
||||
else
|
||||
insn.name == INLINE_MARKER_BEFORE_METHOD_NAME || insn.name == INLINE_MARKER_AFTER_METHOD_NAME
|
||||
methodInsn.name == INLINE_MARKER_BEFORE_METHOD_NAME || methodInsn.name == INLINE_MARKER_AFTER_METHOD_NAME
|
||||
}
|
||||
|
||||
internal fun isBeforeInlineMarker(insn: AbstractInsnNode): Boolean {
|
||||
|
||||
@@ -5,13 +5,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.isBuiltInIntercepted
|
||||
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineUninterceptedOrReturn
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForCoroutineContext
|
||||
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForIntercepted
|
||||
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCoroutineUninterceptedOrReturn
|
||||
import org.jetbrains.kotlin.codegen.createMethodNodeForAlwaysEnabledAssert
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructors
|
||||
@@ -30,25 +28,22 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
fun generateInlineIntrinsicForIr(languageVersionSettings: LanguageVersionSettings, descriptor: FunctionDescriptor): SMAPAndMethodNode? =
|
||||
fun generateInlineIntrinsicForIr(descriptor: FunctionDescriptor): SMAPAndMethodNode? =
|
||||
when {
|
||||
// TODO: implement these as codegen intrinsics (see IrIntrinsicMethods)
|
||||
descriptor.isBuiltInIntercepted(languageVersionSettings) ->
|
||||
createMethodNodeForIntercepted(languageVersionSettings)
|
||||
descriptor.isBuiltInCoroutineContext(languageVersionSettings) ->
|
||||
createMethodNodeForCoroutineContext(descriptor, languageVersionSettings)
|
||||
descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) ->
|
||||
createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSettings)
|
||||
descriptor.isBuiltInCoroutineContext() ->
|
||||
createMethodNodeForCoroutineContext(descriptor)
|
||||
descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn() ->
|
||||
createMethodNodeForSuspendCoroutineUninterceptedOrReturn()
|
||||
else -> null
|
||||
}?.let { SMAPAndMethodNode(it, SMAP(listOf())) }
|
||||
|
||||
internal fun generateInlineIntrinsic(
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
descriptor: FunctionDescriptor,
|
||||
asmMethod: Method,
|
||||
typeSystem: TypeSystemCommonBackendContext
|
||||
): SMAPAndMethodNode? {
|
||||
return generateInlineIntrinsicForIr(languageVersionSettings, descriptor) ?: when {
|
||||
return generateInlineIntrinsicForIr(descriptor) ?: when {
|
||||
isSpecialEnumMethod(descriptor) ->
|
||||
createSpecialEnumMethodBody(descriptor.name.asString(), descriptor.original.typeParameters.single(), typeSystem)
|
||||
TypeOfChecker.isTypeOf(descriptor) ->
|
||||
|
||||
@@ -19,7 +19,7 @@ import org.jetbrains.org.objectweb.asm.tree.*
|
||||
|
||||
object TypeIntrinsics {
|
||||
@JvmStatic
|
||||
fun instanceOf(v: InstructionAdapter, jetType: KotlinType, boxedAsmType: Type, isReleaseCoroutines: Boolean) {
|
||||
fun instanceOf(v: InstructionAdapter, jetType: KotlinType, boxedAsmType: Type) {
|
||||
val functionTypeArity = getFunctionTypeArity(jetType)
|
||||
if (functionTypeArity >= 0) {
|
||||
v.iconst(functionTypeArity)
|
||||
@@ -27,28 +27,26 @@ object TypeIntrinsics {
|
||||
return
|
||||
}
|
||||
|
||||
if (isReleaseCoroutines) {
|
||||
val suspendFunctionTypeArity = getSuspendFunctionTypeArity(jetType)
|
||||
if (suspendFunctionTypeArity >= 0) {
|
||||
val notSuspendLambda = Label()
|
||||
val end = Label()
|
||||
val suspendFunctionTypeArity = getSuspendFunctionTypeArity(jetType)
|
||||
if (suspendFunctionTypeArity >= 0) {
|
||||
val notSuspendLambda = Label()
|
||||
val end = Label()
|
||||
|
||||
with(v) {
|
||||
dup()
|
||||
instanceOf(AsmTypes.SUSPEND_FUNCTION_TYPE)
|
||||
ifeq(notSuspendLambda)
|
||||
iconst(suspendFunctionTypeArity + 1)
|
||||
typeIntrinsic(IS_FUNCTON_OF_ARITY_METHOD_NAME, IS_FUNCTON_OF_ARITY_DESCRIPTOR)
|
||||
goTo(end)
|
||||
with(v) {
|
||||
dup()
|
||||
instanceOf(AsmTypes.SUSPEND_FUNCTION_TYPE)
|
||||
ifeq(notSuspendLambda)
|
||||
iconst(suspendFunctionTypeArity + 1)
|
||||
typeIntrinsic(IS_FUNCTON_OF_ARITY_METHOD_NAME, IS_FUNCTON_OF_ARITY_DESCRIPTOR)
|
||||
goTo(end)
|
||||
|
||||
mark(notSuspendLambda)
|
||||
pop()
|
||||
iconst(0)
|
||||
mark(notSuspendLambda)
|
||||
pop()
|
||||
iconst(0)
|
||||
|
||||
mark(end)
|
||||
}
|
||||
return
|
||||
mark(end)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val isMutableCollectionMethodName = getIsMutableCollectionMethodName(jetType)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.codegen.optimization
|
||||
|
||||
import org.jetbrains.kotlin.codegen.TransformationMethodVisitor
|
||||
import org.jetbrains.kotlin.codegen.inline.InplaceArgumentsMethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.PopBackwardPropagationTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantBoxingMethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.StackPeepholeOptimizationsTransformer
|
||||
@@ -40,6 +41,7 @@ class OptimizationMethodVisitor(
|
||||
UninitializedStoresMethodTransformer(generationState.constructorCallNormalizationMode)
|
||||
|
||||
val normalizationMethodTransformer = CompositeMethodTransformer(
|
||||
InplaceArgumentsMethodTransformer(),
|
||||
FixStackWithLabelNormalizationMethodTransformer(),
|
||||
MethodVerifier("AFTER mandatory stack transformations", generationState)
|
||||
)
|
||||
|
||||
@@ -17,9 +17,8 @@
|
||||
package org.jetbrains.kotlin.codegen.optimization.boxing
|
||||
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.coroutines.RELEASE_COROUTINES_VERSION_SETTINGS
|
||||
import org.jetbrains.kotlin.codegen.coroutines.coroutinesJvmInternalPackageFqName
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
||||
@@ -216,7 +215,7 @@ fun AbstractInsnNode.isPrimitiveBoxing() =
|
||||
}
|
||||
|
||||
private val BOXING_CLASS_INTERNAL_NAME =
|
||||
RELEASE_COROUTINES_VERSION_SETTINGS.coroutinesJvmInternalPackageFqName().child(Name.identifier("Boxing")).topLevelClassInternalName()
|
||||
StandardNames.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("Boxing")).topLevelClassInternalName()
|
||||
|
||||
private fun isJvmPrimitiveName(name: String) = JvmPrimitiveType.values().any { it.javaKeywordName == name }
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.codegen.optimization.removeNodeGetNext
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
@@ -36,7 +35,7 @@ val AbstractInsnNode.isMeaningful: Boolean
|
||||
|
||||
val AbstractInsnNode.isBranchOrCall: Boolean
|
||||
get() =
|
||||
when(this.type) {
|
||||
when (this.type) {
|
||||
AbstractInsnNode.JUMP_INSN,
|
||||
AbstractInsnNode.TABLESWITCH_INSN,
|
||||
AbstractInsnNode.LOOKUPSWITCH_INSN,
|
||||
@@ -85,13 +84,17 @@ fun MethodNode.prepareForEmitting() {
|
||||
|
||||
current = prev
|
||||
}
|
||||
updateMaxStack()
|
||||
}
|
||||
|
||||
fun MethodNode.updateMaxStack() {
|
||||
maxStack = -1
|
||||
accept(
|
||||
MaxStackFrameSizeAndLocalsCalculator(
|
||||
Opcodes.API_VERSION, access, desc,
|
||||
object : MethodVisitor(Opcodes.API_VERSION) {
|
||||
API_VERSION, access, desc,
|
||||
object : MethodVisitor(API_VERSION) {
|
||||
override fun visitMaxs(maxStack: Int, maxLocals: Int) {
|
||||
this@prepareForEmitting.maxStack = maxStack
|
||||
this@updateMaxStack.maxStack = maxStack
|
||||
}
|
||||
})
|
||||
)
|
||||
@@ -100,10 +103,10 @@ fun MethodNode.prepareForEmitting() {
|
||||
fun MethodNode.stripOptimizationMarkers() {
|
||||
var insn = instructions.first
|
||||
while (insn != null) {
|
||||
if (isOptimizationMarker(insn)) {
|
||||
insn = instructions.removeNodeGetNext(insn)
|
||||
insn = if (isOptimizationMarker(insn)) {
|
||||
instructions.removeNodeGetNext(insn)
|
||||
} else {
|
||||
insn = insn.next
|
||||
insn.next
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,7 +126,7 @@ fun MethodNode.removeUnusedLocalVariables() {
|
||||
// Arguments are always used whether or not they are in the local variable table
|
||||
// or used by instructions.
|
||||
var argumentIndex = 0
|
||||
val isStatic = (access and Opcodes.ACC_STATIC) != 0
|
||||
val isStatic = (access and ACC_STATIC) != 0
|
||||
if (!isStatic) {
|
||||
used[argumentIndex++] = true
|
||||
}
|
||||
@@ -230,8 +233,8 @@ val AbstractInsnNode.intConstant: Int?
|
||||
|
||||
fun insnListOf(vararg insns: AbstractInsnNode) = InsnList().apply { insns.forEach { add(it) } }
|
||||
|
||||
fun AbstractInsnNode.isStoreOperation(): Boolean = opcode in Opcodes.ISTORE..Opcodes.ASTORE
|
||||
fun AbstractInsnNode.isLoadOperation(): Boolean = opcode in Opcodes.ILOAD..Opcodes.ALOAD
|
||||
fun AbstractInsnNode.isStoreOperation(): Boolean = opcode in ISTORE..ASTORE
|
||||
fun AbstractInsnNode.isLoadOperation(): Boolean = opcode in ILOAD..ALOAD
|
||||
|
||||
val AbstractInsnNode?.debugText
|
||||
get() =
|
||||
|
||||
@@ -441,7 +441,7 @@ fun MethodNode.usesLocalExceptParameterNullCheck(index: Int): Boolean =
|
||||
it is VarInsnNode && it.opcode == Opcodes.ALOAD && it.`var` == index && !it.isParameterCheckedForNull()
|
||||
}
|
||||
|
||||
internal fun AbstractInsnNode.isParameterCheckedForNull(): Boolean =
|
||||
fun AbstractInsnNode.isParameterCheckedForNull(): Boolean =
|
||||
next?.takeIf { it.opcode == Opcodes.LDC }?.next?.isCheckParameterIsNotNull() == true
|
||||
|
||||
internal fun AbstractInsnNode.isCheckParameterIsNotNull() =
|
||||
|
||||
@@ -37,7 +37,6 @@ import org.jetbrains.kotlin.psi.KtCodeFragment
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.deprecation.CoroutineCompatibilitySupport
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.PrecomputedSuppressCache
|
||||
@@ -158,8 +157,7 @@ class GenerationState private constructor(
|
||||
CompilerDeserializationConfiguration(languageVersionSettings)
|
||||
|
||||
val deprecationProvider = DeprecationResolver(
|
||||
LockBasedStorageManager.NO_LOCKS, languageVersionSettings, CoroutineCompatibilitySupport.ENABLED,
|
||||
JavaDeprecationSettings
|
||||
LockBasedStorageManager.NO_LOCKS, languageVersionSettings, JavaDeprecationSettings
|
||||
)
|
||||
|
||||
init {
|
||||
|
||||
@@ -193,7 +193,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
if (descriptor.isSuspendFunctionNotSuspensionView()) {
|
||||
return mapReturnType(getOrCreateJvmSuspendFunctionView(descriptor as SimpleFunctionDescriptor, isReleaseCoroutines), sw)
|
||||
return mapReturnType(getOrCreateJvmSuspendFunctionView(descriptor as SimpleFunctionDescriptor), sw)
|
||||
}
|
||||
|
||||
if (hasVoidReturnType(descriptor)) {
|
||||
@@ -804,7 +804,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
if (f.isSuspendFunctionNotSuspensionView()) {
|
||||
return mapSignature(getOrCreateJvmSuspendFunctionView(f, isReleaseCoroutines), kind, skipGenericSignature)
|
||||
return mapSignature(getOrCreateJvmSuspendFunctionView(f), kind, skipGenericSignature)
|
||||
}
|
||||
|
||||
if (isDeclarationOfBigArityFunctionInvoke(f) || isDeclarationOfBigArityCreateCoroutineMethod(f)) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
|
||||
import org.jetbrains.kotlin.ideaExt.idea
|
||||
import java.io.File
|
||||
|
||||
@@ -10,8 +9,6 @@ plugins {
|
||||
val compilerModules: Array<String> by rootProject.extra
|
||||
val otherCompilerModules = compilerModules.filter { it != path }
|
||||
|
||||
val tasksWithWarnings: List<String> by rootProject.extra
|
||||
|
||||
val antLauncherJar by configurations.creating
|
||||
|
||||
dependencies {
|
||||
@@ -68,18 +65,6 @@ if (kotlinBuildProperties.isInJpsBuildIdeaSync) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!kotlinBuildProperties.disableWerror) {
|
||||
allprojects {
|
||||
tasks.withType<KotlinCompile<*>> {
|
||||
if (path !in tasksWithWarnings) {
|
||||
kotlinOptions {
|
||||
allWarningsAsErrors = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
projectTest(parallel = true) {
|
||||
dependsOn(":dist")
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.ir.backend.js.ic.buildCache
|
||||
import org.jetbrains.kotlin.ir.backend.js.ic.checkCaches
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
|
||||
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
|
||||
import org.jetbrains.kotlin.js.config.*
|
||||
import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION
|
||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||
@@ -205,7 +206,6 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
cachePath = outputFilePath,
|
||||
project = projectJs,
|
||||
mainModule = mainModule,
|
||||
analyzer = AnalyzerWithCompilerReport(config.configuration),
|
||||
configuration = config.configuration,
|
||||
dependencies = libraries,
|
||||
friendDependencies = friendLibraries,
|
||||
@@ -219,18 +219,37 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
return OK
|
||||
}
|
||||
|
||||
// Run analysis if main module is sources
|
||||
lateinit var sourceModule: ModulesStructure
|
||||
if (arguments.includes == null) {
|
||||
do {
|
||||
sourceModule = prepareAnalyzedSourceModule(
|
||||
projectJs,
|
||||
environmentForJS.getSourceFiles(),
|
||||
configurationJs,
|
||||
libraries,
|
||||
friendLibraries,
|
||||
AnalyzerWithCompilerReport(config.configuration),
|
||||
icUseGlobalSignatures = icCaches.isNotEmpty(),
|
||||
icUseStdlibCache = icCaches.isNotEmpty(),
|
||||
icCache = if (icCaches.isNotEmpty()) checkCaches(libraries, icCaches, skipLib = arguments.includes).data else emptyMap()
|
||||
)
|
||||
val result = sourceModule.jsFrontEndResult.jsAnalysisResult
|
||||
if (result is JsAnalysisResult.RetryWithAdditionalRoots) {
|
||||
environmentForJS.addKotlinSourceRoots(result.additionalKotlinRoots)
|
||||
}
|
||||
} while (result is JsAnalysisResult.RetryWithAdditionalRoots)
|
||||
if (!sourceModule.jsFrontEndResult.jsAnalysisResult.shouldGenerateCode)
|
||||
return OK
|
||||
}
|
||||
|
||||
if (arguments.irProduceKlibDir || arguments.irProduceKlibFile) {
|
||||
if (arguments.irProduceKlibFile) {
|
||||
require(outputFile.extension == KLIB_FILE_EXTENSION) { "Please set up .klib file as output" }
|
||||
}
|
||||
|
||||
generateKLib(
|
||||
project = config.project,
|
||||
files = sourcesFiles,
|
||||
analyzer = AnalyzerWithCompilerReport(config.configuration),
|
||||
configuration = config.configuration,
|
||||
dependencies = libraries,
|
||||
friendDependencies = friendLibraries,
|
||||
sourceModule,
|
||||
irFactory = PersistentIrFactory(), // TODO IrFactoryImpl?
|
||||
outputKlibPath = outputFile.path,
|
||||
nopack = arguments.irProduceKlibDir,
|
||||
@@ -246,28 +265,33 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
|
||||
val includes = arguments.includes
|
||||
|
||||
val mainModule = if (includes != null) {
|
||||
val module = if (includes != null) {
|
||||
if (sourcesFiles.isNotEmpty()) {
|
||||
messageCollector.report(ERROR, "Source files are not supported when -Xinclude is present")
|
||||
}
|
||||
val includesPath = File(includes).canonicalPath
|
||||
val mainLibPath = libraries.find { File(it).canonicalPath == includesPath }
|
||||
?: error("No library with name $includes ($includesPath) found")
|
||||
MainModule.Klib(mainLibPath)
|
||||
val kLib = MainModule.Klib(mainLibPath)
|
||||
ModulesStructure(
|
||||
projectJs,
|
||||
kLib,
|
||||
configurationJs,
|
||||
libraries,
|
||||
friendLibraries,
|
||||
icUseGlobalSignatures = icCaches.isNotEmpty(),
|
||||
icUseStdlibCache = icCaches.isNotEmpty(),
|
||||
icCache = if (icCaches.isNotEmpty()) checkCaches(libraries, icCaches, skipLib = includes).data else emptyMap()
|
||||
)
|
||||
} else {
|
||||
MainModule.SourceFiles(sourcesFiles)
|
||||
sourceModule
|
||||
}
|
||||
|
||||
if (arguments.wasm) {
|
||||
val res = compileWasm(
|
||||
projectJs,
|
||||
mainModule,
|
||||
AnalyzerWithCompilerReport(config.configuration),
|
||||
config.configuration,
|
||||
module,
|
||||
PhaseConfig(wasmPhases),
|
||||
IrFactoryImpl,
|
||||
dependencies = libraries,
|
||||
friendDependencies = friendLibraries,
|
||||
exportedDeclarations = setOf(FqName("main"))
|
||||
)
|
||||
val outputWasmFile = outputFile.withReplacedExtensionOrNull(outputFile.extension, "wasm")!!
|
||||
@@ -289,14 +313,9 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
val start = System.currentTimeMillis()
|
||||
|
||||
val compiledModule = compile(
|
||||
projectJs,
|
||||
mainModule,
|
||||
AnalyzerWithCompilerReport(config.configuration),
|
||||
config.configuration,
|
||||
module,
|
||||
phaseConfig,
|
||||
if (arguments.irDceDriven) PersistentIrFactory() else IrFactoryImpl,
|
||||
dependencies = libraries,
|
||||
friendDependencies = friendLibraries,
|
||||
mainArguments = mainCallArguments,
|
||||
generateFullJs = !arguments.irDce,
|
||||
generateDceJs = arguments.irDce,
|
||||
@@ -316,8 +335,6 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
messageCollector
|
||||
),
|
||||
lowerPerModule = icCaches.isNotEmpty(),
|
||||
useStdlibCache = icCaches.isNotEmpty(),
|
||||
icCache = if (icCaches.isNotEmpty()) checkCaches(libraries, icCaches, skipLib = includes).data else emptyMap(),
|
||||
)
|
||||
|
||||
messageCollector.report(INFO, "Executable production duration: ${System.currentTimeMillis() - start}ms")
|
||||
|
||||
@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.load.java.components.JavaDeprecationSettings
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.deprecation.CoroutineCompatibilitySupport
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -84,7 +83,6 @@ class CliLightClassGenerationSupport(
|
||||
get() = DeprecationResolver(
|
||||
LockBasedStorageManager.NO_LOCKS,
|
||||
languageVersionSettings,
|
||||
CoroutineCompatibilitySupport.ENABLED,
|
||||
JavaDeprecationSettings
|
||||
)
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.config
|
||||
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
fun LanguageVersionSettings.coroutinesPackageFqName(): FqName {
|
||||
return coroutinesPackageFqName(isReleaseCoroutines())
|
||||
}
|
||||
|
||||
fun LanguageVersionSettings.isReleaseCoroutines() = supportsFeature(LanguageFeature.ReleaseCoroutines)
|
||||
|
||||
private fun coroutinesPackageFqName(isReleaseCoroutines: Boolean): FqName {
|
||||
return if (isReleaseCoroutines)
|
||||
StandardNames.COROUTINES_PACKAGE_FQ_NAME_RELEASE
|
||||
else
|
||||
StandardNames.COROUTINES_PACKAGE_FQ_NAME_EXPERIMENTAL
|
||||
}
|
||||
|
||||
fun LanguageVersionSettings.coroutinesIntrinsicsPackageFqName() =
|
||||
coroutinesPackageFqName().child(Name.identifier("intrinsics"))
|
||||
|
||||
fun LanguageVersionSettings.continuationInterfaceFqName() =
|
||||
coroutinesPackageFqName().child(Name.identifier("Continuation"))
|
||||
|
||||
fun LanguageVersionSettings.restrictsSuspensionFqName() =
|
||||
coroutinesPackageFqName().child(Name.identifier("RestrictsSuspension"))
|
||||
|
||||
fun FqName.isBuiltInCoroutineContext(languageVersionSettings: LanguageVersionSettings) =
|
||||
if (languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines))
|
||||
this == StandardNames.COROUTINES_PACKAGE_FQ_NAME_RELEASE.child(Name.identifier("coroutineContext"))
|
||||
else
|
||||
this == StandardNames.COROUTINES_PACKAGE_FQ_NAME_EXPERIMENTAL.child(Name.identifier("coroutineContext")) ||
|
||||
this == StandardNames.COROUTINES_INTRINSICS_PACKAGE_FQ_NAME_EXPERIMENTAL.child(Name.identifier("coroutineContext"))
|
||||
@@ -12,7 +12,7 @@ fun test() {
|
||||
|
||||
bar(1, z = true, y = *arrayOf("my", "yours"))
|
||||
|
||||
bar(0, z = false, y = "", <!ARGUMENT_PASSED_TWICE!>y<!> = "other")
|
||||
bar(0, z = false, y = <!ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION_ERROR!>""<!>, <!ARGUMENT_PASSED_TWICE!>y<!> = "other")
|
||||
bar(0, "", true<!NO_VALUE_FOR_PARAMETER!>)<!>
|
||||
bar(0, z = false, y = "", <!ARGUMENT_PASSED_TWICE!>y<!> = "other", <!ARGUMENT_PASSED_TWICE!>y<!> = "yet other")
|
||||
bar(0, z = false, y = <!ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION_ERROR!>""<!>, <!ARGUMENT_PASSED_TWICE!>y<!> = "other", <!ARGUMENT_PASSED_TWICE!>y<!> = "yet other")
|
||||
}
|
||||
|
||||
@@ -23,6 +23,16 @@ FILE: const.kt
|
||||
public get(): R|kotlin/Int|
|
||||
public final const val l: R|kotlin/Int| = R|/k|
|
||||
public get(): R|kotlin/Int|
|
||||
public final const val m: R|kotlin/String| = String(123).R|kotlin/Any.toString|()
|
||||
public get(): R|kotlin/String|
|
||||
public final const val n: R|kotlin/Int| = String(456).R|kotlin/String.length|
|
||||
public get(): R|kotlin/Int|
|
||||
public final val o: R|kotlin/String| = String(789)
|
||||
public get(): R|kotlin/String|
|
||||
public final const val p: R|kotlin/String| = R|/o|.R|kotlin/Any.toString|()
|
||||
public get(): R|kotlin/String|
|
||||
public final const val q: R|kotlin/Int| = R|/o|.R|kotlin/String.length|
|
||||
public get(): R|kotlin/Int|
|
||||
public final class ForConst : R|kotlin/Any| {
|
||||
public constructor(): R|ForConst| {
|
||||
super<R|kotlin/Any|>()
|
||||
|
||||
@@ -18,6 +18,11 @@ const val i = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>ForConst.one() + "one"<!>
|
||||
const val j = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>4 * ForConst.two()<!>
|
||||
val k = 3 - ForConst.two()
|
||||
const val l = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>k<!>
|
||||
const val m = "123".toString()
|
||||
const val n = "456".length
|
||||
val o = "789"
|
||||
const val p = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>o.toString()<!>
|
||||
const val q = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>o.length<!>
|
||||
|
||||
class ForConst{
|
||||
companion object {
|
||||
|
||||
@@ -38,5 +38,5 @@ object F {
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
const val a = "2"
|
||||
<!WRONG_MODIFIER_TARGET!>const<!> val a = "2"
|
||||
}
|
||||
|
||||
@@ -8,17 +8,17 @@ fun test() {}
|
||||
|
||||
fun test(z: Int, c: Char) {}
|
||||
|
||||
<!REDECLARATION!>open class A {
|
||||
open class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>A<!> {
|
||||
open fun rest(s: String) {}
|
||||
|
||||
open val u = 20
|
||||
}<!>
|
||||
}
|
||||
|
||||
<!REDECLARATION!>class A {
|
||||
class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>A<!> {
|
||||
|
||||
}<!>
|
||||
}
|
||||
|
||||
<!REDECLARATION!>class B : <!FINAL_SUPERTYPE, SUPERTYPE_NOT_INITIALIZED!>A<!> {
|
||||
class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>B<!> : <!FINAL_SUPERTYPE, SUPERTYPE_NOT_INITIALIZED!>A<!> {
|
||||
<!CONFLICTING_OVERLOADS!><!NOTHING_TO_OVERRIDE!>override<!> fun rest(s: String)<!> {}
|
||||
|
||||
<!CONFLICTING_OVERLOADS!>fun rest(s: String)<!> {}
|
||||
@@ -26,17 +26,17 @@ fun test(z: Int, c: Char) {}
|
||||
fun rest(l: Long) {}
|
||||
|
||||
<!NOTHING_TO_OVERRIDE!>override<!> val u = 310
|
||||
}<!>
|
||||
}
|
||||
|
||||
<!REDECLARATION!>interface B<!>
|
||||
interface <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>B<!>
|
||||
|
||||
<!REDECLARATION!>enum class B<!>
|
||||
enum class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>B<!>
|
||||
|
||||
<!REDECLARATION!>val u = 10<!>
|
||||
<!REDECLARATION!>val u = 20<!>
|
||||
val <!REDECLARATION!>u<!> = 10
|
||||
val <!REDECLARATION!>u<!> = 20
|
||||
|
||||
<!REDECLARATION!>typealias TA = A<!>
|
||||
<!REDECLARATION!>typealias TA = B<!>
|
||||
typealias <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>TA<!> = A
|
||||
typealias <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>TA<!> = B
|
||||
|
||||
typealias BA = A
|
||||
|
||||
@@ -52,7 +52,7 @@ fun lol(a: Array<Boolean>) {}
|
||||
|
||||
class M {
|
||||
companion <!REDECLARATION!>object<!> {}
|
||||
<!REDECLARATION!>val Companion = object : Any {}<!>
|
||||
val <!REDECLARATION!>Companion<!> = object : Any {}
|
||||
}
|
||||
|
||||
fun B.foo() {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>public<!> class B
|
||||
<!INCOMPATIBLE_MODIFIERS!>protected<!> <!INCOMPATIBLE_MODIFIERS!>internal<!> class C
|
||||
<!WRONG_MODIFIER_CONTAINING_DECLARATION!>protected<!> <!INCOMPATIBLE_MODIFIERS!>internal<!> class C
|
||||
|
||||
<!INCOMPATIBLE_MODIFIERS!>final<!> <!INCOMPATIBLE_MODIFIERS!>abstract<!> class D
|
||||
<!INCOMPATIBLE_MODIFIERS!>final<!> <!INCOMPATIBLE_MODIFIERS!>open<!> class E
|
||||
|
||||
@@ -6,11 +6,11 @@ infix fun Int.good(x: Int) {}
|
||||
|
||||
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun baz(x: Int, y: Int) {}<!>
|
||||
|
||||
infix class A
|
||||
<!WRONG_MODIFIER_TARGET!>infix<!> class A
|
||||
|
||||
infix typealias B = A
|
||||
<!WRONG_MODIFIER_TARGET!>infix<!> typealias B = A
|
||||
|
||||
infix val x = 1
|
||||
<!WRONG_MODIFIER_TARGET!>infix<!> val x = 1
|
||||
|
||||
class C {
|
||||
infix fun good(x: Int) {}
|
||||
|
||||
@@ -37,7 +37,7 @@ class F(var a: Int, b: Int, closure: () -> Unit, instance: F?) {
|
||||
val a = 10
|
||||
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>
|
||||
test(<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>)
|
||||
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>a<!> = 20
|
||||
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.a = 20
|
||||
}, <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>) {
|
||||
this.a = 30
|
||||
}
|
||||
|
||||
@@ -13,13 +13,13 @@ interface B {
|
||||
}
|
||||
|
||||
interface C {
|
||||
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override operator fun toString(): String = "Rest"<!>
|
||||
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun toString(): String = "Rest"<!>
|
||||
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override operator fun equals(other: Any?): Boolean = false<!>
|
||||
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override operator fun hashCode(): Int = 2<!>
|
||||
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun hashCode(): Int = 2<!>
|
||||
}
|
||||
|
||||
interface D {
|
||||
override operator fun toString(): String
|
||||
override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun toString(): String
|
||||
override operator fun equals(other: Any?): Boolean
|
||||
override operator fun hashCode(): Int
|
||||
override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun hashCode(): Int
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ FILE: notASupertype.kt
|
||||
}
|
||||
|
||||
public final fun g(): R|kotlin/Unit| {
|
||||
this@R|/B|.super<R|kotlin/String|>.<Unresolved name: f>#()
|
||||
this@R|/B|.super<<ERROR TYPE REF: Not a super type>>.<Unresolved name: f>#()
|
||||
this@R|/B|.super<R|A|>.R|/A.f|()
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ open class A {
|
||||
|
||||
class B : <!SUPERTYPE_NOT_INITIALIZED!>A<!> {
|
||||
fun g() {
|
||||
<!NOT_A_SUPERTYPE!>super<String><!>.<!UNRESOLVED_REFERENCE!>f<!>()
|
||||
super<<!NOT_A_SUPERTYPE!>String<!>>.f()
|
||||
super<A>.f()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
sealed class A
|
||||
|
||||
<!REDECLARATION!>class B : A()<!>
|
||||
class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>B<!> : A()
|
||||
|
||||
interface C : <!INTERFACE_WITH_SUPERCLASS!>A<!>
|
||||
|
||||
@@ -30,7 +30,7 @@ sealed class P {
|
||||
|
||||
class K : P()
|
||||
|
||||
<!REDECLARATION!>object B<!> {
|
||||
object <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>B<!> {
|
||||
class I : P()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
FILE: superNotAvailable.kt
|
||||
public final fun R|kotlin/String|.f(): R|kotlin/Unit| {
|
||||
super<<ERROR TYPE REF: No super type>>@f#.<Unresolved name: compareTo>#(String())
|
||||
super<<ERROR TYPE REF: No super type>>.<Unresolved name: compareTo>#(String())
|
||||
<Super not available>#.<Unresolved name: compareTo>#(String())
|
||||
<Super not available>#.<Unresolved name: compareTo>#(String())
|
||||
}
|
||||
public final fun foo(): R|kotlin/Unit| {
|
||||
super<<ERROR TYPE REF: No super type>>
|
||||
super<<ERROR TYPE REF: No super type>>.<Unresolved name: foo>#()
|
||||
super<R|kotlin/Nothing|>.<Unresolved name: foo>#()
|
||||
<Super not allowed>#
|
||||
<Super not available>#.<Unresolved name: foo>#()
|
||||
<Super not available>#.<Unresolved name: foo>#()
|
||||
}
|
||||
public final class A : R|kotlin/Any| {
|
||||
public constructor(): R|A| {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
fun String.f() {
|
||||
<!SUPER_NOT_AVAILABLE!>super@f<!>.<!UNRESOLVED_REFERENCE!>compareTo<!>("")
|
||||
<!SUPER_NOT_AVAILABLE!>super<!>.<!UNRESOLVED_REFERENCE!>compareTo<!>("")
|
||||
<!SUPER_NOT_AVAILABLE!>super@f<!>.compareTo("")
|
||||
<!SUPER_NOT_AVAILABLE!>super<!>.compareTo("")
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
<!SUPER_NOT_AVAILABLE!>super<!>
|
||||
<!SUPER_NOT_AVAILABLE!>super<!>.<!UNRESOLVED_REFERENCE!>foo<!>()
|
||||
<!SUPER_NOT_AVAILABLE!>super<Nothing><!>.<!UNRESOLVED_REFERENCE!>foo<!>()
|
||||
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>
|
||||
<!SUPER_NOT_AVAILABLE!>super<!>.foo()
|
||||
<!SUPER_NOT_AVAILABLE!>super<Nothing><!>.foo()
|
||||
}
|
||||
|
||||
class A {
|
||||
|
||||
@@ -16,7 +16,7 @@ FILE: test.kt
|
||||
private final val DERIVED_FACTORY: R|DiagnosticFactory0<ft<DerivedElement, DerivedElement?>>| = R|/DiagnosticFactory0.DiagnosticFactory0|<R|ft<DerivedElement, DerivedElement?>|>()
|
||||
private get(): R|DiagnosticFactory0<ft<DerivedElement, DerivedElement?>>|
|
||||
public final fun createViaFactory(d: R|EmptyDiagnostic|): R|kotlin/Unit| {
|
||||
lval casted: R|Diagnostic<ft<DerivedElement, DerivedElement?>>| = R|/DERIVED_FACTORY|.R|SubstitutionOverride</DiagnosticFactory0.cast: R|Diagnostic<ft<DerivedElement, DerivedElement?>>|>|(R|<local>/d|)
|
||||
lval casted: R|Diagnostic<ft<DerivedElement, DerivedElement?>>| = R|/DERIVED_FACTORY|.R|SubstitutionOverride</DiagnosticFactory0.cast: R|@EnhancedNullability Diagnostic<ft<DerivedElement, DerivedElement?>>|>|(R|<local>/d|)
|
||||
lval element: R|DerivedElement| = R|<local>/casted|.R|/Diagnostic.element|
|
||||
R|/Fix.Fix|(R|<local>/element|)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
fun x() {}
|
||||
|
||||
operator fun Int.invoke(): Foo = <!UNRESOLVED_LABEL!>this@Foo<!>
|
||||
operator fun Int.invoke(): Foo = this<!UNRESOLVED_LABEL!>@Foo<!>
|
||||
|
||||
class Foo {
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!REDECLARATION!>object A<!>
|
||||
object <!REDECLARATION!>A<!>
|
||||
|
||||
<!REDECLARATION!>val A = 10<!>
|
||||
val <!REDECLARATION!>A<!> = 10
|
||||
|
||||
|
||||
fun foo() = A
|
||||
|
||||
@@ -10,7 +10,7 @@ interface Interface {
|
||||
// Redundant
|
||||
<!REDUNDANT_MODALITY_MODIFIER!>abstract<!> fun foo()
|
||||
// error
|
||||
<!PRIVATE_FUNCTION_WITH_NO_BODY!>private<!> final fun bar()
|
||||
<!PRIVATE_FUNCTION_WITH_NO_BODY!>private<!> <!WRONG_MODIFIER_CONTAINING_DECLARATION!>final<!> fun bar()
|
||||
|
||||
<!REDUNDANT_MODALITY_MODIFIER!>open<!> fun goo() {}
|
||||
<!REDUNDANT_MODALITY_MODIFIER!>abstract<!> fun tar()
|
||||
@@ -63,7 +63,7 @@ interface Derived : Interface {
|
||||
// Redundant
|
||||
override <!REDUNDANT_MODALITY_MODIFIER!>open<!> fun foo() {}
|
||||
// error
|
||||
final class Nested
|
||||
<!WRONG_MODIFIER_CONTAINING_DECLARATION!>final<!> class Nested
|
||||
}
|
||||
// Derived abstract class
|
||||
abstract class AbstractDerived1(override final val gav: Int) : Interface {
|
||||
@@ -82,4 +82,4 @@ abstract interface AbstractInterface
|
||||
// Redundant final object
|
||||
<!REDUNDANT_MODALITY_MODIFIER!>final<!> object FinalObject
|
||||
// Open interface
|
||||
open interface OpenInterface
|
||||
<!REDUNDANT_MODIFIER_FOR_TARGET!>open<!> interface OpenInterface
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||
annotation class Ann
|
||||
|
||||
<!REDECLARATION!>var x: Int
|
||||
var <!REDECLARATION!>x<!>: Int
|
||||
get() = 1
|
||||
set(@Ann private x) { }<!>
|
||||
set(@Ann <!WRONG_MODIFIER_TARGET!>private<!> x) { }
|
||||
|
||||
|
||||
<!REDECLARATION!>var x: String = ""
|
||||
var <!REDECLARATION!>x<!>: String = ""
|
||||
set(param: <!REDUNDANT_SETTER_PARAMETER_TYPE!>String<!>) {
|
||||
field = "$param "
|
||||
}<!>
|
||||
}
|
||||
|
||||
class My {
|
||||
var y: Int = 1
|
||||
@@ -25,4 +25,4 @@ class My {
|
||||
set(param) {
|
||||
field = !param
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fun f() {
|
||||
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> <!CAN_BE_VAL!>var<!> <!UNUSED_VARIABLE!>baz<!> = 0
|
||||
<!REDUNDANT_VISIBILITY_MODIFIER, WRONG_MODIFIER_TARGET!>public<!> <!CAN_BE_VAL!>var<!> <!UNUSED_VARIABLE!>baz<!> = 0
|
||||
class LocalClass {
|
||||
<!REDUNDANT_VISIBILITY_MODIFIER!>internal<!> var foo = 0
|
||||
}
|
||||
@@ -10,11 +10,11 @@ internal <!NOTHING_TO_INLINE!>inline<!> fun internal() {
|
||||
f()
|
||||
}
|
||||
|
||||
<!REDECLARATION!>class C {
|
||||
class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>C<!> {
|
||||
internal val z = object {
|
||||
fun foo() = 13
|
||||
}
|
||||
}<!>
|
||||
}
|
||||
|
||||
class Foo2<
|
||||
T1,
|
||||
@@ -26,12 +26,12 @@ class Foo2<
|
||||
internal inner class B<T,T2,>
|
||||
}
|
||||
|
||||
<!REDECLARATION!><!REDUNDANT_VISIBILITY_MODIFIER!>public<!> class C {
|
||||
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>C<!> {
|
||||
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> val foo: Int = 0
|
||||
|
||||
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> fun bar() {}
|
||||
|
||||
}<!>
|
||||
}
|
||||
|
||||
open class D {
|
||||
protected open fun willRemainProtected() {
|
||||
|
||||
@@ -15,7 +15,7 @@ open class B {
|
||||
override fun foo() {
|
||||
super.foo()
|
||||
|
||||
super.<!UNRESOLVED_REFERENCE!>bar<!>() // should be ambiguity (NB: really we should have overridden bar in C)
|
||||
<!AMBIGUOUS_SUPER!>super<!>.bar() // should be ambiguity (NB: really we should have overridden bar in C)
|
||||
|
||||
super.baz() // Ok
|
||||
baz() // Ok
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class A {
|
||||
<!INLINE_CLASS_NOT_TOP_LEVEL!>inline<!> inner class B(val x: Int)
|
||||
fun foo() {
|
||||
<!INLINE_CLASS_NOT_TOP_LEVEL!>inline<!> class C(val x: Int)
|
||||
<!INLINE_CLASS_NOT_TOP_LEVEL, WRONG_MODIFIER_TARGET!>inline<!> class C(val x: Int)
|
||||
}
|
||||
inner <!INLINE_CLASS_NOT_TOP_LEVEL!>value<!> class D(val x: Int)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ abstract class NotRange4() {
|
||||
}
|
||||
|
||||
abstract class ImproperIterator3 {
|
||||
abstract operator fun hasNext() : Int
|
||||
abstract <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun hasNext() : Int
|
||||
abstract operator fun next() : Int
|
||||
}
|
||||
|
||||
|
||||
28
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/EnumWithToString.fir.txt
vendored
Normal file
28
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/EnumWithToString.fir.txt
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
FILE: EnumWithToString.kt
|
||||
public final enum class Some : R|kotlin/Enum<Some>| {
|
||||
private constructor(): R|Some| {
|
||||
super<R|kotlin/Enum<Some>|>()
|
||||
}
|
||||
|
||||
public final static enum entry ENTRY: R|Some| = object : R|Some| {
|
||||
private constructor(): R|<anonymous>| {
|
||||
super<R|Some|>()
|
||||
}
|
||||
|
||||
public final override fun toString(): R|kotlin/String| {
|
||||
^toString String(Entry)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public open override fun toString(): R|kotlin/String| {
|
||||
^toString String(Some)
|
||||
}
|
||||
|
||||
public final static fun values(): R|kotlin/Array<Some>| {
|
||||
}
|
||||
|
||||
public final static fun valueOf(value: R|kotlin/String|): R|Some| {
|
||||
}
|
||||
|
||||
}
|
||||
7
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/EnumWithToString.kt
vendored
Normal file
7
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/EnumWithToString.kt
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
enum class Some {
|
||||
ENTRY {
|
||||
override fun toString(): String = "Entry"
|
||||
};
|
||||
|
||||
override fun toString(): String = "Some"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
FILE: IntersectionWithJavaString.kt
|
||||
public final fun collapse(path: R|kotlin/String|): R|kotlin/Unit| {
|
||||
lval result: R|ft<kotlin/String, kotlin/String?>| = (R|<local>/path| as R|java/lang/String|).R|java/lang/String.replace|(String(123), String(456))
|
||||
when () {
|
||||
!==(R|<local>/result|, R|<local>/path|) -> {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// FULL_JDK
|
||||
fun collapse(path: String) {
|
||||
val result = (path as java.lang.String).replace("123", "456")
|
||||
if (<!EQUALITY_NOT_APPLICABLE_WARNING!>result !== path<!>) {}
|
||||
}
|
||||
19
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/PersistentStateComponent.fir.txt
vendored
Normal file
19
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/PersistentStateComponent.fir.txt
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
FILE: use.kt
|
||||
public final class BeforeRunTask<T> : R|kotlin/Any| {
|
||||
public constructor<T>(): R|BeforeRunTask<T>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public abstract interface PersistentStateComponent<T> : R|kotlin/Any| {
|
||||
}
|
||||
public final fun <T> deserializeAndLoadState(component: R|PersistentStateComponent<T>|, clazz: R|java/lang/Class<T>| = Q|ComponentSerializationUtil|.R|/ComponentSerializationUtil.getStateClass|<R|ft<T!!, T?>|>(<getClass>(R|<local>/component|).R|kotlin/jvm/java|<R|CapturedType(out PersistentStateComponent<T>)|>)): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun use(beforeRunTask: R|BeforeRunTask<*>|): R|kotlin/Unit| {
|
||||
when () {
|
||||
(R|<local>/beforeRunTask| is R|PersistentStateComponent<*>|) -> {
|
||||
R|/deserializeAndLoadState|<R|CapturedType(*)|>(R|<local>/beforeRunTask|)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
27
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/PersistentStateComponent.kt
vendored
Normal file
27
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/PersistentStateComponent.kt
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// FILE: ComponentSerializationUtil.java
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class ComponentSerializationUtil {
|
||||
@NotNull
|
||||
public static <S> Class<S> getStateClass(@NotNull Class<? extends PersistentStateComponent> aClass)
|
||||
{}
|
||||
}
|
||||
|
||||
// FILE: use.kt
|
||||
|
||||
class BeforeRunTask<T>
|
||||
|
||||
interface PersistentStateComponent<T>
|
||||
|
||||
fun <T> deserializeAndLoadState(
|
||||
component: PersistentStateComponent<T>,
|
||||
clazz: Class<T> = ComponentSerializationUtil.getStateClass(component::class.java)
|
||||
) {}
|
||||
|
||||
fun use(beforeRunTask: BeforeRunTask<*>) {
|
||||
if (beforeRunTask is PersistentStateComponent<*>) {
|
||||
deserializeAndLoadState(beforeRunTask)
|
||||
}
|
||||
}
|
||||
|
||||
42
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/UastPatterns.fir.txt
vendored
Normal file
42
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/UastPatterns.fir.txt
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
FILE: UastPatterns.kt
|
||||
public abstract interface UElement : R|kotlin/Any| {
|
||||
}
|
||||
public abstract interface UExpression : R|UElement| {
|
||||
}
|
||||
public abstract interface UReferenceExpression : R|UExpression| {
|
||||
}
|
||||
public final fun injectionHostOrReferenceExpression(): R|UExpressionPattern.Capture<UExpression>| {
|
||||
^injectionHostOrReferenceExpression R|/uExpression|().R|SubstitutionOverride</UExpressionPattern.Capture.filter: R|UExpressionPattern.Capture<UExpression>|>|(<L> = filter@fun <anonymous>(it: R|UExpression|): R|kotlin/Boolean| <inline=NoInline> {
|
||||
^ (R|<local>/it| is R|UReferenceExpression|)
|
||||
}
|
||||
)
|
||||
}
|
||||
public final fun uExpression(): R|UExpressionPattern.Capture<UExpression>| {
|
||||
^uExpression R|/expressionCapture|<R|UExpression|>(<getClass>(Q|UExpression|).R|kotlin/jvm/java|<R|UExpression|>)
|
||||
}
|
||||
public final fun <T : R|UExpression|> expressionCapture(clazz: R|java/lang/Class<T>|): R|UExpressionPattern.Capture<T>| {
|
||||
^expressionCapture Q|UExpressionPattern|.R|SubstitutionOverride</UExpressionPattern.Capture.Capture>|<R|T|>(R|<local>/clazz|)
|
||||
}
|
||||
public open class UElementPattern<T : R|UElement|, Self : R|UElementPattern<T, Self>|> : R|ObjectPattern<T, Self>| {
|
||||
public constructor<T : R|UElement|, Self : R|UElementPattern<T, Self>|>(clazz: R|java/lang/Class<T>|): R|UElementPattern<T, Self>| {
|
||||
super<R|ObjectPattern<T, Self>|>(R|<local>/clazz|)
|
||||
}
|
||||
|
||||
public final fun filter(filter: R|(T) -> kotlin/Boolean|): R|Self| {
|
||||
^filter (this@R|/UElementPattern| as R|Self|)
|
||||
}
|
||||
|
||||
}
|
||||
public open class UExpressionPattern<T : R|UExpression|, Self : R|UExpressionPattern<T, Self>|> : R|UElementPattern<T, Self>| {
|
||||
public constructor<T : R|UExpression|, Self : R|UExpressionPattern<T, Self>|>(clazz: R|java/lang/Class<T>|): R|UExpressionPattern<T, Self>| {
|
||||
super<R|UElementPattern<T, Self>|>(R|<local>/clazz|)
|
||||
}
|
||||
|
||||
public open class Capture<T : R|UExpression|> : R|UExpressionPattern<T, UExpressionPattern.Capture<T>>| {
|
||||
public constructor<T : R|UExpression|>(clazz: R|java/lang/Class<T>|): R|UExpressionPattern.Capture<T>| {
|
||||
super<R|UExpressionPattern<T, UExpressionPattern.Capture<T>>|>(R|<local>/clazz|)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
38
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/UastPatterns.kt
vendored
Normal file
38
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/UastPatterns.kt
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
// FILE: ObjectPattern.java
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class ObjectPattern<T, Self extends ObjectPattern<T, Self>> {
|
||||
protected ObjectPattern(@NotNull Class<T> aClass) {
|
||||
|
||||
}
|
||||
|
||||
public static class Capture<T> extends ObjectPattern<T,Capture<T>> {
|
||||
public Capture(@NotNull Class<T> aClass) {
|
||||
super(aClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: UastPatterns.kt
|
||||
|
||||
interface UElement
|
||||
|
||||
interface UExpression : UElement
|
||||
|
||||
interface UReferenceExpression : UExpression
|
||||
|
||||
fun injectionHostOrReferenceExpression(): UExpressionPattern.Capture<UExpression> =
|
||||
uExpression().filter { it is UReferenceExpression }
|
||||
|
||||
fun uExpression(): UExpressionPattern.Capture<UExpression> = expressionCapture(UExpression::class.java)
|
||||
|
||||
fun <T : UExpression> expressionCapture(clazz: Class<T>): UExpressionPattern.Capture<T> = UExpressionPattern.Capture(clazz)
|
||||
|
||||
open class UElementPattern<T : UElement, Self : UElementPattern<T, Self>>(clazz: Class<T>) : ObjectPattern<T, Self>(clazz) {
|
||||
fun filter(filter: (T) -> Boolean): Self = this as Self
|
||||
}
|
||||
|
||||
open class UExpressionPattern<T : UExpression, Self : UExpressionPattern<T, Self>>(clazz: Class<T>) : UElementPattern<T, Self>(clazz) {
|
||||
open class Capture<T : UExpression>(clazz: Class<T>) : UExpressionPattern<T, Capture<T>>(clazz)
|
||||
}
|
||||
24
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/WithSpeedSearch.fir.txt
vendored
Normal file
24
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/WithSpeedSearch.fir.txt
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
FILE: WithSpeedSearch.kt
|
||||
public final class JList<E> : R|kotlin/Any| {
|
||||
public constructor<E>(): R|JList<E>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final class ListSpeedSearch<T> : R|kotlin/Any| {
|
||||
public constructor<T>(list: R|JList<T>|): R|ListSpeedSearch<T>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final class XThreadsFramesView : R|kotlin/Any| {
|
||||
public constructor(): R|XThreadsFramesView| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
private final fun <J : R|JList<*>|> R|J|.withSpeedSearch(): R|J| {
|
||||
lval search: R|ListSpeedSearch<out kotlin/Any?>| = R|/ListSpeedSearch.ListSpeedSearch|<R|CapturedType(*)|>(this@R|/XThreadsFramesView.withSpeedSearch|)
|
||||
^withSpeedSearch this@R|/XThreadsFramesView.withSpeedSearch|
|
||||
}
|
||||
|
||||
}
|
||||
10
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/WithSpeedSearch.kt
vendored
Normal file
10
compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/WithSpeedSearch.kt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
class JList<E>
|
||||
|
||||
class ListSpeedSearch<T>(list: JList<T>)
|
||||
|
||||
class XThreadsFramesView {
|
||||
private fun <J> J.withSpeedSearch(): J where J : JList<*> {
|
||||
val search = ListSpeedSearch(this)
|
||||
return this
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ fun test() {
|
||||
val Any.bar get() = "456"
|
||||
val String.bar get() = "987"
|
||||
|
||||
<!REDECLARATION!>val t = "".bar<!>
|
||||
val <!REDECLARATION!>t<!> = "".bar
|
||||
|
||||
val p = Pair(0, "")
|
||||
|
||||
@@ -21,4 +21,4 @@ open class Base<T>(val x: T)
|
||||
class Derived : Base<Int>(10)
|
||||
val xx = Derived().x + 1
|
||||
|
||||
<!REDECLARATION!>val t = throw AssertionError("")<!>
|
||||
val <!REDECLARATION!>t<!> = throw AssertionError("")
|
||||
|
||||
@@ -5038,6 +5038,36 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
public void testDailyAggregatedDoubleFactor() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/DailyAggregatedDoubleFactor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("EnumWithToString.kt")
|
||||
public void testEnumWithToString() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/EnumWithToString.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("IntersectionWithJavaString.kt")
|
||||
public void testIntersectionWithJavaString() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/IntersectionWithJavaString.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("PersistentStateComponent.kt")
|
||||
public void testPersistentStateComponent() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/PersistentStateComponent.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("UastPatterns.kt")
|
||||
public void testUastPatterns() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/UastPatterns.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("WithSpeedSearch.kt")
|
||||
public void testWithSpeedSearch() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/WithSpeedSearch.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
@@ -5038,6 +5038,36 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
public void testDailyAggregatedDoubleFactor() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/DailyAggregatedDoubleFactor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("EnumWithToString.kt")
|
||||
public void testEnumWithToString() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/EnumWithToString.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("IntersectionWithJavaString.kt")
|
||||
public void testIntersectionWithJavaString() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/IntersectionWithJavaString.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("PersistentStateComponent.kt")
|
||||
public void testPersistentStateComponent() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/PersistentStateComponent.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("UastPatterns.kt")
|
||||
public void testUastPatterns() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/UastPatterns.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("WithSpeedSearch.kt")
|
||||
public void testWithSpeedSearch() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/WithSpeedSearch.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
@@ -5908,6 +5908,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/kt4034.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("lambdaInTryFalsePositive.kt")
|
||||
public void testLambdaInTryFalsePositive() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/lambdaInTryFalsePositive.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ReturnFromFunctionInObject.kt")
|
||||
public void testReturnFromFunctionInObject() throws Exception {
|
||||
@@ -6013,6 +6019,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/controlStructures"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("breakToLabel.kt")
|
||||
public void testBreakToLabel() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/controlStructures/breakToLabel.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("catchGenerics.kt")
|
||||
public void testCatchGenerics() throws Exception {
|
||||
@@ -16843,6 +16855,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/innerNestedClassFromJava.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("integerNotNullable.kt")
|
||||
public void testIntegerNotNullable() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/integerNotNullable.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invisiblePackagePrivateInheritedMember.kt")
|
||||
public void testInvisiblePackagePrivateInheritedMember() throws Exception {
|
||||
@@ -21688,6 +21706,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinOutProjection.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinStarProjection.kt")
|
||||
public void testKotlinStarProjection() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinStarProjection.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("listSuperType.kt")
|
||||
public void testListSuperType() throws Exception {
|
||||
@@ -22366,6 +22390,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/properties")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Properties {
|
||||
@Test
|
||||
@TestMetadata("abstarctPropertyInPrimaryConstructor.kt")
|
||||
public void testAbstarctPropertyInPrimaryConstructor() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/properties/abstarctPropertyInPrimaryConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInProperties() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/properties"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
@@ -22799,6 +22829,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredTypeParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("RedeclaredValueParameters.kt")
|
||||
public void testRedeclaredValueParameters() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredValueParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("RedeclaringPrivateToFile.kt")
|
||||
public void testRedeclaringPrivateToFile() throws Exception {
|
||||
@@ -28022,6 +28058,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("otherModuleInheritance.kt")
|
||||
public void testOtherModuleInheritance() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("protected.kt")
|
||||
public void testProtected() throws Exception {
|
||||
|
||||
@@ -5908,6 +5908,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/kt4034.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("lambdaInTryFalsePositive.kt")
|
||||
public void testLambdaInTryFalsePositive() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/lambdaInTryFalsePositive.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ReturnFromFunctionInObject.kt")
|
||||
public void testReturnFromFunctionInObject() throws Exception {
|
||||
@@ -6013,6 +6019,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/controlStructures"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("breakToLabel.kt")
|
||||
public void testBreakToLabel() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/controlStructures/breakToLabel.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("catchGenerics.kt")
|
||||
public void testCatchGenerics() throws Exception {
|
||||
@@ -16843,6 +16855,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/innerNestedClassFromJava.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("integerNotNullable.kt")
|
||||
public void testIntegerNotNullable() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/integerNotNullable.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invisiblePackagePrivateInheritedMember.kt")
|
||||
public void testInvisiblePackagePrivateInheritedMember() throws Exception {
|
||||
@@ -21688,6 +21706,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinOutProjection.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinStarProjection.kt")
|
||||
public void testKotlinStarProjection() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinStarProjection.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("listSuperType.kt")
|
||||
public void testListSuperType() throws Exception {
|
||||
@@ -22366,6 +22390,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/properties")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Properties {
|
||||
@Test
|
||||
@TestMetadata("abstarctPropertyInPrimaryConstructor.kt")
|
||||
public void testAbstarctPropertyInPrimaryConstructor() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/properties/abstarctPropertyInPrimaryConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInProperties() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/properties"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
@@ -22799,6 +22829,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredTypeParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("RedeclaredValueParameters.kt")
|
||||
public void testRedeclaredValueParameters() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredValueParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("RedeclaringPrivateToFile.kt")
|
||||
public void testRedeclaringPrivateToFile() throws Exception {
|
||||
@@ -28022,6 +28058,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("otherModuleInheritance.kt")
|
||||
public void testOtherModuleInheritance() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("protected.kt")
|
||||
public void testProtected() throws Exception {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ plugins {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":generators"))
|
||||
implementation(project(":compiler:fir:tree"))
|
||||
implementation(project(":compiler:fir:tree:tree-generator"))
|
||||
implementation(project(":compiler:resolution.common"))
|
||||
|
||||
@@ -29,6 +29,7 @@ fun main(args: Array<String>) {
|
||||
alias<FirStatement>("BasicExpressionChecker")
|
||||
alias<FirQualifiedAccess>("QualifiedAccessChecker")
|
||||
alias<FirQualifiedAccessExpression>("QualifiedAccessExpressionChecker")
|
||||
alias<FirCall>("CallChecker")
|
||||
alias<FirFunctionCall>("FunctionCallChecker")
|
||||
alias<FirVariableAssignment>("VariableAssignmentChecker")
|
||||
alias<FirTryExpression>("TryExpressionChecker")
|
||||
|
||||
@@ -96,7 +96,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val UNRESOLVED_REFERENCE by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
|
||||
parameter<String>("reference")
|
||||
}
|
||||
val UNRESOLVED_LABEL by error<PsiElement>()
|
||||
val UNRESOLVED_LABEL by error<PsiElement>(PositioningStrategy.LABEL)
|
||||
val DESERIALIZATION_ERROR by error<PsiElement>()
|
||||
val ERROR_FROM_JAVA_RESOLUTION by error<PsiElement>()
|
||||
val MISSING_STDLIB_CLASS by error<PsiElement>()
|
||||
@@ -141,6 +141,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
|
||||
val SUPERTYPES by object : DiagnosticGroup("Supertypes") {
|
||||
val NOT_A_SUPERTYPE by error<PsiElement>()
|
||||
val TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER by warning<KtElement>()
|
||||
val SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE by error<PsiElement>()
|
||||
val QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE by error<KtTypeReference> {
|
||||
parameter<Symbol>("otherSuperType")
|
||||
@@ -177,6 +178,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<FirRegularClassSymbol>("type")
|
||||
parameter<Collection<ConeKotlinType>>("bounds")
|
||||
}
|
||||
val AMBIGUOUS_SUPER by error<KtSuperExpression>()
|
||||
}
|
||||
|
||||
val CONSTRUCTOR_PROBLEMS by object : DiagnosticGroup("Constructor problems") {
|
||||
@@ -305,10 +307,22 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<KtModifierKeywordToken>("redundantModifier")
|
||||
parameter<KtModifierKeywordToken>("conflictingModifier")
|
||||
}
|
||||
val DEPRECATED_MODIFIER by warning<PsiElement> {
|
||||
parameter<KtModifierKeywordToken>("deprecatedModifier")
|
||||
parameter<KtModifierKeywordToken>("actualModifier")
|
||||
}
|
||||
val DEPRECATED_MODIFIER_PAIR by error<PsiElement> {
|
||||
parameter<KtModifierKeywordToken>("deprecatedModifier")
|
||||
parameter<KtModifierKeywordToken>("conflictingModifier")
|
||||
}
|
||||
val DEPRECATED_MODIFIER_FOR_TARGET by warning<PsiElement> {
|
||||
parameter<KtModifierKeywordToken>("deprecatedModifier")
|
||||
parameter<String>("target")
|
||||
}
|
||||
val REDUNDANT_MODIFIER_FOR_TARGET by warning<PsiElement> {
|
||||
parameter<KtModifierKeywordToken>("redundantModifier")
|
||||
parameter<String>("target")
|
||||
}
|
||||
val INCOMPATIBLE_MODIFIERS by error<PsiElement> {
|
||||
parameter<KtModifierKeywordToken>("modifier1")
|
||||
parameter<KtModifierKeywordToken>("modifier2")
|
||||
@@ -325,6 +339,17 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val INFIX_MODIFIER_REQUIRED by error<PsiElement> {
|
||||
parameter<FirNamedFunctionSymbol>("functionSymbol")
|
||||
}
|
||||
val WRONG_MODIFIER_CONTAINING_DECLARATION by error<PsiElement> {
|
||||
parameter<KtModifierKeywordToken>("modifier")
|
||||
parameter<String>("target")
|
||||
}
|
||||
val DEPRECATED_MODIFIER_CONTAINING_DECLARATION by warning<PsiElement> {
|
||||
parameter<KtModifierKeywordToken>("modifier")
|
||||
parameter<String>("target")
|
||||
}
|
||||
val INAPPLICABLE_OPERATOR_MODIFIER by error<PsiElement>(PositioningStrategy.OPERATOR_MODIFIER) {
|
||||
parameter<String>("message")
|
||||
}
|
||||
}
|
||||
|
||||
val INLINE_CLASSES by object : DiagnosticGroup("Inline classes") {
|
||||
@@ -420,6 +445,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
}
|
||||
|
||||
val SPREAD_OF_NULLABLE by error<PsiElement>(PositioningStrategy.SPREAD_OPERATOR)
|
||||
|
||||
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION by deprecationError<KtExpression>(LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm)
|
||||
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION by deprecationError<KtExpression>(LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm)
|
||||
}
|
||||
|
||||
val AMBIGUITY by object : DiagnosticGroup("Ambiguity") {
|
||||
@@ -444,7 +472,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val RECURSION_IN_IMPLICIT_TYPES by error<PsiElement>()
|
||||
val INFERENCE_ERROR by error<PsiElement>()
|
||||
val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error<PsiElement>()
|
||||
val UPPER_BOUND_VIOLATED by warning<PsiElement> {
|
||||
val UPPER_BOUND_VIOLATED by error<PsiElement> {
|
||||
parameter<ConeKotlinType>("expectedUpperBound")
|
||||
parameter<ConeKotlinType>("actualUpperBound")
|
||||
}
|
||||
@@ -553,7 +581,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<ConeKotlinType>("typeB")
|
||||
}
|
||||
|
||||
val TYPE_VARIANCE_CONFLICT by warning<PsiElement>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
|
||||
val TYPE_VARIANCE_CONFLICT by error<PsiElement>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
|
||||
parameter<FirTypeParameterSymbol>("typeParameter")
|
||||
parameter<Variance>("typeParameterVariance")
|
||||
parameter<Variance>("variance")
|
||||
@@ -714,7 +742,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val CONFLICTING_OVERLOADS by error<PsiElement>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
|
||||
parameter<Collection<Symbol>>("conflictingOverloads")
|
||||
}
|
||||
val REDECLARATION by error<PsiElement> {
|
||||
val REDECLARATION by error<KtNamedDeclaration>(PositioningStrategy.NAME_IDENTIFIER) {
|
||||
parameter<Collection<Symbol>>("conflictingDeclarations")
|
||||
}
|
||||
val PACKAGE_OR_CLASSIFIER_REDECLARATION by error<KtNamedDeclaration>(PositioningStrategy.ACTUAL_DECLARATION_NAME) {
|
||||
parameter<Collection<Symbol>>("conflictingDeclarations")
|
||||
}
|
||||
val METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE by error<PsiElement>()
|
||||
@@ -826,6 +857,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
}
|
||||
val ACCESSOR_FOR_DELEGATED_PROPERTY by error<KtPropertyAccessor>()
|
||||
val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error<KtModifierListOwner>(PositioningStrategy.ABSTRACT_MODIFIER)
|
||||
}
|
||||
|
||||
val MPP_PROJECTS by object : DiagnosticGroup("Multi-platform projects") {
|
||||
@@ -1012,6 +1044,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error<KtElement> {
|
||||
parameter<String>("illegalReason")
|
||||
}
|
||||
val COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT by error<PsiElement>(PositioningStrategy.COMMAS)
|
||||
}
|
||||
|
||||
val CONTEXT_TRACKING by object : DiagnosticGroup("Context tracking") {
|
||||
@@ -1088,6 +1121,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<ConeKotlinType>("leftType")
|
||||
parameter<ConeKotlinType>("rightType")
|
||||
}
|
||||
val INC_DEC_SHOULD_NOT_RETURN_UNIT by error<KtExpression>(PositioningStrategy.OPERATOR)
|
||||
val ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT by error<KtExpression>(PositioningStrategy.OPERATOR) {
|
||||
parameter<FirNamedFunctionSymbol>("functionSymbol")
|
||||
parameter<String>("operator")
|
||||
}
|
||||
}
|
||||
|
||||
val TYPE_ALIAS by object : DiagnosticGroup("Type alias") {
|
||||
@@ -1179,11 +1217,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
}
|
||||
|
||||
val DECLARATION_CANT_BE_INLINED by error<KtDeclaration>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
|
||||
|
||||
val OVERRIDE_BY_INLINE by warning<KtDeclaration>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
|
||||
|
||||
val NON_INTERNAL_PUBLISHED_API by error<KtElement>()
|
||||
|
||||
|
||||
val INVALID_DEFAULT_FUNCTIONAL_PARAMETER_FOR_INLINE by error<KtElement>() {
|
||||
parameter<FirExpression>("defaultValue")
|
||||
parameter<FirValueParameterSymbol>("parameter")
|
||||
@@ -1231,13 +1269,6 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val RETURN_FOR_BUILT_IN_SUSPEND by error<KtReturnExpression>()
|
||||
}
|
||||
|
||||
val JVM by object : DiagnosticGroup("jvm") {
|
||||
val JAVA_TYPE_MISMATCH by error<KtExpression> {
|
||||
parameter<ConeKotlinType>("expectedType")
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val exposedVisibilityDiagnosticInit: DiagnosticBuilder.() -> Unit = {
|
||||
|
||||
@@ -7,7 +7,9 @@ package org.jetbrains.kotlin.fir.checkers.generator.diagnostics
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.fir.PrivateForInline
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.*
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
@Suppress("UNUSED_VARIABLE", "LocalVariableName", "ClassName", "unused")
|
||||
@OptIn(PrivateForInline::class)
|
||||
@@ -15,4 +17,11 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
|
||||
val DECLARATIONS by object : DiagnosticGroup("Declarations") {
|
||||
val CONFLICTING_JVM_DECLARATIONS by error<PsiElement>()
|
||||
}
|
||||
|
||||
val TYPES by object : DiagnosticGroup("Types") {
|
||||
val JAVA_TYPE_MISMATCH by error<KtExpression> {
|
||||
parameter<ConeKotlinType>("expectedType")
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,10 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
||||
ACTUAL_DECLARATION_NAME,
|
||||
UNREACHABLE_CODE,
|
||||
INLINE_PARAMETER_MODIFIER,
|
||||
ABSTRACT_MODIFIER,
|
||||
LABEL,
|
||||
COMMAS,
|
||||
OPERATOR_MODIFIER,
|
||||
|
||||
;
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics.jvm
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
/*
|
||||
* This file was generated automatically
|
||||
@@ -17,4 +19,7 @@ object FirJvmErrors {
|
||||
// Declarations
|
||||
val CONFLICTING_JVM_DECLARATIONS by error0<PsiElement>()
|
||||
|
||||
// Types
|
||||
val JAVA_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
|
||||
|
||||
}
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.fir.StandardTypes
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
@@ -109,7 +110,7 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
|
||||
// actually created because of type projection from `get`. Hence, to workaround this problem, we simply remove all the out
|
||||
// projection and type capturing and compare the types after such erasure. This way, we won't incorrectly reject any valid code
|
||||
// though we may accept some invalid code. But in presence of the unsound flexible types, we are allowing invalid code already.
|
||||
val argTypeWithoutOutProjection = argType.removeOutProjection(true)
|
||||
val argTypeWithoutOutProjection = argType.removeOutProjection(isCovariant = true)
|
||||
val lowerBoundWithoutCapturing = context.session.inferenceComponents.approximator.approximateToSuperType(
|
||||
lowerBound,
|
||||
TypeApproximatorConfiguration.FinalApproximationAfterResolutionAndInference
|
||||
@@ -121,36 +122,39 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
|
||||
lowerBoundWithoutCapturing.withNullability(ConeNullability.NULLABLE, typeCtx)
|
||||
)
|
||||
) {
|
||||
reporter.reportOn(arg.source, FirErrors.JAVA_TYPE_MISMATCH, argType, expectedType, context)
|
||||
reporter.reportOn(arg.source, FirJvmErrors.JAVA_TYPE_MISMATCH, expectedType, argType, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.removeOutProjection(positive: Boolean): ConeKotlinType {
|
||||
private fun ConeKotlinType.removeOutProjection(isCovariant: Boolean): ConeKotlinType {
|
||||
return when (this) {
|
||||
is ConeFlexibleType -> ConeFlexibleType(lowerBound.removeOutProjection(positive), upperBound.removeOutProjection(positive))
|
||||
is ConeFlexibleType -> ConeFlexibleType(
|
||||
lowerBound.removeOutProjection(isCovariant),
|
||||
upperBound.removeOutProjection(isCovariant)
|
||||
)
|
||||
is ConeCapturedType -> ConeCapturedType(
|
||||
captureStatus,
|
||||
lowerType?.removeOutProjection(positive),
|
||||
lowerType?.removeOutProjection(isCovariant),
|
||||
nullability,
|
||||
constructor.apply {
|
||||
ConeCapturedTypeConstructor(
|
||||
projection.removeOutProjection(positive),
|
||||
supertypes?.map { it.removeOutProjection(positive) },
|
||||
projection.removeOutProjection(isCovariant),
|
||||
supertypes?.map { it.removeOutProjection(isCovariant) },
|
||||
typeParameterMarker
|
||||
)
|
||||
},
|
||||
attributes,
|
||||
isProjectionNotNull
|
||||
)
|
||||
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType(original.removeOutProjection(positive))
|
||||
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType(original.removeOutProjection(isCovariant))
|
||||
is ConeIntersectionType -> ConeIntersectionType(
|
||||
intersectedTypes.map { it.removeOutProjection(positive) },
|
||||
alternativeType?.removeOutProjection(positive)
|
||||
intersectedTypes.map { it.removeOutProjection(isCovariant) },
|
||||
alternativeType?.removeOutProjection(isCovariant)
|
||||
)
|
||||
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(
|
||||
lookupTag,
|
||||
typeArguments.map { it.removeOutProjection(positive) }.toTypedArray(),
|
||||
typeArguments.map { it.removeOutProjection(isCovariant) }.toTypedArray(),
|
||||
isNullable,
|
||||
attributes
|
||||
)
|
||||
@@ -158,13 +162,20 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeTypeProjection.removeOutProjection(positive: Boolean): ConeTypeProjection {
|
||||
/**
|
||||
* @param isCovariant true if the current context is covariant and false if contravariant.
|
||||
*
|
||||
* This function only remove out projections in covariant context.
|
||||
* 'in' projections are never removed, nor would an out projection in a contravariant context.
|
||||
*/
|
||||
private fun ConeTypeProjection.removeOutProjection(isCovariant: Boolean): ConeTypeProjection {
|
||||
return when (this) {
|
||||
is ConeKotlinTypeProjectionOut -> if (positive) type else this
|
||||
is ConeKotlinType -> this.removeOutProjection(true)
|
||||
is ConeKotlinTypeConflictingProjection -> ConeKotlinTypeConflictingProjection(type.removeOutProjection(true))
|
||||
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(type.removeOutProjection(!positive))
|
||||
is ConeStarProjection -> this
|
||||
is ConeKotlinTypeProjectionOut -> if (isCovariant) type else this
|
||||
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(type.removeOutProjection(!isCovariant))
|
||||
is ConeStarProjection -> if (isCovariant) StandardTypes.Any else this
|
||||
// Don't remove nested projections for types at invariant position.
|
||||
is ConeKotlinTypeConflictingProjection,
|
||||
is ConeKotlinType -> this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +191,10 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
|
||||
for (immediateSuperType in subTypeConstructor.supertypes()) {
|
||||
val immediateSuperTypeConstructor = immediateSuperType.typeConstructor()
|
||||
if (superTypeConstructor == immediateSuperTypeConstructor) return true
|
||||
if (this@isTypeConstructorEqualOrSubClassOf.isTypeConstructorEqualOrSubClassOf(immediateSuperTypeConstructor, superTypeConstructor)) return true
|
||||
if (this@isTypeConstructorEqualOrSubClassOf.isTypeConstructorEqualOrSubClassOf(
|
||||
immediateSuperTypeConstructor, superTypeConstructor
|
||||
)
|
||||
) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.jvm.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDefaultErrorMessages
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.CONFLICTING_JVM_DECLARATIONS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JAVA_TYPE_MISMATCH
|
||||
|
||||
object FirJvmDefaultErrorMessages {
|
||||
fun installJvmErrorMessages() {
|
||||
FirDefaultErrorMessages.Companion.MAP.also { map ->
|
||||
map.put(CONFLICTING_JVM_DECLARATIONS, "Platform declaration clash")
|
||||
map.put(JAVA_TYPE_MISMATCH, "Java type mismatch expected {0} but found {1}. Use explicit cast", RENDER_TYPE, RENDER_TYPE)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
get() = _qualifiedAccessCheckers
|
||||
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
|
||||
get() = _qualifiedAccessExpressionCheckers
|
||||
override val callCheckers: Set<FirCallChecker>
|
||||
get() = _callCheckers
|
||||
override val functionCallCheckers: Set<FirFunctionCallChecker>
|
||||
get() = _functionCallCheckers
|
||||
override val variableAssignmentCheckers: Set<FirVariableAssignmentChecker>
|
||||
@@ -73,6 +75,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
private val _basicExpressionCheckers: MutableSet<FirBasicExpressionChecker> = mutableSetOf()
|
||||
private val _qualifiedAccessCheckers: MutableSet<FirQualifiedAccessChecker> = mutableSetOf()
|
||||
private val _qualifiedAccessExpressionCheckers: MutableSet<FirQualifiedAccessExpressionChecker> = mutableSetOf()
|
||||
private val _callCheckers: MutableSet<FirCallChecker> = mutableSetOf()
|
||||
private val _functionCallCheckers: MutableSet<FirFunctionCallChecker> = mutableSetOf()
|
||||
private val _variableAssignmentCheckers: MutableSet<FirVariableAssignmentChecker> = mutableSetOf()
|
||||
private val _tryExpressionCheckers: MutableSet<FirTryExpressionChecker> = mutableSetOf()
|
||||
@@ -104,6 +107,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
_basicExpressionCheckers += checkers.basicExpressionCheckers
|
||||
_qualifiedAccessCheckers += checkers.qualifiedAccessCheckers
|
||||
_qualifiedAccessExpressionCheckers += checkers.qualifiedAccessExpressionCheckers
|
||||
_callCheckers += checkers.callCheckers
|
||||
_functionCallCheckers += checkers.functionCallCheckers
|
||||
_variableAssignmentCheckers += checkers.variableAssignmentCheckers
|
||||
_tryExpressionCheckers += checkers.tryExpressionCheckers
|
||||
|
||||
@@ -20,6 +20,7 @@ abstract class ExpressionCheckers {
|
||||
open val basicExpressionCheckers: Set<FirBasicExpressionChecker> = emptySet()
|
||||
open val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker> = emptySet()
|
||||
open val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker> = emptySet()
|
||||
open val callCheckers: Set<FirCallChecker> = emptySet()
|
||||
open val functionCallCheckers: Set<FirFunctionCallChecker> = emptySet()
|
||||
open val variableAssignmentCheckers: Set<FirVariableAssignmentChecker> = emptySet()
|
||||
open val tryExpressionCheckers: Set<FirTryExpressionChecker> = emptySet()
|
||||
@@ -49,7 +50,8 @@ abstract class ExpressionCheckers {
|
||||
@CheckersComponentInternal internal val allBasicExpressionCheckers: Set<FirBasicExpressionChecker> by lazy { basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allQualifiedAccessCheckers: Set<FirQualifiedAccessChecker> by lazy { qualifiedAccessCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allQualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker> by lazy { qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
|
||||
@CheckersComponentInternal internal val allFunctionCallCheckers: Set<FirFunctionCallChecker> by lazy { functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
|
||||
@CheckersComponentInternal internal val allCallCheckers: Set<FirCallChecker> by lazy { callCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allFunctionCallCheckers: Set<FirFunctionCallChecker> by lazy { functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allVariableAssignmentCheckers: Set<FirVariableAssignmentChecker> by lazy { variableAssignmentCheckers + qualifiedAccessCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allTryExpressionCheckers: Set<FirTryExpressionChecker> by lazy { tryExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allWhenExpressionCheckers: Set<FirWhenExpressionChecker> by lazy { whenExpressionCheckers + basicExpressionCheckers }
|
||||
@@ -58,20 +60,20 @@ abstract class ExpressionCheckers {
|
||||
@CheckersComponentInternal internal val allLogicExpressionCheckers: Set<FirLogicExpressionChecker> by lazy { logicExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allReturnExpressionCheckers: Set<FirReturnExpressionChecker> by lazy { returnExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allBlockCheckers: Set<FirBlockChecker> by lazy { blockCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allAnnotationCallCheckers: Set<FirAnnotationCallChecker> by lazy { annotationCallCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allCheckNotNullCallCheckers: Set<FirCheckNotNullCallChecker> by lazy { checkNotNullCallCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allAnnotationCallCheckers: Set<FirAnnotationCallChecker> by lazy { annotationCallCheckers + basicExpressionCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allCheckNotNullCallCheckers: Set<FirCheckNotNullCallChecker> by lazy { checkNotNullCallCheckers + basicExpressionCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allElvisExpressionCheckers: Set<FirElvisExpressionChecker> by lazy { elvisExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allGetClassCallCheckers: Set<FirGetClassCallChecker> by lazy { getClassCallCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allGetClassCallCheckers: Set<FirGetClassCallChecker> by lazy { getClassCallCheckers + basicExpressionCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allSafeCallExpressionCheckers: Set<FirSafeCallExpressionChecker> by lazy { safeCallExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allEqualityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker> by lazy { equalityOperatorCallCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allStringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker> by lazy { stringConcatenationCallCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allTypeOperatorCallCheckers: Set<FirTypeOperatorCallChecker> by lazy { typeOperatorCallCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allEqualityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker> by lazy { equalityOperatorCallCheckers + basicExpressionCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allStringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker> by lazy { stringConcatenationCallCheckers + callCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allTypeOperatorCallCheckers: Set<FirTypeOperatorCallChecker> by lazy { typeOperatorCallCheckers + basicExpressionCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allResolvedQualifierCheckers: Set<FirResolvedQualifierChecker> by lazy { resolvedQualifierCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allConstExpressionCheckers: Set<FirConstExpressionChecker> by lazy { constExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allCallableReferenceAccessCheckers: Set<FirCallableReferenceAccessChecker> by lazy { callableReferenceAccessCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
|
||||
@CheckersComponentInternal internal val allThisReceiverExpressionCheckers: Set<FirThisReceiverExpressionChecker> by lazy { thisReceiverExpressionCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
|
||||
@CheckersComponentInternal internal val allWhileLoopCheckers: Set<FirWhileLoopChecker> by lazy { whileLoopCheckers + loopExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allDoWhileLoopCheckers: Set<FirDoWhileLoopChecker> by lazy { doWhileLoopCheckers + loopExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allArrayOfCallCheckers: Set<FirArrayOfCallChecker> by lazy { arrayOfCallCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allArrayOfCallCheckers: Set<FirArrayOfCallChecker> by lazy { arrayOfCallCheckers + basicExpressionCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allClassReferenceExpressionCheckers: Set<FirClassReferenceExpressionChecker> by lazy { classReferenceExpressionCheckers + basicExpressionCheckers }
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirBinaryLogicExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirBlock
|
||||
import org.jetbrains.kotlin.fir.expressions.FirCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
|
||||
import org.jetbrains.kotlin.fir.expressions.FirCheckNotNullCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirClassReferenceExpression
|
||||
@@ -42,6 +43,7 @@ import org.jetbrains.kotlin.fir.expressions.FirWhileLoop
|
||||
typealias FirBasicExpressionChecker = FirExpressionChecker<FirStatement>
|
||||
typealias FirQualifiedAccessChecker = FirExpressionChecker<FirQualifiedAccess>
|
||||
typealias FirQualifiedAccessExpressionChecker = FirExpressionChecker<FirQualifiedAccessExpression>
|
||||
typealias FirCallChecker = FirExpressionChecker<FirCall>
|
||||
typealias FirFunctionCallChecker = FirExpressionChecker<FirFunctionCall>
|
||||
typealias FirVariableAssignmentChecker = FirExpressionChecker<FirVariableAssignment>
|
||||
typealias FirTryExpressionChecker = FirExpressionChecker<FirTryExpression>
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitInvisibleAbstractMethodsInSuperclasses
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitNonReifiedArraysAsReifiedTypeArguments
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitUseSiteTargetAnnotationsOnSuperTypes
|
||||
@@ -71,6 +72,7 @@ import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.KtPropertyAccessor
|
||||
import org.jetbrains.kotlin.psi.KtReturnExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.KtSuperExpression
|
||||
import org.jetbrains.kotlin.psi.KtTypeAlias
|
||||
import org.jetbrains.kotlin.psi.KtTypeParameter
|
||||
import org.jetbrains.kotlin.psi.KtTypeProjection
|
||||
@@ -127,7 +129,7 @@ object FirErrors {
|
||||
// Unresolved
|
||||
val INVISIBLE_REFERENCE by error1<PsiElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val UNRESOLVED_REFERENCE by error1<PsiElement, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val UNRESOLVED_LABEL by error0<PsiElement>()
|
||||
val UNRESOLVED_LABEL by error0<PsiElement>(SourceElementPositioningStrategies.LABEL)
|
||||
val DESERIALIZATION_ERROR by error0<PsiElement>()
|
||||
val ERROR_FROM_JAVA_RESOLUTION by error0<PsiElement>()
|
||||
val MISSING_STDLIB_CLASS by error0<PsiElement>()
|
||||
@@ -151,6 +153,7 @@ object FirErrors {
|
||||
|
||||
// Supertypes
|
||||
val NOT_A_SUPERTYPE by error0<PsiElement>()
|
||||
val TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER by warning0<KtElement>()
|
||||
val SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE by error0<PsiElement>()
|
||||
val QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE by error1<KtTypeReference, FirBasedSymbol<*>>()
|
||||
val SUPERTYPE_INITIALIZED_IN_INTERFACE by error0<KtTypeReference>()
|
||||
@@ -171,6 +174,7 @@ object FirErrors {
|
||||
val PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE by error0<KtModifierListOwner>(SourceElementPositioningStrategies.VARIANCE_MODIFIER)
|
||||
val INCONSISTENT_TYPE_PARAMETER_VALUES by error3<KtClass, FirTypeParameterSymbol, FirRegularClassSymbol, Collection<ConeKotlinType>>(SourceElementPositioningStrategies.SUPERTYPES_LIST)
|
||||
val INCONSISTENT_TYPE_PARAMETER_BOUNDS by error3<PsiElement, FirTypeParameterSymbol, FirRegularClassSymbol, Collection<ConeKotlinType>>()
|
||||
val AMBIGUOUS_SUPER by error0<KtSuperExpression>()
|
||||
|
||||
// Constructor problems
|
||||
val CONSTRUCTOR_IN_OBJECT by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
@@ -253,12 +257,18 @@ object FirErrors {
|
||||
val INAPPLICABLE_INFIX_MODIFIER by error0<PsiElement>()
|
||||
val REPEATED_MODIFIER by error1<PsiElement, KtModifierKeywordToken>()
|
||||
val REDUNDANT_MODIFIER by error2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
|
||||
val DEPRECATED_MODIFIER by warning2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
|
||||
val DEPRECATED_MODIFIER_PAIR by error2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
|
||||
val DEPRECATED_MODIFIER_FOR_TARGET by warning2<PsiElement, KtModifierKeywordToken, String>()
|
||||
val REDUNDANT_MODIFIER_FOR_TARGET by warning2<PsiElement, KtModifierKeywordToken, String>()
|
||||
val INCOMPATIBLE_MODIFIERS by error2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
|
||||
val REDUNDANT_OPEN_IN_INTERFACE by warning0<KtModifierListOwner>(SourceElementPositioningStrategies.OPEN_MODIFIER)
|
||||
val WRONG_MODIFIER_TARGET by error2<PsiElement, KtModifierKeywordToken, String>()
|
||||
val OPERATOR_MODIFIER_REQUIRED by error2<PsiElement, FirNamedFunctionSymbol, String>()
|
||||
val INFIX_MODIFIER_REQUIRED by error1<PsiElement, FirNamedFunctionSymbol>()
|
||||
val WRONG_MODIFIER_CONTAINING_DECLARATION by error2<PsiElement, KtModifierKeywordToken, String>()
|
||||
val DEPRECATED_MODIFIER_CONTAINING_DECLARATION by warning2<PsiElement, KtModifierKeywordToken, String>()
|
||||
val INAPPLICABLE_OPERATOR_MODIFIER by error1<PsiElement, String>(SourceElementPositioningStrategies.OPERATOR_MODIFIER)
|
||||
|
||||
// Inline classes
|
||||
val INLINE_CLASS_NOT_TOP_LEVEL by error0<KtDeclaration>(SourceElementPositioningStrategies.INLINE_OR_VALUE_MODIFIER)
|
||||
@@ -298,6 +308,8 @@ object FirErrors {
|
||||
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0<KtValueArgument>()
|
||||
val NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER by error1<KtElement, String>()
|
||||
val SPREAD_OF_NULLABLE by error0<PsiElement>(SourceElementPositioningStrategies.SPREAD_OPERATOR)
|
||||
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION by deprecationError0<KtExpression>(ProhibitAssigningSingleElementsToVarargsInNamedForm)
|
||||
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION by deprecationError0<KtExpression>(ProhibitAssigningSingleElementsToVarargsInNamedForm)
|
||||
|
||||
// Ambiguity
|
||||
val OVERLOAD_RESOLUTION_AMBIGUITY by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
@@ -310,7 +322,7 @@ object FirErrors {
|
||||
val RECURSION_IN_IMPLICIT_TYPES by error0<PsiElement>()
|
||||
val INFERENCE_ERROR by error0<PsiElement>()
|
||||
val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error0<PsiElement>()
|
||||
val UPPER_BOUND_VIOLATED by warning2<PsiElement, ConeKotlinType, ConeKotlinType>()
|
||||
val UPPER_BOUND_VIOLATED by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
|
||||
val UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
|
||||
val TYPE_ARGUMENTS_NOT_ALLOWED by error0<PsiElement>()
|
||||
val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error2<PsiElement, Int, FirRegularClassSymbol>()
|
||||
@@ -350,7 +362,7 @@ object FirErrors {
|
||||
val DYNAMIC_UPPER_BOUND by error0<KtTypeReference>()
|
||||
val INCOMPATIBLE_TYPES by error2<KtElement, ConeKotlinType, ConeKotlinType>()
|
||||
val INCOMPATIBLE_TYPES_WARNING by warning2<KtElement, ConeKotlinType, ConeKotlinType>()
|
||||
val TYPE_VARIANCE_CONFLICT by warning4<PsiElement, FirTypeParameterSymbol, Variance, Variance, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val TYPE_VARIANCE_CONFLICT by error4<PsiElement, FirTypeParameterSymbol, Variance, Variance, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val TYPE_VARIANCE_CONFLICT_IN_EXPANDED_TYPE by error4<PsiElement, FirTypeParameterSymbol, Variance, Variance, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val SMARTCAST_IMPOSSIBLE by error3<KtExpression, ConeKotlinType, FirExpression, String>()
|
||||
|
||||
@@ -394,7 +406,8 @@ object FirErrors {
|
||||
// Redeclarations
|
||||
val MANY_COMPANION_OBJECTS by error0<KtObjectDeclaration>(SourceElementPositioningStrategies.COMPANION_OBJECT)
|
||||
val CONFLICTING_OVERLOADS by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val REDECLARATION by error1<PsiElement, Collection<FirBasedSymbol<*>>>()
|
||||
val REDECLARATION by error1<KtNamedDeclaration, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
|
||||
val PACKAGE_OR_CLASSIFIER_REDECLARATION by error1<KtNamedDeclaration, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.ACTUAL_DECLARATION_NAME)
|
||||
val METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE by error0<PsiElement>()
|
||||
|
||||
// Invalid local declarations
|
||||
@@ -457,6 +470,7 @@ object FirErrors {
|
||||
val WRONG_SETTER_RETURN_TYPE by error0<KtTypeReference>()
|
||||
val WRONG_GETTER_RETURN_TYPE by error2<KtTypeReference, ConeKotlinType, ConeKotlinType>()
|
||||
val ACCESSOR_FOR_DELEGATED_PROPERTY by error0<KtPropertyAccessor>()
|
||||
val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error0<KtModifierListOwner>(SourceElementPositioningStrategies.ABSTRACT_MODIFIER)
|
||||
|
||||
// Multi-platform projects
|
||||
val EXPECTED_DECLARATION_WITH_BODY by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
@@ -537,6 +551,7 @@ object FirErrors {
|
||||
val INVALID_IF_AS_EXPRESSION by error0<KtIfExpression>(SourceElementPositioningStrategies.IF_EXPRESSION)
|
||||
val ELSE_MISPLACED_IN_WHEN by error0<KtWhenEntry>(SourceElementPositioningStrategies.ELSE_ENTRY)
|
||||
val ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error1<KtElement, String>()
|
||||
val COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT by error0<PsiElement>(SourceElementPositioningStrategies.COMMAS)
|
||||
|
||||
// Context tracking
|
||||
val TYPE_PARAMETER_IS_NOT_AN_EXPRESSION by error1<KtSimpleNameExpression, FirTypeParameterSymbol>()
|
||||
@@ -567,6 +582,8 @@ object FirErrors {
|
||||
val EQUALITY_NOT_APPLICABLE by error3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
|
||||
val EQUALITY_NOT_APPLICABLE_WARNING by warning3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
|
||||
val INCOMPATIBLE_ENUM_COMPARISON_ERROR by error2<KtElement, ConeKotlinType, ConeKotlinType>()
|
||||
val INC_DEC_SHOULD_NOT_RETURN_UNIT by error0<KtExpression>(SourceElementPositioningStrategies.OPERATOR)
|
||||
val ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT by error2<KtExpression, FirNamedFunctionSymbol, String>(SourceElementPositioningStrategies.OPERATOR)
|
||||
|
||||
// Type alias
|
||||
val TOPLEVEL_TYPEALIASES_ONLY by error0<KtTypeAlias>()
|
||||
@@ -636,7 +653,4 @@ object FirErrors {
|
||||
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val RETURN_FOR_BUILT_IN_SUSPEND by error0<KtReturnExpression>()
|
||||
|
||||
// jvm
|
||||
val JAVA_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
|
||||
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
get() = setOf(
|
||||
FirFunctionNameChecker,
|
||||
FirFunctionTypeParametersSyntaxChecker,
|
||||
FirOperatorModifierChecker,
|
||||
)
|
||||
|
||||
override val propertyCheckers: Set<FirPropertyChecker>
|
||||
@@ -57,6 +58,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
FirInitializerTypeMismatchChecker,
|
||||
FirDelegatedPropertyChecker,
|
||||
FirInlinePropertyChecker,
|
||||
FirPropertyFromParameterChecker,
|
||||
)
|
||||
|
||||
override val classCheckers: Set<FirClassChecker>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirCommaInWhenConditionChecker
|
||||
|
||||
object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
override val annotationCallCheckers: Set<FirAnnotationCallChecker>
|
||||
@@ -29,8 +30,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
|
||||
get() = setOf(
|
||||
FirCallableReferenceChecker,
|
||||
FirSuperNotAvailableChecker,
|
||||
FirNotASupertypeChecker,
|
||||
FirSuperReferenceChecker,
|
||||
FirSuperclassNotAccessibleFromInterfaceChecker,
|
||||
FirAbstractSuperCallChecker,
|
||||
FirQualifiedSupertypeExtendedByOtherSupertypeChecker,
|
||||
@@ -45,12 +45,19 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirSuspendCallChecker,
|
||||
)
|
||||
|
||||
override val callCheckers: Set<FirCallChecker>
|
||||
get() = setOf(
|
||||
FirNamedVarargChecker,
|
||||
)
|
||||
|
||||
override val functionCallCheckers: Set<FirFunctionCallChecker>
|
||||
get() = setOf(
|
||||
FirConventionFunctionCallChecker,
|
||||
FirDivisionByZeroChecker,
|
||||
FirConstructorCallChecker,
|
||||
FirSpreadOfNullableChecker
|
||||
FirSpreadOfNullableChecker,
|
||||
FirAssignmentOperatorCallChecker,
|
||||
FirNamedVarargChecker,
|
||||
)
|
||||
|
||||
override val tryExpressionCheckers: Set<FirTryExpressionChecker>
|
||||
@@ -69,6 +76,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirExhaustiveWhenChecker,
|
||||
FirWhenConditionChecker,
|
||||
FirWhenSubjectChecker,
|
||||
FirCommaInWhenConditionChecker,
|
||||
)
|
||||
|
||||
override val loopExpressionCheckers: Set<FirLoopExpressionChecker>
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
@@ -212,10 +213,10 @@ internal object ConeTypeCompatibilityChecker {
|
||||
val classes = classesOrInterfaces.filter { !it.isInterface }
|
||||
// Java force single inheritance, so any pair of unrelated classes are incompatible.
|
||||
if (classes.size >= 2) {
|
||||
return if (classes.any { it.getHasPredefinedEqualityContract(this) }) {
|
||||
compatibilityUpperBound
|
||||
} else {
|
||||
Compatibility.SOFT_INCOMPATIBLE
|
||||
return when {
|
||||
classes.any { it.firClass.classId.packageFqName.startsWith(Name.identifier("java")) } -> Compatibility.SOFT_INCOMPATIBLE
|
||||
classes.any { it.getHasPredefinedEqualityContract(this) } -> compatibilityUpperBound
|
||||
else -> Compatibility.SOFT_INCOMPATIBLE
|
||||
}
|
||||
}
|
||||
val finalClass = classes.firstOrNull { it.isFinal } ?: return null
|
||||
|
||||
@@ -24,6 +24,8 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
private val compileTimeExtensionFunctions = setOf(Name.identifier("floorDiv"), Name.identifier("mod"))
|
||||
|
||||
fun ConeKotlinType.canBeUsedForConstVal(): Boolean = with(lowerBoundIfFlexible()) { isPrimitive || isString || isUnsignedType }
|
||||
|
||||
internal fun checkConstantArguments(
|
||||
@@ -145,6 +147,15 @@ internal fun checkConstantArguments(
|
||||
checkConstantArguments(exp, session)?.let { return it }
|
||||
}
|
||||
}
|
||||
in compileTimeExtensionFunctions -> {
|
||||
if (calleeReference !is FirResolvedNamedReference) return ConstantArgumentKind.NOT_CONST
|
||||
val symbol = calleeReference.resolvedSymbol as? FirCallableSymbol
|
||||
if (symbol?.callableId?.packageName?.asString() != "kotlin") return ConstantArgumentKind.NOT_CONST
|
||||
|
||||
for (exp in (expression as FirCall).arguments.plus(expression.extensionReceiver)) {
|
||||
checkConstantArguments(exp, session)?.let { return it }
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
if (expression.arguments.isNotEmpty() || calleeReference !is FirResolvedNamedReference) {
|
||||
return ConstantArgumentKind.NOT_CONST
|
||||
@@ -160,8 +171,20 @@ internal fun checkConstantArguments(
|
||||
}
|
||||
}
|
||||
expression is FirQualifiedAccessExpression -> {
|
||||
val propertySymbol = expressionSymbol as? FirPropertySymbol ?: return ConstantArgumentKind.NOT_CONST
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
val property = propertySymbol.fir
|
||||
when {
|
||||
(expressionSymbol as FirPropertySymbol).isLocal || expressionSymbol.callableId.className?.isRoot == false ->
|
||||
property.name.asString() == "length" -> {
|
||||
val coneType =
|
||||
expression.dispatchReceiver.typeRef.coneTypeSafe<ConeKotlinType>() ?: return ConstantArgumentKind.NOT_CONST
|
||||
val receiverClassId = coneType.lowerBoundIfFlexible().classId
|
||||
if (receiverClassId == StandardClassIds.String) {
|
||||
return checkConstantArguments(expression.dispatchReceiver, session)
|
||||
}
|
||||
}
|
||||
propertySymbol.isLocal || propertySymbol.callableId.className?.isRoot == false ->
|
||||
return ConstantArgumentKind.NOT_CONST
|
||||
expression.typeRef.coneType.classId == StandardClassIds.KClass ->
|
||||
return ConstantArgumentKind.NOT_KCLASS_LITERAL
|
||||
@@ -170,9 +193,7 @@ internal fun checkConstantArguments(
|
||||
expression.dispatchReceiver is FirThisReceiverExpression ->
|
||||
return null
|
||||
}
|
||||
@OptIn(SymbolInternals::class)
|
||||
val property = expressionSymbol.fir as? FirProperty
|
||||
return when (property?.initializer) {
|
||||
return when (property.initializer) {
|
||||
is FirConstExpression<*> -> {
|
||||
if (property.isVal)
|
||||
ConstantArgumentKind.NOT_CONST_VAL_IN_CONST_EXPRESSION
|
||||
|
||||
@@ -142,7 +142,7 @@ interface FirDeclarationPresenter {
|
||||
appendRepresentation(it.returnTypeRef)
|
||||
}
|
||||
|
||||
fun represent(it: FirProperty) = buildString {
|
||||
fun represent(it: FirVariable) = buildString {
|
||||
append('[')
|
||||
it.receiverTypeRef?.let {
|
||||
appendRepresentation(it)
|
||||
@@ -241,7 +241,7 @@ open class FirDeclarationInspector(
|
||||
declaration is FirSimpleFunction -> collectFunction(presenter.represent(declaration), declaration)
|
||||
declaration is FirRegularClass -> collectNonFunctionDeclaration(presenter.represent(declaration), declaration)
|
||||
declaration is FirTypeAlias -> collectNonFunctionDeclaration(presenter.represent(declaration), declaration)
|
||||
declaration is FirProperty -> collectNonFunctionDeclaration(presenter.represent(declaration), declaration)
|
||||
declaration is FirVariable -> collectNonFunctionDeclaration(presenter.represent(declaration), declaration)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,14 +9,18 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.analysis.getChild
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock
|
||||
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.SessionHolder
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
|
||||
@@ -33,13 +37,12 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.name.*
|
||||
import org.jetbrains.kotlin.psi.KtModifierList
|
||||
import org.jetbrains.kotlin.psi.KtParameter.VAL_VAR_TOKEN_SET
|
||||
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType
|
||||
import org.jetbrains.kotlin.resolve.AnnotationTargetList
|
||||
import org.jetbrains.kotlin.resolve.AnnotationTargetLists
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
@@ -578,7 +581,11 @@ fun checkTypeMismatch(
|
||||
rValueType = lValueType
|
||||
lValueType = tempType
|
||||
}
|
||||
reporter.reportOn(source, FirErrors.RESULT_TYPE_MISMATCH, lValueType, rValueType, context)
|
||||
if (rValueType.isUnit) {
|
||||
reporter.reportOn(source, FirErrors.INC_DEC_SHOULD_NOT_RETURN_UNIT, context)
|
||||
} else {
|
||||
reporter.reportOn(source, FirErrors.RESULT_TYPE_MISMATCH, lValueType, rValueType, context)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
reporter.reportOn(source, FirErrors.ASSIGNMENT_TYPE_MISMATCH, lValueType, rValueType, context)
|
||||
@@ -671,3 +678,80 @@ fun FirFunctionSymbol<*>.isFunctionForExpectTypeFromCastFeature(): Boolean {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun getActualTargetList(annotated: FirDeclaration): AnnotationTargetList {
|
||||
fun CallableId.isMember(): Boolean {
|
||||
return classId != null || isLocal // TODO: Replace with .containingClass (after fixing)
|
||||
}
|
||||
|
||||
return when (annotated) {
|
||||
is FirRegularClass -> {
|
||||
AnnotationTargetList(
|
||||
KotlinTarget.classActualTargets(annotated.classKind, annotated.isInner, annotated.isCompanion, annotated.isLocal)
|
||||
)
|
||||
}
|
||||
is FirEnumEntry -> AnnotationTargetList(
|
||||
KotlinTarget.classActualTargets(ClassKind.ENUM_ENTRY, annotated.isInner, isCompanionObject = false, isLocalClass = false)
|
||||
)
|
||||
is FirProperty -> {
|
||||
when {
|
||||
annotated.isLocal ->
|
||||
if (annotated.source?.kind == FirFakeSourceElementKind.DesugaredComponentFunctionCall) {
|
||||
TargetLists.T_DESTRUCTURING_DECLARATION
|
||||
} else {
|
||||
TargetLists.T_LOCAL_VARIABLE
|
||||
}
|
||||
annotated.symbol.callableId.isMember() ->
|
||||
if (annotated.source?.kind == FirFakeSourceElementKind.PropertyFromParameter) {
|
||||
TargetLists.T_VALUE_PARAMETER_WITH_VAL
|
||||
} else {
|
||||
TargetLists.T_MEMBER_PROPERTY(annotated.hasBackingField, annotated.delegate != null)
|
||||
}
|
||||
else ->
|
||||
TargetLists.T_TOP_LEVEL_PROPERTY(annotated.hasBackingField, annotated.delegate != null)
|
||||
}
|
||||
}
|
||||
is FirValueParameter -> {
|
||||
when {
|
||||
annotated.hasValOrVar -> TargetLists.T_VALUE_PARAMETER_WITH_VAL
|
||||
else -> TargetLists.T_VALUE_PARAMETER_WITHOUT_VAL
|
||||
}
|
||||
}
|
||||
is FirConstructor -> TargetLists.T_CONSTRUCTOR
|
||||
is FirAnonymousFunction -> {
|
||||
TargetLists.T_FUNCTION_EXPRESSION
|
||||
}
|
||||
is FirSimpleFunction -> {
|
||||
when {
|
||||
annotated.isLocal -> TargetLists.T_LOCAL_FUNCTION
|
||||
annotated.symbol.callableId.isMember() -> TargetLists.T_MEMBER_FUNCTION
|
||||
else -> TargetLists.T_TOP_LEVEL_FUNCTION
|
||||
}
|
||||
}
|
||||
is FirTypeAlias -> TargetLists.T_TYPEALIAS
|
||||
is FirPropertyAccessor -> if (annotated.isGetter) TargetLists.T_PROPERTY_GETTER else TargetLists.T_PROPERTY_SETTER
|
||||
is FirFile -> TargetLists.T_FILE
|
||||
is FirTypeParameter -> TargetLists.T_TYPE_PARAMETER
|
||||
is FirAnonymousInitializer -> TargetLists.T_INITIALIZER
|
||||
is FirAnonymousObject ->
|
||||
if (annotated.source?.kind == FirFakeSourceElementKind.EnumInitializer) {
|
||||
AnnotationTargetList(
|
||||
KotlinTarget.classActualTargets(
|
||||
ClassKind.ENUM_ENTRY,
|
||||
isInnerClass = false,
|
||||
isCompanionObject = false,
|
||||
isLocalClass = false
|
||||
)
|
||||
)
|
||||
} else {
|
||||
TargetLists.T_OBJECT_LITERAL
|
||||
}
|
||||
// TODO: properly implement those cases
|
||||
// is KtDestructuringDeclarationEntry -> TargetLists.T_LOCAL_VARIABLE
|
||||
// is KtDestructuringDeclaration -> TargetLists.T_DESTRUCTURING_DECLARATION
|
||||
// is KtLambdaExpression -> TargetLists.T_FUNCTION_LITERAL
|
||||
else -> TargetLists.EMPTY
|
||||
}
|
||||
}
|
||||
|
||||
private typealias TargetLists = AnnotationTargetLists
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user