From 254ed6de14c5ca64609fd49ad0cfaa7b44404c26 Mon Sep 17 00:00:00 2001 From: Pavel Talanov Date: Fri, 10 Feb 2012 22:34:34 +0400 Subject: [PATCH] implement CallType logic --- .../k2js/translate/context/StaticContext.java | 8 ++ .../expression/ExpressionVisitor.java | 11 +- .../translate/expression/ForTranslator.java | 7 +- .../translate/reference/AccessTranslator.java | 3 +- .../reference/ArrayAccessTranslator.java | 4 +- .../translate/reference/CallTranslator.java | 132 ++++++++++++------ .../k2js/translate/reference/CallType.java | 51 +++---- .../KotlinPropertyAccessTranslator.java | 15 +- .../reference/PropertyAccessTranslator.java | 14 +- .../QualifiedExpressionTranslator.java | 46 +++--- .../reference/ReferenceTranslator.java | 2 +- .../k2js/translate/utils/BindingUtils.java | 4 +- .../k2js/translate/utils/DescriptorUtils.java | 2 +- .../propertyAccess/cases/safeAccess.kt | 13 +- .../propertyAccess/cases/safeCall.kt | 1 - .../org/jetbrains/k2js/test/MiscTest.java | 2 +- 16 files changed, 173 insertions(+), 142 deletions(-) diff --git a/translator/src/org/jetbrains/k2js/translate/context/StaticContext.java b/translator/src/org/jetbrains/k2js/translate/context/StaticContext.java index 43bc58a8a8d..578ebf998df 100644 --- a/translator/src/org/jetbrains/k2js/translate/context/StaticContext.java +++ b/translator/src/org/jetbrains/k2js/translate/context/StaticContext.java @@ -126,6 +126,14 @@ public class StaticContext { @Nullable public JsNameRef getQualifierForDescriptor(@NotNull DeclarationDescriptor descriptor) { + + //TODO: refactor + if (descriptor instanceof PropertyDescriptor) { + return null; + } + if (isVariableAsFunction(descriptor)) { + return null; + } //TODO: hack! if (AnnotationsUtils.isNativeObject(descriptor)) { return null; diff --git a/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java b/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java index a7c0521fe85..b51d6bf5243 100644 --- a/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java @@ -17,10 +17,7 @@ import org.jetbrains.k2js.translate.general.TranslatorVisitor; import org.jetbrains.k2js.translate.operation.BinaryOperationTranslator; import org.jetbrains.k2js.translate.operation.IncrementTranslator; import org.jetbrains.k2js.translate.operation.UnaryOperationTranslator; -import org.jetbrains.k2js.translate.reference.AccessTranslator; -import org.jetbrains.k2js.translate.reference.CallTranslator; -import org.jetbrains.k2js.translate.reference.QualifiedExpressionTranslator; -import org.jetbrains.k2js.translate.reference.ReferenceTranslator; +import org.jetbrains.k2js.translate.reference.*; import org.jetbrains.k2js.translate.utils.BindingUtils; import org.jetbrains.k2js.translate.utils.TranslationUtils; @@ -135,7 +132,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull public JsNode visitCallExpression(@NotNull JetCallExpression expression, @NotNull TranslationContext context) { - return CallTranslator.translate(expression, null, context); + return CallTranslator.translate(expression, null, CallType.NORMAL, context); } @Override @@ -260,7 +257,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull public JsNode visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression, @NotNull TranslationContext context) { - return QualifiedExpressionTranslator.translateDotQualifiedExpression(expression, context); + return QualifiedExpressionTranslator.translateQualifiedExpression(expression, context); } @Override @@ -289,7 +286,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull public JsNode visitSafeQualifiedExpression(@NotNull JetSafeQualifiedExpression expression, @NotNull TranslationContext context) { - return QualifiedExpressionTranslator.translateSafeQualifiedExpression(expression, context); + return QualifiedExpressionTranslator.translateQualifiedExpression(expression, context); } @Override diff --git a/translator/src/org/jetbrains/k2js/translate/expression/ForTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/ForTranslator.java index f9af7b11f07..6ea2cbe90b4 100644 --- a/translator/src/org/jetbrains/k2js/translate/expression/ForTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/expression/ForTranslator.java @@ -13,6 +13,7 @@ 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.reference.CallTranslator; +import org.jetbrains.k2js.translate.reference.CallType; import static org.jetbrains.k2js.translate.utils.BindingUtils.*; import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopBody; @@ -66,13 +67,13 @@ public final class ForTranslator extends AbstractTranslator { @NotNull private JsExpression nextMethodInvocation(@NotNull TemporaryVariable iterator) { FunctionDescriptor nextFunction = getNextFunction(context().bindingContext(), getLoopRange()); - return CallTranslator.translate(iterator.nameReference(), nextFunction, context()); + return CallTranslator.translate(iterator.nameReference(), nextFunction, CallType.NORMAL, context()); } @NotNull private JsExpression hasNextMethodInvocation(@NotNull TemporaryVariable iterator) { CallableDescriptor hasNextFunction = getHasNextCallable(context().bindingContext(), getLoopRange()); - return CallTranslator.translate(iterator.nameReference(), hasNextFunction, context()); + return CallTranslator.translate(iterator.nameReference(), hasNextFunction, CallType.NORMAL, context()); } @NotNull @@ -80,7 +81,7 @@ public final class ForTranslator extends AbstractTranslator { JetExpression rangeExpression = getLoopRange(); JsExpression range = Translation.translateAsExpression(rangeExpression, context()); FunctionDescriptor iteratorFunction = getIteratorFunction(context().bindingContext(), rangeExpression); - return CallTranslator.translate(range, iteratorFunction, context()); + return CallTranslator.translate(range, iteratorFunction, CallType.NORMAL, context()); } @NotNull diff --git a/translator/src/org/jetbrains/k2js/translate/reference/AccessTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/AccessTranslator.java index 07ee927f461..56e33883dc5 100644 --- a/translator/src/org/jetbrains/k2js/translate/reference/AccessTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/reference/AccessTranslator.java @@ -24,7 +24,8 @@ public abstract class AccessTranslator extends AbstractTranslator { return QualifiedExpressionTranslator.getAccessTranslator((JetQualifiedExpression) referenceExpression, context); } assert referenceExpression instanceof JetSimpleNameExpression; - return PropertyAccessTranslator.newInstance((JetSimpleNameExpression) referenceExpression, null, context); + return PropertyAccessTranslator.newInstance((JetSimpleNameExpression) referenceExpression, + null, CallType.NORMAL, context); } if (referenceExpression instanceof JetArrayAccessExpression) { return ArrayAccessTranslator.newInstance((JetArrayAccessExpression) referenceExpression, context); diff --git a/translator/src/org/jetbrains/k2js/translate/reference/ArrayAccessTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/ArrayAccessTranslator.java index 7ebc4f880fd..855e0bfd01c 100644 --- a/translator/src/org/jetbrains/k2js/translate/reference/ArrayAccessTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/reference/ArrayAccessTranslator.java @@ -44,7 +44,7 @@ public final class ArrayAccessTranslator extends AccessTranslator { ResolvedCall resolvedCall = BindingUtils.getResolvedCall(context().bindingContext(), expression); List arguments = translateIndexExpressions(); return CallTranslator.translate(translateArrayExpression(), arguments, resolvedCall, - methodDescriptor, context()); + methodDescriptor, CallType.NORMAL, context()); } @Override @@ -54,7 +54,7 @@ public final class ArrayAccessTranslator extends AccessTranslator { List arguments = translateIndexExpressions(); arguments.add(expression); return CallTranslator.translate(translateArrayExpression(), arguments, resolvedCall, - methodDescriptor, context()); + methodDescriptor, CallType.NORMAL, context()); } @NotNull diff --git a/translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java index 47cbabb461b..07bdc8f8b66 100644 --- a/translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java @@ -33,6 +33,19 @@ import static org.jetbrains.k2js.translate.utils.TranslationUtils.*; //TODO: reorder methods properly public final class CallTranslator extends AbstractTranslator { + private static class CallParameters { + + public CallParameters(@Nullable JsExpression receiver, @NotNull JsExpression functionReference) { + this.receiver = receiver; + this.functionReference = functionReference; + } + + @Nullable + public /*var*/ JsExpression receiver; + @NotNull + public /*var*/ JsExpression functionReference; + } + private static final class Builder { @NotNull @@ -48,7 +61,7 @@ public final class CallTranslator extends AbstractTranslator { List arguments = Collections.emptyList(); ResolvedCall resolvedCall = getResolvedCall(context.bindingContext(), unaryExpression.getOperationReference()); - return new CallTranslator(receiver, null, arguments, resolvedCall, null, context); + return new CallTranslator(receiver, null, arguments, resolvedCall, null, CallType.NORMAL, context); } //TODO: method too long @@ -71,19 +84,20 @@ public final class CallTranslator extends AbstractTranslator { ResolvedCall resolvedCall = getResolvedCall(context.bindingContext(), binaryExpression.getOperationReference()); - return new CallTranslator(receiver, null, arguments, resolvedCall, null, context); + return new CallTranslator(receiver, null, arguments, resolvedCall, null, CallType.NORMAL, context); } @NotNull private CallTranslator buildFromCallExpression(@NotNull JetCallExpression callExpression, - @Nullable JsExpression receiver) { + @Nullable JsExpression receiver, + @NotNull CallType callType) { ResolvedCall resolvedCall = getResolvedCallForCallExpression(context.bindingContext(), callExpression); List arguments = translateArgumentsForCallExpression(callExpression, context); JsExpression callee = null; if (resolvedCall.getCandidateDescriptor() instanceof ExpressionAsFunctionDescriptor) { callee = Translation.translateAsExpression(getCallee(callExpression), context); } - return new CallTranslator(receiver, callee, arguments, resolvedCall, null, context); + return new CallTranslator(receiver, callee, arguments, resolvedCall, null, callType, context); } @NotNull @@ -130,25 +144,29 @@ public final class CallTranslator extends AbstractTranslator { @NotNull public static JsExpression translate(@Nullable JsExpression receiver, @NotNull CallableDescriptor descriptor, + @NotNull CallType callType, @NotNull TranslationContext context) { return translate(receiver, Collections.emptyList(), - ResolvedCallImpl.create(descriptor), null, context); + ResolvedCallImpl.create(descriptor), null, callType, context); } @NotNull public static JsExpression translate(@Nullable JsExpression receiver, @NotNull ResolvedCall resolvedCall, @Nullable CallableDescriptor descriptorToCall, + @NotNull CallType callType, @NotNull TranslationContext context) { - return translate(receiver, Collections.emptyList(), resolvedCall, descriptorToCall, context); + return (new CallTranslator(receiver, null, Collections.emptyList(), resolvedCall, + descriptorToCall, CallType.SAFE, context)).translate(); } @NotNull public static JsExpression translate(@Nullable JsExpression receiver, @NotNull List arguments, @NotNull ResolvedCall resolvedCall, @Nullable CallableDescriptor descriptorToCall, + @NotNull CallType callType, @NotNull TranslationContext context) { - return (new CallTranslator(receiver, null, arguments, resolvedCall, descriptorToCall, context)).translate(); + return (new CallTranslator(receiver, null, arguments, resolvedCall, descriptorToCall, callType, context)).translate(); } @NotNull @@ -160,8 +178,9 @@ public final class CallTranslator extends AbstractTranslator { @NotNull public static JsExpression translate(@NotNull JetCallExpression callExpression, @Nullable JsExpression receiver, + @NotNull CallType callType, @NotNull TranslationContext context) { - return (new Builder(context).buildFromCallExpression(callExpression, receiver)).translate(); + return (new Builder(context).buildFromCallExpression(callExpression, receiver, callType)).translate(); } @NotNull @@ -200,15 +219,20 @@ public final class CallTranslator extends AbstractTranslator { @NotNull private final CallableDescriptor descriptor; + @NotNull + private final CallType callType; + private CallTranslator(@Nullable JsExpression receiver, @Nullable JsExpression callee, @NotNull List arguments, @NotNull ResolvedCall resolvedCall, @Nullable CallableDescriptor descriptorToCall, + @NotNull CallType callType, @NotNull TranslationContext context) { super(context); this.receiver = receiver; this.arguments = arguments; this.resolvedCall = resolvedCall; + this.callType = callType; if (descriptorToCall != null) { this.descriptor = descriptorToCall; } else { @@ -234,8 +258,16 @@ public final class CallTranslator extends AbstractTranslator { return methodCall(); } + + private boolean isExtensionFunctionLiteral() { + boolean isLiteral = descriptor instanceof VariableAsFunctionDescriptor + || descriptor instanceof ExpressionAsFunctionDescriptor; + return isExtensionFunction() && isLiteral; + } + @NotNull private JsExpression extensionFunctionLiteralCall() { + //TODO: call type receiver = getExtensionFunctionCallReceiver(); List callArguments = generateExtensionCallArgumentList(); JsInvocation callMethodInvocation = generateCallMethodInvocation(); @@ -247,21 +279,17 @@ public final class CallTranslator extends AbstractTranslator { JsNameRef callMethodNameRef = AstUtil.newQualifiedNameRef("call"); JsInvocation callMethodInvocation = new JsInvocation(); callMethodInvocation.setQualifier(callMethodNameRef); - AstUtil.setQualifier(callMethodInvocation, calleeReference()); + AstUtil.setQualifier(callMethodInvocation, callParameters().functionReference); return callMethodInvocation; } - private boolean isExtensionFunctionLiteral() { - boolean isLiteral = descriptor instanceof VariableAsFunctionDescriptor - || descriptor instanceof ExpressionAsFunctionDescriptor; - return isExtensionFunction() && isLiteral; - } - @NotNull private JsExpression extensionFunctionCall() { receiver = getExtensionFunctionCallReceiver(); List argumentList = generateExtensionCallArgumentList(); - return AstUtil.newInvocation(calleeReference(), argumentList); + JsExpression functionReference = callParameters().functionReference; + AstUtil.setQualifier(functionReference, callParameters().receiver); + return AstUtil.newInvocation(functionReference, argumentList); } @NotNull @@ -295,13 +323,24 @@ public final class CallTranslator extends AbstractTranslator { assert descriptor instanceof FunctionDescriptor; FunctionIntrinsic functionIntrinsic = context().intrinsics().getFunctionIntrinsic((FunctionDescriptor) descriptor); - JsExpression receiverExpression = thisObject(); + JsExpression receiverExpression = resolveThisObject(/*do not get qualifier*/false); return functionIntrinsic.apply(receiverExpression, arguments, context()); } @NotNull - private JsInvocation methodCall() { - return AstUtil.newInvocation(calleeReference(), arguments); + private JsExpression methodCall() { + final CallParameters callParameters = callParameters(); + return callType.constructCall(callParameters.receiver, new CallType.CallConstructor() { + @NotNull + @Override + public JsExpression construct(@Nullable JsExpression receiver) { + JsExpression functionReference = callParameters.functionReference; + if (receiver != null) { + AstUtil.setQualifier(functionReference, receiver); + } + return AstUtil.newInvocation(functionReference, arguments); + } + }, context()); } private boolean isConstructor() { @@ -313,54 +352,59 @@ public final class CallTranslator extends AbstractTranslator { } @NotNull - private JsExpression calleeReference() { + private CallParameters callParameters() { if (callee != null) { - return callee; + return new CallParameters(null, callee); } - if (isVariableDescriptor(descriptor)) { - //TODO: write tests on this cases - VariableDescriptor variableDescriptor = - getVariableDescriptorForVariableAsFunction((VariableAsFunctionDescriptor) descriptor); - if (variableDescriptor instanceof PropertyDescriptor) { - return getterCall((PropertyDescriptor) variableDescriptor); - } - return qualifiedMethodReference(variableDescriptor); + JsExpression thisObject = resolveThisObject(/*just get qualifier if null*/ true); + JsExpression functionReference = functionReference(); + return new CallParameters(thisObject, functionReference); + } + + @NotNull + private JsExpression functionReference() { + if (!isVariableAsFunction(descriptor)) { + return ReferenceTranslator.translateAsLocalNameReference(descriptor, context()); } - return qualifiedMethodReference(descriptor); + VariableDescriptor variableDescriptor = + getVariableDescriptorForVariableAsFunction((VariableAsFunctionDescriptor) descriptor); + if (variableDescriptor instanceof PropertyDescriptor) { + return getterCall((PropertyDescriptor) variableDescriptor); + } + return ReferenceTranslator.translateAsLocalNameReference(variableDescriptor, context()); } @NotNull private JsExpression getterCall(@NotNull PropertyDescriptor variableDescriptor) { + //TODO: call type? return PropertyAccessTranslator.translateAsPropertyGetterCall(variableDescriptor, resolvedCall, context()); } @NotNull - private JsExpression qualifiedMethodReference(@NotNull DeclarationDescriptor descriptor) { - JsExpression thisObject = thisObject(); - if (thisObject == null) { - return ReferenceTranslator.translateAsFQReference(descriptor, context()); - } - JsExpression methodReference = ReferenceTranslator.translateAsLocalNameReference(descriptor, context()); - AstUtil.setQualifier(methodReference, thisObject); - return methodReference; + private JsExpression translateAsFunctionWithNoThisObject(@NotNull DeclarationDescriptor descriptor) { + return ReferenceTranslator.translateAsFQReference(descriptor, context()); } + //TODO: refactor @Nullable - private JsExpression thisObject() { + private JsExpression resolveThisObject(boolean getQualifierIfNull) { if (receiver != null) { return receiver; } ReceiverDescriptor thisObject = resolvedCall.getThisObject(); - if (!thisObject.exists()) { - return null; + if (thisObject.exists()) { + DeclarationDescriptor expectedThisDescriptor = getDeclarationDescriptorForReceiver(thisObject); + return TranslationUtils.getThisObject(context(), expectedThisDescriptor); } - DeclarationDescriptor expectedThisDescriptor = getDeclarationDescriptorForReceiver(thisObject); - return TranslationUtils.getThisObject(context(), expectedThisDescriptor); + if (getQualifierIfNull) { + return context().getQualifierForDescriptor(descriptor); + } + return null; } @NotNull private JsExpression constructorCall() { - JsExpression constructorReference = ReferenceTranslator.translateAsFQReference(descriptor, context()); + JsExpression constructorReference = translateAsFunctionWithNoThisObject(descriptor); JsNew constructorCall = new JsNew(constructorReference); constructorCall.setArguments(arguments); return constructorCall; diff --git a/translator/src/org/jetbrains/k2js/translate/reference/CallType.java b/translator/src/org/jetbrains/k2js/translate/reference/CallType.java index 6fe2a65c31f..6fce7259477 100644 --- a/translator/src/org/jetbrains/k2js/translate/reference/CallType.java +++ b/translator/src/org/jetbrains/k2js/translate/reference/CallType.java @@ -6,6 +6,7 @@ import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsNullLiteral; import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression; import org.jetbrains.jet.lang.psi.JetQualifiedExpression; import org.jetbrains.jet.lang.psi.JetSafeQualifiedExpression; @@ -21,20 +22,16 @@ public enum CallType { SAFE { @NotNull @Override - JsExpression mutateSelector(@NotNull JsExpression selector, @NotNull TranslationContext context) { - TemporaryVariable temporaryVariable = context.declareTemporary(selector); - return newSequence(temporaryVariable.assignmentExpression(), temporaryVariable.nameReference()); - } - - @NotNull - @Override - JsExpression mutateExpression(@NotNull JsExpression mutatedSelector, - @NotNull JsExpression expressionWithMutatedSelector, - @NotNull TranslationContext context) { + JsExpression constructCall(@Nullable JsExpression receiver, @NotNull CallConstructor constructor, + @NotNull TranslationContext context) { + assert receiver != null; + TemporaryVariable temporaryVariable = context.declareTemporary(receiver); JsNullLiteral nullLiteral = context.program().getNullLiteral(); //TODO: find similar not null checks - JsBinaryOperation notNullCheck = AstUtil.notEqual(expressionWithMutatedSelector, nullLiteral); - return new JsConditional(notNullCheck, expressionWithMutatedSelector, nullLiteral); + JsBinaryOperation notNullCheck = AstUtil.notEqual(temporaryVariable.nameReference(), nullLiteral); + JsConditional callMethodIfNotNullElseNull = + new JsConditional(notNullCheck, constructor.construct(temporaryVariable.nameReference()), nullLiteral); + return newSequence(temporaryVariable.assignmentExpression(), callMethodIfNotNullElseNull); } }, //TODO: bang qualifier is not implemented in frontend for now @@ -42,31 +39,18 @@ public enum CallType { NORMAL { @NotNull @Override - JsExpression mutateSelector(@NotNull JsExpression selector, @NotNull TranslationContext context) { - // do not mutate - return selector; - } - - @NotNull - @Override - JsExpression mutateExpression(@NotNull JsExpression mutatedSelector, - @NotNull JsExpression expression, - @NotNull TranslationContext context) { - // do not mutate - return expression; + JsExpression constructCall(@Nullable JsExpression receiver, @NotNull CallConstructor constructor, + @NotNull TranslationContext context) { + return constructor.construct(receiver); } }; @NotNull - abstract JsExpression mutateSelector(@NotNull JsExpression selector, @NotNull TranslationContext context); + abstract JsExpression constructCall(@Nullable JsExpression receiver, @NotNull CallConstructor constructor, + @NotNull TranslationContext context); @NotNull - abstract JsExpression mutateExpression(@NotNull JsExpression mutatedSelector, - @NotNull JsExpression expression, - @NotNull TranslationContext context); - - @NotNull - public static CallType getCallTypeForQualifierExpression(@NotNull JetQualifiedExpression expression) { + public static CallType getCallTypeForQualifiedExpression(@NotNull JetQualifiedExpression expression) { if (expression instanceof JetSafeQualifiedExpression) { return SAFE; } @@ -74,4 +58,9 @@ public enum CallType { return NORMAL; } + public interface CallConstructor { + @NotNull + JsExpression construct(@Nullable JsExpression receiver); + } + } \ No newline at end of file diff --git a/translator/src/org/jetbrains/k2js/translate/reference/KotlinPropertyAccessTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/KotlinPropertyAccessTranslator.java index 3107111c863..8bb64aa070d 100644 --- a/translator/src/org/jetbrains/k2js/translate/reference/KotlinPropertyAccessTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/reference/KotlinPropertyAccessTranslator.java @@ -37,24 +37,15 @@ public final class KotlinPropertyAccessTranslator extends PropertyAccessTranslat @Override @NotNull public JsExpression translateAsGet() { - return getterCall(); - } - - @NotNull - private JsExpression getterCall() { - return CallTranslator.translate(qualifier, resolvedCall, propertyDescriptor.getGetter(), context()); + return CallTranslator.translate(qualifier, resolvedCall, propertyDescriptor.getGetter(), getCallType(), context()); } @Override @NotNull public JsExpression translateAsSet(@NotNull JsExpression toSetTo) { - return setterCall(toSetTo); + return CallTranslator.translate(qualifier, Arrays.asList(toSetTo), + resolvedCall, propertyDescriptor.getSetter(), getCallType(), context()); } - @NotNull - private JsExpression setterCall(@NotNull JsExpression toSetTo) { - return CallTranslator.translate(qualifier, Arrays.asList(toSetTo), - resolvedCall, propertyDescriptor.getSetter(), context()); - } } diff --git a/translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java index ae37f295ba8..f7447229fa2 100644 --- a/translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java @@ -36,13 +36,18 @@ public abstract class PropertyAccessTranslator extends AccessTranslator { @NotNull public static PropertyAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression, @Nullable JsExpression qualifier, + @NotNull CallType callType, @NotNull TranslationContext context) { + PropertyAccessTranslator result; PropertyDescriptor propertyDescriptor = getPropertyDescriptor(expression, context); if (isNativeObject(propertyDescriptor) || isBackingFieldReference(expression)) { - return new NativePropertyAccessTranslator(propertyDescriptor, qualifier, context); + result = new NativePropertyAccessTranslator(propertyDescriptor, qualifier, context); + } else { + ResolvedCall resolvedCall = getResolvedCall(context.bindingContext(), expression); + result = new KotlinPropertyAccessTranslator(propertyDescriptor, qualifier, resolvedCall, context); } - ResolvedCall resolvedCall = getResolvedCall(context.bindingContext(), expression); - return new KotlinPropertyAccessTranslator(propertyDescriptor, qualifier, resolvedCall, context); + result.setCallType(callType); + return result; } @NotNull @@ -67,8 +72,9 @@ public abstract class PropertyAccessTranslator extends AccessTranslator { @NotNull public static JsExpression translateAsPropertyGetterCall(@NotNull JetSimpleNameExpression expression, @Nullable JsExpression qualifier, + @NotNull CallType callType, @NotNull TranslationContext context) { - return (newInstance(expression, qualifier, context)) + return (newInstance(expression, qualifier, callType, context)) .translateAsGet(); } diff --git a/translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java index c5207f189ba..38b577b126b 100644 --- a/translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java @@ -1,18 +1,16 @@ package org.jetbrains.k2js.translate.reference; -import com.google.dart.compiler.backend.js.ast.JsConditional; import com.google.dart.compiler.backend.js.ast.JsExpression; -import com.google.dart.compiler.backend.js.ast.JsNullLiteral; -import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.k2js.translate.context.TemporaryVariable; +import org.jetbrains.jet.lang.psi.JetCallExpression; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetQualifiedExpression; +import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.k2js.translate.context.TranslationContext; import static org.jetbrains.k2js.translate.general.Translation.translateAsExpression; import static org.jetbrains.k2js.translate.utils.PsiUtils.getNotNullSimpleNameSelector; import static org.jetbrains.k2js.translate.utils.PsiUtils.getSelector; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.notNullCheck; /** * @author Pavel Talanov @@ -28,44 +26,38 @@ public final class QualifiedExpressionTranslator { JsExpression receiver = translateReceiver(expression, context); PropertyAccessTranslator result = - PropertyAccessTranslator.newInstance(getNotNullSimpleNameSelector(expression), receiver, context); - result.setCallType(CallType.getCallTypeForQualifierExpression(expression)); + PropertyAccessTranslator.newInstance(getNotNullSimpleNameSelector(expression), receiver, + CallType.getCallTypeForQualifiedExpression(expression), context); + result.setCallType(CallType.getCallTypeForQualifiedExpression(expression)); return result; } @NotNull - public static JsExpression translateSafeQualifiedExpression(@NotNull JetSafeQualifiedExpression expression, - @NotNull TranslationContext context) { - TemporaryVariable receiver = context.declareTemporary(translateReceiver(expression, context)); - JsNullLiteral nullLiteral = context.program().getNullLiteral(); - JetExpression selector = getSelector(expression); - JsExpression thenExpression = translate(receiver.nameReference(), selector, context); - JsConditional callMethodIfNotNullConditional - = new JsConditional(notNullCheck(context, receiver.nameReference()), thenExpression, nullLiteral); - return AstUtil.newSequence(receiver.assignmentExpression(), callMethodIfNotNullConditional); - } - - @NotNull - public static JsExpression translateDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression, - @NotNull TranslationContext context) { + public static JsExpression translateQualifiedExpression(@NotNull JetQualifiedExpression expression, + @NotNull TranslationContext context) { JsExpression receiver = translateReceiver(expression, context); JetExpression selector = getSelector(expression); - return translate(receiver, selector, context); + CallType callType = CallType.getCallTypeForQualifiedExpression(expression); + return dispatchToCorrectTranslator(receiver, selector, callType, context); } @NotNull - private static JsExpression translate(@NotNull JsExpression receiver, @NotNull JetExpression selector, - @NotNull TranslationContext context) { + private static JsExpression dispatchToCorrectTranslator(@NotNull JsExpression receiver, + @NotNull JetExpression selector, + @NotNull CallType callType, + @NotNull TranslationContext context) { if (PropertyAccessTranslator.canBePropertyGetterCall(selector, context)) { + assert selector instanceof JetSimpleNameExpression : "Selectors for properties must be simple names."; return PropertyAccessTranslator.translateAsPropertyGetterCall - ((JetSimpleNameExpression) selector, receiver, context); + ((JetSimpleNameExpression) selector, receiver, callType, context); } if (selector instanceof JetCallExpression) { - return CallTranslator.translate((JetCallExpression) selector, receiver, context); + return CallTranslator.translate((JetCallExpression) selector, receiver, callType, context); } throw new AssertionError("Unexpected qualified expression"); } + //TODO: if has duplications @NotNull private static JsExpression translateReceiver(@NotNull JetQualifiedExpression expression, @NotNull TranslationContext context) { diff --git a/translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java index 4ff7a4b7abf..8f3929d3ee9 100644 --- a/translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java @@ -19,7 +19,7 @@ public final class ReferenceTranslator { public static JsExpression translateSimpleName(@NotNull JetSimpleNameExpression expression, @NotNull TranslationContext context) { if (PropertyAccessTranslator.canBePropertyGetterCall(expression, context)) { - return PropertyAccessTranslator.translateAsPropertyGetterCall(expression, null, context); + return PropertyAccessTranslator.translateAsPropertyGetterCall(expression, null, CallType.NORMAL, context); } DeclarationDescriptor referencedDescriptor = getDescriptorForReferenceExpression(context.bindingContext(), expression); diff --git a/translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java b/translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java index c902fdba5b6..81c129daa6b 100644 --- a/translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java +++ b/translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java @@ -16,7 +16,7 @@ import java.util.Collection; import java.util.List; import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getVariableDescriptorForVariableAsFunction; -import static org.jetbrains.k2js.translate.utils.DescriptorUtils.isVariableDescriptor; +import static org.jetbrains.k2js.translate.utils.DescriptorUtils.isVariableAsFunction; /** * @author Pavel Talanov @@ -191,7 +191,7 @@ public final class BindingUtils { private static DeclarationDescriptor getNullableDescriptorForReferenceExpression(@NotNull BindingContext context, @NotNull JetReferenceExpression reference) { DeclarationDescriptor referencedDescriptor = context.get(BindingContext.REFERENCE_TARGET, reference); - if (isVariableDescriptor(referencedDescriptor)) { + if (isVariableAsFunction(referencedDescriptor)) { assert referencedDescriptor != null; return getVariableDescriptorForVariableAsFunction((VariableAsFunctionDescriptor) referencedDescriptor); } diff --git a/translator/src/org/jetbrains/k2js/translate/utils/DescriptorUtils.java b/translator/src/org/jetbrains/k2js/translate/utils/DescriptorUtils.java index 49ae1de3727..5f34dd18cae 100644 --- a/translator/src/org/jetbrains/k2js/translate/utils/DescriptorUtils.java +++ b/translator/src/org/jetbrains/k2js/translate/utils/DescriptorUtils.java @@ -111,7 +111,7 @@ public final class DescriptorUtils { } - public static boolean isVariableDescriptor(@Nullable DeclarationDescriptor referencedDescriptor) { + public static boolean isVariableAsFunction(@Nullable DeclarationDescriptor referencedDescriptor) { return referencedDescriptor instanceof VariableAsFunctionDescriptor; } diff --git a/translator/testFiles/propertyAccess/cases/safeAccess.kt b/translator/testFiles/propertyAccess/cases/safeAccess.kt index 302de0ca00c..7eace25a6fe 100644 --- a/translator/testFiles/propertyAccess/cases/safeAccess.kt +++ b/translator/testFiles/propertyAccess/cases/safeAccess.kt @@ -4,12 +4,15 @@ class A() { var c = 3 } -fun box() { +fun box() : Boolean { var a1 : A? = A() var a2 : A? = null - a1?.c++ - a2?.c++ + a1?.c = 4 + a2?.c = 5 + if (a1?.c != 4) { + return false; + } a2 = a1 - a2?.c++ - return (a2?.c == 5) + a2?.c = 5 + return (a2?.c == 5) && (a1?.c == 5) } \ No newline at end of file diff --git a/translator/testFiles/propertyAccess/cases/safeCall.kt b/translator/testFiles/propertyAccess/cases/safeCall.kt index ea4920b3909..b6b446186f4 100644 --- a/translator/testFiles/propertyAccess/cases/safeCall.kt +++ b/translator/testFiles/propertyAccess/cases/safeCall.kt @@ -2,7 +2,6 @@ package foo class A() { fun doSomething() { - } } diff --git a/translatorTests/test/org/jetbrains/k2js/test/MiscTest.java b/translatorTests/test/org/jetbrains/k2js/test/MiscTest.java index 45df222b32d..48f04fd54e4 100644 --- a/translatorTests/test/org/jetbrains/k2js/test/MiscTest.java +++ b/translatorTests/test/org/jetbrains/k2js/test/MiscTest.java @@ -14,7 +14,7 @@ public final class MiscTest extends AbstractExpressionTest { return MAIN; } - public void testNamespaceProperties() throws Exception { + public void testLocalPropertys() throws Exception { testFunctionOutput("localProperty.jet", "foo", "box", 50); }