@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);
  }
  @Nullable
  private static JetType computeUnsafeReturnType(
      @NotNull JetFunctionLiteralExpression expression,
      @NotNull ExpressionTypingContext context,
      @NotNull SimpleFunctionDescriptorImpl functionDescriptor,
      @Nullable JetType expectedReturnType) {
    JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
    JetBlockExpression bodyExpression = functionLiteral.getBodyExpression();
    assert bodyExpression != null;

    JetScope functionInnerScope =
        FunctionDescriptorUtil.getFunctionInnerScope(
            context.scope, functionDescriptor, context.trace);
    JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
    JetType declaredReturnType = null;
    if (returnTypeRef != null) {
      declaredReturnType =
          context
              .expressionTypingServices
              .getTypeResolver()
              .resolveType(context.scope, returnTypeRef, context.trace, true);
      // This is needed for ControlStructureTypingVisitor#visitReturnExpression() to properly
      // type-check returned expressions
      functionDescriptor.setReturnType(declaredReturnType);
      if (expectedReturnType != null) {
        if (!JetTypeChecker.INSTANCE.isSubtypeOf(declaredReturnType, expectedReturnType)) {
          context.trace.report(EXPECTED_RETURN_TYPE_MISMATCH.on(returnTypeRef, expectedReturnType));
        }
      }
    }

    // Type-check the body
    ExpressionTypingContext newContext =
        context
            .replaceScope(functionInnerScope)
            .replaceExpectedType(
                declaredReturnType != null
                    ? declaredReturnType
                    : (expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE));

    JetType typeOfBodyExpression =
        context
            .expressionTypingServices
            .getBlockReturnedType(bodyExpression, COERCION_TO_UNIT, newContext)
            .getType();

    List<JetType> returnedExpressionTypes =
        Lists.newArrayList(
            getTypesOfLocallyReturnedExpressions(
                functionLiteral, context.trace, collectReturns(bodyExpression)));
    ContainerUtil.addIfNotNull(returnedExpressionTypes, typeOfBodyExpression);

    if (declaredReturnType != null) return declaredReturnType;
    if (returnedExpressionTypes.isEmpty()) return null;
    return CommonSupertypes.commonSupertype(returnedExpressionTypes);
  }