Search in sources :

Example 1 with ExpressionReceiver

use of org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver in project kotlin by JetBrains.

the class BasicExpressionTypingVisitor method checkInExpression.

@NotNull
public KotlinTypeInfo checkInExpression(@NotNull KtElement callElement, @NotNull KtSimpleNameExpression operationSign, @NotNull ValueArgument leftArgument, @Nullable KtExpression right, @NotNull ExpressionTypingContext context) {
    KtExpression left = leftArgument.getArgumentExpression();
    ExpressionTypingContext contextWithNoExpectedType = context.replaceExpectedType(NO_EXPECTED_TYPE);
    if (right == null) {
        if (left != null)
            facade.getTypeInfo(left, contextWithNoExpectedType);
        return TypeInfoFactoryKt.noTypeInfo(context);
    }
    KotlinTypeInfo rightTypeInfo = facade.getTypeInfo(right, contextWithNoExpectedType);
    DataFlowInfo dataFlowInfo = rightTypeInfo.getDataFlowInfo();
    ExpressionReceiver receiver = safeGetExpressionReceiver(facade, right, contextWithNoExpectedType);
    ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(dataFlowInfo);
    OverloadResolutionResults<FunctionDescriptor> resolutionResult = components.callResolver.resolveCallWithGivenName(contextWithDataFlow, CallMaker.makeCall(callElement, receiver, null, operationSign, Collections.singletonList(leftArgument)), operationSign, OperatorNameConventions.CONTAINS);
    KotlinType containsType = OverloadResolutionResultsUtil.getResultingType(resolutionResult, context.contextDependency);
    ensureBooleanResult(operationSign, OperatorNameConventions.CONTAINS, containsType, context);
    if (left != null) {
        dataFlowInfo = facade.getTypeInfo(left, contextWithDataFlow).getDataFlowInfo().and(dataFlowInfo);
        rightTypeInfo = rightTypeInfo.replaceDataFlowInfo(dataFlowInfo);
    }
    if (resolutionResult.isSuccess()) {
        return rightTypeInfo.replaceType(components.builtIns.getBooleanType());
    } else {
        return rightTypeInfo.clearType();
    }
}
Also used : ExpressionReceiver(org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver) DataFlowInfo(org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo) NotNull(org.jetbrains.annotations.NotNull)

Example 2 with ExpressionReceiver

use of org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver in project kotlin by JetBrains.

the class BasicExpressionTypingVisitor method visitUnaryExpression.

