@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
 protected JetTypeInfo visitAssignment(
     JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
   ExpressionTypingContext context =
       contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceScope(scope);
   JetExpression left =
       context.expressionTypingServices.deparenthesize(expression.getLeft(), context);
   JetExpression right = expression.getRight();
   if (left instanceof JetArrayAccessExpression) {
     JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
     if (right == null) return JetTypeInfo.create(null, context.dataFlowInfo);
     JetTypeInfo typeInfo =
         basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context, context.trace);
     basic.checkLValue(context.trace, arrayAccessExpression);
     return JetTypeInfo.create(
         checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType),
         typeInfo.getDataFlowInfo());
   }
   JetTypeInfo leftInfo = facade.getTypeInfo(expression.getLeft(), context);
   JetType leftType = leftInfo.getType();
   DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
   if (right != null) {
     JetTypeInfo rightInfo =
         facade.getTypeInfo(
             right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType));
     dataFlowInfo = rightInfo.getDataFlowInfo();
   }
   if (leftType != null) { // if leftType == null, some another error has been generated
     basic.checkLValue(context.trace, expression.getLeft());
   }
   return DataFlowUtils.checkStatementType(expression, contextWithExpectedType, dataFlowInfo);
 }
 @Nullable
 private JetType checkAssignmentType(
     @Nullable JetType assignmentType,
     @NotNull JetBinaryExpression expression,
     @NotNull ExpressionTypingContext context) {
   if (assignmentType != null
       && !KotlinBuiltIns.getInstance().isUnit(assignmentType)
       && context.expectedType != TypeUtils.NO_EXPECTED_TYPE
       && TypeUtils.equalTypes(context.expectedType, assignmentType)) {
     context.trace.report(Errors.ASSIGNMENT_TYPE_MISMATCH.on(expression, context.expectedType));
     return null;
   }
   return DataFlowUtils.checkStatementType(expression, context);
 }
 @Override
 public JetTypeInfo visitBinaryExpression(
     JetBinaryExpression expression, ExpressionTypingContext context) {
   JetSimpleNameExpression operationSign = expression.getOperationReference();
   IElementType operationType = operationSign.getReferencedNameElementType();
   JetTypeInfo result;
   if (operationType == JetTokens.EQ) {
     result = visitAssignment(expression, context);
   } else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
     result = visitAssignmentOperation(expression, context);
   } else {
     return facade.getTypeInfo(expression, context);
   }
   return DataFlowUtils.checkType(result.getType(), expression, context, result.getDataFlowInfo());
 }
 @Override
 public JetTypeInfo visitClass(JetClass klass, ExpressionTypingContext context) {
   TopDownAnalyzer.processClassOrObject(
       context.expressionTypingServices.getProject(),
       context.trace,
       scope,
       scope.getContainingDeclaration(),
       klass);
   ClassDescriptor classDescriptor =
       context.trace.getBindingContext().get(BindingContext.CLASS, klass);
   if (classDescriptor != null) {
     scope.addClassifierDescriptor(classDescriptor);
   }
   return DataFlowUtils.checkStatementType(klass, context, context.dataFlowInfo);
 }
  @Override
  public JetTypeInfo visitFunctionLiteralExpression(
      @NotNull JetFunctionLiteralExpression expression, ExpressionTypingContext context) {
    JetBlockExpression bodyExpression = expression.getFunctionLiteral().getBodyExpression();
    if (bodyExpression == null) return null;

    Name callerName = getCallerName(expression);
    if (callerName != null) {
      context.labelResolver.enterLabeledElement(new LabelName(callerName.asString()), expression);
    }

    JetType expectedType = context.expectedType;
    boolean functionTypeExpected =
        !noExpectedType(expectedType)
            && KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(expectedType);

    AnonymousFunctionDescriptor functionDescriptor =
        createFunctionDescriptor(expression, context, functionTypeExpected);
    JetType safeReturnType =
        computeReturnType(expression, context, functionDescriptor, functionTypeExpected);
    functionDescriptor.setReturnType(safeReturnType);

    JetType receiver =
        DescriptorUtils.getReceiverParameterType(functionDescriptor.getReceiverParameter());
    List<JetType> valueParametersTypes =
        DescriptorUtils.getValueParametersTypes(functionDescriptor.getValueParameters());
    JetType resultType =
        KotlinBuiltIns.getInstance()
            .getFunctionType(
                Collections.<AnnotationDescriptor>emptyList(),
                receiver,
                valueParametersTypes,
                safeReturnType);
    if (!noExpectedType(expectedType)
        && KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(expectedType)) {
      // all checks were done before
      return JetTypeInfo.create(resultType, context.dataFlowInfo);
    }

    if (callerName != null) {
      context.labelResolver.exitLabeledElement(expression);
    }

    return DataFlowUtils.checkType(resultType, expression, context, context.dataFlowInfo);
  }
  @Override
  public JetTypeInfo visitProperty(JetProperty property, ExpressionTypingContext context) {
    JetTypeReference receiverTypeRef = property.getReceiverTypeRef();
    if (receiverTypeRef != null) {
      context.trace.report(LOCAL_EXTENSION_PROPERTY.on(receiverTypeRef));
    }

    JetPropertyAccessor getter = property.getGetter();
    if (getter != null) {
      context.trace.report(LOCAL_VARIABLE_WITH_GETTER.on(getter));
    }

    JetPropertyAccessor setter = property.getSetter();
    if (setter != null) {
      context.trace.report(LOCAL_VARIABLE_WITH_SETTER.on(setter));
    }

    VariableDescriptor propertyDescriptor =
        context
            .expressionTypingServices
            .getDescriptorResolver()
            .resolveLocalVariableDescriptor(
                scope.getContainingDeclaration(),
                scope,
                property,
                context.dataFlowInfo,
                context.trace);
    JetExpression initializer = property.getInitializer();
    DataFlowInfo dataFlowInfo = context.dataFlowInfo;
    if (initializer != null) {
      JetType outType = propertyDescriptor.getType();
      JetTypeInfo typeInfo =
          facade.getTypeInfo(initializer, context.replaceExpectedType(outType).replaceScope(scope));
      dataFlowInfo = typeInfo.getDataFlowInfo();
    }

    {
      VariableDescriptor olderVariable = scope.getLocalVariable(propertyDescriptor.getName());
      ExpressionTypingUtils.checkVariableShadowing(context, propertyDescriptor, olderVariable);
    }

    scope.addVariableDescriptor(propertyDescriptor);
    ModifiersChecker.create(context.trace).checkModifiersForLocalDeclaration(property);
    return DataFlowUtils.checkStatementType(property, context, dataFlowInfo);
  }
 @Override
 public JetTypeInfo visitMultiDeclaration(
     JetMultiDeclaration multiDeclaration, final ExpressionTypingContext context) {
   final JetExpression initializer = multiDeclaration.getInitializer();
   if (initializer == null) {
     context.trace.report(INITIALIZER_REQUIRED_FOR_MULTIDECLARATION.on(multiDeclaration));
     return JetTypeInfo.create(null, context.dataFlowInfo);
   }
   final ExpressionReceiver expressionReceiver =
       ExpressionTypingUtils.getExpressionReceiver(
           facade, initializer, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE));
   DataFlowInfo dataFlowInfo = facade.getTypeInfo(initializer, context).getDataFlowInfo();
   if (expressionReceiver == null) {
     return JetTypeInfo.create(null, dataFlowInfo);
   }
   ExpressionTypingUtils.defineLocalVariablesFromMultiDeclaration(
       scope, multiDeclaration, expressionReceiver, initializer, context);
   return DataFlowUtils.checkStatementType(multiDeclaration, context, dataFlowInfo);
 }
 @Override
 public JetTypeInfo visitObjectDeclaration(
     JetObjectDeclaration declaration, ExpressionTypingContext context) {
   TopDownAnalyzer.processClassOrObject(
       context.expressionTypingServices.getProject(),
       context.trace,
       scope,
       scope.getContainingDeclaration(),
       declaration);
   ClassDescriptor classDescriptor =
       context.trace.getBindingContext().get(BindingContext.CLASS, declaration);
   if (classDescriptor != null) {
     VariableDescriptor variableDescriptor =
         context
             .expressionTypingServices
             .getDescriptorResolver()
             .resolveObjectDeclaration(
                 scope.getContainingDeclaration(), declaration, classDescriptor, context.trace);
     scope.addVariableDescriptor(variableDescriptor);
   }
   return DataFlowUtils.checkStatementType(declaration, context, context.dataFlowInfo);
 }
  @Override
  public JetTypeInfo visitNamedFunction(
      JetNamedFunction function, ExpressionTypingContext context) {
    SimpleFunctionDescriptor functionDescriptor =
        context
            .expressionTypingServices
            .getDescriptorResolver()
            .resolveFunctionDescriptor(
                scope.getContainingDeclaration(), scope, function, context.trace);

    scope.addFunctionDescriptor(functionDescriptor);
    JetScope functionInnerScope =
        FunctionDescriptorUtil.getFunctionInnerScope(
            context.scope, functionDescriptor, context.trace);
    context.expressionTypingServices.checkFunctionReturnType(
        functionInnerScope,
        function,
        functionDescriptor,
        context.dataFlowInfo,
        null,
        context.trace);
    ModifiersChecker.create(context.trace).checkModifiersForLocalDeclaration(function);
    return DataFlowUtils.checkStatementType(function, context, context.dataFlowInfo);
  }
 @Override
 public JetTypeInfo visitDeclaration(JetDeclaration dcl, ExpressionTypingContext context) {
   return DataFlowUtils.checkStatementType(dcl, context, context.dataFlowInfo);
 }