report type mismatch deeply on branches for if

in type argument inference case
This commit is contained in:
Svetlana Isakova
2013-07-31 18:16:01 +04:00
parent c5b6ee4df3
commit e2f681c587
5 changed files with 107 additions and 27 deletions
@@ -21,7 +21,6 @@ import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory2;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingTrace;
@@ -223,7 +222,14 @@ public class TracingStrategyImpl implements TracingStrategy {
return;
}
if (constraintSystem.hasOnlyExpectedTypeMismatch()) {
reportTypeInferenceExpectedTypeMismatch(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH, reference, data, trace);
JetType declaredReturnType = data.descriptor.getReturnType();
if (declaredReturnType == null) return;
JetType substitutedReturnType = constraintSystem.getResultingSubstitutor().substitute(declaredReturnType, Variance.INVARIANT);
assert substitutedReturnType != null; //todo
assert !noExpectedType(data.expectedType) : "Expected type doesn't exist, but there is an expected type mismatch error";
trace.report(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(reference, data.expectedType, substitutedReturnType));
}
else if (constraintSystem.hasTypeConstructorMismatch()) {
trace.report(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH.on(reference, data));
@@ -237,20 +243,6 @@ public class TracingStrategyImpl implements TracingStrategy {
}
}
public static void reportTypeInferenceExpectedTypeMismatch(
@NotNull DiagnosticFactory2<JetExpression, JetType, JetType> diagnosticFactory,
@NotNull JetExpression reportOn, @NotNull InferenceErrorData.ExtendedInferenceErrorData data, @NotNull BindingTrace trace
) {
JetType declaredReturnType = data.descriptor.getReturnType();
if (declaredReturnType == null) return;
JetType substitutedReturnType = data.constraintSystem.getResultingSubstitutor().substitute(declaredReturnType, Variance.INVARIANT);
assert substitutedReturnType != null; //todo
assert !noExpectedType(data.expectedType) : "Expected type doesn't exist, but there is an expected type mismatch error";
trace.report(diagnosticFactory.on(reportOn, data.expectedType, substitutedReturnType));
}
@Override
public void upperBoundViolated(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {
trace.report(Errors.TYPE_INFERENCE_UPPER_BOUND_VIOLATED.on(reference, inferenceErrorData));
@@ -27,6 +27,7 @@ import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
@@ -37,21 +38,16 @@ import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategy;
import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategyImpl;
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeImpl;
import org.jetbrains.jet.lang.types.Variance;
import org.jetbrains.jet.lang.types.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.jet.lang.diagnostics.Errors.TYPE_MISMATCH;
import static org.jetbrains.jet.lang.resolve.BindingContext.CALL;
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
@@ -216,6 +212,50 @@ public class ControlStructureTypingUtils {
}
/*package*/ static TracingStrategy createTracingForIf(final @NotNull Call callForIf) {
class CheckTypeContext {
public BindingTrace trace;
public JetType expectedType;
CheckTypeContext(@NotNull BindingTrace trace, @NotNull JetType expectedType) {
this.trace = trace;
this.expectedType = expectedType;
}
}
final JetVisitor<Void, CheckTypeContext> checkTypeVisitor = new JetVisitor<Void, CheckTypeContext>() {
private void checkExpressionType(@Nullable JetExpression expression, CheckTypeContext c) {
if (expression == null) return;
expression.accept(this, c);
}
@Override
public Void visitIfExpression(JetIfExpression ifExpression, CheckTypeContext c) {
checkExpressionType(ifExpression.getThen(), c);
checkExpressionType(ifExpression.getElse(), c);
return null;
}
@Override
public Void visitBlockExpression(JetBlockExpression expression, CheckTypeContext c) {
List<JetElement> statements = expression.getStatements();
if (!statements.isEmpty()) {
JetElement lastElement = statements.get(statements.size() - 1);
if (lastElement instanceof JetExpression) {
checkExpressionType((JetExpression) lastElement, c);
}
}
return null;
}
@Override
public Void visitExpression(JetExpression expression, CheckTypeContext c) {
JetTypeInfo typeInfo = BindingContextUtils.getRecordedTypeInfo(expression, c.trace.getBindingContext());
if (typeInfo != null) {
DataFlowUtils.checkType(typeInfo.getType(), expression, c.expectedType, typeInfo.getDataFlowInfo(), c.trace);
}
return null;
}
};
return new ThrowingOnErrorTracingStrategy("resolve 'if' as a call") {
@Override
@@ -245,9 +285,10 @@ public class ControlStructureTypingUtils {
return;
}
if (constraintSystem.hasOnlyExpectedTypeMismatch()) {
JetExpression ifExpression = callForIf.getCalleeExpression();
assert ifExpression != null;
TracingStrategyImpl.reportTypeInferenceExpectedTypeMismatch(TYPE_MISMATCH, ifExpression, data, trace);
JetExpression expression = callForIf.getCalleeExpression();
if (expression != null) {
expression.accept(checkTypeVisitor, new CheckTypeContext(trace, data.expectedType));
}
return;
}
super.typeInferenceFailed(trace, data);
@@ -151,7 +151,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
result = thenTypeInfo;
}
else {
result = JetTypeInfo.create(CommonSupertypes.commonSupertype(Arrays.asList(thenType, elseType)), thenDataFlowInfo.or(elseDataFlowInfo));
result = JetTypeInfo.create(TypeUtils.commonSupertypeForPossiblyNumberTypes(Arrays.asList(thenType, elseType)), thenDataFlowInfo.or(elseDataFlowInfo));
}
return DataFlowUtils.checkImplicitCast(result.getType(), ifExpression, contextWithExpectedType, isStatement, result.getDataFlowInfo());
@@ -0,0 +1,27 @@
package b
fun bar(i: Int) = i
fun test(a: Int?, b: Int?) {
bar(if (a == null) return else <!TYPE_MISMATCH!>b<!>)
}
fun test(a: Int?, b: Int?, c: Int?) {
bar(if (a == null) return else if (b == null) return else <!TYPE_MISMATCH!>c<!>)
}
fun test(a: Any?, b: Any?, c: Int?) {
bar(if (a == null) if (b == null) <!TYPE_MISMATCH!>c<!> else return else return)
}
fun test(a: Int?, b: Any?, c: Int?) {
bar(if (a == null) {
return
} else {
if (b == null) {
return
} else {
<!TYPE_MISMATCH!>c<!>
}
})
}
@@ -1258,6 +1258,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
}
@TestMetadata("compiler/testData/diagnostics/tests/controlStructures")
@InnerTestClasses({ControlStructures.If.class})
public static class ControlStructures extends AbstractDiagnosticsTestWithEagerResolve {
public void testAllFilesPresentInControlStructures() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/controlStructures"), Pattern.compile("^(.+)\\.kt$"), true);
@@ -1323,6 +1324,25 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/controlStructures/when.kt234.kt973.kt");
}
@TestMetadata("compiler/testData/diagnostics/tests/controlStructures/if")
public static class If extends AbstractDiagnosticsTestWithEagerResolve {
public void testAllFilesPresentInIf() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/controlStructures/if"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("reportTypeMismatchDeeplyOnBranches.kt")
public void testReportTypeMismatchDeeplyOnBranches() throws Exception {
doTest("compiler/testData/diagnostics/tests/controlStructures/if/reportTypeMismatchDeeplyOnBranches.kt");
}
}
public static Test innerSuite() {
TestSuite suite = new TestSuite("ControlStructures");
suite.addTestSuite(ControlStructures.class);
suite.addTestSuite(If.class);
return suite;
}
}
@TestMetadata("compiler/testData/diagnostics/tests/dataClasses")
@@ -5353,7 +5373,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
suite.addTestSuite(Cast.class);
suite.addTestSuite(CheckArguments.class);
suite.addTestSuite(ControlFlowAnalysis.class);
suite.addTestSuite(ControlStructures.class);
suite.addTest(ControlStructures.innerSuite());
suite.addTestSuite(DataClasses.class);
suite.addTest(DataFlow.innerSuite());
suite.addTestSuite(DataFlowInfoTraversal.class);