Search in sources :

Example 1 with InferenceErrorData

use of org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData in project kotlin by JetBrains.

the class ControlStructureTypingUtils method createTracingForSpecialConstruction.

@NotNull
private TracingStrategy createTracingForSpecialConstruction(@NotNull final Call call, @NotNull String constructionName, @NotNull final ExpressionTypingContext context) {
    class CheckTypeContext {

        public BindingTrace trace;

        public KotlinType expectedType;

        CheckTypeContext(@NotNull BindingTrace trace, @NotNull KotlinType expectedType) {
            this.trace = trace;
            this.expectedType = expectedType;
        }

        CheckTypeContext makeTypeNullable() {
            if (TypeUtils.noExpectedType(expectedType))
                return this;
            return new CheckTypeContext(trace, TypeUtils.makeNullable(expectedType));
        }
    }
    final KtVisitor<Boolean, CheckTypeContext> checkTypeVisitor = new KtVisitor<Boolean, CheckTypeContext>() {

        private boolean checkExpressionType(@NotNull KtExpression expression, CheckTypeContext c) {
            KotlinTypeInfo typeInfo = BindingContextUtils.getRecordedTypeInfo(expression, c.trace.getBindingContext());
            if (typeInfo == null)
                return false;
            Ref<Boolean> hasError = Ref.create();
            dataFlowAnalyzer.checkType(typeInfo.getType(), expression, context.replaceExpectedType(c.expectedType).replaceDataFlowInfo(typeInfo.getDataFlowInfo()).replaceBindingTrace(c.trace), hasError);
            return hasError.get();
        }

        private boolean checkExpressionTypeRecursively(@Nullable KtExpression expression, CheckTypeContext c) {
            if (expression == null)
                return false;
            return expression.accept(this, c);
        }

        private boolean checkSubExpressions(KtExpression firstSub, KtExpression secondSub, KtExpression expression, CheckTypeContext firstContext, CheckTypeContext secondContext, CheckTypeContext context) {
            boolean errorWasReported = checkExpressionTypeRecursively(firstSub, firstContext);
            errorWasReported |= checkExpressionTypeRecursively(secondSub, secondContext);
            return errorWasReported || checkExpressionType(expression, context);
        }

        @Override
        public Boolean visitWhenExpression(@NotNull KtWhenExpression whenExpression, CheckTypeContext c) {
            boolean errorWasReported = false;
            for (KtWhenEntry whenEntry : whenExpression.getEntries()) {
                KtExpression entryExpression = whenEntry.getExpression();
                if (entryExpression != null) {
                    errorWasReported |= checkExpressionTypeRecursively(entryExpression, c);
                }
            }
            errorWasReported |= checkExpressionType(whenExpression, c);
            return errorWasReported;
        }

        @Override
        public Boolean visitIfExpression(@NotNull KtIfExpression ifExpression, CheckTypeContext c) {
            KtExpression thenBranch = ifExpression.getThen();
            KtExpression elseBranch = ifExpression.getElse();
            if (thenBranch == null || elseBranch == null) {
                return checkExpressionType(ifExpression, c);
            }
            return checkSubExpressions(thenBranch, elseBranch, ifExpression, c, c, c);
        }

        @Override
        public Boolean visitBlockExpression(@NotNull KtBlockExpression expression, CheckTypeContext c) {
            if (expression.getStatements().isEmpty()) {
                return checkExpressionType(expression, c);
            }
            KtExpression lastStatement = KtPsiUtil.getLastStatementInABlock(expression);
            if (lastStatement != null) {
                return checkExpressionTypeRecursively(lastStatement, c);
            }
            return false;
        }

        @Override
        public Boolean visitPostfixExpression(@NotNull KtPostfixExpression expression, CheckTypeContext c) {
            if (expression.getOperationReference().getReferencedNameElementType() == KtTokens.EXCLEXCL) {
                return checkExpressionTypeRecursively(expression.getBaseExpression(), c.makeTypeNullable());
            }
            return super.visitPostfixExpression(expression, c);
        }

        @Override
        public Boolean visitBinaryExpression(@NotNull KtBinaryExpression expression, CheckTypeContext c) {
            if (expression.getOperationReference().getReferencedNameElementType() == KtTokens.ELVIS) {
                return checkSubExpressions(expression.getLeft(), expression.getRight(), expression, c.makeTypeNullable(), c, c);
            }
            return super.visitBinaryExpression(expression, c);
        }

        @Override
        public Boolean visitExpression(@NotNull KtExpression expression, CheckTypeContext c) {
            return checkExpressionType(expression, c);
        }
    };
    return new ThrowingOnErrorTracingStrategy("resolve " + constructionName + " as a call") {

        @Override
        public <D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall) {
        //do nothing
        }

        @Override
        public void bindCall(@NotNull BindingTrace trace, @NotNull Call call) {
            trace.record(CALL, call.getCalleeExpression(), call);
        }

        @Override
        public <D extends CallableDescriptor> void bindResolvedCall(@NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall) {
            trace.record(RESOLVED_CALL, call, resolvedCall);
        }

        @Override
        public void typeInferenceFailed(@NotNull ResolutionContext<?> context, @NotNull InferenceErrorData data) {
            ConstraintSystem constraintSystem = data.constraintSystem;
            ConstraintSystemStatus status = constraintSystem.getStatus();
            assert !status.isSuccessful() : "Report error only for not successful constraint system";
            if (status.hasErrorInConstrainingTypes() || status.hasUnknownParameters()) {
                return;
            }
            KtExpression expression = (KtExpression) call.getCallElement();
            if (status.hasOnlyErrorsDerivedFrom(EXPECTED_TYPE_POSITION) || status.hasConflictingConstraints() || status.hasTypeInferenceIncorporationError()) {
                // todo after KT-... remove this line
                if (noTypeCheckingErrorsInExpression(expression, context.trace, data.expectedType)) {
                    KtExpression calleeExpression = call.getCalleeExpression();
                    if (calleeExpression instanceof KtWhenExpression || calleeExpression instanceof KtIfExpression) {
                        if (status.hasConflictingConstraints() || status.hasTypeInferenceIncorporationError()) {
                            // TODO provide comprehensible error report for hasConflictingConstraints() case (if possible)
                            context.trace.report(TYPE_INFERENCE_FAILED_ON_SPECIAL_CONSTRUCT.on(expression));
                        }
                    }
                }
                return;
            }
            KtDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, KtNamedDeclaration.class);
            logError("Expression: " + (parentDeclaration != null ? parentDeclaration.getText() : expression.getText()) + "\nConstraint system status: \n" + ConstraintsUtil.getDebugMessageForStatus(status));
        }

        private boolean noTypeCheckingErrorsInExpression(KtExpression expression, @NotNull BindingTrace trace, @NotNull KotlinType expectedType) {
            return Boolean.TRUE != expression.accept(checkTypeVisitor, new CheckTypeContext(trace, expectedType));
        }
    };
}
Also used : ResolutionContext(org.jetbrains.kotlin.resolve.calls.context.ResolutionContext) ConstraintSystem(org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem) ConstraintSystemStatus(org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemStatus) NotNull(org.jetbrains.annotations.NotNull) InferenceErrorData(org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData) ResolvedCall(org.jetbrains.kotlin.resolve.calls.model.ResolvedCall) BindingTrace(org.jetbrains.kotlin.resolve.BindingTrace) ResolvedCall(org.jetbrains.kotlin.resolve.calls.model.ResolvedCall) Nullable(org.jetbrains.annotations.Nullable) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

NotNull (org.jetbrains.annotations.NotNull)1 Nullable (org.jetbrains.annotations.Nullable)1 BindingTrace (org.jetbrains.kotlin.resolve.BindingTrace)1 ResolutionContext (org.jetbrains.kotlin.resolve.calls.context.ResolutionContext)1 ConstraintSystem (org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem)1 ConstraintSystemStatus (org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemStatus)1 InferenceErrorData (org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData)1 ResolvedCall (org.jetbrains.kotlin.resolve.calls.model.ResolvedCall)1