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