@Override
  public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) {
    ClassDescriptor classDescriptor = bindingContext.get(CLASS, expression.getObjectDeclaration());
    if (classDescriptor == null) {
      // working around a problem with shallow analysis
      super.visitObjectLiteralExpression(expression);
      return;
    }

    final String name = inventAnonymousClassName(expression.getObjectDeclaration());
    recordClosure(
        bindingTrace,
        expression.getObjectDeclaration(),
        classDescriptor,
        peekFromStack(classStack),
        JvmClassName.byInternalName(name),
        false);

    classStack.push(classDescriptor);
    //noinspection ConstantConditions
    nameStack.push(bindingContext.get(FQN, classDescriptor).getInternalName());
    super.visitObjectLiteralExpression(expression);
    nameStack.pop();
    classStack.pop();
  }
  @Override
  public JetTypeInfo visitObjectLiteralExpression(
      @NotNull final JetObjectLiteralExpression expression, final ExpressionTypingContext context) {
    DelegatingBindingTrace delegatingBindingTrace =
        context.trace.get(TRACE_DELTAS_CACHE, expression.getObjectDeclaration());
    if (delegatingBindingTrace != null) {
      delegatingBindingTrace.addAllMyDataTo(context.trace);
      JetType type = context.trace.get(EXPRESSION_TYPE, expression);
      return DataFlowUtils.checkType(type, expression, context, context.dataFlowInfo);
    }
    final JetType[] result = new JetType[1];
    final TemporaryBindingTrace temporaryTrace =
        TemporaryBindingTrace.create(
            context.trace, "trace to resolve object literal expression", expression);
    ObservableBindingTrace.RecordHandler<PsiElement, ClassDescriptor> handler =
        new ObservableBindingTrace.RecordHandler<PsiElement, ClassDescriptor>() {

          @Override
          public void handleRecord(
              WritableSlice<PsiElement, ClassDescriptor> slice,
              PsiElement declaration,
              final ClassDescriptor descriptor) {
            if (slice == CLASS && declaration == expression.getObjectDeclaration()) {
              JetType defaultType =
                  DeferredType.create(
                      context.trace,
                      createRecursionIntolerantLazyValueWithDefault(
                          ErrorUtils.createErrorType("Recursive dependency"),
                          new Function0<JetType>() {
                            @Override
                            public JetType invoke() {
                              return descriptor.getDefaultType();
                            }
                          }));
              result[0] = defaultType;
              if (!context.trace.get(PROCESSED, expression)) {
                temporaryTrace.record(EXPRESSION_TYPE, expression, defaultType);
                temporaryTrace.record(PROCESSED, expression);
              }
            }
          }
        };
    ObservableBindingTrace traceAdapter = new ObservableBindingTrace(temporaryTrace);
    traceAdapter.addHandler(CLASS, handler);
    TopDownAnalyzer.processClassOrObject(
        context.replaceBindingTrace(traceAdapter).replaceContextDependency(INDEPENDENT),
        context.scope.getContainingDeclaration(),
        expression.getObjectDeclaration());

    DelegatingBindingTrace cloneDelta =
        new DelegatingBindingTrace(
            new BindingTraceContext().getBindingContext(),
            "cached delta trace for object literal expression resolve",
            expression);
    temporaryTrace.addAllMyDataTo(cloneDelta);
    context.trace.record(TRACE_DELTAS_CACHE, expression.getObjectDeclaration(), cloneDelta);
    temporaryTrace.commit();
    return DataFlowUtils.checkType(result[0], expression, context, context.dataFlowInfo);
  }
  @NotNull
  public static JvmClassName classNameForAnonymousClass(
      @NotNull BindingContext bindingContext, @NotNull JetElement expression) {
    if (expression instanceof JetObjectLiteralExpression) {
      JetObjectLiteralExpression jetObjectLiteralExpression =
          (JetObjectLiteralExpression) expression;
      expression = jetObjectLiteralExpression.getObjectDeclaration();
    }

    ClassDescriptor descriptor = bindingContext.get(CLASS, expression);
    if (descriptor == null) {
      SimpleFunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
      assert functionDescriptor != null;
      return classNameForAnonymousClass(bindingContext, functionDescriptor);
    }

    return fqn(bindingContext, descriptor);
  }
  @Override
  public JetType visitObjectLiteralExpression(
      final JetObjectLiteralExpression expression, final ExpressionTypingContext context) {
    final JetType[] result = new JetType[1];
    ObservableBindingTrace.RecordHandler<PsiElement, ClassDescriptor> handler =
        new ObservableBindingTrace.RecordHandler<PsiElement, ClassDescriptor>() {

          @Override
          public void handleRecord(
              WritableSlice<PsiElement, ClassDescriptor> slice,
              PsiElement declaration,
              final ClassDescriptor descriptor) {
            if (slice == CLASS && declaration == expression.getObjectDeclaration()) {
              JetType defaultType =
                  DeferredType.create(
                      context.trace,
                      new LazyValueWithDefault<JetType>(
                          ErrorUtils.createErrorType("Recursive dependency")) {
                        @Override
                        protected JetType compute() {
                          return descriptor.getDefaultType();
                        }
                      });
              result[0] = defaultType;
              if (!context.trace.get(PROCESSED, expression)) {
                context.trace.record(EXPRESSION_TYPE, expression, defaultType);
                context.trace.record(PROCESSED, expression);
              }
            }
          }
        };
    ObservableBindingTrace traceAdapter = new ObservableBindingTrace(context.trace);
    traceAdapter.addHandler(CLASS, handler);
    TopDownAnalyzer.processObject(
        context.semanticServices,
        traceAdapter,
        context.scope,
        context.scope.getContainingDeclaration(),
        expression.getObjectDeclaration());
    return DataFlowUtils.checkType(result[0], expression, context);
  }