JS backend: In CallInfo: receiver1, receiver2 -> ExplicitReceivers. Drop CallInfo.nullableReceiverForSafeCall, move constructSafeCall to extension for CallInfo

This commit is contained in:
Erokhin Stanislav
2014-01-30 15:43:01 +04:00
parent 257d13e90b
commit 4d287c96d6
2 changed files with 57 additions and 63 deletions
@@ -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<out CallableDescriptor>, receiver: JsExpression?): CallInfo {
return createCallInfo(resolvedCall, ExplicitReceivers(receiver))
}
fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall<out FunctionDescriptor>, receiver: JsExpression?): FunctionCallInfo {
return getCallInfo(resolvedCall, ExplicitReceivers(receiver));
}
// two receiver need only for FunctionCall in VariableAsFunctionResolvedCall
fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall<out FunctionDescriptor>, 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<out CallableDescriptor>, receiver1: JsExpression?, receiver2: JsExpression?): CallInfo {
private fun TranslationContext.createCallInfo(resolvedCall: ResolvedCall<out CallableDescriptor>, 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<out Cal
return null
}
return when (receiverKind) {
THIS_OBJECT -> getNotNullReceiver1()
BOTH_RECEIVERS -> getNotNullReceiver2()
THIS_OBJECT, BOTH_RECEIVERS -> explicitReceivers.receiverOrThisObject
else -> this.getThisObject(receiverValue)
}
}
@@ -122,7 +147,8 @@ private fun TranslationContext.createCallInfo(resolvedCall: ResolvedCall<out Cal
return null
}
return when (receiverKind) {
RECEIVER_ARGUMENT, BOTH_RECEIVERS -> getNotNullReceiver1()
RECEIVER_ARGUMENT -> explicitReceivers.receiverOrThisObject
BOTH_RECEIVERS -> explicitReceivers.receiverObject
else -> this.getThisObject(receiverValue)
}
}
@@ -132,8 +158,8 @@ private fun TranslationContext.createCallInfo(resolvedCall: ResolvedCall<out Cal
return null
}
return when (receiverKind) {
BOTH_RECEIVERS -> getNotNullReceiver1()
else -> getNotNullReceiver1()
BOTH_RECEIVERS -> explicitReceivers.receiverObject
else -> explicitReceivers.receiverOrThisObject
}
}
return object : CallInfo {
@@ -141,26 +167,5 @@ private fun TranslationContext.createCallInfo(resolvedCall: ResolvedCall<out Cal
override val resolvedCall: ResolvedCall<out CallableDescriptor> = resolvedCall
override val thisObject: JsExpression? = getThisObject()
override val receiverObject: JsExpression? = getReceiverObject()
override val nullableReceiverForSafeCall: JsExpression? = getNullableReceiverForSafeCall()
};
}
fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall<out CallableDescriptor>, receiver: JsExpression?): CallInfo {
return createCallInfo(resolvedCall, receiver, null)
}
fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall<out FunctionDescriptor>, receiver: JsExpression?): FunctionCallInfo {
return getCallInfo(resolvedCall, receiver, null);
}
// two receiver need only for FunctionCall in VariableAsFunctionResolvedCall
fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall<out FunctionDescriptor>, 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)
}
}
@@ -37,7 +37,7 @@ val functionCallCases: CallCaseDispatcher<FunctionCallCase, FunctionCallInfo> =
val variableAccessCases: CallCaseDispatcher<VariableAccessCase, VariableAccessInfo> = createVariableAccessCases()
fun TranslationContext.buildCall(resolvedCall: ResolvedCall<out FunctionDescriptor>, receiverOrThisObject: JsExpression? = null): JsExpression {
return buildCall(resolvedCall, receiverOrThisObject, null)
return buildCall(resolvedCall, ExplicitReceivers(receiverOrThisObject))
}
fun TranslationContext.buildGet(resolvedCall: ResolvedCall<out VariableDescriptor>, receiverOrThisObject: JsExpression? = null): JsExpression {
@@ -66,23 +66,23 @@ fun ResolvedCall<out CallableDescriptor>.expectedReceivers(): Boolean {
return this.getExplicitReceiverKind() != NO_EXPLICIT_RECEIVER
}
private fun TranslationContext.buildCall(resolvedCall: ResolvedCall<out FunctionDescriptor>, receiver1: JsExpression?, receiver2: JsExpression?): JsExpression {
private fun TranslationContext.buildCall(resolvedCall: ResolvedCall<out FunctionDescriptor>, 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<I : CallInfo> {
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<I : CallInfo> {
callInfo.bothReceivers()
}
return if (callInfo.isSafeCall())
constructSafeCall(result)
else
return result
return callInfo.constructSafeCallIsNeeded(result)
}
}