From 8c952ebfdbf45ad66bbf9ed235e8ef53995449df Mon Sep 17 00:00:00 2001 From: Erokhin Stanislav Date: Wed, 14 Aug 2013 19:40:43 +0400 Subject: [PATCH] JS backend: added delegate property support. --- .../test/semantics/DelegatePropertyTest.java | 67 +++++++++++++++++ .../k2js/translate/context/Namer.java | 22 ++++++ .../declaration/NamespaceTranslator.java | 5 ++ .../declaration/PropertyTranslator.java | 73 ++++++++++++++++--- .../initializer/InitializerUtils.java | 16 ++++ .../initializer/InitializerVisitor.java | 4 + .../k2js/translate/utils/JsAstUtils.java | 9 +++ .../cases/delegateByTopLevelFun.kt | 20 +++++ .../cases/delegateByTopLevelProperty.kt | 20 +++++ .../cases/delegateForExtProperty.kt | 13 ++++ .../cases/getAsExtensionFun.kt | 13 ++++ .../cases/propertyMetadata.kt | 33 +++++++++ .../cases/setAsExtensionFun.kt | 19 +++++ .../delegateProperty/cases/simple.kt | 29 ++++++++ .../delegateProperty/cases/topLevelVal.kt | 10 +++ .../delegateProperty/cases/topLevelVar.kt | 15 ++++ .../delegateProperty/cases/withGenerics.kt | 41 +++++++++++ js/js.translator/testFiles/kotlin_lib.js | 9 +++ 18 files changed, 407 insertions(+), 11 deletions(-) create mode 100644 js/js.tests/test/org/jetbrains/k2js/test/semantics/DelegatePropertyTest.java create mode 100644 js/js.translator/testFiles/delegateProperty/cases/delegateByTopLevelFun.kt create mode 100644 js/js.translator/testFiles/delegateProperty/cases/delegateByTopLevelProperty.kt create mode 100644 js/js.translator/testFiles/delegateProperty/cases/delegateForExtProperty.kt create mode 100644 js/js.translator/testFiles/delegateProperty/cases/getAsExtensionFun.kt create mode 100644 js/js.translator/testFiles/delegateProperty/cases/propertyMetadata.kt create mode 100644 js/js.translator/testFiles/delegateProperty/cases/setAsExtensionFun.kt create mode 100644 js/js.translator/testFiles/delegateProperty/cases/simple.kt create mode 100644 js/js.translator/testFiles/delegateProperty/cases/topLevelVal.kt create mode 100644 js/js.translator/testFiles/delegateProperty/cases/topLevelVar.kt create mode 100644 js/js.translator/testFiles/delegateProperty/cases/withGenerics.kt diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/DelegatePropertyTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/DelegatePropertyTest.java new file mode 100644 index 00000000000..a812bd39f5d --- /dev/null +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/DelegatePropertyTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.k2js.test.semantics; + +import org.jetbrains.k2js.test.SingleFileTranslationTest; + +public class DelegatePropertyTest extends SingleFileTranslationTest { + public DelegatePropertyTest() { + super("delegateProperty/"); + } + + public void testSimple() throws Exception { + checkFooBoxIsOk(); + } + + public void testPropertyMetadata() throws Exception { + checkFooBoxIsOk(); + } + + public void testWithGenerics() throws Exception { + checkFooBoxIsOk(); + } + + + public void testDelegateByTopLevelFun() throws Exception { + checkFooBoxIsOk(); + } + + public void testDelegateByTopLevelProperty() throws Exception { + checkFooBoxIsOk(); + } + + public void testDelegateForExtProperty() throws Exception { + checkFooBoxIsOk(); + } + + public void testGetAsExtensionFun() throws Exception { + checkFooBoxIsOk(); + } + + public void testSetAsExtensionFun() throws Exception { + checkFooBoxIsOk(); + } + + public void testTopLevelVal() throws Exception { + checkFooBoxIsOk(); + } + + public void testTopLevelVar() throws Exception { + checkFooBoxIsOk(); + } + +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java index 6a9cfeb656e..dcea37d62d6 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java @@ -52,6 +52,10 @@ public final class Namer { private static final String CLASS_OBJECT_GETTER = "object$"; private static final String CLASS_OBJECT_INITIALIZER = "object_initializer$"; + + private static final String DELEGATE_POSTFIX = "$delegate"; + private static final String PROPERTY_METADATA = "PropertyMetadata"; + private static final Named CLASS_OBJECT_INITIALIZER_NAMED = new Named() { @NotNull @Override @@ -114,19 +118,32 @@ public final class Namer { return getNameWithPrefix(propertyName, SETTER_PREFIX); } + @NotNull public static JsExpression getClassObjectAccessor(@NotNull JsExpression referenceToClass) { return new JsInvocation(new JsNameRef(CLASS_OBJECT_GETTER, referenceToClass)); } + @NotNull public static Named getNamedForClassObjectInitializer() { return CLASS_OBJECT_INITIALIZER_NAMED; } + @NotNull + public static String getDelegateName(@NotNull String propertyName) { + return propertyName + DELEGATE_POSTFIX; + } + + @NotNull + public static JsNameRef getDelegateNameRef(String propertyName) { + return new JsNameRef(getDelegateName(propertyName), JsLiteral.THIS); + } + @NotNull private static String getNameWithPrefix(@NotNull String name, @NotNull String prefix) { return prefix + name; } + @NotNull public static Namer newInstance(@NotNull JsScope rootScope) { return new Namer(rootScope); } @@ -193,6 +210,11 @@ public final class Namer { return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject()); } + @NotNull + public JsNameRef propertyMetadataRef() { + return new JsNameRef(PROPERTY_METADATA, kotlinObject()); + } + @NotNull private JsNameRef kotlin(@NotNull JsName name) { return new JsNameRef(name, kotlinObject()); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java index f069789be71..d807eab3e08 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java @@ -42,6 +42,7 @@ import java.util.List; import java.util.Map; import static org.jetbrains.k2js.translate.expression.LiteralFunctionTranslator.createPlace; +import static org.jetbrains.k2js.translate.initializer.InitializerUtils.generateInitializerForDelegate; import static org.jetbrains.k2js.translate.initializer.InitializerUtils.generateInitializerForProperty; import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptor; @@ -213,6 +214,10 @@ final class NamespaceTranslator extends AbstractTranslator { initializerStatements.add(generateInitializerForProperty(context, propertyDescriptor, value)); } } + + JsStatement delegate = generateInitializerForDelegate(context, property); + if (delegate != null) initializerStatements.add(delegate); + return null; } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.java index 12848063b9f..6b278532158 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.java @@ -20,23 +20,26 @@ import com.google.dart.compiler.backend.js.ast.*; import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.PropertyAccessorDescriptor; -import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; -import org.jetbrains.jet.lang.descriptors.PropertyGetterDescriptor; -import org.jetbrains.jet.lang.descriptors.PropertySetterDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.JetProperty; import org.jetbrains.jet.lang.psi.JetPropertyAccessor; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.expression.FunctionTranslator; import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.Translation; +import org.jetbrains.k2js.translate.reference.CallBuilder; +import org.jetbrains.k2js.translate.reference.CallType; import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; import org.jetbrains.k2js.translate.utils.TranslationUtils; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.assignmentToBackingField; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.backingFieldReference; +import static org.jetbrains.k2js.translate.context.Namer.getDelegateNameRef; +import static org.jetbrains.k2js.translate.utils.TranslationUtils.*; /** * Translates single property /w accessors. @@ -134,11 +137,50 @@ public final class PropertyTranslator extends AbstractTranslator { return generateDefaultAccessor(getterDescriptor, generateDefaultGetterFunction(getterDescriptor)); } + private JsExpression createPropertyMetadata() { + JsNameRef propertyMetadataRef = context().namer().propertyMetadataRef(); + JsExpression argument = context().program().getStringLiteral(getPropertyName()); + if (context().isEcma5()) { + return new JsInvocation(propertyMetadataRef, argument); + } else { + return new JsNew(propertyMetadataRef, Collections.singletonList(argument)); + } + } + + private JsExpression getDelegateCall(ResolvedCall call, List args) { + return CallBuilder.build(context()) + .receiver(getDelegateNameRef(getPropertyName())) + .args(args) + .resolvedCall(call) + .type(CallType.NORMAL) + .translate(); + } + + private String getPropertyName() { + return descriptor.getName().asString(); + } + @NotNull - private JsFunction generateDefaultGetterFunction(@NotNull PropertyGetterDescriptor descriptor) { - JsFunction fun = new JsFunction(context().getScopeForDescriptor(descriptor.getContainingDeclaration())); - fun.setBody(new JsBlock(new JsReturn(backingFieldReference(context(), this.descriptor)))); - return fun; + private JsFunction generateDefaultGetterFunction(@NotNull PropertyGetterDescriptor getterDescriptor) { + JsExpression value; + ResolvedCall delegatedCall = bindingContext().get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, getterDescriptor); + if (delegatedCall != null) { + value = getDelegateCall(delegatedCall, getDelegateCallArgs(null)); + } else { + value = backingFieldReference(context(), this.descriptor); + } + return simpleReturnFunction(context().getScopeForDescriptor(getterDescriptor.getContainingDeclaration()), value); + } + + @NotNull + private List getDelegateCallArgs(@Nullable JsExpression valueExpression) { + List args = new ArrayList(); + args.add(JsLiteral.THIS); + args.add(createPropertyMetadata()); + if (valueExpression != null) { + args.add(valueExpression); + } + return args; } @NotNull @@ -153,7 +195,16 @@ public final class PropertyTranslator extends AbstractTranslator { JsFunction fun = new JsFunction(context().getScopeForDescriptor(setterDescriptor.getContainingDeclaration())); JsParameter defaultParameter = new JsParameter(propertyAccessContext(setterDescriptor).scope().declareTemporary()); fun.getParameters().add(defaultParameter); - fun.setBody(new JsBlock(assignmentToBackingField(context(), descriptor, defaultParameter.getName().makeRef()).makeStmt())); + JsExpression setExpression; + + ResolvedCall delegatedCall = bindingContext().get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, setterDescriptor); + JsNameRef defaultParameterRef = defaultParameter.getName().makeRef(); + if (delegatedCall != null) { + setExpression = getDelegateCall(delegatedCall, getDelegateCallArgs(defaultParameterRef)); + } else { + setExpression = assignmentToBackingField(context(), descriptor, defaultParameterRef); + } + fun.setBody(new JsBlock(setExpression.makeStmt())); return fun; } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerUtils.java index 21e7dfc64db..8f633c1c4e8 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerUtils.java @@ -22,9 +22,13 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.Named; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; +import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetObjectDeclaration; +import org.jetbrains.jet.lang.psi.JetProperty; +import org.jetbrains.k2js.translate.context.Namer; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.declaration.ClassTranslator; +import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.utils.JsAstUtils; import java.util.List; @@ -49,6 +53,18 @@ public final class InitializerUtils { } } + @Nullable + public static JsStatement generateInitializerForDelegate(@NotNull TranslationContext context, @NotNull JetProperty property) { + JetExpression delegate = property.getDelegateExpression(); + if (delegate != null) { + JsExpression value = Translation.translateAsExpression(delegate, context); + String name = property.getName(); + assert name != null: "Delegate property must have name"; + return JsAstUtils.defineSimpleProperty(Namer.getDelegateName(name), value, context); + } + return null; + } + public static void generate(@NotNull JetObjectDeclaration declaration, @NotNull List initializers, @Nullable List definitions, diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java index 839ee8def8a..bd5450a17b7 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java @@ -26,6 +26,7 @@ import org.jetbrains.k2js.translate.general.TranslatorVisitor; import java.util.List; import static org.jetbrains.k2js.translate.general.Translation.translateAsStatement; +import static org.jetbrains.k2js.translate.initializer.InitializerUtils.generateInitializerForDelegate; import static org.jetbrains.k2js.translate.initializer.InitializerUtils.generateInitializerForProperty; import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptor; @@ -44,6 +45,9 @@ public final class InitializerVisitor extends TranslatorVisitor { Translation.translateAsExpression(initializer, context))); } + JsStatement delegate = generateInitializerForDelegate(context, property); + if (delegate != null) result.add(delegate); + return null; } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java index b5c8ef3dc29..77b1a3ca736 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java @@ -238,6 +238,15 @@ public final class JsAstUtils { return invocation; } + @NotNull + public static JsStatement defineSimpleProperty(@NotNull String name, @NotNull JsExpression value, @NotNull TranslationContext context) { + if (context.isEcma5()) { + return defineProperty(name, createDataDescriptor(value, false), context).makeStmt(); + } else { + return assignment(new JsNameRef(name, JsLiteral.THIS), value).makeStmt(); + } + } + @NotNull public static JsObjectLiteral createPropertyDataDescriptor(@NotNull FunctionDescriptor descriptor, @NotNull JsExpression value) { diff --git a/js/js.translator/testFiles/delegateProperty/cases/delegateByTopLevelFun.kt b/js/js.translator/testFiles/delegateProperty/cases/delegateByTopLevelFun.kt new file mode 100644 index 00000000000..2e6101a8b60 --- /dev/null +++ b/js/js.translator/testFiles/delegateProperty/cases/delegateByTopLevelFun.kt @@ -0,0 +1,20 @@ +package foo +class Delegate { + var inner = 1 + fun get(t: Any?, p: PropertyMetadata): Int = inner + fun set(t: Any?, p: PropertyMetadata, i: Int) { inner = i } +} + +fun foo() = Delegate() + +class A { + var prop: Int by foo() +} + +fun box(): String { + val c = A() + if(c.prop != 1) return "fail get" + c.prop = 2 + if (c.prop != 2) return "fail set" + return "OK" +} diff --git a/js/js.translator/testFiles/delegateProperty/cases/delegateByTopLevelProperty.kt b/js/js.translator/testFiles/delegateProperty/cases/delegateByTopLevelProperty.kt new file mode 100644 index 00000000000..a6ff8d5293e --- /dev/null +++ b/js/js.translator/testFiles/delegateProperty/cases/delegateByTopLevelProperty.kt @@ -0,0 +1,20 @@ +package foo +class Delegate { + var inner = 1 + fun get(t: Any?, p: PropertyMetadata): Int = inner + fun set(t: Any?, p: PropertyMetadata, i: Int) { inner = i } +} + +val p = Delegate() + +class A { + var prop: Int by p +} + +fun box(): String { + val c = A() + if(c.prop != 1) return "fail get" + c.prop = 2 + if (c.prop != 2) return "fail set" + return "OK" +} diff --git a/js/js.translator/testFiles/delegateProperty/cases/delegateForExtProperty.kt b/js/js.translator/testFiles/delegateProperty/cases/delegateForExtProperty.kt new file mode 100644 index 00000000000..2e4dfeba0a9 --- /dev/null +++ b/js/js.translator/testFiles/delegateProperty/cases/delegateForExtProperty.kt @@ -0,0 +1,13 @@ +package foo +class Delegate { + fun get(t: A, p: PropertyMetadata): Int = 1 +} + +val A.prop: Int by Delegate() + +class A { +} + +fun box(): String { + return if(A().prop == 1) "OK" else "fail" +} diff --git a/js/js.translator/testFiles/delegateProperty/cases/getAsExtensionFun.kt b/js/js.translator/testFiles/delegateProperty/cases/getAsExtensionFun.kt new file mode 100644 index 00000000000..aa2301e7bac --- /dev/null +++ b/js/js.translator/testFiles/delegateProperty/cases/getAsExtensionFun.kt @@ -0,0 +1,13 @@ +package foo +class Delegate { +} + +fun Delegate.get(t: Any?, p: PropertyMetadata): Int = 1 + +class A { + val prop: Int by Delegate() +} + +fun box(): String { + return if(A().prop == 1) "OK" else "fail" +} diff --git a/js/js.translator/testFiles/delegateProperty/cases/propertyMetadata.kt b/js/js.translator/testFiles/delegateProperty/cases/propertyMetadata.kt new file mode 100644 index 00000000000..7fd472562cb --- /dev/null +++ b/js/js.translator/testFiles/delegateProperty/cases/propertyMetadata.kt @@ -0,0 +1,33 @@ +package foo + +trait WithName { + var name: String +} + +class GetPropertyName() { + fun get(withName: WithName, property: PropertyMetadata) : String { + return withName.name + ":" + property.name; + } + fun set(withName: WithName, property: PropertyMetadata, value: String) { + withName.name = value + ":" + property.name + } +} + +class A : WithName { + override var name = "propertyName" + val d = GetPropertyName() + + val a by d + var OK by d +} + +fun box(): String { + val a = A() + if (a.a != "propertyName:a") return "a.a != 'propertyName:a', it: " + a.a + if (a.OK != "propertyName:OK") return "a.OK != 'propertyName:aOK', it: " + a.OK + a.OK = "property" + + if (a.a != "property:OK:a") return "a.a != 'property:OK:a', it: " + a.a + + return "OK" +} diff --git a/js/js.translator/testFiles/delegateProperty/cases/setAsExtensionFun.kt b/js/js.translator/testFiles/delegateProperty/cases/setAsExtensionFun.kt new file mode 100644 index 00000000000..cb8addff4c2 --- /dev/null +++ b/js/js.translator/testFiles/delegateProperty/cases/setAsExtensionFun.kt @@ -0,0 +1,19 @@ +package foo +class Delegate { + var inner = 1 + fun get(t: Any?, p: PropertyMetadata): Int = inner +} + +fun Delegate.set(t: Any?, p: PropertyMetadata, i: Int) { inner = i } + +class A { + var prop: Int by Delegate() +} + +fun box(): String { + val c = A() + if(c.prop != 1) return "fail get" + c.prop = 2 + if (c.prop != 2) return "fail set" + return "OK" +} diff --git a/js/js.translator/testFiles/delegateProperty/cases/simple.kt b/js/js.translator/testFiles/delegateProperty/cases/simple.kt new file mode 100644 index 00000000000..7acdded67fe --- /dev/null +++ b/js/js.translator/testFiles/delegateProperty/cases/simple.kt @@ -0,0 +1,29 @@ +package foo + +trait WithNumber { + var number: Int +} + +class IncNumber(val inc: Int) { + fun get(withNumber: WithNumber, property: PropertyMetadata) : Int { + return withNumber.number + inc; + } + fun set(withNumber: WithNumber, property: PropertyMetadata, value: Int) { + withNumber.number = value; + } +} + +class A : WithNumber { + override var number: Int = 5 + var nextNumber by IncNumber(3) +} + +fun box(): String { + if (A().nextNumber != 8) return "A().nextNumber != 8" + + val a = A() + a.nextNumber = 10; + if (a.number != 10) return "a.number != 10, it: " + a.number + if (a.nextNumber != 13) return "a.nextNumber != 13, it: " + a.nextNumber + return "OK" +} diff --git a/js/js.translator/testFiles/delegateProperty/cases/topLevelVal.kt b/js/js.translator/testFiles/delegateProperty/cases/topLevelVal.kt new file mode 100644 index 00000000000..8b33b122def --- /dev/null +++ b/js/js.translator/testFiles/delegateProperty/cases/topLevelVal.kt @@ -0,0 +1,10 @@ +package foo +class Delegate { + fun get(t: Any?, p: PropertyMetadata): Int = 1 +} + +val prop: Int by Delegate() + +fun box(): String { + return if(prop == 1) "OK" else "fail" +} diff --git a/js/js.translator/testFiles/delegateProperty/cases/topLevelVar.kt b/js/js.translator/testFiles/delegateProperty/cases/topLevelVar.kt new file mode 100644 index 00000000000..058191ccbe6 --- /dev/null +++ b/js/js.translator/testFiles/delegateProperty/cases/topLevelVar.kt @@ -0,0 +1,15 @@ +package foo +class Delegate { + var inner = 1 + fun get(t: Any?, p: PropertyMetadata): Int = inner + fun set(t: Any?, p: PropertyMetadata, i: Int) { inner = i } +} + +var prop: Int by Delegate() + +fun box(): String { + if(prop != 1) return "fail get" + prop = 2 + if (prop != 2) return "fail set" + return "OK" +} diff --git a/js/js.translator/testFiles/delegateProperty/cases/withGenerics.kt b/js/js.translator/testFiles/delegateProperty/cases/withGenerics.kt new file mode 100644 index 00000000000..836caf4f654 --- /dev/null +++ b/js/js.translator/testFiles/delegateProperty/cases/withGenerics.kt @@ -0,0 +1,41 @@ +package foo + +trait Getter { + fun get(): T +} + +class Delegate(val getter: Getter) { + var t: T? = null + fun get(obj: Any, property: PropertyMetadata) : T { + if (t != null) { + return t!! + } + return getter.get() + } + fun set(obj: Any, property: PropertyMetadata, value: T) { + t = value + } +} + +class A : Getter { + var value = 0 + override fun get(): Int { + return value + } + val delegate = Delegate(this) + + val a by delegate + var b by delegate +} + +fun box(): String { + val a = A() + if (a.a != 0) return "a.a != 0" + if (a.b != 0) return "a.b != 0" + + a.b = 4 + if (a.a != 4) return "a.a != 4" + if (a.b != 4) return "a.b != 4" + + return "OK" +} diff --git a/js/js.translator/testFiles/kotlin_lib.js b/js/js.translator/testFiles/kotlin_lib.js index d7bb54036e3..03bae487702 100644 --- a/js/js.translator/testFiles/kotlin_lib.js +++ b/js/js.translator/testFiles/kotlin_lib.js @@ -172,6 +172,15 @@ String.prototype.contains = function (s) { }; })(); + Kotlin.PropertyMetadata = Kotlin.$createClass(null, { + initialize: function(name) { + this.$name = name; + }, + get_name: function () { + return this.$name; + } + }); + Kotlin.AbstractCollection = Kotlin.$createClass(Kotlin.Collection, { size: function () { return this.$size;