Support local 'toDelegatedFor' properties
This commit is contained in:
committed by
Stanislav Erokhin
parent
c5e14a2059
commit
937a933150
@@ -50,7 +50,6 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.codegen.when.SwitchCodegen;
|
||||
import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
|
||||
import org.jetbrains.kotlin.config.*;
|
||||
import org.jetbrains.kotlin.coroutines.CoroutineUtilKt;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
@@ -4080,13 +4079,52 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
initializer.put(initializer.type, v);
|
||||
|
||||
markLineNumber(variableDeclaration, false);
|
||||
|
||||
storeTo.storeSelector(initializer.type, v);
|
||||
Type resultType = initializer.type;
|
||||
|
||||
if (isDelegatedLocalVariable(variableDescriptor)) {
|
||||
StackValue metadataValue = getVariableMetadataValue(variableDescriptor);
|
||||
initializePropertyMetadata((KtProperty) variableDeclaration, variableDescriptor, metadataValue);
|
||||
|
||||
ResolvedCall<FunctionDescriptor> toDelegateForResolvedCall = bindingContext.get(TO_DELEGATE_FOR_RESOLVED_CALL, variableDescriptor);
|
||||
if (toDelegateForResolvedCall != null) {
|
||||
resultType = generateToDelegateForCallForLocalVariable(initializer, metadataValue, toDelegateForResolvedCall);
|
||||
}
|
||||
}
|
||||
|
||||
storeTo.storeSelector(resultType, v);
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Type generateToDelegateForCallForLocalVariable(
|
||||
@NotNull StackValue initializer,
|
||||
final StackValue metadataValue,
|
||||
ResolvedCall<FunctionDescriptor> toDelegateForResolvedCall
|
||||
) {
|
||||
StackValue toDelegateForReceiver = StackValue.onStack(initializer.type);
|
||||
|
||||
List<? extends ValueArgument> arguments = toDelegateForResolvedCall.getCall().getValueArguments();
|
||||
assert arguments.size() == 2 :
|
||||
"Resolved call for '" +
|
||||
OperatorNameConventions.TO_DELEGATE_FOR.asString() +
|
||||
"' should have exactly 2 value parameters";
|
||||
|
||||
tempVariables.put(arguments.get(0).asElement(), StackValue.constant(null, AsmTypes.OBJECT_TYPE));
|
||||
tempVariables.put(
|
||||
arguments.get(1).asElement(),
|
||||
new StackValue(K_PROPERTY_TYPE) {
|
||||
@Override
|
||||
public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
|
||||
metadataValue.put(type, v);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
StackValue result = invokeFunction(toDelegateForResolvedCall, toDelegateForReceiver);
|
||||
result.put(result.type, v);
|
||||
tempVariables.remove(arguments.get(0).asElement());
|
||||
tempVariables.remove(arguments.get(1).asElement());
|
||||
return result.type;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -4305,7 +4343,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
if (descriptor instanceof CallableDescriptor) {
|
||||
return generateExtensionReceiver((CallableDescriptor) descriptor);
|
||||
}
|
||||
throw new UnsupportedOperationException("Neither this nor receiver: " + descriptor);
|
||||
throw new UnsupportedOperationException("Neither this nor receiver: " + descriptor + expression.getParent().getContainingFile().getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// WITH_RUNTIME
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
var log: String = ""
|
||||
|
||||
inline fun <T> runLogged(entry: String, action: () -> T): T {
|
||||
log += entry
|
||||
return action()
|
||||
}
|
||||
|
||||
operator fun String.toDelegateFor(host: Any?, p: Any): String =
|
||||
runLogged("tdf($this);") { this }
|
||||
|
||||
operator fun String.getValue(receiver: Any?, p: Any): String =
|
||||
runLogged("get($this);") { this }
|
||||
|
||||
fun box(): String {
|
||||
val testO by runLogged("O;") { "O" }
|
||||
val testK by runLogged("K;") { "K" }
|
||||
val testOK = runLogged("OK;") { testO + testK }
|
||||
|
||||
assertEquals("O;tdf(O);K;tdf(K);OK;get(O);get(K);", log)
|
||||
return testOK
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// WITH_RUNTIME
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
var log: String = ""
|
||||
|
||||
fun <T> runLogged(entry: String, action: () -> T): T {
|
||||
log += entry
|
||||
return action()
|
||||
}
|
||||
|
||||
operator fun String.toDelegateFor(host: Any?, p: Any): String =
|
||||
runLogged("tdf($this);") { this }
|
||||
|
||||
operator fun String.getValue(receiver: Any?, p: Any): String =
|
||||
runLogged("get($this);") { this }
|
||||
|
||||
fun box(): String {
|
||||
val testO by runLogged("O;") { "O" }
|
||||
val testK by runLogged("K;") { "K" }
|
||||
val testOK = runLogged("OK;") { testO + testK }
|
||||
|
||||
assertEquals("O;tdf(O);K;tdf(K);OK;get(O);get(K);", log)
|
||||
return testOK
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// WITH_RUNTIME
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
var log: String = ""
|
||||
|
||||
class MyClass(val value: String)
|
||||
|
||||
fun runLogged(entry: String, action: () -> String): String {
|
||||
log += entry
|
||||
return action()
|
||||
}
|
||||
|
||||
fun runLogged2(entry: String, action: () -> MyClass): MyClass {
|
||||
log += entry
|
||||
return action()
|
||||
}
|
||||
|
||||
operator fun MyClass.toDelegateFor(host: Any?, p: Any): String =
|
||||
runLogged("tdf(${this.value});") { this.value }
|
||||
|
||||
operator fun String.getValue(receiver: Any?, p: Any): String =
|
||||
runLogged("get($this);") { this }
|
||||
|
||||
|
||||
fun box(): String {
|
||||
val testO by runLogged2("O;") { MyClass("O") }
|
||||
val testK by runLogged("K;") { "K" }
|
||||
val testOK = runLogged("OK;") { testO + testK }
|
||||
|
||||
assertEquals("O;tdf(O);K;OK;get(O);get(K);", log)
|
||||
return testOK
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
public final class LocalKt {
|
||||
private static @org.jetbrains.annotations.NotNull field log: java.lang.String
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static @org.jetbrains.annotations.NotNull method getLog(): java.lang.String
|
||||
public final static @org.jetbrains.annotations.NotNull method getValue(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.Nullable p1: java.lang.Object, @org.jetbrains.annotations.NotNull p2: java.lang.Object): java.lang.String
|
||||
public final static method runLogged(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.jvm.functions.Function0): java.lang.Object
|
||||
public final static method setLog(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||
public final static @org.jetbrains.annotations.NotNull method toDelegateFor(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.Nullable p1: java.lang.Object, @org.jetbrains.annotations.NotNull p2: java.lang.Object): java.lang.String
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
public final class LocalCapturedKt {
|
||||
private static @org.jetbrains.annotations.NotNull field log: java.lang.String
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static @org.jetbrains.annotations.NotNull method getLog(): java.lang.String
|
||||
public final static @org.jetbrains.annotations.NotNull method getValue(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.Nullable p1: java.lang.Object, @org.jetbrains.annotations.NotNull p2: java.lang.Object): java.lang.String
|
||||
public final static method runLogged(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.jvm.functions.Function0): java.lang.Object
|
||||
public final static method setLog(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||
public final static @org.jetbrains.annotations.NotNull method toDelegateFor(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.Nullable p1: java.lang.Object, @org.jetbrains.annotations.NotNull p2: java.lang.Object): java.lang.String
|
||||
}
|
||||
compiler/testData/codegen/light-analysis/delegatedProperty/toDelegateFor/localDifferentReceivers.txt
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
public final class LocalDifferentReceiversKt {
|
||||
private static @org.jetbrains.annotations.NotNull field log: java.lang.String
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static @org.jetbrains.annotations.NotNull method getLog(): java.lang.String
|
||||
public final static @org.jetbrains.annotations.NotNull method getValue(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.Nullable p1: java.lang.Object, @org.jetbrains.annotations.NotNull p2: java.lang.Object): java.lang.String
|
||||
public final static @org.jetbrains.annotations.NotNull method runLogged(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.jvm.functions.Function0): java.lang.String
|
||||
public final static @org.jetbrains.annotations.NotNull method runLogged2(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.jvm.functions.Function0): MyClass
|
||||
public final static method setLog(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||
public final static @org.jetbrains.annotations.NotNull method toDelegateFor(@org.jetbrains.annotations.NotNull p0: MyClass, @org.jetbrains.annotations.Nullable p1: java.lang.Object, @org.jetbrains.annotations.NotNull p2: java.lang.Object): java.lang.String
|
||||
}
|
||||
|
||||
|
||||
public final class MyClass {
|
||||
private final @org.jetbrains.annotations.NotNull field value: java.lang.String
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||
public final @org.jetbrains.annotations.NotNull method getValue(): java.lang.String
|
||||
}
|
||||
+18
@@ -6049,6 +6049,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("local.kt")
|
||||
public void testLocal() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/local.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localCaptured.kt")
|
||||
public void testLocalCaptured() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/localCaptured.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localDifferentReceivers.kt")
|
||||
public void testLocalDifferentReceivers() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/localDifferentReceivers.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("memberExtension.kt")
|
||||
public void testMemberExtension() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/memberExtension.kt");
|
||||
|
||||
@@ -6049,6 +6049,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("local.kt")
|
||||
public void testLocal() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/local.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localCaptured.kt")
|
||||
public void testLocalCaptured() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/localCaptured.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localDifferentReceivers.kt")
|
||||
public void testLocalDifferentReceivers() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/localDifferentReceivers.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("memberExtension.kt")
|
||||
public void testMemberExtension() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/memberExtension.kt");
|
||||
|
||||
+18
@@ -6049,6 +6049,24 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("local.kt")
|
||||
public void testLocal() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/local.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localCaptured.kt")
|
||||
public void testLocalCaptured() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/localCaptured.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localDifferentReceivers.kt")
|
||||
public void testLocalDifferentReceivers() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/localDifferentReceivers.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("memberExtension.kt")
|
||||
public void testMemberExtension() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/memberExtension.kt");
|
||||
|
||||
+36
@@ -6986,6 +6986,42 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("local.kt")
|
||||
public void testLocal() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/local.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("localCaptured.kt")
|
||||
public void testLocalCaptured() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/localCaptured.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("localDifferentReceivers.kt")
|
||||
public void testLocalDifferentReceivers() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/localDifferentReceivers.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("memberExtension.kt")
|
||||
public void testMemberExtension() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/toDelegateFor/memberExtension.kt");
|
||||
|
||||
Reference in New Issue
Block a user