KT-4773: use receiver for delegated extension property

This commit is contained in:
Alexey Tsvetkov
2014-09-25 15:50:23 +04:00
parent 3424142b65
commit ed14f86957
2 changed files with 104 additions and 20 deletions
@@ -28,8 +28,11 @@ import org.jetbrains.k2js.translate.general.AbstractTranslator
import org.jetbrains.k2js.translate.general.Translation
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils
import org.jetbrains.k2js.translate.context.Namer.getDelegateNameRef
import org.jetbrains.k2js.translate.context.Namer.*
import org.jetbrains.k2js.translate.utils.ast.*
import org.jetbrains.k2js.translate.utils.TranslationUtils.*
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils.isExtension
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall
/**
* Translates single property /w accessors.
@@ -113,12 +116,36 @@ private class PropertyTranslator(
private fun generateDefaultGetterFunction(getterDescriptor: PropertyGetterDescriptor): JsFunction {
val delegatedCall = bindingContext().get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, getterDescriptor)
val value = if (delegatedCall != null)
CallTranslator.translate(context(), delegatedCall, getDelegateNameRef(propertyName))
else
backingFieldReference(context(), this.descriptor)
if (delegatedCall != null) {
return generateDelegatedGetterFunction(getterDescriptor, delegatedCall)
}
return simpleReturnFunction(context().getScopeForDescriptor(getterDescriptor.getContainingDeclaration()), value)
val scope = context().getScopeForDescriptor(getterDescriptor.getContainingDeclaration())
val result = backingFieldReference(context(), descriptor)
val body = JsBlock(JsReturn(result))
return JsFunction(scope, body, accessorDescription(getterDescriptor))
}
private fun generateDelegatedGetterFunction(
getterDescriptor: PropertyGetterDescriptor,
delegatedCall: ResolvedCall<FunctionDescriptor>
): JsFunction {
val scope = context().getScopeForDescriptor(getterDescriptor.getContainingDeclaration())
val function = JsFunction(scope, JsBlock(), accessorDescription(getterDescriptor))
val delegateRef = getDelegateNameRef(propertyName)
val delegatedJsCall = CallTranslator.translate(context(), delegatedCall, delegateRef)
if (isExtension(getterDescriptor)) {
val receiver = function.addParameter(getReceiverParameterName()).getName()
val arguments = (delegatedJsCall as JsInvocation).getArguments()
arguments.set(0, receiver.makeRef())
}
val returnResult = JsReturn(delegatedJsCall)
function.addStatement(returnResult)
return function
}
private fun generateDefaultSetter(): JsPropertyInitializer {
@@ -127,25 +154,29 @@ private class PropertyTranslator(
}
private fun generateDefaultSetterFunction(setterDescriptor: PropertySetterDescriptor): JsFunction {
val jsFunction = JsFunction(context().getScopeForDescriptor(setterDescriptor.getContainingDeclaration()),
"setter for " + setterDescriptor.getName().asString())
val containingScope = context().getScopeForDescriptor(setterDescriptor.getContainingDeclaration())
val function = JsFunction(containingScope, JsBlock(), accessorDescription(setterDescriptor))
assert(setterDescriptor.getValueParameters().size() == 1, "Setter must have 1 parameter")
val valueParameterDescriptor = setterDescriptor.getValueParameters().get(0)
val defaultParameter = JsParameter(jsFunction.getScope().declareTemporary())
val defaultParameterRef = defaultParameter.getName().makeRef()
val contextWithAliased = context().innerContextWithAliased(valueParameterDescriptor, defaultParameterRef)
val correspondingPropertyName = setterDescriptor.getCorrespondingProperty().getName().asString()
val valueParameter = function.addParameter(correspondingPropertyName).getName()
val withAliased = context().innerContextWithAliased(setterDescriptor.getValueParameters().get(0), valueParameter.makeRef())
val delegatedCall = context().bindingContext().get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, setterDescriptor)
val delegatedCall = bindingContext().get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, setterDescriptor)
if (delegatedCall != null) {
val delegatedJsCall = CallTranslator.translate(withAliased, delegatedCall, getDelegateNameRef(correspondingPropertyName))
function.addStatement(delegatedJsCall.makeStmt())
val setExpression = if (delegatedCall != null)
CallTranslator.translate(contextWithAliased, delegatedCall, getDelegateNameRef(propertyName))
else
assignmentToBackingField(contextWithAliased, descriptor, defaultParameterRef)
if (isExtension(setterDescriptor)) {
val receiver = function.addParameter(getReceiverParameterName(), 0).getName()
(delegatedJsCall as JsInvocation).getArguments().set(0, receiver.makeRef())
}
} else {
val assignment = assignmentToBackingField(withAliased, descriptor, valueParameter.makeRef())
function.addStatement(assignment.makeStmt())
}
jsFunction.getParameters().add(defaultParameter)
jsFunction.setBody(JsBlock(setExpression.makeStmt()))
return jsFunction
return function
}
private fun generateDefaultAccessor(accessorDescriptor: PropertyAccessorDescriptor, function: JsFunction): JsPropertyInitializer =
@@ -153,4 +184,19 @@ private class PropertyTranslator(
private fun translateCustomAccessor(expression: JetPropertyAccessor): JsPropertyInitializer =
Translation.functionTranslator(expression, context()).translateAsEcma5PropertyDescriptor()
private fun accessorDescription(accessorDescriptor: PropertyAccessorDescriptor): String {
val accessorType =
when(accessorDescriptor) {
is PropertyGetterDescriptor ->
"getter"
is PropertySetterDescriptor ->
"setter"
else ->
throw IllegalArgumentException("Unknown accessor type ${accessorDescriptor.javaClass}")
}
val name = accessorDescriptor.getName().asString()
return "$accessorType for $name"
}
}
@@ -0,0 +1,38 @@
/*
* 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.utils.ast
import com.google.dart.compiler.backend.js.ast.JsFunction
import com.google.dart.compiler.backend.js.ast.JsStatement
import com.google.dart.compiler.backend.js.ast.JsParameter
public fun JsFunction.addStatement(stmt: JsStatement) {
getBody().getStatements().add(stmt)
}
public fun JsFunction.addParameter(identifier: String, index: Int? = null): JsParameter {
val name = getScope().declareFreshName(identifier)
val parameter = JsParameter(name)
if (index == null) {
getParameters().add(parameter)
} else {
getParameters().add(index, parameter)
}
return parameter
}