Support local 'toDelegatedFor' properties

This commit is contained in:
Mikhael Bogdanov
2016-12-08 17:14:19 +01:00
committed by Stanislav Erokhin
parent c5e14a2059
commit 937a933150
11 changed files with 253 additions and 4 deletions
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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");
@@ -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");
@@ -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");