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    }