From 4d287c96d6785425372ce3500983a342c324143b Mon Sep 17 00:00:00 2001 From: Erokhin Stanislav Date: Thu, 30 Jan 2014 15:43:01 +0400 Subject: [PATCH] JS backend: In CallInfo: receiver1, receiver2 -> ExplicitReceivers. Drop CallInfo.nullableReceiverForSafeCall, move constructSafeCall to extension for CallInfo --- .../k2js/translate/reference/CallInfo.kt | 87 ++++++++++--------- ...earCallTranslator.kt => CallTranslator.kt} | 33 +++---- 2 files changed, 57 insertions(+), 63 deletions(-) rename js/js.translator/src/org/jetbrains/k2js/translate/reference/{ClearCallTranslator.kt => CallTranslator.kt} (87%) diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallInfo.kt b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallInfo.kt index f504914a6db..036eda910c3 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallInfo.kt +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallInfo.kt @@ -38,7 +38,6 @@ trait CallInfo { val thisObject: JsExpression? val receiverObject: JsExpression? - val nullableReceiverForSafeCall: JsExpression? } // if value == null, it is get access @@ -46,6 +45,29 @@ class VariableAccessInfo(callInfo: CallInfo, val value: JsExpression? = null): C class FunctionCallInfo(callInfo: CallInfo, val argumentsInfo: CallArgumentTranslator.ArgumentsInfo) : CallInfo by callInfo +/** + * no receivers - thisObjectOrReceiverObject = null, receiverObject = null + * this - thisObjectOrReceiverObject = this, receiverObject = null + * receiver - thisObjectOrReceiverObject = receiver, receiverObject = null + * both - thisObjectOrReceiverObject = this, receiverObject = receiver + */ +class ExplicitReceivers(val receiverOrThisObject: JsExpression?, val receiverObject: JsExpression? = null) + +fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall, receiver: JsExpression?): CallInfo { + return createCallInfo(resolvedCall, ExplicitReceivers(receiver)) +} + +fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall, receiver: JsExpression?): FunctionCallInfo { + return getCallInfo(resolvedCall, ExplicitReceivers(receiver)); +} + +// two receiver need only for FunctionCall in VariableAsFunctionResolvedCall +fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall, explicitReceivers: ExplicitReceivers): FunctionCallInfo { + val callInfo = createCallInfo(resolvedCall, explicitReceivers) + val argumentsInfo = CallArgumentTranslator.translate(resolvedCall, explicitReceivers.receiverOrThisObject, this) + return FunctionCallInfo(callInfo, argumentsInfo) +} + val CallInfo.callableDescriptor: CallableDescriptor get() { @@ -57,9 +79,6 @@ fun CallInfo.isExtension(): Boolean { fun CallInfo.isMemberCall(): Boolean { return thisObject != null } -fun CallInfo.isSafeCall(): Boolean { - return resolvedCall.isSafeCall() -} fun CallInfo.isNative(): Boolean { return AnnotationsUtils.isNativeObject(callableDescriptor) } @@ -67,6 +86,20 @@ fun CallInfo.isSuperInvocation() : Boolean { val thisObject = resolvedCall.getThisObject() return thisObject is ExpressionReceiver && ((thisObject as ExpressionReceiver)).getExpression() is JetSuperExpression } +fun CallInfo.constructSafeCallIsNeeded(result: JsExpression): JsExpression { + if (!resolvedCall.isSafeCall()) + return result + + val nullableReceiverForSafeCall = when (resolvedCall.getExplicitReceiverKind()) { + BOTH_RECEIVERS, RECEIVER_ARGUMENT -> receiverObject + else -> thisObject + } + return CallType.SAFE.constructCall(nullableReceiverForSafeCall, object : CallType.CallConstructor { + override fun construct(receiver: JsExpression?): JsExpression { + return result + } + }, context) +} val VariableAccessInfo.variableDescriptor: VariableDescriptor get() { @@ -81,28 +114,21 @@ fun VariableAccessInfo.isGetAccess(): Boolean { } val FunctionCallInfo.functionName : JsName - get() { // getter, because for several descriptors name is undefined. Example: {(a) -> a+1}(3) + get() { return context.getNameForDescriptor(callableDescriptor) } fun FunctionCallInfo.hasSpreadOperator() : Boolean { return argumentsInfo.isHasSpreadOperator() } + private fun TranslationContext.getThisObject(receiverValue: ReceiverValue): JsExpression { assert(receiverValue.exists(), "receiverValue must be exist here") return getThisObject(getDeclarationDescriptorForReceiver(receiverValue)) } -private fun TranslationContext.createCallInfo(resolvedCall: ResolvedCall, receiver1: JsExpression?, receiver2: JsExpression?): CallInfo { +private fun TranslationContext.createCallInfo(resolvedCall: ResolvedCall, explicitReceivers: ExplicitReceivers): CallInfo { val receiverKind = resolvedCall.getExplicitReceiverKind() - fun getNotNullReceiver1(): JsExpression { - assert(receiver1 != null, "ResolvedCall say, that receiver(1) must be not null") - return receiver1!! - } - fun getNotNullReceiver2(): JsExpression { - assert(receiver2 != null, "ResolvedCall say, that receiver(2) must be not null") - return receiver2!! - } fun getThisObject(): JsExpression? { val receiverValue = resolvedCall.getThisObject() @@ -110,8 +136,7 @@ private fun TranslationContext.createCallInfo(resolvedCall: ResolvedCall getNotNullReceiver1() - BOTH_RECEIVERS -> getNotNullReceiver2() + THIS_OBJECT, BOTH_RECEIVERS -> explicitReceivers.receiverOrThisObject else -> this.getThisObject(receiverValue) } } @@ -122,7 +147,8 @@ private fun TranslationContext.createCallInfo(resolvedCall: ResolvedCall getNotNullReceiver1() + RECEIVER_ARGUMENT -> explicitReceivers.receiverOrThisObject + BOTH_RECEIVERS -> explicitReceivers.receiverObject else -> this.getThisObject(receiverValue) } } @@ -132,8 +158,8 @@ private fun TranslationContext.createCallInfo(resolvedCall: ResolvedCall getNotNullReceiver1() - else -> getNotNullReceiver1() + BOTH_RECEIVERS -> explicitReceivers.receiverObject + else -> explicitReceivers.receiverOrThisObject } } return object : CallInfo { @@ -141,26 +167,5 @@ private fun TranslationContext.createCallInfo(resolvedCall: ResolvedCall = resolvedCall override val thisObject: JsExpression? = getThisObject() override val receiverObject: JsExpression? = getReceiverObject() - override val nullableReceiverForSafeCall: JsExpression? = getNullableReceiverForSafeCall() }; -} - -fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall, receiver: JsExpression?): CallInfo { - return createCallInfo(resolvedCall, receiver, null) -} - -fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall, receiver: JsExpression?): FunctionCallInfo { - return getCallInfo(resolvedCall, receiver, null); -} - -// two receiver need only for FunctionCall in VariableAsFunctionResolvedCall -fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall, receiver1: JsExpression?, receiver2: JsExpression?): FunctionCallInfo { - val callInfo = createCallInfo(resolvedCall, receiver1, receiver2) - - val receiverForArgsTranslator = if (resolvedCall.getExplicitReceiverKind() == BOTH_RECEIVERS) // TODO: remove this hack - receiver2 - else - receiver1 - val argumentsInfo = CallArgumentTranslator.translate(resolvedCall, receiverForArgsTranslator, this) - return FunctionCallInfo(callInfo, argumentsInfo) -} +} \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ClearCallTranslator.kt b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.kt similarity index 87% rename from js/js.translator/src/org/jetbrains/k2js/translate/reference/ClearCallTranslator.kt rename to js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.kt index 49ec0f58a0f..976e278e630 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ClearCallTranslator.kt +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.kt @@ -37,7 +37,7 @@ val functionCallCases: CallCaseDispatcher = val variableAccessCases: CallCaseDispatcher = createVariableAccessCases() fun TranslationContext.buildCall(resolvedCall: ResolvedCall, receiverOrThisObject: JsExpression? = null): JsExpression { - return buildCall(resolvedCall, receiverOrThisObject, null) + return buildCall(resolvedCall, ExplicitReceivers(receiverOrThisObject)) } fun TranslationContext.buildGet(resolvedCall: ResolvedCall, receiverOrThisObject: JsExpression? = null): JsExpression { @@ -66,23 +66,23 @@ fun ResolvedCall.expectedReceivers(): Boolean { return this.getExplicitReceiverKind() != NO_EXPLICIT_RECEIVER } -private fun TranslationContext.buildCall(resolvedCall: ResolvedCall, receiver1: JsExpression?, receiver2: JsExpression?): JsExpression { +private fun TranslationContext.buildCall(resolvedCall: ResolvedCall, explicitReceivers: ExplicitReceivers): JsExpression { if (resolvedCall is VariableAsFunctionResolvedCall) { - assert(receiver2 == null, "receiver2 for VariableAsFunctionResolvedCall must be null") // TODO: add debug info + assert(explicitReceivers.receiverObject == null, "VariableAsFunctionResolvedCall must have one receiver") // TODO: add debug info val variableCall = resolvedCall.getVariableCall() if (variableCall.expectedReceivers()) { - val newReceiver = buildGet(variableCall, receiver1) - return buildCall(resolvedCall.getFunctionCall(), newReceiver, null) + val newReceiver = buildGet(variableCall, explicitReceivers.receiverOrThisObject) + return buildCall(resolvedCall.getFunctionCall(), ExplicitReceivers(newReceiver)) } else { - val newReceiver2 = buildGet(variableCall, null) - if (receiver1 == null) - return buildCall(resolvedCall.getFunctionCall(), newReceiver2) + val thisObject = buildGet(variableCall, null) + if (explicitReceivers.receiverOrThisObject == null) + return buildCall(resolvedCall.getFunctionCall(), ExplicitReceivers(thisObject)) else - return buildCall(resolvedCall.getFunctionCall(), receiver1, newReceiver2) + return buildCall(resolvedCall.getFunctionCall(), ExplicitReceivers(thisObject, explicitReceivers.receiverOrThisObject)) } } - val functionCallInfo = getCallInfo(resolvedCall, receiver1, receiver2) + val functionCallInfo = getCallInfo(resolvedCall, explicitReceivers) return functionCallCases.translate(functionCallInfo) } @@ -113,14 +113,6 @@ trait CallCase { throw unsupported() } - fun constructSafeCall(result: JsExpression): JsExpression { - return CallType.SAFE.constructCall(callInfo.nullableReceiverForSafeCall, object : CallType.CallConstructor { - override fun construct(receiver: JsExpression?): JsExpression { - return result - } - }, callInfo.context) - } - final fun translate(): JsExpression { val result = if (callInfo.thisObject == null) { if (callInfo.receiverObject == null) @@ -134,10 +126,7 @@ trait CallCase { callInfo.bothReceivers() } - return if (callInfo.isSafeCall()) - constructSafeCall(result) - else - return result + return callInfo.constructSafeCallIsNeeded(result) } }