@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 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); }
@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 <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; }
@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); }