@Override
public KotlinTypeInfo visitUnaryExpression(@NotNull KtUnaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
    ExpressionTypingContext context = isUnaryExpressionDependentOnExpectedType(expression) ? contextWithExpectedType : contextWithExpectedType.replaceContextDependency(INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE);
    KtExpression baseExpression = expression.getBaseExpression();
    if (baseExpression == null)
        return TypeInfoFactoryKt.noTypeInfo(context);
    KtSimpleNameExpression operationSign = expression.getOperationReference();
    IElementType operationType = operationSign.getReferencedNameElementType();
    // Special case for expr!!
    if (operationType == KtTokens.EXCLEXCL) {
        return visitExclExclExpression(expression, context);
    }
    // Type check the base expression
    KotlinTypeInfo typeInfo = facade.safeGetTypeInfo(baseExpression, context);
    KotlinType type = ExpressionTypingUtils.safeGetType(typeInfo);
    ExpressionReceiver receiver = ExpressionReceiver.Companion.create(baseExpression, type, context.trace.getBindingContext());
    Call call = CallMaker.makeCall(receiver, expression);
    // Conventions for unary operations
    Name name = OperatorConventions.UNARY_OPERATION_NAMES.get(operationType);
    if (name == null) {
        context.trace.report(UNSUPPORTED.on(operationSign, "visitUnaryExpression"));
        return typeInfo.clearType();
    }
    // a[i]++/-- takes special treatment because it is actually let j = i, arr = a in arr.set(j, a.get(j).inc())
    if ((operationType == KtTokens.PLUSPLUS || operationType == KtTokens.MINUSMINUS) && baseExpression instanceof KtArrayAccessExpression) {
        KtExpression stubExpression = ExpressionTypingUtils.createFakeExpressionOfType(baseExpression.getProject(), context.trace, "e", type);
        TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve array access set method for unary expression", expression);
        ExpressionTypingContext newContext = context.replaceBindingTrace(temporaryBindingTrace);
        resolveImplicitArrayAccessSetMethod((KtArrayAccessExpression) baseExpression, stubExpression, newContext, context.trace);
    }
    // Resolve the operation reference
    OverloadResolutionResults<FunctionDescriptor> resolutionResults = components.callResolver.resolveCallWithGivenName(context, call, expression.getOperationReference(), name);
    if (!resolutionResults.isSuccess()) {
        return typeInfo.clearType();
    }
    // Computing the return type
    KotlinType returnType = resolutionResults.getResultingDescriptor().getReturnType();
    KotlinType result;
    if (operationType == KtTokens.PLUSPLUS || operationType == KtTokens.MINUSMINUS) {
        assert returnType != null : "returnType is null for " + resolutionResults.getResultingDescriptor();
        if (KotlinBuiltIns.isUnit(returnType)) {
            result = ErrorUtils.createErrorType(components.builtIns.getUnit().getName().asString());
            context.trace.report(INC_DEC_SHOULD_NOT_RETURN_UNIT.on(operationSign));
        } else {
            KotlinType receiverType = receiver.getType();
            if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(returnType, receiverType)) {
                context.trace.report(RESULT_TYPE_MISMATCH.on(operationSign, name.asString(), receiverType, returnType));
            } else {
                context.trace.record(BindingContext.VARIABLE_REASSIGNMENT, expression);
                KtExpression stubExpression = ExpressionTypingUtils.createFakeExpressionOfType(baseExpression.getProject(), context.trace, "e", type);
                checkLValue(context.trace, context, baseExpression, stubExpression, expression);
            }
            // x++ type is x type, but ++x type is x.inc() type
            DataFlowValue receiverValue = DataFlowValueFactory.createDataFlowValue((ReceiverValue) call.getExplicitReceiver(), contextWithExpectedType);
            if (expression instanceof KtPrefixExpression) {
                result = returnType;
            } else {
                result = receiverType;
                // Also record data flow information for x++ value (= x)
                DataFlowValue returnValue = DataFlowValueFactory.createDataFlowValue(expression, receiverType, contextWithExpectedType);
                typeInfo = typeInfo.replaceDataFlowInfo(typeInfo.getDataFlowInfo().assign(returnValue, receiverValue, components.languageVersionSettings));
            }
        }
    } else {
        result = returnType;
    }
    CompileTimeConstant<?> value = components.constantExpressionEvaluator.evaluateExpression(expression, contextWithExpectedType.trace, contextWithExpectedType.expectedType);
    if (value != null) {
        return components.dataFlowAnalyzer.createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType);
    }
    return components.dataFlowAnalyzer.checkType(typeInfo.replaceType(result), expression, contextWithExpectedType.replaceDataFlowInfo(typeInfo.getDataFlowInfo()));
}
Also used : ResolvedCall(org.jetbrains.kotlin.resolve.calls.model.ResolvedCall) DataFlowValue(org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue) DataFlowValueFactory.createDataFlowValue(org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory.createDataFlowValue) Name(org.jetbrains.kotlin.name.Name) IElementType(com.intellij.psi.tree.IElementType) ExpressionReceiver(org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver)

Example 3 with ExpressionReceiver

use of org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver in project kotlin by JetBrains.

the class InOperationTranslator method translateInt.

@Nullable
private JsExpression translateInt() {
    ResolvedCall<? extends CallableDescriptor> rightCall = CallUtilKt.getResolvedCallWithAssert(right, bindingContext());
    if (!(rightCall.getResultingDescriptor() instanceof FunctionDescriptor)) {
        return null;
    }
    FunctionDescriptor callDescriptor = (FunctionDescriptor) rightCall.getResultingDescriptor();
    if (!INT_RANGE_TEST.apply(callDescriptor)) {
        return null;
    }
    if (!(rightCall.getDispatchReceiver() instanceof ExpressionReceiver)) {
        return null;
    }
    KtExpression lower = ((ExpressionReceiver) rightCall.getDispatchReceiver()).getExpression();
    KtExpression upper = rightCall.getCall().getValueArguments().get(0).getArgumentExpression();
    assert upper != null : "Parse error occurred: " + PsiUtilsKt.getTextWithLocation(right);
    return translateInt(lower, upper);
}
Also used : ExpressionReceiver(org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver) FunctionDescriptor(org.jetbrains.kotlin.descriptors.FunctionDescriptor) Nullable(org.jetbrains.annotations.Nullable)

