@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);
 }
  @NotNull
  public JetTypeInfo getSimpleNameExpressionTypeInfo(
      @NotNull JetSimpleNameExpression nameExpression,
      @NotNull ReceiverValue receiver,
      @Nullable ASTNode callOperationNode,
      @NotNull ResolutionContext context) {
    boolean[] result = new boolean[1];

    TemporaryBindingTrace traceForVariable =
        TemporaryBindingTrace.create(context.trace, "trace to resolve as variable", nameExpression);
    JetType type =
        getVariableType(
            nameExpression,
            receiver,
            callOperationNode,
            context.replaceBindingTrace(traceForVariable),
            result);
    if (result[0]) {
      traceForVariable.commit();
      if (type instanceof NamespaceType && context.expressionPosition == ExpressionPosition.FREE) {
        type = null;
      }
      return JetTypeInfo.create(type, context.dataFlowInfo);
    }

    Call call =
        CallMaker.makeCall(
            nameExpression,
            receiver,
            callOperationNode,
            nameExpression,
            Collections.<ValueArgument>emptyList());
    TemporaryBindingTrace traceForFunction =
        TemporaryBindingTrace.create(context.trace, "trace to resolve as function", nameExpression);
    ResolvedCall<FunctionDescriptor> resolvedCall =
        getResolvedCallForFunction(
            call,
            nameExpression,
            receiver,
            context,
            ResolveMode.TOP_LEVEL_CALL,
            ResolutionResultsCache.create(),
            result);
    if (result[0]) {
      FunctionDescriptor functionDescriptor =
          resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
      traceForFunction.commit();
      boolean hasValueParameters =
          functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
      context.trace.report(
          FUNCTION_CALL_EXPECTED.on(nameExpression, nameExpression, hasValueParameters));
      type = functionDescriptor != null ? functionDescriptor.getReturnType() : null;
      return JetTypeInfo.create(type, context.dataFlowInfo);
    }

    traceForVariable.commit();
    return JetTypeInfo.create(null, context.dataFlowInfo);
  }
 @NotNull
 private JetTypeInfo getSelectorReturnTypeInfo(
     @NotNull ReceiverValue receiver,
     @Nullable ASTNode callOperationNode,
     @NotNull JetExpression selectorExpression,
     @NotNull ResolutionContext context,
     @NotNull ResolveMode resolveMode,
     @NotNull ResolutionResultsCache resolutionResultsCache) {
   if (selectorExpression instanceof JetCallExpression) {
     return getCallExpressionTypeInfoWithoutFinalTypeCheck(
         (JetCallExpression) selectorExpression,
         receiver,
         callOperationNode,
         context,
         resolveMode,
         resolutionResultsCache);
   } else if (selectorExpression instanceof JetSimpleNameExpression) {
     return getSimpleNameExpressionTypeInfo(
         (JetSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
   } else if (selectorExpression instanceof JetQualifiedExpression) {
     JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) selectorExpression;
     JetExpression newReceiverExpression = qualifiedExpression.getReceiverExpression();
     JetTypeInfo newReceiverTypeInfo =
         getSelectorReturnTypeInfo(
             receiver,
             callOperationNode,
             newReceiverExpression,
             context.replaceExpectedType(NO_EXPECTED_TYPE),
             resolveMode,
             resolutionResultsCache);
     JetType newReceiverType = newReceiverTypeInfo.getType();
     DataFlowInfo newReceiverDataFlowInfo = newReceiverTypeInfo.getDataFlowInfo();
     JetExpression newSelectorExpression = qualifiedExpression.getSelectorExpression();
     if (newReceiverType != null && newSelectorExpression != null) {
       ExpressionReceiver expressionReceiver =
           new ExpressionReceiver(newReceiverExpression, newReceiverType);
       return getSelectorReturnTypeInfo(
           expressionReceiver,
           qualifiedExpression.getOperationTokenNode(),
           newSelectorExpression,
           context.replaceDataFlowInfo(newReceiverDataFlowInfo),
           resolveMode,
           resolutionResultsCache);
     }
   } else {
     context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
   }
   return JetTypeInfo.create(null, context.dataFlowInfo);
 }
 @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 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);
  }
  @NotNull
  public TypeInfoForCall getQualifiedExpressionExtendedTypeInfo(
      @NotNull JetQualifiedExpression expression,
      @NotNull ResolutionContext context,
      @NotNull ResolveMode resolveMode) {
    // TODO : functions as values
    JetExpression selectorExpression = expression.getSelectorExpression();
    JetExpression receiverExpression = expression.getReceiverExpression();
    JetTypeInfo receiverTypeInfo =
        expressionTypingServices.getTypeInfoWithNamespaces(
            receiverExpression,
            context.scope,
            NO_EXPECTED_TYPE,
            context.dataFlowInfo,
            context.trace);
    JetType receiverType = receiverTypeInfo.getType();
    if (selectorExpression == null) return TypeInfoForCall.create(null, context.dataFlowInfo);
    if (receiverType == null)
      receiverType = ErrorUtils.createErrorType("Type for " + expression.getText());

    context = context.replaceDataFlowInfo(receiverTypeInfo.getDataFlowInfo());

    if (selectorExpression instanceof JetSimpleNameExpression) {
      ConstantUtils.propagateConstantValues(
          expression, context.trace, (JetSimpleNameExpression) selectorExpression);
    }

    TypeInfoForCall selectorReturnTypeInfo =
        getSelectorReturnTypeInfo(
            new ExpressionReceiver(receiverExpression, receiverType),
            expression.getOperationTokenNode(),
            selectorExpression,
            context,
            resolveMode);
    JetType selectorReturnType = selectorReturnTypeInfo.getType();

    // TODO move further
    if (!(receiverType instanceof NamespaceType)
        && expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
      if (selectorReturnType != null
          && !selectorReturnType.isNullable()
          && !KotlinBuiltIns.getInstance().isUnit(selectorReturnType)) {
        if (receiverType.isNullable()) {
          selectorReturnType = TypeUtils.makeNullable(selectorReturnType);
        }
      }
    }

    // TODO : this is suspicious: remove this code?
    if (selectorReturnType != null) {
      context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, selectorReturnType);
    }
    JetTypeInfo typeInfo =
        JetTypeInfo.create(selectorReturnType, selectorReturnTypeInfo.getDataFlowInfo());
    if (resolveMode == ResolveMode.TOP_LEVEL_CALL) {
      DataFlowUtils.checkType(typeInfo.getType(), expression, context, typeInfo.getDataFlowInfo());
    }
    return TypeInfoForCall.create(typeInfo, selectorReturnTypeInfo);
  }
 @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);
 }
 @NotNull
 public <D extends CallableDescriptor> JetTypeInfo getCallExpressionTypeInfo(
     @NotNull JetCallExpression callExpression,
     @NotNull ReceiverValue receiver,
     @Nullable ASTNode callOperationNode,
     @NotNull ResolutionContext context,
     @NotNull ResolveMode resolveMode,
     @NotNull ResolutionResultsCache resolutionResultsCache) {
   JetTypeInfo typeInfo =
       getCallExpressionTypeInfoWithoutFinalTypeCheck(
           callExpression,
           receiver,
           callOperationNode,
           context,
           resolveMode,
           resolutionResultsCache);
   if (resolveMode == ResolveMode.TOP_LEVEL_CALL) {
     DataFlowUtils.checkType(
         typeInfo.getType(), callExpression, context, typeInfo.getDataFlowInfo());
   }
   return typeInfo;
 }
  @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);
  }
  @NotNull
  public <D extends CallableDescriptor> JetTypeInfo getCallExpressionTypeInfoWithoutFinalTypeCheck(
      @NotNull JetCallExpression callExpression,
      @NotNull ReceiverValue receiver,
      @Nullable ASTNode callOperationNode,
      @NotNull ResolutionContext context,
      @NotNull ResolveMode resolveMode,
      @NotNull ResolutionResultsCache resolutionResultsCache) {
    boolean[] result = new boolean[1];
    Call call = CallMaker.makeCall(receiver, callOperationNode, callExpression);

    TemporaryBindingTrace traceForFunction =
        TemporaryBindingTrace.create(
            context.trace, "trace to resolve as function call", callExpression);
    ResolvedCallWithTrace<FunctionDescriptor> resolvedCall =
        getResolvedCallForFunction(
            call,
            callExpression,
            receiver,
            context.replaceBindingTrace(traceForFunction),
            resolveMode,
            resolutionResultsCache,
            result);
    if (result[0]) {
      FunctionDescriptor functionDescriptor =
          resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
      traceForFunction.commit();
      if (callExpression.getValueArgumentList() == null
          && callExpression.getFunctionLiteralArguments().isEmpty()) {
        // there are only type arguments
        boolean hasValueParameters =
            functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
        context.trace.report(
            FUNCTION_CALL_EXPECTED.on(callExpression, callExpression, hasValueParameters));
      }
      if (functionDescriptor == null) {
        return JetTypeInfo.create(null, context.dataFlowInfo);
      }
      JetType type = functionDescriptor.getReturnType();

      return JetTypeInfo.create(type, resolvedCall.getDataFlowInfo());
    }

    JetExpression calleeExpression = callExpression.getCalleeExpression();
    if (calleeExpression instanceof JetSimpleNameExpression
        && callExpression.getTypeArgumentList() == null) {
      TemporaryBindingTrace traceForVariable =
          TemporaryBindingTrace.create(
              context.trace, "trace to resolve as variable with 'invoke' call", callExpression);
      JetType type =
          getVariableType(
              (JetSimpleNameExpression) calleeExpression,
              receiver,
              callOperationNode,
              context.replaceBindingTrace(traceForVariable),
              result);
      if (result[0]) {
        traceForVariable.commit();
        context.trace.report(
            FUNCTION_EXPECTED.on(
                (JetReferenceExpression) calleeExpression,
                calleeExpression,
                type != null ? type : ErrorUtils.createErrorType("")));
        return JetTypeInfo.create(null, context.dataFlowInfo);
      }
    }
    traceForFunction.commit();
    return JetTypeInfo.create(null, context.dataFlowInfo);
  }
 @Override
 public JetTypeInfo visitJetElement(JetElement element, ExpressionTypingContext context) {
   context.trace.report(UNSUPPORTED.on(element, "in a block"));
   return JetTypeInfo.create(null, context.dataFlowInfo);
 }
  @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);
  }