001 /*
002 * Copyright 2010-2016 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.kotlin.js.translate.expression;
018
019 import com.intellij.psi.PsiElement;
020 import com.intellij.psi.util.PsiTreeUtil;
021 import com.intellij.util.SmartList;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
025 import org.jetbrains.kotlin.descriptors.*;
026 import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
027 import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention;
028 import org.jetbrains.kotlin.js.backend.ast.*;
029 import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
030 import org.jetbrains.kotlin.js.translate.context.Namer;
031 import org.jetbrains.kotlin.js.translate.context.TranslationContext;
032 import org.jetbrains.kotlin.js.translate.declaration.ClassTranslator;
033 import org.jetbrains.kotlin.js.translate.declaration.PropertyTranslatorKt;
034 import org.jetbrains.kotlin.js.translate.general.Translation;
035 import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor;
036 import org.jetbrains.kotlin.js.translate.operation.BinaryOperationTranslator;
037 import org.jetbrains.kotlin.js.translate.operation.UnaryOperationTranslator;
038 import org.jetbrains.kotlin.js.translate.reference.*;
039 import org.jetbrains.kotlin.js.translate.utils.*;
040 import org.jetbrains.kotlin.psi.*;
041 import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
042 import org.jetbrains.kotlin.resolve.BindingContext;
043 import org.jetbrains.kotlin.resolve.BindingContextUtils;
044 import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
045 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
046 import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
047 import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
048 import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
049 import org.jetbrains.kotlin.resolve.inline.InlineUtil;
050 import org.jetbrains.kotlin.types.KotlinType;
051 import org.jetbrains.kotlin.types.expressions.DoubleColonLHS;
052
053 import java.util.ArrayList;
054 import java.util.List;
055
056 import static org.jetbrains.kotlin.js.translate.context.Namer.*;
057 import static org.jetbrains.kotlin.js.translate.general.Translation.translateAsExpression;
058 import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.*;
059 import static org.jetbrains.kotlin.js.translate.utils.ErrorReportingUtils.message;
060 import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.convertToStatement;
061 import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.newVar;
062 import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getReceiverParameterForDeclaration;
063 import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateInitializerForProperty;
064 import static org.jetbrains.kotlin.resolve.BindingContext.*;
065 import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure;
066 import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt.getResolvedCallWithAssert;
067 import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionExpression;
068 import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral;
069
070 public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
071 @Override
072 protected JsNode emptyResult(@NotNull TranslationContext context) {
073 return JsLiteral.NULL;
074 }
075
076 @Override
077 @NotNull
078 public JsNode visitConstantExpression(@NotNull KtConstantExpression expression, @NotNull TranslationContext context) {
079 return translateConstantExpression(expression, context).source(expression);
080 }
081
082 @NotNull
083 private static JsNode translateConstantExpression(@NotNull KtConstantExpression expression, @NotNull TranslationContext context) {
084 CompileTimeConstant<?> compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext());
085 assert compileTimeValue != null : message(expression, "Expression is not compile time value: " + expression.getText() + " ");
086
087 JsNode result = Translation.translateConstant(compileTimeValue, expression, context);
088 if (result == null) {
089 throw new AssertionError(message(expression, "Unsupported constant expression: " + expression.getText() + " "));
090 }
091
092 return result;
093 }
094
095 @Override
096 @NotNull
097 public JsNode visitBlockExpression(@NotNull KtBlockExpression jetBlock, @NotNull TranslationContext context) {
098 List<KtExpression> statements = jetBlock.getStatements();
099 JsBlock jsBlock = new JsBlock();
100 for (KtExpression statement : statements) {
101 JsNode jsNode = Translation.translateExpression(statement, context, jsBlock);
102 JsStatement jsStatement = convertToStatement(jsNode);
103 if (!JsAstUtils.isEmptyStatement(jsStatement)) {
104 jsBlock.getStatements().add(jsStatement);
105 }
106 }
107 return jsBlock;
108 }
109
110 @Override
111 public JsNode visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration, @NotNull TranslationContext context) {
112 KtExpression jetInitializer = multiDeclaration.getInitializer();
113 assert jetInitializer != null : "Initializer for multi declaration must be not null";
114 JsExpression initializer = Translation.translateAsExpression(jetInitializer, context);
115 return DestructuringDeclarationTranslator.translate(multiDeclaration, context.scope().declareTemporary(), initializer, context);
116 }
117
118 @Override
119 @NotNull
120 public JsNode visitReturnExpression(@NotNull KtReturnExpression jetReturnExpression, @NotNull TranslationContext context) {
121 KtExpression returned = jetReturnExpression.getReturnedExpression();
122
123 // TODO: add related descriptor to context and use it here
124 KtDeclarationWithBody parent = PsiTreeUtil.getParentOfType(jetReturnExpression, KtDeclarationWithBody.class);
125 if (parent instanceof KtSecondaryConstructor) {
126 return new JsReturn(new JsNameRef(Namer.ANOTHER_THIS_PARAMETER_NAME)).source(jetReturnExpression);
127 }
128
129 JsReturn jsReturn;
130 if (returned == null) {
131 jsReturn = new JsReturn(null);
132 }
133 else {
134 JsExpression jsReturnExpression = translateAsExpression(returned, context);
135
136 KotlinType returnedType = context.bindingContext().getType(returned);
137
138 if (KotlinBuiltIns.isCharOrNullableChar(returnedType) &&
139 TranslationUtils.shouldBoxReturnValue((CallableDescriptor)context.getDeclarationDescriptor())) {
140 jsReturnExpression = JsAstUtils.charToBoxedChar(jsReturnExpression);
141 }
142
143 jsReturn = new JsReturn(jsReturnExpression);
144 }
145
146 MetadataProperties.setReturnTarget(jsReturn, getNonLocalReturnTarget(jetReturnExpression, context));
147
148 return jsReturn.source(jetReturnExpression);
149 }
150
151 @Nullable
152 private static FunctionDescriptor getNonLocalReturnTarget(
153 @NotNull KtReturnExpression expression,
154 @NotNull TranslationContext context
155 ) {
156 DeclarationDescriptor descriptor = context.getDeclarationDescriptor();
157 assert descriptor instanceof CallableMemberDescriptor : "Return expression can only be inside callable declaration: " +
158 PsiUtilsKt.getTextWithLocation(expression);
159 KtSimpleNameExpression target = expression.getTargetLabel();
160
161 //call inside lambda
162 if (isFunctionLiteral(descriptor) || isFunctionExpression(descriptor)) {
163 if (target == null) {
164 if (isFunctionLiteral(descriptor)) {
165 return BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, true).getFirst();
166 }
167 }
168 else {
169 PsiElement element = context.bindingContext().get(LABEL_TARGET, target);
170 descriptor = context.bindingContext().get(DECLARATION_TO_DESCRIPTOR, element);
171 }
172 }
173
174 assert descriptor == null || descriptor instanceof FunctionDescriptor :
175 "Function descriptor expected to be target of return label: " + PsiUtilsKt.getTextWithLocation(expression);
176 return (FunctionDescriptor) descriptor;
177 }
178
179 @Override
180 @NotNull
181 public JsNode visitParenthesizedExpression(@NotNull KtParenthesizedExpression expression,
182 @NotNull TranslationContext context) {
183 KtExpression expressionInside = expression.getExpression();
184 if (expressionInside != null) {
185 return Translation.translateExpression(expressionInside, context);
186 }
187 return JsEmpty.INSTANCE;
188 }
189
190 @Override
191 @NotNull
192 public JsNode visitBinaryExpression(@NotNull KtBinaryExpression expression,
193 @NotNull TranslationContext context) {
194 return BinaryOperationTranslator.translate(expression, context);
195 }
196
197 @Override
198 @NotNull
199 // assume it is a local variable declaration
200 public JsNode visitProperty(@NotNull KtProperty expression, @NotNull TranslationContext context) {
201 VariableDescriptor descriptor = BindingContextUtils.getNotNull(context.bindingContext(), BindingContext.VARIABLE, expression);
202
203 JsExpression initializer = translateInitializerForProperty(expression, context);
204
205 KtExpression delegateExpression = expression.getDelegateExpression();
206 if (delegateExpression != null) {
207 SmartList<JsPropertyInitializer> propertyInitializers = new SmartList<JsPropertyInitializer>();
208 PropertyTranslatorKt.translateAccessors((VariableDescriptorWithAccessors) descriptor, propertyInitializers, context);
209 JsExpression initializerValue = PropertyTranslatorKt.translateDelegateOrInitializerExpression(context, expression);
210 assert initializerValue != null : "Initializer must be non-null for property with delegate";
211 JsPropertyInitializer delegateInitializer = new JsPropertyInitializer(
212 context.program().getStringLiteral(Namer.getDelegateName(descriptor.getName().asString())), initializerValue);
213 propertyInitializers.add(delegateInitializer);
214 initializer = new JsObjectLiteral(propertyInitializers, true);
215 }
216
217 JsName name = context.getNameForDescriptor(descriptor);
218 if (isVarCapturedInClosure(context.bindingContext(), descriptor)) {
219 JsNameRef alias = getCapturedVarAccessor(name.makeRef());
220 initializer = JsAstUtils.wrapValue(alias, initializer == null ? JsLiteral.NULL : initializer);
221 }
222
223 return newVar(name, initializer).source(expression);
224 }
225
226 @Override
227 @NotNull
228 public JsNode visitCallableReferenceExpression(@NotNull KtCallableReferenceExpression expression, @NotNull TranslationContext context) {
229 return CallableReferenceTranslator.INSTANCE.translate(expression, context);
230 }
231
232 @Override
233 public JsNode visitClassLiteralExpression(
234 @NotNull KtClassLiteralExpression expression, TranslationContext context
235 ) {
236 KtExpression receiverExpression = expression.getReceiverExpression();
237 assert receiverExpression != null : "Class literal expression should have a left-hand side";
238
239 DoubleColonLHS lhs = context.bindingContext().get(DOUBLE_COLON_LHS, receiverExpression);
240 assert lhs != null : "Class literal expression should have LHS resolved";
241
242 if (lhs instanceof DoubleColonLHS.Expression && !((DoubleColonLHS.Expression) lhs).isObjectQualifier()) {
243 JsExpression receiver = translateAsExpression(receiverExpression, context);
244 return new JsInvocation(context.namer().kotlin(GET_KCLASS_FROM_EXPRESSION), receiver);
245 }
246
247 return new JsInvocation(context.namer().kotlin(GET_KCLASS), UtilsKt.getReferenceToJsClass(lhs.getType(), context));
248 }
249
250
251 @Override
252 @NotNull
253 public JsNode visitCallExpression(
254 @NotNull KtCallExpression expression,
255 @NotNull TranslationContext context
256 ) {
257 return CallExpressionTranslator.translate(expression, null, context).source(expression);
258 }
259
260 @Override
261 @NotNull
262 public JsNode visitIfExpression(@NotNull KtIfExpression expression, @NotNull TranslationContext context) {
263 assert expression.getCondition() != null : "condition should not ne null: " + expression.getText();
264 JsExpression testExpression = Translation.translateAsExpression(expression.getCondition(), context);
265
266 boolean isKotlinExpression = BindingContextUtilsKt.isUsedAsExpression(expression, context.bindingContext());
267
268 KtExpression thenExpression = expression.getThen();
269 KtExpression elseExpression = expression.getElse();
270
271 JsStatement thenStatement =
272 thenExpression != null ? Translation.translateAsStatementAndMergeInBlockIfNeeded(thenExpression, context) : null;
273 JsStatement elseStatement =
274 elseExpression != null ? Translation.translateAsStatementAndMergeInBlockIfNeeded(elseExpression, context) : null;
275
276 if (isKotlinExpression) {
277 JsExpression jsThenExpression = JsAstUtils.extractExpressionFromStatement(thenStatement);
278 JsExpression jsElseExpression = JsAstUtils.extractExpressionFromStatement(elseStatement);
279 boolean canBeJsExpression = jsThenExpression != null && jsElseExpression != null;
280 if (canBeJsExpression) {
281 return new JsConditional(testExpression, jsThenExpression, jsElseExpression).source(expression);
282 }
283 }
284 if (thenStatement == null) {
285 thenStatement = JsEmpty.INSTANCE;
286 }
287 JsIf ifStatement = new JsIf(testExpression, thenStatement, elseStatement);
288 return ifStatement.source(expression);
289 }
290
291 @Override
292 @NotNull
293 public JsExpression visitSimpleNameExpression(@NotNull KtSimpleNameExpression expression,
294 @NotNull TranslationContext context) {
295 return ReferenceTranslator.translateSimpleName(expression, context).source(expression);
296 }
297
298 @Override
299 @NotNull
300 public JsNode visitWhileExpression(@NotNull KtWhileExpression expression, @NotNull TranslationContext context) {
301 return LoopTranslator.createWhile(false, expression, context);
302 }
303
304 @Override
305 @NotNull
306 public JsNode visitDoWhileExpression(@NotNull KtDoWhileExpression expression, @NotNull TranslationContext context) {
307 return LoopTranslator.createWhile(true, expression, context);
308 }
309
310 @Override
311 @NotNull
312 public JsNode visitStringTemplateExpression(@NotNull KtStringTemplateExpression expression, @NotNull TranslationContext context) {
313 JsStringLiteral stringLiteral = resolveAsStringConstant(expression, context);
314 if (stringLiteral != null) {
315 return stringLiteral;
316 }
317 return resolveAsTemplate(expression, context).source(expression);
318 }
319
320 @NotNull
321 private static JsNode resolveAsTemplate(@NotNull KtStringTemplateExpression expression,
322 @NotNull TranslationContext context) {
323 return StringTemplateTranslator.translate(expression, context);
324 }
325
326 @Nullable
327 private static JsStringLiteral resolveAsStringConstant(@NotNull KtExpression expression,
328 @NotNull TranslationContext context) {
329 Object value = getCompileTimeValue(context.bindingContext(), expression);
330 if (value == null) {
331 return null;
332 }
333 assert value instanceof String : "Compile time constant template should be a String constant.";
334 String constantString = (String) value;
335 return context.program().getStringLiteral(constantString);
336 }
337
338 @Override
339 @NotNull
340 public JsNode visitDotQualifiedExpression(@NotNull KtDotQualifiedExpression expression, @NotNull TranslationContext context) {
341 return QualifiedExpressionTranslator.translateQualifiedExpression(expression, context);
342 }
343
344 @Override
345 public JsNode visitLabeledExpression(@NotNull KtLabeledExpression expression, @NotNull TranslationContext context) {
346 KtExpression baseExpression = expression.getBaseExpression();
347 assert baseExpression != null;
348
349 if (BindingContextUtilsKt.isUsedAsExpression(expression, context.bindingContext())) {
350 return Translation.translateAsExpression(baseExpression, context).source(expression);
351 }
352
353 JsScope scope = context.scope();
354 assert scope instanceof JsFunctionScope: "Labeled statement is unexpected outside of function scope";
355 JsFunctionScope functionScope = (JsFunctionScope) scope;
356
357 String labelIdent = getReferencedName(expression.getTargetLabel());
358
359 JsName labelName = functionScope.enterLabel(labelIdent);
360 JsStatement baseStatement = Translation.translateAsStatement(baseExpression, context);
361 functionScope.exitLabel();
362
363 return new JsLabel(labelName, baseStatement).source(expression);
364 }
365
366 @Override
367 @NotNull
368 public JsNode visitPrefixExpression(
369 @NotNull KtPrefixExpression expression,
370 @NotNull TranslationContext context
371 ) {
372 return UnaryOperationTranslator.translate(expression, context).source(expression);
373 }
374
375 @Override
376 @NotNull
377 public JsNode visitPostfixExpression(@NotNull KtPostfixExpression expression,
378 @NotNull TranslationContext context) {
379 return UnaryOperationTranslator.translate(expression, context).source(expression);
380 }
381
382 @Override
383 @NotNull
384 public JsNode visitIsExpression(@NotNull KtIsExpression expression,
385 @NotNull TranslationContext context) {
386 return Translation.patternTranslator(context).translateIsExpression(expression);
387 }
388
389 @Override
390 @NotNull
391 public JsNode visitSafeQualifiedExpression(@NotNull KtSafeQualifiedExpression expression,
392 @NotNull TranslationContext context) {
393 return QualifiedExpressionTranslator.translateQualifiedExpression(expression, context).source(expression);
394 }
395
396 @Override
397 @Nullable
398 public JsNode visitWhenExpression(@NotNull KtWhenExpression expression,
399 @NotNull TranslationContext context) {
400 return WhenTranslator.translate(expression, context);
401 }
402
403 @Override
404 @NotNull
405 public JsNode visitBinaryWithTypeRHSExpression(
406 @NotNull KtBinaryExpressionWithTypeRHS expression,
407 @NotNull TranslationContext context
408 ) {
409 JsExpression jsExpression;
410
411 if (PatternTranslator.isCastExpression(expression)) {
412 jsExpression = PatternTranslator.newInstance(context).translateCastExpression(expression);
413 }
414 else {
415 jsExpression = Translation.translateAsExpression(expression.getLeft(), context);
416 }
417
418 return jsExpression.source(expression);
419 }
420
421 private static String getReferencedName(KtSimpleNameExpression expression) {
422 return expression.getReferencedName()
423 .replaceAll("^@", "")
424 .replaceAll("(?:^`(.*)`$)", "$1");
425 }
426
427 private static JsNameRef getTargetLabel(KtExpressionWithLabel expression, TranslationContext context) {
428 KtSimpleNameExpression labelElement = expression.getTargetLabel();
429 if (labelElement == null) {
430 return null;
431 }
432
433 String labelIdent = getReferencedName(labelElement);
434 JsScope scope = context.scope();
435 assert scope instanceof JsFunctionScope: "Labeled statement is unexpected outside of function scope";
436 JsName labelName = ((JsFunctionScope) scope).findLabel(labelIdent);
437 assert labelName != null;
438 return labelName.makeRef();
439 }
440
441 @Override
442 @NotNull
443 public JsNode visitBreakExpression(@NotNull KtBreakExpression expression, @NotNull TranslationContext context) {
444 return new JsBreak(getTargetLabel(expression, context)).source(expression);
445 }
446
447 @Override
448 @NotNull
449 public JsNode visitContinueExpression(@NotNull KtContinueExpression expression, @NotNull TranslationContext context) {
450 return new JsContinue(getTargetLabel(expression, context)).source(expression);
451 }
452
453 @Override
454 @NotNull
455 public JsNode visitLambdaExpression(@NotNull KtLambdaExpression expression, @NotNull TranslationContext context) {
456 return new LiteralFunctionTranslator(context).translate(expression.getFunctionLiteral());
457 }
458
459 @Override
460 @NotNull
461 public JsNode visitNamedFunction(@NotNull KtNamedFunction expression, @NotNull TranslationContext context) {
462 JsExpression alias = new LiteralFunctionTranslator(context).translate(expression);
463
464 FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression);
465 JsNameRef nameRef = (JsNameRef) ReferenceTranslator.translateAsValueReference(descriptor, context);
466 assert nameRef.getName() != null;
467 if (InlineUtil.isInline(descriptor)) {
468 MetadataProperties.setStaticRef(nameRef.getName(), alias);
469 }
470
471 boolean isExpression = BindingContextUtilsKt.isUsedAsExpression(expression, context.bindingContext());
472 JsNode result = isExpression ? alias : JsAstUtils.newVar(nameRef.getName(), alias);
473
474 return result.source(expression);
475 }
476
477 @Override
478 @NotNull
479 public JsNode visitThisExpression(@NotNull KtThisExpression expression, @NotNull TranslationContext context) {
480 DeclarationDescriptor thisExpression =
481 getDescriptorForReferenceExpression(context.bindingContext(), expression.getInstanceReference());
482 assert thisExpression != null : "This expression must reference a descriptor: " + expression.getText();
483
484 return context.getDispatchReceiver(getReceiverParameterForDeclaration(thisExpression)).source(expression);
485 }
486
487 @Override
488 @NotNull
489 public JsNode visitArrayAccessExpression(@NotNull KtArrayAccessExpression expression,
490 @NotNull TranslationContext context) {
491 return AccessTranslationUtils.translateAsGet(expression, context);
492 }
493
494 @Override
495 @NotNull
496 public JsNode visitSuperExpression(@NotNull KtSuperExpression expression, @NotNull TranslationContext context) {
497 ResolvedCall<? extends CallableDescriptor> resolvedCall = getResolvedCallWithAssert(expression, context.bindingContext());
498 return context.getDispatchReceiver((ReceiverParameterDescriptor) resolvedCall.getResultingDescriptor());
499 }
500
501 @Override
502 @NotNull
503 public JsNode visitForExpression(@NotNull KtForExpression expression,
504 @NotNull TranslationContext context) {
505 return LoopTranslator.translateForExpression(expression, context).source(expression);
506 }
507
508 @Override
509 @NotNull
510 public JsNode visitTryExpression(
511 @NotNull KtTryExpression expression,
512 @NotNull TranslationContext context
513 ) {
514 return new TryTranslator(expression, context).translate();
515 }
516
517 @Override
518 @NotNull
519 public JsNode visitThrowExpression(@NotNull KtThrowExpression expression,
520 @NotNull TranslationContext context) {
521 KtExpression thrownExpression = expression.getThrownExpression();
522 assert thrownExpression != null : "Thrown expression must not be null";
523 return new JsThrow(translateAsExpression(thrownExpression, context)).source(expression);
524 }
525
526 @Override
527 @NotNull
528 public JsNode visitObjectLiteralExpression(@NotNull KtObjectLiteralExpression expression, @NotNull TranslationContext context) {
529 ClassDescriptor descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), expression.getObjectDeclaration());
530 translateClassOrObject(expression.getObjectDeclaration(), descriptor, context);
531
532 JsExpression constructor = ReferenceTranslator.translateAsTypeReference(descriptor, context);
533 List<DeclarationDescriptor> closure = context.getClassOrConstructorClosure(descriptor);
534 List<JsExpression> closureArgs = new ArrayList<JsExpression>();
535 if (closure != null) {
536 for (DeclarationDescriptor capturedValue : closure) {
537 closureArgs.add(context.getArgumentForClosureConstructor(capturedValue));
538 }
539 }
540
541 // In case of object expressions like this:
542 // object : SuperClass(A, B, ...)
543 // we may capture local variables in expressions A, B, etc. We don't want to generate local fields for these variables.
544 // Our ClassTranslator is capable of such thing, but case of object expression is a little special.
545 // Consider the following:
546 //
547 // class A(val x: Int) {
548 // fun foo() { object : A(x) }
549 //
550 // By calling A(x) super constructor we capture `this` explicitly. However, we can't tell which `A::this` we are mentioning,
551 // either `this` of an object literal or `this` of enclosing `class A`.
552 // Frontend treats it as `this` of enclosing class declaration, therefore it expects backend to generate
553 // super call in scope of `fun foo()` rather than define inner scope for object's constructor.
554 // Thus we generate this call here rather than relying on ClassTranslator.
555 ResolvedCall<FunctionDescriptor> superCall = BindingUtils.getSuperCall(context.bindingContext(),
556 expression.getObjectDeclaration());
557 if (superCall != null) {
558 closureArgs.addAll(CallArgumentTranslator.translate(superCall, null, context).getTranslateArguments());
559 }
560
561 return new JsNew(constructor, closureArgs);
562 }
563
564 @Override
565 public JsNode visitAnnotatedExpression(@NotNull KtAnnotatedExpression expression, TranslationContext context) {
566 for (KtAnnotationEntry entry : expression.getAnnotationEntries()) {
567 AnnotationDescriptor descriptor = context.bindingContext().get(BindingContext.ANNOTATION, entry);
568 if (descriptor == null) continue;
569
570 ClassifierDescriptor classifierDescriptor = descriptor.getType().getConstructor().getDeclarationDescriptor();
571 if (classifierDescriptor == null) continue;
572
573 KotlinRetention retention = DescriptorUtilsKt.getAnnotationRetention(classifierDescriptor);
574
575 if (retention == KotlinRetention.SOURCE) {
576 KtExpression baseExpression = expression.getBaseExpression();
577 if (baseExpression == null) continue;
578
579 return baseExpression.accept(this, context);
580 }
581 }
582
583 return super.visitAnnotatedExpression(expression, context);
584 }
585
586 @Override
587 public JsNode visitClass(@NotNull KtClass klass, TranslationContext context) {
588 ClassDescriptor descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), klass);
589 translateClassOrObject(klass, descriptor, context);
590 return JsEmpty.INSTANCE;
591 }
592
593 @Override
594 public JsNode visitTypeAlias(@NotNull KtTypeAlias typeAlias, TranslationContext data) {
595 // Resolved by front-end, not used by backend
596 return JsEmpty.INSTANCE;
597 }
598
599 private static void translateClassOrObject(
600 @NotNull KtClassOrObject declaration,
601 @NotNull ClassDescriptor descriptor,
602 @NotNull TranslationContext context
603 ) {
604 JsScope scope = context.getScopeForDescriptor(descriptor);
605 TranslationContext classContext = context.innerWithUsageTracker(scope, descriptor);
606 ClassTranslator.translate(declaration, classContext);
607 }
608 }