JS backend: added the support dynamic.
This commit is contained in:
@@ -179,7 +179,7 @@ object DynamicCallableDescriptors {
|
||||
}
|
||||
}
|
||||
|
||||
fun DeclarationDescriptor.isDynamic(): Boolean {
|
||||
public fun DeclarationDescriptor.isDynamic(): Boolean {
|
||||
if (this !is CallableDescriptor) return false
|
||||
val dispatchReceiverParameter = getDispatchReceiverParameter()
|
||||
return dispatchReceiverParameter != null && dispatchReceiverParameter.getType().isDynamic()
|
||||
|
||||
@@ -35,6 +35,18 @@ import com.google.dart.compiler.backend.js.ast.JsArrayAccess
|
||||
import org.jetbrains.k2js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.k2js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.k2js.PredefinedAnnotation
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.isDynamic
|
||||
import org.jetbrains.jet.lang.psi.Call
|
||||
import org.jetbrains.k2js.translate.operation.OperatorTable
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation
|
||||
import org.jetbrains.jet.lang.psi.JetPrefixExpression
|
||||
import com.google.dart.compiler.backend.js.ast.JsPrefixOperation
|
||||
import org.jetbrains.jet.lang.psi.JetPostfixExpression
|
||||
import com.google.dart.compiler.backend.js.ast.JsPostfixOperation
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression
|
||||
import org.jetbrains.jet.lexer.JetTokens
|
||||
import org.jetbrains.jet.lang.psi.JetOperationExpression
|
||||
import org.jetbrains.k2js.translate.utils.PsiUtils
|
||||
|
||||
public fun addReceiverToArgs(receiver: JsExpression, arguments: List<JsExpression>): List<JsExpression> {
|
||||
if (arguments.isEmpty())
|
||||
@@ -230,6 +242,64 @@ object SuperCallCase : FunctionCallCase {
|
||||
}
|
||||
}
|
||||
|
||||
object DynamicInvokeAndBracketAccessCallCase : FunctionCallCase {
|
||||
fun canApply(callInfo: FunctionCallInfo): Boolean =
|
||||
callInfo.resolvedCall.getCall().getCallType() != Call.CallType.DEFAULT && callInfo.callableDescriptor.isDynamic()
|
||||
|
||||
override fun FunctionCallInfo.dispatchReceiver(): JsExpression {
|
||||
val arguments = argumentsInfo.getTranslateArguments()
|
||||
val callType = resolvedCall.getCall().getCallType()
|
||||
return when (callType) {
|
||||
Call.CallType.INVOKE ->
|
||||
JsInvocation(dispatchReceiver, arguments)
|
||||
Call.CallType.ARRAY_GET_METHOD ->
|
||||
JsArrayAccess(dispatchReceiver, arguments[0])
|
||||
Call.CallType.ARRAY_SET_METHOD ->
|
||||
JsAstUtils.assignment(JsArrayAccess(dispatchReceiver, arguments[0]), arguments[1])
|
||||
|
||||
else ->
|
||||
unsupported("Unsupported call type: $callType, callInfo: $this")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object DynamicOperatorCallCase : FunctionCallCase {
|
||||
fun canApply(callInfo: FunctionCallInfo): Boolean =
|
||||
callInfo.callableDescriptor.isDynamic() &&
|
||||
callInfo.resolvedCall.getCall().getCallElement() let {
|
||||
it is JetOperationExpression &&
|
||||
PsiUtils.getOperationToken(it) let { (it == JetTokens.NOT_IN || OperatorTable.hasCorrespondingOperator(it)) }
|
||||
}
|
||||
|
||||
override fun FunctionCallInfo.dispatchReceiver(): JsExpression {
|
||||
val callElement = resolvedCall.getCall().getCallElement() as JetOperationExpression
|
||||
val operationToken = PsiUtils.getOperationToken(callElement)
|
||||
|
||||
val arguments = argumentsInfo.getTranslateArguments()
|
||||
|
||||
return when (callElement) {
|
||||
is JetBinaryExpression -> {
|
||||
// `!in` translated as `in` and will be wrapped by negation operation in BinaryOperationTranslator#translateAsOverloadedBinaryOperation by mayBeWrapWithNegation
|
||||
val operationTokenToFind = if (operationToken == JetTokens.NOT_IN) JetTokens.IN_KEYWORD else operationToken
|
||||
val binaryOperator = OperatorTable.getBinaryOperator(operationTokenToFind)
|
||||
|
||||
if (operationTokenToFind == JetTokens.IN_KEYWORD)
|
||||
JsBinaryOperation(binaryOperator, arguments[0], dispatchReceiver)
|
||||
else
|
||||
JsBinaryOperation(binaryOperator, dispatchReceiver, arguments[0])
|
||||
}
|
||||
is JetPrefixExpression -> {
|
||||
JsPrefixOperation(OperatorTable.getUnaryOperator(operationToken), dispatchReceiver)
|
||||
}
|
||||
is JetPostfixExpression -> {
|
||||
// TODO drop hack with ":JsExpression" when KT-5569 will be fixed
|
||||
JsPostfixOperation(OperatorTable.getUnaryOperator(operationToken), dispatchReceiver): JsExpression
|
||||
}
|
||||
else -> unsupported("Unsupported callElement type: ${callElement.javaClass}, callElement: $callElement, callInfo: $this")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun FunctionCallInfo.translateFunctionCall(): JsExpression {
|
||||
val intrinsic = DelegateFunctionIntrinsic.intrinsic(this)
|
||||
|
||||
@@ -250,6 +320,12 @@ fun FunctionCallInfo.translateFunctionCall(): JsExpression {
|
||||
ConstructorCallCase.translate(this)
|
||||
SuperCallCase.canApply(this) ->
|
||||
SuperCallCase.translate(this)
|
||||
|
||||
DynamicInvokeAndBracketAccessCallCase.canApply(this) ->
|
||||
DynamicInvokeAndBracketAccessCallCase.translate(this)
|
||||
DynamicOperatorCallCase.canApply(this) ->
|
||||
DynamicOperatorCallCase.translate(this)
|
||||
|
||||
else ->
|
||||
DefaultFunctionCallCase.translate(this)
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.reflect.ReflectionTypes;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.TasksPackage;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.k2js.config.Config;
|
||||
import org.jetbrains.k2js.config.EcmaVersion;
|
||||
@@ -229,6 +230,21 @@ public final class StaticContext {
|
||||
private final class NameGenerator extends Generator<JsName> {
|
||||
|
||||
public NameGenerator() {
|
||||
Rule<JsName> namesForDynamic = new Rule<JsName>() {
|
||||
@Override
|
||||
@Nullable
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (TasksPackage.isDynamic(descriptor)) {
|
||||
String name = descriptor.getName().asString();
|
||||
JsScope scope = getEnclosingScope(descriptor);
|
||||
assert scope instanceof JsFunctionScope;
|
||||
return ((JsFunctionScope) scope).declareNameUnsafe(name);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Rule<JsName> namesForStandardClasses = new Rule<JsName>() {
|
||||
@Override
|
||||
@Nullable
|
||||
@@ -332,6 +348,8 @@ public final class StaticContext {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
addRule(namesForDynamic);
|
||||
addRule(namesForStandardClasses);
|
||||
addRule(constructorOrClassObjectHasTheSameNameAsTheClass);
|
||||
addRule(propertyOrPropertyAccessor);
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.k2js.translate.operation.OperatorTable
|
||||
import org.jetbrains.k2js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils
|
||||
import org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.isDynamic
|
||||
|
||||
|
||||
object CompareToBOIF : BinaryOperationIntrinsicFactory {
|
||||
@@ -67,6 +68,8 @@ object CompareToBOIF : BinaryOperationIntrinsicFactory {
|
||||
override public fun getSupportTokens(): ImmutableSet<JetToken> = OperatorConventions.COMPARISON_OPERATIONS
|
||||
|
||||
override public fun getIntrinsic(descriptor: FunctionDescriptor): BinaryOperationIntrinsic? {
|
||||
if (descriptor.isDynamic()) return CompareToIntrinsic
|
||||
|
||||
if (!JsDescriptorUtils.isBuiltin(descriptor)) return null
|
||||
|
||||
return when {
|
||||
|
||||
@@ -34,6 +34,8 @@ import org.jetbrains.jet.lexer.JetToken
|
||||
import org.jetbrains.jet.lexer.JetTokens
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern
|
||||
import org.jetbrains.jet.lang.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.jet.lang.types.isDynamic
|
||||
|
||||
object EqualsBOIF : BinaryOperationIntrinsicFactory {
|
||||
|
||||
@@ -57,6 +59,17 @@ object EqualsBOIF : BinaryOperationIntrinsicFactory {
|
||||
return JsBinaryOperation(if (isNegated) JsBinaryOperator.REF_NEQ else JsBinaryOperator.REF_EQ, left, right)
|
||||
}
|
||||
|
||||
val resolvedCall = expression.getResolvedCall(context.bindingContext())
|
||||
val appliedToDynamic =
|
||||
resolvedCall != null &&
|
||||
with(resolvedCall.getDispatchReceiver()) {
|
||||
if (exists()) getType().isDynamic() else false
|
||||
}
|
||||
|
||||
if (appliedToDynamic) {
|
||||
return JsBinaryOperation(if (isNegated) JsBinaryOperator.NEQ else JsBinaryOperator.EQ, left, right)
|
||||
}
|
||||
|
||||
val result = TopLevelFIF.KOTLIN_EQUALS.apply(left, Arrays.asList<JsExpression>(right), context)
|
||||
return if (isNegated) JsAstUtils.negated(result) else result
|
||||
}
|
||||
|
||||
+4
@@ -209,6 +209,10 @@ public final class BinaryOperationTranslator extends AbstractTranslator {
|
||||
if (rightBlock.isEmpty()) {
|
||||
return new JsBinaryOperation(operator, leftExpression, rightExpression);
|
||||
}
|
||||
else if (OperatorConventions.IDENTITY_EQUALS_OPERATIONS.contains(operationToken)) {
|
||||
context().addStatementsToCurrentBlockFrom(rightBlock);
|
||||
return new JsBinaryOperation(operator, leftExpression, rightExpression);
|
||||
}
|
||||
|
||||
assert operationToken.equals(JetTokens.ANDAND) || operationToken.equals(JetTokens.OROR) : "Unsupported binary operation: " + expression.getText();
|
||||
boolean isOror = operationToken.equals(JetTokens.OROR);
|
||||
|
||||
+11
-2
@@ -23,8 +23,10 @@ import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetUnaryExpression;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.TasksPackage;
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
@@ -34,8 +36,10 @@ import org.jetbrains.k2js.translate.reference.CachedAccessTranslator;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.reference.AccessTranslationUtils.getCachedAccessTranslator;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.newSequence;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getBaseExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.isPrefix;
|
||||
import static org.jetbrains.k2js.translate.utils.TemporariesUtils.temporariesInitialization;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.hasCorrespondingFunctionIntrinsic;
|
||||
|
||||
@@ -50,7 +54,7 @@ public abstract class IncrementTranslator extends AbstractTranslator {
|
||||
@NotNull
|
||||
public static JsExpression translate(@NotNull JetUnaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
if (hasCorrespondingFunctionIntrinsic(context, expression)) {
|
||||
if (hasCorrespondingFunctionIntrinsic(context, expression) || isDynamic(context, expression)) {
|
||||
return IntrinsicIncrementTranslator.doTranslate(expression, context);
|
||||
}
|
||||
return (new OverloadedIncrementTranslator(expression, context)).translateIncrementExpression();
|
||||
@@ -121,4 +125,9 @@ public abstract class IncrementTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
abstract JsExpression operationExpression(@NotNull JsExpression receiver);
|
||||
|
||||
private static boolean isDynamic(TranslationContext context, JetUnaryExpression expression) {
|
||||
CallableDescriptor operationDescriptor = getCallableDescriptorForOperationExpression(context.bindingContext(), expression);
|
||||
return TasksPackage.isDynamic(operationDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@ public final class OperatorTable {
|
||||
.put(JetTokens.DIVEQ, JsBinaryOperator.ASG_DIV)
|
||||
.put(JetTokens.MULTEQ, JsBinaryOperator.ASG_MUL)
|
||||
.put(JetTokens.PERCEQ, JsBinaryOperator.ASG_MOD)
|
||||
.put(JetTokens.IN_KEYWORD, JsBinaryOperator.INOP)
|
||||
.put(JetTokens.EQEQEQ, JsBinaryOperator.REF_EQ)
|
||||
.put(JetTokens.EXCLEQEQEQ, JsBinaryOperator.REF_NEQ)
|
||||
.build();
|
||||
|
||||
private static final ImmutableBiMap<JetToken, JsUnaryOperator> unaryOperatorsMap = ImmutableBiMap.<JetToken, JsUnaryOperator>builder()
|
||||
@@ -59,6 +62,9 @@ public final class OperatorTable {
|
||||
private OperatorTable() {
|
||||
}
|
||||
|
||||
public static boolean hasCorrespondingOperator(@NotNull JetToken token) {
|
||||
return binaryOperatorsMap.containsKey(token) || unaryOperatorsMap.containsKey(token);
|
||||
}
|
||||
|
||||
public static boolean hasCorrespondingBinaryOperator(@NotNull JetToken token) {
|
||||
return binaryOperatorsMap.containsKey(token);
|
||||
|
||||
@@ -71,7 +71,7 @@ public final class PsiUtils {
|
||||
public static JetToken getOperationToken(@NotNull JetOperationExpression expression) {
|
||||
JetSimpleNameExpression operationExpression = expression.getOperationReference();
|
||||
IElementType elementType = operationExpression.getReferencedNameElementType();
|
||||
assert elementType instanceof JetToken : "Unary expression should have operation token of type JetToken";
|
||||
assert elementType instanceof JetToken : "Expected JetToken type, but " + elementType.getClass() + ", expression: " + expression.getText();
|
||||
return (JetToken) elementType;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user