@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);
 }
  @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 JetType visitFunctionLiteralExpression(
      JetFunctionLiteralExpression expression, ExpressionTypingContext context) {
    JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
    JetBlockExpression bodyExpression = functionLiteral.getBodyExpression();
    if (bodyExpression == null) return null;

    JetType expectedType = context.expectedType;
    boolean functionTypeExpected =
        expectedType != TypeUtils.NO_EXPECTED_TYPE
            && JetStandardClasses.isFunctionType(expectedType);

    NamedFunctionDescriptorImpl functionDescriptor =
        createFunctionDescriptor(expression, context, functionTypeExpected);

    List<JetType> parameterTypes = Lists.newArrayList();
    List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
    for (ValueParameterDescriptor valueParameter : valueParameters) {
      parameterTypes.add(valueParameter.getOutType());
    }
    ReceiverDescriptor receiverParameter = functionDescriptor.getReceiverParameter();
    JetType receiver = receiverParameter != NO_RECEIVER ? receiverParameter.getType() : null;

    JetType returnType = TypeUtils.NO_EXPECTED_TYPE;
    JetScope functionInnerScope =
        FunctionDescriptorUtil.getFunctionInnerScope(
            context.scope, functionDescriptor, context.trace);
    JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
    if (returnTypeRef != null) {
      returnType = context.getTypeResolver().resolveType(context.scope, returnTypeRef);
      context
          .getServices()
          .checkFunctionReturnType(
              expression,
              context
                  .replaceScope(functionInnerScope)
                  .replaceExpectedType(returnType)
                  .replaceExpectedReturnType(returnType)
                  .replaceDataFlowInfo(context.dataFlowInfo));
    } else {
      if (functionTypeExpected) {
        returnType = JetStandardClasses.getReturnTypeFromFunctionType(expectedType);
      }
      returnType =
          context
              .getServices()
              .getBlockReturnedType(
                  functionInnerScope,
                  bodyExpression,
                  CoercionStrategy.COERCION_TO_UNIT,
                  context.replaceExpectedType(returnType).replaceExpectedReturnType(returnType));
    }
    JetType safeReturnType =
        returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
    functionDescriptor.setReturnType(safeReturnType);

    boolean hasDeclaredValueParameters = functionLiteral.getValueParameterList() != null;
    if (!hasDeclaredValueParameters && functionTypeExpected) {
      JetType expectedReturnType = JetStandardClasses.getReturnTypeFromFunctionType(expectedType);
      if (JetStandardClasses.isUnit(expectedReturnType)) {
        functionDescriptor.setReturnType(JetStandardClasses.getUnitType());
        return DataFlowUtils.checkType(
            JetStandardClasses.getFunctionType(
                Collections.<AnnotationDescriptor>emptyList(),
                receiver,
                parameterTypes,
                JetStandardClasses.getUnitType()),
            expression,
            context);
      }
    }
    return DataFlowUtils.checkType(
        JetStandardClasses.getFunctionType(
            Collections.<AnnotationDescriptor>emptyList(),
            receiver,
            parameterTypes,
            safeReturnType),
        expression,
        context);
  }
  @NotNull
  protected JetTypeInfo visitAssignmentOperation(
      JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
    // There is a temporary binding trace for an opportunity to resolve set method for array if
    // needed (the initial trace should be used there)
    TemporaryBindingTrace temporaryBindingTrace =
        TemporaryBindingTrace.create(
            contextWithExpectedType.trace,
            "trace to resolve array set method for binary expression",
            expression);
    ExpressionTypingContext context =
        contextWithExpectedType
            .replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE)
            .replaceBindingTrace(temporaryBindingTrace);

    JetSimpleNameExpression operationSign = expression.getOperationReference();
    IElementType operationType = operationSign.getReferencedNameElementType();
    JetTypeInfo leftInfo = facade.getTypeInfo(expression.getLeft(), context);
    JetType leftType = leftInfo.getType();
    DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();

    JetExpression right = expression.getRight();
    JetExpression left = JetPsiUtil.deparenthesizeWithNoTypeResolution(expression.getLeft());
    if (right == null || left == null) {
      temporaryBindingTrace.commit();
      return JetTypeInfo.create(null, dataFlowInfo);
    }

    if (leftType == null) {
      dataFlowInfo =
          facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
      context.trace.report(UNRESOLVED_REFERENCE.on(operationSign));
      temporaryBindingTrace.commit();
      return JetTypeInfo.create(null, dataFlowInfo);
    }
    ExpressionReceiver receiver = new ExpressionReceiver(left, leftType);

    // We check that defined only one of '+=' and '+' operations, and call it (in the case '+' we
    // then also assign)
    // Check for '+='
    Name name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType);
    TemporaryBindingTrace assignmentOperationTrace =
        TemporaryBindingTrace.create(
            context.trace, "trace to check assignment operation like '+=' for", expression);
    OverloadResolutionResults<FunctionDescriptor> assignmentOperationDescriptors =
        basic.getResolutionResultsForBinaryCall(
            scope,
            name,
            context.replaceBindingTrace(assignmentOperationTrace),
            expression,
            receiver);
    JetType assignmentOperationType =
        OverloadResolutionResultsUtil.getResultType(assignmentOperationDescriptors);

    // Check for '+'
    Name counterpartName =
        OperatorConventions.BINARY_OPERATION_NAMES.get(
            OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
    TemporaryBindingTrace binaryOperationTrace =
        TemporaryBindingTrace.create(
            context.trace, "trace to check binary operation like '+' for", expression);
    OverloadResolutionResults<FunctionDescriptor> binaryOperationDescriptors =
        basic.getResolutionResultsForBinaryCall(
            scope,
            counterpartName,
            context.replaceBindingTrace(binaryOperationTrace),
            expression,
            receiver);
    JetType binaryOperationType =
        OverloadResolutionResultsUtil.getResultType(binaryOperationDescriptors);

    JetType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType;
    if (assignmentOperationType != null && binaryOperationType != null) {
      OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults =
          OverloadResolutionResultsUtil.ambiguity(
              assignmentOperationDescriptors, binaryOperationDescriptors);
      context.trace.report(
          ASSIGN_OPERATOR_AMBIGUITY.on(
              operationSign, ambiguityResolutionResults.getResultingCalls()));
      Collection<DeclarationDescriptor> descriptors = Sets.newHashSet();
      for (ResolvedCall<? extends FunctionDescriptor> call :
          ambiguityResolutionResults.getResultingCalls()) {
        descriptors.add(call.getResultingDescriptor());
      }
      dataFlowInfo =
          facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
      context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors);
    } else if (assignmentOperationType != null) {
      assignmentOperationTrace.commit();
      if (!KotlinBuiltIns.getInstance().isUnit(assignmentOperationType)) {
        context.trace.report(
            ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(
                operationSign,
                assignmentOperationDescriptors.getResultingDescriptor(),
                operationSign));
      }
    } else {
      binaryOperationTrace.commit();
      context.trace.record(VARIABLE_REASSIGNMENT, expression);
      if (left instanceof JetArrayAccessExpression) {
        ExpressionTypingContext contextForResolve =
            context
                .replaceScope(scope)
                .replaceBindingTrace(
                    TemporaryBindingTrace.create(
                        contextWithExpectedType.trace,
                        "trace to resolve array set method for assignment",
                        expression));
        basic.resolveArrayAccessSetMethod(
            (JetArrayAccessExpression) left, right, contextForResolve, context.trace);
      }
      dataFlowInfo =
          facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
    }
    basic.checkLValue(context.trace, expression.getLeft());
    temporaryBindingTrace.commit();
    return JetTypeInfo.create(
        checkAssignmentType(type, expression, contextWithExpectedType), dataFlowInfo);
  }