JS backend: support for explicit delegation
#KT-4479 Fixed
This commit is contained in:
@@ -18,18 +18,19 @@ package org.jetbrains.jet.backend.common;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.JetDelegationSpecifier;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
|
||||
import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Backend-independent utility class.
|
||||
@@ -91,6 +92,66 @@ public class CodegenUtil {
|
||||
return function;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PropertyDescriptor getDelegatePropertyIfAny(JetExpression expression, ClassDescriptor classDescriptor, BindingContext bindingContext) {
|
||||
PropertyDescriptor propertyDescriptor = null;
|
||||
if (expression instanceof JetSimpleNameExpression) {
|
||||
ResolvedCall<?> call = CallUtilPackage.getResolvedCall(expression, bindingContext);
|
||||
if (call != null) {
|
||||
CallableDescriptor callResultingDescriptor = call.getResultingDescriptor();
|
||||
if (callResultingDescriptor instanceof ValueParameterDescriptor) {
|
||||
ValueParameterDescriptor valueParameterDescriptor = (ValueParameterDescriptor) callResultingDescriptor;
|
||||
// constructor parameter
|
||||
if (valueParameterDescriptor.getContainingDeclaration() instanceof ConstructorDescriptor) {
|
||||
// constructor of my class
|
||||
if (valueParameterDescriptor.getContainingDeclaration().getContainingDeclaration() == classDescriptor) {
|
||||
propertyDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, valueParameterDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// todo: when and if frontend will allow properties defined not as constructor parameters to be used in delegation specifier
|
||||
}
|
||||
}
|
||||
return propertyDescriptor;
|
||||
}
|
||||
|
||||
public static boolean isFinalPropertyWithBackingField(PropertyDescriptor propertyDescriptor, BindingContext bindingContext) {
|
||||
return propertyDescriptor != null &&
|
||||
!propertyDescriptor.isVar() &&
|
||||
Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor));
|
||||
}
|
||||
|
||||
public static Map<CallableMemberDescriptor, CallableMemberDescriptor> getDelegates(ClassDescriptor descriptor, ClassDescriptor toClass) {
|
||||
Map<CallableMemberDescriptor, CallableMemberDescriptor> result = new LinkedHashMap<CallableMemberDescriptor, CallableMemberDescriptor>();
|
||||
for (DeclarationDescriptor declaration : descriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
|
||||
if (declaration instanceof CallableMemberDescriptor) {
|
||||
CallableMemberDescriptor callableMemberDescriptor = (CallableMemberDescriptor) declaration;
|
||||
if (callableMemberDescriptor.getKind() == CallableMemberDescriptor.Kind.DELEGATION) {
|
||||
Set<? extends CallableMemberDescriptor> overriddenDescriptors = callableMemberDescriptor.getOverriddenDescriptors();
|
||||
for (CallableMemberDescriptor overriddenDescriptor : overriddenDescriptors) {
|
||||
if (overriddenDescriptor.getContainingDeclaration() == toClass) {
|
||||
assert !result.containsKey(callableMemberDescriptor) :
|
||||
"overridden is already set for " + callableMemberDescriptor;
|
||||
result.put(callableMemberDescriptor, overriddenDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ClassDescriptor getSuperClassByDelegationSpecifier(@NotNull JetDelegationSpecifier specifier, @NotNull BindingContext bindingContext) {
|
||||
JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference());
|
||||
assert superType != null : "superType should not be null: " + specifier.getText();
|
||||
|
||||
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
|
||||
assert superClassDescriptor != null : "superClassDescriptor should not be null: " + specifier.getText();
|
||||
return superClassDescriptor;
|
||||
}
|
||||
|
||||
private static boolean valueParameterClassesMatch(
|
||||
@NotNull List<ValueParameterDescriptor> parameters,
|
||||
@NotNull List<ClassifierDescriptor> classifiers
|
||||
|
||||
@@ -1313,14 +1313,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
for (JetDelegationSpecifier specifier : delegationSpecifiers) {
|
||||
if (specifier instanceof JetDelegatorByExpressionSpecifier) {
|
||||
JetExpression expression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression();
|
||||
PropertyDescriptor propertyDescriptor = getDelegatePropertyIfAny(expression);
|
||||
PropertyDescriptor propertyDescriptor = CodegenUtil.getDelegatePropertyIfAny(expression, descriptor, bindingContext);
|
||||
|
||||
ClassDescriptor superClassDescriptor = getSuperClass(specifier);
|
||||
|
||||
if (propertyDescriptor != null &&
|
||||
!propertyDescriptor.isVar() &&
|
||||
Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor))) {
|
||||
// final property with backing field
|
||||
if (CodegenUtil.isFinalPropertyWithBackingField(propertyDescriptor, bindingContext)) {
|
||||
result.addField((JetDelegatorByExpressionSpecifier) specifier, propertyDescriptor);
|
||||
}
|
||||
else {
|
||||
@@ -1334,12 +1331,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
@NotNull
|
||||
private ClassDescriptor getSuperClass(@NotNull JetDelegationSpecifier specifier) {
|
||||
JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference());
|
||||
assert superType != null;
|
||||
|
||||
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
|
||||
assert superClassDescriptor != null;
|
||||
return superClassDescriptor;
|
||||
return CodegenUtil.getSuperClassByDelegationSpecifier(specifier, bindingContext);
|
||||
}
|
||||
|
||||
private void genCallToDelegatorByExpressionSpecifier(
|
||||
@@ -1361,26 +1353,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
@Nullable
|
||||
private PropertyDescriptor getDelegatePropertyIfAny(JetExpression expression) {
|
||||
PropertyDescriptor propertyDescriptor = null;
|
||||
if (expression instanceof JetSimpleNameExpression) {
|
||||
ResolvedCall<?> call = CallUtilPackage.getResolvedCall(expression, bindingContext);
|
||||
if (call != null) {
|
||||
CallableDescriptor callResultingDescriptor = call.getResultingDescriptor();
|
||||
if (callResultingDescriptor instanceof ValueParameterDescriptor) {
|
||||
ValueParameterDescriptor valueParameterDescriptor = (ValueParameterDescriptor) callResultingDescriptor;
|
||||
// constructor parameter
|
||||
if (valueParameterDescriptor.getContainingDeclaration() instanceof ConstructorDescriptor) {
|
||||
// constructor of my class
|
||||
if (valueParameterDescriptor.getContainingDeclaration().getContainingDeclaration() == descriptor) {
|
||||
propertyDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, valueParameterDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// todo: when and if frontend will allow properties defined not as constructor parameters to be used in delegation specifier
|
||||
}
|
||||
}
|
||||
return propertyDescriptor;
|
||||
return CodegenUtil.getDelegatePropertyIfAny(expression, descriptor, bindingContext);
|
||||
}
|
||||
|
||||
private void lookupConstructorExpressionsInClosureIfPresent(final ConstructorContext constructorContext) {
|
||||
@@ -1737,24 +1710,16 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
|
||||
protected void generateDelegates(ClassDescriptor toClass, DelegationFieldsInfo.Field field) {
|
||||
for (DeclarationDescriptor declaration : descriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
|
||||
if (declaration instanceof CallableMemberDescriptor) {
|
||||
CallableMemberDescriptor callableMemberDescriptor = (CallableMemberDescriptor) declaration;
|
||||
if (callableMemberDescriptor.getKind() == CallableMemberDescriptor.Kind.DELEGATION) {
|
||||
Set<? extends CallableMemberDescriptor> overriddenDescriptors = callableMemberDescriptor.getOverriddenDescriptors();
|
||||
for (CallableMemberDescriptor overriddenDescriptor : overriddenDescriptors) {
|
||||
if (overriddenDescriptor.getContainingDeclaration() == toClass) {
|
||||
if (declaration instanceof PropertyDescriptor) {
|
||||
propertyCodegen
|
||||
.genDelegate((PropertyDescriptor) declaration, (PropertyDescriptor) overriddenDescriptor, field.getStackValue());
|
||||
}
|
||||
else if (declaration instanceof FunctionDescriptor) {
|
||||
functionCodegen
|
||||
.genDelegate((FunctionDescriptor) declaration, (FunctionDescriptor) overriddenDescriptor, field.getStackValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Map.Entry<CallableMemberDescriptor, CallableMemberDescriptor> entry : CodegenUtil.getDelegates(descriptor, toClass).entrySet()) {
|
||||
CallableMemberDescriptor callableMemberDescriptor = entry.getKey();
|
||||
CallableMemberDescriptor overriddenDescriptor = entry.getValue();
|
||||
if (callableMemberDescriptor instanceof PropertyDescriptor) {
|
||||
propertyCodegen
|
||||
.genDelegate((PropertyDescriptor) callableMemberDescriptor, (PropertyDescriptor) overriddenDescriptor, field.getStackValue());
|
||||
}
|
||||
else if (callableMemberDescriptor instanceof FunctionDescriptor) {
|
||||
functionCodegen
|
||||
.genDelegate((FunctionDescriptor) callableMemberDescriptor, (FunctionDescriptor) overriddenDescriptor, field.getStackValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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 DelegationTest extends SingleFileTranslationTest {
|
||||
|
||||
public DelegationTest() {
|
||||
super("delegation/");
|
||||
}
|
||||
|
||||
public void testDelegation2() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegation3() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegation4() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegationGenericArg() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegationMethodsWithArgs() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegationByInh() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegationChain() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegationByExprWithArgs() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegationByArg() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegationByNewInstance() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegationByFunExpr() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegationByIfExpr() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegationEvaluationOrder1() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegationEvaluationOrder2() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegationExtFun1() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegationExtFun2() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDelegationExtProp() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ public final class Namer {
|
||||
private static final String SETTER_PREFIX = "set_";
|
||||
private static final String GETTER_PREFIX = "get_";
|
||||
private static final String BACKING_FIELD_PREFIX = "$";
|
||||
private static final String DELEGATE_POSTFIX = "$delegate";
|
||||
private static final String DELEGATE = "$delegate";
|
||||
|
||||
private static final String SUPER_METHOD_NAME = "baseInitializer";
|
||||
|
||||
@@ -131,9 +131,14 @@ public final class Namer {
|
||||
return new JsNameRef(getPrototypeName(), classOrTraitExpression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getDelegatePrefix() {
|
||||
return DELEGATE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getDelegateName(@NotNull String propertyName) {
|
||||
return propertyName + DELEGATE_POSTFIX;
|
||||
return propertyName + DELEGATE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -125,14 +125,16 @@ public final class ClassTranslator extends AbstractTranslator {
|
||||
declarationContext = fixContextForClassObjectAccessing(declarationContext);
|
||||
|
||||
invocationArguments.add(getSuperclassReferences(declarationContext));
|
||||
DelegationTranslator delegationTranslator = new DelegationTranslator(classDeclaration, context());
|
||||
if (!isTrait()) {
|
||||
JsFunction initializer = new ClassInitializerTranslator(classDeclaration, declarationContext).generateInitializeMethod();
|
||||
JsFunction initializer = new ClassInitializerTranslator(classDeclaration, declarationContext).generateInitializeMethod(delegationTranslator);
|
||||
invocationArguments.add(initializer.getBody().getStatements().isEmpty() ? JsLiteral.NULL : initializer);
|
||||
}
|
||||
|
||||
translatePropertiesAsConstructorParameters(declarationContext, properties);
|
||||
DeclarationBodyVisitor bodyVisitor = new DeclarationBodyVisitor(properties, staticProperties);
|
||||
bodyVisitor.traverseContainer(classDeclaration, declarationContext);
|
||||
delegationTranslator.generateDelegated(properties);
|
||||
mayBeAddEnumEntry(bodyVisitor.getEnumEntryList(), staticProperties, declarationContext);
|
||||
|
||||
if (KotlinBuiltIns.getInstance().isData(descriptor)) {
|
||||
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.translate.declaration
|
||||
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.jet.lang.descriptors.*
|
||||
import org.jetbrains.jet.lang.psi.*
|
||||
import org.jetbrains.k2js.translate.context.Namer
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator
|
||||
import org.jetbrains.k2js.translate.general.Translation
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils
|
||||
import org.jetbrains.k2js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils.*
|
||||
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
||||
import org.jetbrains.jet.backend.common.CodegenUtil
|
||||
import java.util.HashMap
|
||||
import com.google.dart.compiler.backend.js.ast.JsLiteral
|
||||
import org.jetbrains.k2js.translate.declaration.propertyTranslator.addGetterAndSetter
|
||||
|
||||
public class DelegationTranslator(
|
||||
private val classDeclaration: JetClassOrObject,
|
||||
context: TranslationContext
|
||||
) : AbstractTranslator(context) {
|
||||
|
||||
private val classDescriptor: ClassDescriptor =
|
||||
BindingUtils.getClassDescriptor(context.bindingContext(), classDeclaration);
|
||||
|
||||
private val delegationBySpecifiers =
|
||||
classDeclaration.getDelegationSpecifiers().filterIsInstance(javaClass<JetDelegatorByExpressionSpecifier>());
|
||||
|
||||
private class Field (val name: String, val generateField: Boolean)
|
||||
private val fields = HashMap<JetDelegatorByExpressionSpecifier, Field>();
|
||||
|
||||
{
|
||||
for (specifier in delegationBySpecifiers) {
|
||||
val expression = specifier.getDelegateExpression() ?:
|
||||
throw IllegalArgumentException("delegate expression should not be null: ${specifier.getText()}")
|
||||
val descriptor = getSuperClass(specifier)
|
||||
val propertyDescriptor = CodegenUtil.getDelegatePropertyIfAny(expression, classDescriptor, bindingContext())
|
||||
|
||||
if (CodegenUtil.isFinalPropertyWithBackingField(propertyDescriptor, bindingContext())) {
|
||||
fields.put(specifier, Field(propertyDescriptor!!.getName().asString(), false))
|
||||
}
|
||||
else {
|
||||
val typeFqName = DescriptorUtils.getFqNameSafe(descriptor)
|
||||
val delegateName = getMangledMemberNameForExplicitDelegation(Namer.getDelegatePrefix(), classDeclaration.getFqName(), typeFqName)
|
||||
fields.put(specifier, Field(delegateName, true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun addInitCode(statements: MutableList<JsStatement>) {
|
||||
for (specifier in delegationBySpecifiers) {
|
||||
val field = fields.get(specifier)!!
|
||||
if (field.generateField) {
|
||||
val expression = specifier.getDelegateExpression()!!
|
||||
val delegateInitExpr = Translation.translateAsExpression(expression, context())
|
||||
statements.add(JsAstUtils.defineSimpleProperty(field.name, delegateInitExpr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun generateDelegated(properties: MutableList<JsPropertyInitializer>) {
|
||||
for (specifier in delegationBySpecifiers) {
|
||||
generateDelegates(getSuperClass(specifier), fields.get(specifier)!!, properties)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSuperClass(specifier: JetDelegationSpecifier): ClassDescriptor =
|
||||
CodegenUtil.getSuperClassByDelegationSpecifier(specifier, bindingContext())
|
||||
|
||||
private fun generateDelegates(toClass: ClassDescriptor, field: Field, properties: MutableList<JsPropertyInitializer>) {
|
||||
for ((descriptor, overriddenDescriptor) in CodegenUtil.getDelegates(classDescriptor, toClass)) {
|
||||
when (descriptor) {
|
||||
is PropertyDescriptor ->
|
||||
generateDelegateCallForPropertyMember(descriptor, field.name, properties)
|
||||
is FunctionDescriptor ->
|
||||
generateDelegateCallForFunctionMember(descriptor, overriddenDescriptor as FunctionDescriptor, field.name, properties)
|
||||
else ->
|
||||
throw IllegalArgumentException("Expected property or function ${descriptor}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateDelegateCallForPropertyMember(
|
||||
descriptor: PropertyDescriptor,
|
||||
delegateName: String,
|
||||
properties: MutableList<JsPropertyInitializer>
|
||||
) {
|
||||
val propertyName: String = descriptor.getName().asString()
|
||||
|
||||
fun generateDelegateGetterFunction(getterDescriptor: PropertyGetterDescriptor): JsFunction {
|
||||
val delegateRefName = context().getScopeForDescriptor(getterDescriptor).declareName(delegateName)
|
||||
val delegateRef = JsNameRef(delegateRefName, JsLiteral.THIS)
|
||||
|
||||
val returnExpression = if (JsDescriptorUtils.isExtension(descriptor)) {
|
||||
val getterName = context().getNameForDescriptor(getterDescriptor)
|
||||
val receiver = Namer.getReceiverParameterName()
|
||||
JsInvocation(JsNameRef(getterName, delegateRef), JsNameRef(receiver))
|
||||
}
|
||||
else {
|
||||
JsNameRef(propertyName, delegateRef): JsExpression // TODO remove explicit type specification after resolving KT-5569
|
||||
}
|
||||
|
||||
val jsFunction = simpleReturnFunction(context().getScopeForDescriptor(getterDescriptor.getContainingDeclaration()), returnExpression)
|
||||
if (JsDescriptorUtils.isExtension(descriptor)) {
|
||||
val receiverName = jsFunction.getScope().declareName(Namer.getReceiverParameterName())
|
||||
jsFunction.getParameters().add(JsParameter(receiverName))
|
||||
}
|
||||
return jsFunction
|
||||
}
|
||||
|
||||
fun generateDelegateSetterFunction(setterDescriptor: PropertySetterDescriptor): JsFunction {
|
||||
val jsFunction = JsFunction(context().getScopeForDescriptor(setterDescriptor.getContainingDeclaration()))
|
||||
|
||||
assert(setterDescriptor.getValueParameters().size() == 1, "Setter must have 1 parameter")
|
||||
val defaultParameter = JsParameter(jsFunction.getScope().declareTemporary())
|
||||
val defaultParameterRef = defaultParameter.getName().makeRef()
|
||||
|
||||
val delegateRefName = context().getScopeForDescriptor(setterDescriptor).declareName(delegateName)
|
||||
val delegateRef = JsNameRef(delegateRefName, JsLiteral.THIS)
|
||||
|
||||
val setExpression = if (JsDescriptorUtils.isExtension(descriptor)) {
|
||||
val setterName = context().getNameForDescriptor(setterDescriptor)
|
||||
val setterNameRef = JsNameRef(setterName, delegateRef)
|
||||
val extensionFunctionReceiverName = jsFunction.getScope().declareName(Namer.getReceiverParameterName())
|
||||
jsFunction.getParameters().add(JsParameter(extensionFunctionReceiverName))
|
||||
JsInvocation(setterNameRef, JsNameRef(extensionFunctionReceiverName), defaultParameterRef)
|
||||
}
|
||||
else {
|
||||
val propertyNameRef = JsNameRef(propertyName, delegateRef)
|
||||
JsAstUtils.assignment(propertyNameRef, defaultParameterRef)
|
||||
}
|
||||
|
||||
jsFunction.getParameters().add(defaultParameter)
|
||||
jsFunction.setBody(JsBlock(setExpression.makeStmt()))
|
||||
return jsFunction
|
||||
}
|
||||
|
||||
fun generateDelegateAccessor(accessorDescriptor: PropertyAccessorDescriptor, function: JsFunction): JsPropertyInitializer =
|
||||
translateFunctionAsEcma5PropertyDescriptor(function, accessorDescriptor, context())
|
||||
|
||||
fun generateDelegateGetter(): JsPropertyInitializer {
|
||||
val getterDescriptor = descriptor.getGetter() ?: throw IllegalStateException("Getter descriptor should not be null")
|
||||
return generateDelegateAccessor(getterDescriptor, generateDelegateGetterFunction(getterDescriptor))
|
||||
}
|
||||
|
||||
fun generateDelegateSetter(): JsPropertyInitializer {
|
||||
val setterDescriptor = descriptor.getSetter() ?: throw IllegalStateException("Setter descriptor should not be null")
|
||||
return generateDelegateAccessor(setterDescriptor, generateDelegateSetterFunction(setterDescriptor))
|
||||
}
|
||||
|
||||
properties.addGetterAndSetter(descriptor, context(), ::generateDelegateGetter, ::generateDelegateSetter
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private fun generateDelegateCallForFunctionMember(
|
||||
descriptor: FunctionDescriptor,
|
||||
overriddenDescriptor: FunctionDescriptor,
|
||||
delegateName: String,
|
||||
properties: MutableList<JsPropertyInitializer>
|
||||
) {
|
||||
val delegateMemberFunctionName = context().getNameForDescriptor(descriptor)
|
||||
val overriddenMemberFunctionName = context().getNameForDescriptor(overriddenDescriptor)
|
||||
val delegateRefName = context().getScopeForDescriptor(descriptor).declareName(delegateName)
|
||||
val delegateRef = JsNameRef(delegateRefName, JsLiteral.THIS)
|
||||
val overriddenMemberFunctionRef = JsNameRef(overriddenMemberFunctionName, delegateRef)
|
||||
|
||||
val parameters = SmartList<JsParameter>()
|
||||
val args = SmartList<JsExpression>()
|
||||
val functionScope = context().getScopeForDescriptor(descriptor);
|
||||
|
||||
if (JsDescriptorUtils.isExtension(descriptor)) {
|
||||
val extensionFunctionReceiverName = functionScope.declareName(Namer.getReceiverParameterName())
|
||||
parameters.add(JsParameter(extensionFunctionReceiverName))
|
||||
args.add(JsNameRef(extensionFunctionReceiverName))
|
||||
}
|
||||
|
||||
for (param in descriptor.getValueParameters()) {
|
||||
val paramName = param.getName().asString()
|
||||
val jsParamName = functionScope.declareName(paramName)
|
||||
parameters.add(JsParameter(jsParamName))
|
||||
args.add(JsNameRef(jsParamName))
|
||||
}
|
||||
|
||||
val functionObject = simpleReturnFunction(context().getScopeForDescriptor(descriptor), JsInvocation(overriddenMemberFunctionRef, args))
|
||||
functionObject.getParameters().addAll(parameters)
|
||||
properties.add(JsPropertyInitializer(delegateMemberFunctionName.makeRef(), functionObject))
|
||||
}
|
||||
}
|
||||
+24
-15
@@ -54,6 +54,27 @@ public fun translateAccessors(
|
||||
translateAccessors(descriptor, null, result, context)
|
||||
}
|
||||
|
||||
public fun MutableList<JsPropertyInitializer>.addGetterAndSetter(
|
||||
descriptor: PropertyDescriptor,
|
||||
context: TranslationContext,
|
||||
generateGetter: () -> JsPropertyInitializer,
|
||||
generateSetter: () -> JsPropertyInitializer
|
||||
) {
|
||||
val to: MutableList<JsPropertyInitializer>
|
||||
if (!JsDescriptorUtils.isExtension(descriptor)) {
|
||||
to = SmartList<JsPropertyInitializer>()
|
||||
this.add(JsPropertyInitializer(context.getNameForDescriptor(descriptor).makeRef(), JsObjectLiteral(to, true)))
|
||||
}
|
||||
else {
|
||||
to = this
|
||||
}
|
||||
|
||||
to.add(generateGetter())
|
||||
if (descriptor.isVar()) {
|
||||
to.add(generateSetter())
|
||||
}
|
||||
}
|
||||
|
||||
private class PropertyTranslator(
|
||||
val descriptor: PropertyDescriptor,
|
||||
val declaration: JetProperty?,
|
||||
@@ -63,19 +84,7 @@ private class PropertyTranslator(
|
||||
private val propertyName: String = descriptor.getName().asString()
|
||||
|
||||
fun translate(result: MutableList<JsPropertyInitializer>) {
|
||||
val to: MutableList<JsPropertyInitializer>
|
||||
if (!JsDescriptorUtils.isExtension(descriptor)) {
|
||||
to = SmartList<JsPropertyInitializer>()
|
||||
result.add(JsPropertyInitializer(context().getNameForDescriptor(descriptor).makeRef(), JsObjectLiteral(to, true)))
|
||||
}
|
||||
else {
|
||||
to = result
|
||||
}
|
||||
|
||||
to.add(generateGetter())
|
||||
if (descriptor.isVar()) {
|
||||
to.add(generateSetter())
|
||||
}
|
||||
result.addGetterAndSetter(descriptor, context(), { generateGetter() }, { generateSetter() })
|
||||
}
|
||||
|
||||
private fun generateGetter(): JsPropertyInitializer =
|
||||
@@ -84,9 +93,9 @@ private class PropertyTranslator(
|
||||
private fun generateSetter(): JsPropertyInitializer =
|
||||
if (hasCustomSetter()) translateCustomAccessor(getCustomSetterDeclaration()) else generateDefaultSetter()
|
||||
|
||||
private fun hasCustomGetter() = declaration != null && declaration.getGetter() != null && getCustomGetterDeclaration().hasBody()
|
||||
private fun hasCustomGetter() = declaration?.getGetter() != null && getCustomGetterDeclaration().hasBody()
|
||||
|
||||
private fun hasCustomSetter() = declaration != null && declaration.getSetter() != null && getCustomSetterDeclaration().hasBody()
|
||||
private fun hasCustomSetter() = declaration?.getSetter() != null && getCustomSetterDeclaration().hasBody()
|
||||
|
||||
private fun getCustomGetterDeclaration(): JetPropertyAccessor =
|
||||
declaration?.getGetter() ?:
|
||||
|
||||
+3
-1
@@ -33,6 +33,7 @@ import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.k2js.translate.context.Namer;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.declaration.DelegationTranslator;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.reference.CallArgumentTranslator;
|
||||
|
||||
@@ -62,7 +63,7 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsFunction generateInitializeMethod() {
|
||||
public JsFunction generateInitializeMethod(DelegationTranslator delegationTranslator) {
|
||||
//TODO: it's inconsistent that we have scope for class and function for constructor, currently have problems implementing better way
|
||||
ConstructorDescriptor primaryConstructor = getConstructor(bindingContext(), classDeclaration);
|
||||
JsFunction result = context().getFunctionObject(primaryConstructor);
|
||||
@@ -70,6 +71,7 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
|
||||
// for properties declared as constructor parameters
|
||||
result.getParameters().addAll(translatePrimaryConstructorParameters());
|
||||
mayBeAddCallToSuperMethod(result);
|
||||
delegationTranslator.addInitCode(initializerStatements);
|
||||
new InitializerVisitor(initializerStatements).traverseContainer(classDeclaration, context());
|
||||
|
||||
List<JsStatement> statements = result.getBody().getStatements();
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.OverrideResolver;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryConstVariable;
|
||||
@@ -202,6 +203,12 @@ public final class TranslationUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getMangledMemberNameForExplicitDelegation(@NotNull String suggestedName, FqName classFqName, FqName typeFqName) {
|
||||
String forCalculateId = classFqName.asString() + ":" + typeFqName.asString();
|
||||
return getStableMangledName(suggestedName, forCalculateId);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getStableMangledName(@NotNull String suggestedName, String forCalculateId) {
|
||||
int absHashCode = Math.abs(forCalculateId.hashCode());
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// This test was adapted from compiler/testData/codegen/box/classes
|
||||
package foo
|
||||
|
||||
trait Trait1 {
|
||||
fun foo(): String
|
||||
}
|
||||
|
||||
trait Trait2 {
|
||||
fun bar(): String
|
||||
}
|
||||
|
||||
class T1 : Trait1 {
|
||||
override fun foo() = "aaa"
|
||||
}
|
||||
|
||||
class T2 : Trait2 {
|
||||
override fun bar() = "bbb"
|
||||
}
|
||||
|
||||
class C(a: Trait1, b: Trait2) : Trait1 by a, Trait2 by b
|
||||
|
||||
fun box(): String {
|
||||
val c = C(T1(), T2())
|
||||
if (c.foo() != "aaa") return "fail"
|
||||
if (c.bar() != "bbb") return "fail"
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// This test was adapted from compiler/testData/codegen/box/classes
|
||||
package foo
|
||||
|
||||
trait One {
|
||||
public open fun foo(): Int
|
||||
public open fun faz(): Int = 10
|
||||
}
|
||||
trait Two {
|
||||
public open fun foo(): Int
|
||||
public open fun quux(): Int = 100
|
||||
}
|
||||
|
||||
class OneImpl : One {
|
||||
public override fun foo() = 1
|
||||
}
|
||||
class TwoImpl : Two {
|
||||
public override fun foo() = 2
|
||||
}
|
||||
|
||||
class Test2(a: One, b: Two) : Two by b, One by a {
|
||||
public override fun foo() = 0
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var t2 = Test2(OneImpl(), TwoImpl())
|
||||
if (t2.foo() != 0)
|
||||
return "Fail #1"
|
||||
if (t2.faz() != 10)
|
||||
return "Fail #2"
|
||||
if (t2.quux() != 100)
|
||||
return "Fail #3"
|
||||
if (t2 !is One)
|
||||
return "Fail #4"
|
||||
if (t2 !is Two)
|
||||
return "Fail #5"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// This test was adapted from compiler/testData/codegen/box/classes
|
||||
package foo
|
||||
|
||||
open trait First {
|
||||
public open fun foo(): Int
|
||||
}
|
||||
|
||||
open trait Second : First {
|
||||
public open fun bar(): Int
|
||||
}
|
||||
|
||||
class Impl : Second {
|
||||
public override fun foo() = 1
|
||||
public override fun bar() = 2
|
||||
}
|
||||
|
||||
class Test(s: Second) : Second by s {}
|
||||
|
||||
fun box(): String {
|
||||
var t = Test(Impl())
|
||||
if (t.foo() != 1)
|
||||
return "Fail #1"
|
||||
if (t.bar() != 2)
|
||||
return "Fail #2"
|
||||
if (t !is First)
|
||||
return "Fail #3"
|
||||
if (t !is Second)
|
||||
return "Fail #4"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package foo
|
||||
|
||||
trait Base {
|
||||
abstract fun foo(x: String): String
|
||||
var prop: String
|
||||
}
|
||||
|
||||
class BaseImpl(val s: String) : Base {
|
||||
override fun foo(x: String): String = "Base: ${s}:${x}"
|
||||
override var prop: String = "prop"
|
||||
}
|
||||
|
||||
class Derived(b: Base) : Base by b
|
||||
|
||||
|
||||
fun box(): String {
|
||||
var d = Derived(BaseImpl("test"))
|
||||
assertEquals("Base: test:!!", d.foo("!!"), "delegation by argument, function member")
|
||||
assertEquals("prop", d.prop, "delegation by argument, get property")
|
||||
|
||||
d.prop = "new value"
|
||||
assertEquals("new value", d.prop, "delegation by argument, set property")
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package foo
|
||||
|
||||
trait Base {
|
||||
abstract fun foo(arg: String): String
|
||||
}
|
||||
|
||||
class BaseImpl(val s1: String, val s2: String) : Base {
|
||||
override fun foo(arg: String): String = "BaseImpl:foo ${s1}:${s2}:${arg}"
|
||||
}
|
||||
|
||||
class Derived(s1: String, s2: String) : Base by BaseImpl(s1, s2)
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("BaseImpl:foo arg1:arg2:!!", Derived("arg1", "arg2").foo("!!"), "delegation with two arguments")
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package foo
|
||||
|
||||
trait Base {
|
||||
abstract fun foo(x: String): String
|
||||
}
|
||||
|
||||
class BaseImpl(val s: String) : Base {
|
||||
override fun foo(x: String): String = "Base: ${s}:${x}"
|
||||
}
|
||||
|
||||
fun newBase(s: String): Base = BaseImpl(s)
|
||||
|
||||
class Derived() : Base by newBase("test")
|
||||
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("Base: test:!!", Derived().foo("!!"), "delegation by function expression")
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package foo
|
||||
|
||||
trait Base {
|
||||
abstract fun foo(x: String): String
|
||||
}
|
||||
|
||||
class BaseImpl(val s: String) : Base {
|
||||
override fun foo(x: String): String = "Base: ${s}:${x}"
|
||||
}
|
||||
|
||||
var global = true
|
||||
|
||||
class Derived() : Base by if (global) BaseImpl("then") else BaseImpl("else")
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("Base: then:!!", Derived().foo("!!"), "delegation by if expression")
|
||||
global = false
|
||||
assertEquals("Base: else:!!", Derived().foo("!!"), "delegation by if expression")
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package foo
|
||||
|
||||
trait Base {
|
||||
abstract fun foo(s: String): String
|
||||
var prop: String
|
||||
}
|
||||
|
||||
trait Base1 : Base {
|
||||
}
|
||||
|
||||
trait Base2 : Base1 {
|
||||
override fun foo(s: String): String = "Base2:foo ${s}"
|
||||
}
|
||||
|
||||
class Base2Impl() : Base2 {
|
||||
override var prop: String = ""
|
||||
set(value) {
|
||||
$prop = "prop:${value}"
|
||||
}
|
||||
}
|
||||
|
||||
class Derived() : Base by Base2Impl()
|
||||
|
||||
class Derived1() : Base1 by Base2Impl()
|
||||
|
||||
class Derived2() : Base2 by Base2Impl()
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("Base2:foo !!", Derived().foo("!!"), "delegation (Base)")
|
||||
assertEquals("Base2:foo !!", Derived1().foo("!!"), "delegation (Base1)")
|
||||
assertEquals("Base2:foo !!", Derived2().foo("!!"), "delegation (Base2)")
|
||||
|
||||
var d = Derived()
|
||||
d.prop = "A"
|
||||
assertEquals("prop:A", d.prop, "delegation (Base) set property")
|
||||
|
||||
var d1 = Derived1()
|
||||
d1.prop = "B"
|
||||
assertEquals("prop:B", d1.prop, "delegation (Base1) set property")
|
||||
|
||||
var d2 = Derived1()
|
||||
d2.prop = "C"
|
||||
assertEquals("prop:C", d2.prop, "delegation (Base2) set property")
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package foo
|
||||
|
||||
trait Base {
|
||||
abstract fun foo(x: String): String
|
||||
}
|
||||
|
||||
class BaseImpl(val s: String) : Base {
|
||||
override fun foo(x: String): String = "Base: ${s}:${x}"
|
||||
}
|
||||
|
||||
class Derived() : Base by BaseImpl("test")
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("Base: test:!!", Derived().foo("!!"), "delegation by new instance")
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package foo
|
||||
|
||||
trait Base {
|
||||
abstract fun foo(x: String): String
|
||||
var prop: String
|
||||
}
|
||||
|
||||
class BaseImpl(val s: String) : Base {
|
||||
override fun foo(x: String) = "BaseImpl.foo: ${s}:${x}"
|
||||
override var prop: String = "init"
|
||||
set(value) {
|
||||
$prop = "prop:${value}"
|
||||
}
|
||||
}
|
||||
|
||||
class Base2Impl(val s: String) : Base by BaseImpl("${s} by BaseImpl")
|
||||
|
||||
class Derived(val s: String) : Base by Base2Impl("${s} by Base2Impl")
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("BaseImpl.foo: Derived by Base2Impl by BaseImpl:!!", Derived("Derived").foo("!!"))
|
||||
|
||||
var d = Derived("Derived")
|
||||
assertEquals("init", d.prop)
|
||||
|
||||
d.prop = "A"
|
||||
assertEquals("prop:A", d.prop)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package foo
|
||||
|
||||
trait Base {
|
||||
abstract fun foo(x: String): String
|
||||
}
|
||||
|
||||
class BaseImpl(val s: String) : Base {
|
||||
override fun foo(x: String): String = "Base: ${s}:${x}"
|
||||
}
|
||||
|
||||
var global = ""
|
||||
|
||||
open class DerivedBase() {
|
||||
{
|
||||
global += ":DerivedBase"
|
||||
}
|
||||
}
|
||||
|
||||
fun newBase(): Base {
|
||||
global += ":newBase"
|
||||
return BaseImpl("test")
|
||||
}
|
||||
|
||||
class Derived() : DerivedBase(), Base by newBase() {
|
||||
{
|
||||
global += ":Derived"
|
||||
}
|
||||
}
|
||||
|
||||
class Derived1() : Base by newBase(), DerivedBase() {
|
||||
{
|
||||
global += ":Derived"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var d = Derived()
|
||||
assertEquals(":DerivedBase:newBase:Derived", global, "evaluation order")
|
||||
|
||||
global = ""
|
||||
var d1 = Derived1()
|
||||
assertEquals(":DerivedBase:newBase:Derived", global, "evaluation order")
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package foo
|
||||
|
||||
trait Base {
|
||||
abstract fun foo(x: String): String
|
||||
}
|
||||
|
||||
class BaseImpl(val s: String) : Base {
|
||||
override fun foo(x: String): String = "Base: ${s}:${x}"
|
||||
}
|
||||
|
||||
trait Base2 {
|
||||
abstract fun bar(x: String): String
|
||||
}
|
||||
|
||||
class Base2Impl(val s: String) : Base2 {
|
||||
override fun bar(x: String): String = "Base2: ${s}:${x}"
|
||||
}
|
||||
|
||||
var global = ""
|
||||
|
||||
open class DerivedBase() {
|
||||
{
|
||||
global += ":DerivedBase"
|
||||
}
|
||||
}
|
||||
|
||||
fun newBase(): Base {
|
||||
global += ":newBase"
|
||||
return BaseImpl("test")
|
||||
}
|
||||
|
||||
fun newBase2(): Base2 {
|
||||
global += ":newBase2"
|
||||
return Base2Impl("test")
|
||||
}
|
||||
|
||||
class Derived() : DerivedBase(), Base by newBase(), Base2 by newBase2() {
|
||||
{
|
||||
global += ":Derived"
|
||||
}
|
||||
}
|
||||
|
||||
class Derived1() : Base by newBase(), DerivedBase(), Base2 by newBase2() {
|
||||
{
|
||||
global += ":Derived"
|
||||
}
|
||||
}
|
||||
|
||||
class Derived2() : Base by newBase(), Base2 by newBase2(), DerivedBase() {
|
||||
{
|
||||
global += ":Derived"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var d = Derived()
|
||||
assertEquals(":DerivedBase:newBase:newBase2:Derived", global, "evaluation order 1")
|
||||
|
||||
global = ""
|
||||
var d1 = Derived1()
|
||||
assertEquals(":DerivedBase:newBase:newBase2:Derived", global, "evaluation order 2")
|
||||
|
||||
global = ""
|
||||
var d2 = Derived2()
|
||||
assertEquals(":DerivedBase:newBase:newBase2:Derived", global, "evaluation order 3")
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package foo
|
||||
|
||||
trait Base {
|
||||
abstract fun Int.foo(): String
|
||||
}
|
||||
|
||||
open class BaseImpl(val s: String) : Base {
|
||||
override fun Int.foo(): String = "Int.foo ${s}:${this}"
|
||||
}
|
||||
|
||||
class Derived() : Base by BaseImpl("test") {
|
||||
fun bar(x: Int): String = x.foo()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("Int.foo test:5", Derived().bar(5))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package foo
|
||||
|
||||
trait Base {
|
||||
abstract fun String.foo(arg: String): String
|
||||
}
|
||||
|
||||
open class BaseImpl(val s: String) : Base {
|
||||
override fun String.foo(arg: String): String = "Int.foo ${s}:${this}:${arg}"
|
||||
}
|
||||
|
||||
class Derived() : Base by BaseImpl("test") {
|
||||
fun bar(x: String, arg: String): String = x.foo(arg)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("Int.foo test:A:B", Derived().bar("A", "B"))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package foo
|
||||
|
||||
trait Base {
|
||||
var prop: String
|
||||
var Int.foo: String
|
||||
}
|
||||
|
||||
open class BaseImpl(val s: String) : Base {
|
||||
override var prop: String = "init"
|
||||
override var Int.foo: String
|
||||
get() = "get Int.foo:${s}:${this}"
|
||||
set(value) {
|
||||
prop = "set Int.foo:${s}:${this}:${value}"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Derived() : Base by BaseImpl("test") {
|
||||
fun getFooValue(x: Int): String = x.foo
|
||||
fun setFooValue(x: Int, value: String) {
|
||||
x.foo = value
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var d = Derived()
|
||||
assertEquals("get Int.foo:test:5", d.getFooValue(5))
|
||||
|
||||
d.setFooValue(10, "A")
|
||||
assertEquals("set Int.foo:test:10:A", d.prop)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// This test was adapted from compiler/testData/codegen/box/classes
|
||||
package foo
|
||||
|
||||
trait A<T> {
|
||||
fun foo(t: T): String
|
||||
}
|
||||
|
||||
class Derived(a: A<Int>) : A<Int> by a
|
||||
|
||||
fun box(): String {
|
||||
val o = object : A<Int> {
|
||||
override fun foo(t: Int) = if (t == 42) "OK" else "Fail $t"
|
||||
}
|
||||
return Derived(o).foo(42)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// This test was adapted from compiler/testData/codegen/box/classes
|
||||
package foo
|
||||
|
||||
trait TextField {
|
||||
fun getText(): String
|
||||
}
|
||||
|
||||
trait InputTextField : TextField {
|
||||
fun setText(text: String)
|
||||
}
|
||||
|
||||
trait MooableTextField : InputTextField {
|
||||
fun moo(a: Int, b: Int, c: Int): Int
|
||||
}
|
||||
|
||||
class SimpleTextField : MooableTextField {
|
||||
private var text2 = ""
|
||||
override fun getText() = text2
|
||||
override fun setText(text: String) {
|
||||
this.text2 = text
|
||||
}
|
||||
override fun moo(a: Int, b: Int, c: Int) = a + b + c
|
||||
}
|
||||
|
||||
class TextFieldWrapper(textField: MooableTextField) : MooableTextField by textField
|
||||
|
||||
fun box(): String {
|
||||
val textField = TextFieldWrapper(SimpleTextField())
|
||||
textField.setText("hello world!")
|
||||
|
||||
if (!textField.getText().equals("hello world!")) return "FAIL #!1"
|
||||
if (textField.moo(1, 2, 3) != 6) return "FAIL #2"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user