Example 4 with ExpressionReceiver

use of org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver in project kotlin by JetBrains.

the class ExpressionTypingVisitorForStatements method visitAssignmentOperation.

@NotNull
protected KotlinTypeInfo visitAssignmentOperation(KtBinaryExpression 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)
    TemporaryTraceAndCache temporary = TemporaryTraceAndCache.create(contextWithExpectedType, "trace to resolve array set method for binary expression", expression);
    ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceTraceAndCache(temporary).replaceContextDependency(INDEPENDENT);
    KtSimpleNameExpression operationSign = expression.getOperationReference();
    IElementType operationType = operationSign.getReferencedNameElementType();
    KtExpression leftOperand = expression.getLeft();
    KotlinTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(leftOperand, context, facade);
    KotlinType leftType = leftInfo.getType();
    KtExpression right = expression.getRight();
    KtExpression left = leftOperand == null ? null : deparenthesize(leftOperand);
    if (right == null || left == null) {
        temporary.commit();
        return leftInfo.clearType();
    }
    if (leftType == null) {
        KotlinTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
        context.trace.report(UNRESOLVED_REFERENCE.on(operationSign, operationSign));
        temporary.commit();
        return rightInfo.clearType();
    }
    ExpressionReceiver receiver = ExpressionReceiver.Companion.create(left, leftType, context.trace.getBindingContext());
    // 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);
    TemporaryTraceAndCache temporaryForAssignmentOperation = TemporaryTraceAndCache.create(context, "trace to check assignment operation like '+=' for", expression);
    OverloadResolutionResults<FunctionDescriptor> assignmentOperationDescriptors = components.callResolver.resolveBinaryCall(context.replaceTraceAndCache(temporaryForAssignmentOperation).replaceScope(scope), receiver, expression, name);
    KotlinType assignmentOperationType = OverloadResolutionResultsUtil.getResultingType(assignmentOperationDescriptors, context.contextDependency);
    OverloadResolutionResults<FunctionDescriptor> binaryOperationDescriptors;
    KotlinType binaryOperationType;
    TemporaryTraceAndCache temporaryForBinaryOperation = TemporaryTraceAndCache.create(context, "trace to check binary operation like '+' for", expression);
    TemporaryBindingTrace ignoreReportsTrace = TemporaryBindingTrace.create(context.trace, "Trace for checking assignability");
    boolean lhsAssignable = basic.checkLValue(ignoreReportsTrace, context, left, right, expression);
    if (assignmentOperationType == null || lhsAssignable) {
        // Check for '+'
        Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
        binaryOperationDescriptors = components.callResolver.resolveBinaryCall(context.replaceTraceAndCache(temporaryForBinaryOperation).replaceScope(scope), receiver, expression, counterpartName);
        binaryOperationType = OverloadResolutionResultsUtil.getResultingType(binaryOperationDescriptors, context.contextDependency);
    } else {
        binaryOperationDescriptors = OverloadResolutionResultsImpl.nameNotFound();
        binaryOperationType = null;
    }
    KotlinType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType;
    KotlinTypeInfo rightInfo = leftInfo;
    boolean hasRemAssignOperation = atLeastOneOperation(assignmentOperationDescriptors.getResultingCalls(), OperatorNameConventions.REM_ASSIGN);
    boolean hasRemBinaryOperation = atLeastOneOperation(binaryOperationDescriptors.getResultingCalls(), OperatorNameConventions.REM);
    boolean oneTypeOfModRemOperations = hasRemAssignOperation == hasRemBinaryOperation;
    if (assignmentOperationDescriptors.isSuccess() && binaryOperationDescriptors.isSuccess() && oneTypeOfModRemOperations) {
        // Both 'plus()' and 'plusAssign()' available => ambiguity
        OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors);
        context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls()));
        Collection<DeclarationDescriptor> descriptors = Sets.newHashSet();
        for (ResolvedCall<?> resolvedCall : ambiguityResolutionResults.getResultingCalls()) {
            descriptors.add(resolvedCall.getResultingDescriptor());
        }
        rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
        context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors);
    } else if (assignmentOperationType != null && (assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess()) && (!hasRemBinaryOperation || !binaryOperationDescriptors.isSuccess())) {
        // There's 'plusAssign()', so we do a.plusAssign(b)
        temporaryForAssignmentOperation.commit();
        if (!KotlinTypeChecker.DEFAULT.equalTypes(components.builtIns.getUnitType(), assignmentOperationType)) {
            context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign));
        }
    } else {
        // There's only 'plus()', so we try 'a = a + b'
        temporaryForBinaryOperation.commit();
        context.trace.record(VARIABLE_REASSIGNMENT, expression);
        if (left instanceof KtArrayAccessExpression) {
            ExpressionTypingContext contextForResolve = context.replaceScope(scope).replaceBindingTrace(TemporaryBindingTrace.create(context.trace, "trace to resolve array set method for assignment", expression));
            basic.resolveImplicitArrayAccessSetMethod((KtArrayAccessExpression) left, right, contextForResolve, context.trace);
        }
        rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
        KotlinType expectedType = refineTypeFromPropertySetterIfPossible(context.trace.getBindingContext(), leftOperand, leftType);
        components.dataFlowAnalyzer.checkType(binaryOperationType, expression, context.replaceExpectedType(expectedType).replaceDataFlowInfo(rightInfo.getDataFlowInfo()).replaceCallPosition(new CallPosition.PropertyAssignment(left)));
        basic.checkLValue(context.trace, context, leftOperand, right, expression);
    }
    temporary.commit();
    return rightInfo.replaceType(checkAssignmentType(type, expression, contextWithExpectedType));
}
Also used : KotlinType(org.jetbrains.kotlin.types.KotlinType) CallPosition(org.jetbrains.kotlin.resolve.calls.context.CallPosition) Name(org.jetbrains.kotlin.name.Name) TemporaryBindingTrace(org.jetbrains.kotlin.resolve.TemporaryBindingTrace) IElementType(com.intellij.psi.tree.IElementType) ExpressionReceiver(org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver) TemporaryTraceAndCache(org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache) NotNull(org.jetbrains.annotations.NotNull)

