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 com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
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.diagnostics.Errors;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||||
@@ -223,7 +222,14 @@ public class TracingStrategyImpl implements TracingStrategy {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (constraintSystem.hasOnlyExpectedTypeMismatch()) {
|
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()) {
|
else if (constraintSystem.hasTypeConstructorMismatch()) {
|
||||||
trace.report(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH.on(reference, data));
|
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
|
@Override
|
||||||
public void upperBoundViolated(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {
|
public void upperBoundViolated(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {
|
||||||
trace.report(Errors.TYPE_INFERENCE_UPPER_BOUND_VIOLATED.on(reference, 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.TypeParameterDescriptorImpl;
|
||||||
import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
|
import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
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.BindingTrace;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
|
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.results.OverloadResolutionResults;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
|
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.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.calls.util.CallMaker;
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||||
import org.jetbrains.jet.lang.types.ErrorUtils;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
|
||||||
import org.jetbrains.jet.lang.types.JetTypeImpl;
|
|
||||||
import org.jetbrains.jet.lang.types.Variance;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
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.CALL;
|
||||||
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_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) {
|
/*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") {
|
return new ThrowingOnErrorTracingStrategy("resolve 'if' as a call") {
|
||||||
@Override
|
@Override
|
||||||
@@ -245,9 +285,10 @@ public class ControlStructureTypingUtils {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (constraintSystem.hasOnlyExpectedTypeMismatch()) {
|
if (constraintSystem.hasOnlyExpectedTypeMismatch()) {
|
||||||
JetExpression ifExpression = callForIf.getCalleeExpression();
|
JetExpression expression = callForIf.getCalleeExpression();
|
||||||
assert ifExpression != null;
|
if (expression != null) {
|
||||||
TracingStrategyImpl.reportTypeInferenceExpectedTypeMismatch(TYPE_MISMATCH, ifExpression, data, trace);
|
expression.accept(checkTypeVisitor, new CheckTypeContext(trace, data.expectedType));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
super.typeInferenceFailed(trace, data);
|
super.typeInferenceFailed(trace, data);
|
||||||
|
|||||||
+1
-1
@@ -151,7 +151,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
result = thenTypeInfo;
|
result = thenTypeInfo;
|
||||||
}
|
}
|
||||||
else {
|
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());
|
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")
|
@TestMetadata("compiler/testData/diagnostics/tests/controlStructures")
|
||||||
|
@InnerTestClasses({ControlStructures.If.class})
|
||||||
public static class ControlStructures extends AbstractDiagnosticsTestWithEagerResolve {
|
public static class ControlStructures extends AbstractDiagnosticsTestWithEagerResolve {
|
||||||
public void testAllFilesPresentInControlStructures() throws Exception {
|
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);
|
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");
|
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")
|
@TestMetadata("compiler/testData/diagnostics/tests/dataClasses")
|
||||||
@@ -5353,7 +5373,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
|||||||
suite.addTestSuite(Cast.class);
|
suite.addTestSuite(Cast.class);
|
||||||
suite.addTestSuite(CheckArguments.class);
|
suite.addTestSuite(CheckArguments.class);
|
||||||
suite.addTestSuite(ControlFlowAnalysis.class);
|
suite.addTestSuite(ControlFlowAnalysis.class);
|
||||||
suite.addTestSuite(ControlStructures.class);
|
suite.addTest(ControlStructures.innerSuite());
|
||||||
suite.addTestSuite(DataClasses.class);
|
suite.addTestSuite(DataClasses.class);
|
||||||
suite.addTest(DataFlow.innerSuite());
|
suite.addTest(DataFlow.innerSuite());
|
||||||
suite.addTestSuite(DataFlowInfoTraversal.class);
|
suite.addTestSuite(DataFlowInfoTraversal.class);
|
||||||
|
|||||||
Reference in New Issue
Block a user