report type mismatch deeply on branches for if
in type argument inference case
This commit is contained in:
+8
-16
@@ -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));
|
||||
|
||||
+50
-9
@@ -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);
|
||||
|
||||
+1
-1
@@ -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());
|
||||
|
||||
+27
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user