Example 5 with ExpressionReceiver

use of org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver in project kotlin by JetBrains.

the class ExpressionTypingVisitorForStatements method visitDestructuringDeclaration.

@Override
public KotlinTypeInfo visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration, ExpressionTypingContext context) {
    components.annotationResolver.resolveAnnotationsWithArguments(scope, multiDeclaration.getModifierList(), context.trace);
    KtExpression initializer = multiDeclaration.getInitializer();
    if (initializer == null) {
        context.trace.report(INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION.on(multiDeclaration));
    }
    ExpressionReceiver expressionReceiver = initializer != null ? ExpressionTypingUtils.getExpressionReceiver(facade, initializer, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT)) : null;
    components.destructuringDeclarationResolver.defineLocalVariablesFromDestructuringDeclaration(scope, multiDeclaration, expressionReceiver, initializer, context);
    components.modifiersChecker.withTrace(context.trace).checkModifiersForDestructuringDeclaration(multiDeclaration);
    components.identifierChecker.checkDeclaration(multiDeclaration, context.trace);
    if (expressionReceiver == null) {
        return TypeInfoFactoryKt.noTypeInfo(context);
    } else {
        return facade.getTypeInfo(initializer, context).replaceType(components.dataFlowAnalyzer.checkStatementType(multiDeclaration, context));
    }
}
Also used : ExpressionReceiver(org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver)

Aggregations

ExpressionReceiver (org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver)11 NotNull (org.jetbrains.annotations.NotNull)5 Name (org.jetbrains.kotlin.name.Name)3 ResolvedCall (org.jetbrains.kotlin.resolve.calls.model.ResolvedCall)3 KotlinType (org.jetbrains.kotlin.types.KotlinType)3 IElementType (com.intellij.psi.tree.IElementType)2 DataFlowInfo (org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo)2 Nullable (org.jetbrains.annotations.Nullable)1 FunctionDescriptor (org.jetbrains.kotlin.descriptors.FunctionDescriptor)1 ModifiersChecker (org.jetbrains.kotlin.resolve.ModifiersChecker)1 TemporaryBindingTrace (org.jetbrains.kotlin.resolve.TemporaryBindingTrace)1 CallPosition (org.jetbrains.kotlin.resolve.calls.context.CallPosition)1 TemporaryTraceAndCache (org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache)1 OverloadResolutionResults (org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults)1 DataFlowValue (org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue)1 DataFlowValueFactory.createDataFlowValue (org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory.createDataFlowValue)1 LexicalWritableScope (org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope)1 ReceiverValue (org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue)1 TransientReceiver (org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver)1