use data flow info in constraint system
intersect data flow value possible types add intersection type (or exact type for the most cases) as a lower bound to constraint system always get common super type for intersection type as a result (avoid returning it, even in error messages)
This commit is contained in:
@@ -578,7 +578,7 @@ public class CandidateResolver {
|
||||
CallResolutionContext<?> newContext = context.replaceBindingTrace(traceToResolveArgument).replaceExpectedType(expectedType);
|
||||
JetTypeInfo typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(argumentExpression, newContext,
|
||||
resolveFunctionArgumentBodies, traceToResolveArgument);
|
||||
JetType type = typeInfoForCall.getType();
|
||||
JetType type = updateResultTypeForSmartCasts(typeInfoForCall.getType(), argumentExpression, context);
|
||||
constraintSystem.addSubtypeConstraint(type, effectiveExpectedType, ConstraintPosition.getValueParameterPosition(
|
||||
valueParameterDescriptor.getIndex()));
|
||||
if (isErrorType != null) {
|
||||
@@ -586,6 +586,22 @@ public class CandidateResolver {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JetType updateResultTypeForSmartCasts(
|
||||
@Nullable JetType type,
|
||||
@Nullable JetExpression argumentExpression,
|
||||
@NotNull CallCandidateResolutionContext<?> context
|
||||
) {
|
||||
if (argumentExpression == null || type == null) return type;
|
||||
|
||||
DataFlowValue dataFlowValue =
|
||||
DataFlowValueFactory.INSTANCE.createDataFlowValue(argumentExpression, type, context.trace.getBindingContext());
|
||||
Set<JetType> possibleTypes = context.dataFlowInfo.getPossibleTypes(dataFlowValue);
|
||||
if (possibleTypes.isEmpty()) return type;
|
||||
|
||||
return TypeUtils.intersect(JetTypeChecker.INSTANCE, possibleTypes);
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkAllValueArguments(
|
||||
@NotNull CallCandidateResolutionContext<D> context,
|
||||
@NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies) {
|
||||
|
||||
+7
@@ -110,6 +110,12 @@ public class ConstraintsUtil {
|
||||
@Nullable
|
||||
private static JetType commonSupertype(@NotNull Collection<JetType> lowerBounds) {
|
||||
if (lowerBounds.isEmpty()) return null;
|
||||
if (lowerBounds.size() == 1) {
|
||||
JetType type = lowerBounds.iterator().next();
|
||||
if (type.getConstructor() instanceof IntersectionTypeConstructor) {
|
||||
return commonSupertype(type.getConstructor().getSupertypes());
|
||||
}
|
||||
}
|
||||
return CommonSupertypes.commonSupertype(lowerBounds);
|
||||
}
|
||||
|
||||
@@ -124,6 +130,7 @@ public class ConstraintsUtil {
|
||||
@NotNull TypeConstraints typeConstraints
|
||||
) {
|
||||
if (suggestion == null) return false;
|
||||
if (!suggestion.getConstructor().isDenotable()) return false;
|
||||
if (typeConstraints.getExactBounds().size() > 1) return false;
|
||||
|
||||
for (JetType exactBound : typeConstraints.getExactBounds()) {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package a
|
||||
|
||||
fun <T> id(t: T): T = t
|
||||
|
||||
fun <T> two(u: T, <!UNUSED_PARAMETER!>v<!>: T): T = u
|
||||
|
||||
fun <T> three(<!UNUSED_PARAMETER!>a<!>: T, <!UNUSED_PARAMETER!>b<!>: T, c: T): T = c
|
||||
|
||||
trait A
|
||||
trait B: A
|
||||
trait C: A
|
||||
|
||||
fun test(a: A, b: B, c: C) {
|
||||
if (a is B && a is C) {
|
||||
val d: C = id(a)
|
||||
val e: Any = id(a)
|
||||
val f = id(a)
|
||||
val g = two(a, b)
|
||||
g: B
|
||||
g: A
|
||||
|
||||
val h: Any = two(a, b)
|
||||
|
||||
val k = three(a, b, c)
|
||||
k: A
|
||||
<!TYPE_MISMATCH!>k<!>: B
|
||||
val l: Int = <!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>three<!>(a, b, c)
|
||||
|
||||
use(d, e, f, g, h, k, l)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> foo(t: T, <!UNUSED_PARAMETER!>l<!>: MutableList<T>): T = t
|
||||
|
||||
fun testErrorMessages(a: A, ml: MutableList<String>) {
|
||||
if (a is B && a is C) {
|
||||
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>foo<!>(a, ml)
|
||||
}
|
||||
|
||||
if(a is C) {
|
||||
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>foo<!>(a, ml)
|
||||
}
|
||||
}
|
||||
|
||||
fun rr(s: String?) {
|
||||
if (s != null) {
|
||||
val l = arrayListOf("", s)
|
||||
l: MutableList<String>
|
||||
<!TYPE_MISMATCH!>l<!>: MutableList<String?>
|
||||
}
|
||||
}
|
||||
|
||||
//from library
|
||||
fun arrayListOf<T>(vararg <!UNUSED_PARAMETER!>values<!>: T): MutableList<T> = throw Exception()
|
||||
|
||||
fun use(vararg a: Any) = a
|
||||
@@ -0,0 +1,40 @@
|
||||
//KT-1355 Type inference fails with autocast and generic function
|
||||
//tests for Map.set
|
||||
package a
|
||||
|
||||
import java.util.HashMap
|
||||
|
||||
fun foo(map: MutableMap<Int, String>, value: String?) {
|
||||
if (value != null) {
|
||||
map.put(1, value) //ok
|
||||
map.set(1, value) //type inference failed
|
||||
map[1] = value //type inference failed
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------
|
||||
|
||||
public data open class Tag(public var tagName: String) {
|
||||
public val attributes: MutableMap<String, String> = HashMap<String, String>()
|
||||
public val contents: MutableList<Tag> = arrayListOf()
|
||||
|
||||
public var id: String?
|
||||
get() = attributes["id"]
|
||||
set(value) {
|
||||
if(value == null) {
|
||||
attributes.remove("id")
|
||||
}
|
||||
else {
|
||||
attributes["id"] = value<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
|
||||
attributes["id"] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//from library
|
||||
fun <K, V> MutableMap<K, V>.set(key : K, value : V) = this.put(key, value)
|
||||
|
||||
fun arrayListOf<T>(vararg <!UNUSED_PARAMETER!>values<!>: T): MutableList<T> = throw Exception()
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
//KT-2746 Do autocasts in inference
|
||||
import java.util.HashMap
|
||||
|
||||
class C<T>(t :T)
|
||||
|
||||
fun test1(a: Any) {
|
||||
if (a is String) {
|
||||
val <!UNUSED_VARIABLE!>c<!>: C<String> = C(a)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun f<T>(t :T): C<T> = C(t)
|
||||
|
||||
fun test2(a: Any) {
|
||||
if (a is String) {
|
||||
val <!UNUSED_VARIABLE!>c1<!>: C<String> = f(a)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
//KT-2851 Type inference failed passing in not-null after smart-cast value in Pair
|
||||
package a
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val value: String? = ""
|
||||
if (value != null) {
|
||||
foo(Pair("val", value))
|
||||
foo(Pair("val", value<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>))
|
||||
foo(Pair<String, String>("val", value))
|
||||
}
|
||||
}
|
||||
|
||||
fun foo(<!UNUSED_PARAMETER!>map<!>: Pair<String, String>) {}
|
||||
|
||||
|
||||
//from library
|
||||
public class Pair<out A, out B> (
|
||||
public val first: A,
|
||||
public val second: B
|
||||
)
|
||||
@@ -5070,6 +5070,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/smartCasts")
|
||||
@InnerTestClasses({SmartCasts.Inference.class})
|
||||
public static class SmartCasts extends AbstractDiagnosticsTestWithEagerResolve {
|
||||
public void testAllFilesPresentInSmartCasts() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/smartCasts"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
@@ -5115,6 +5116,40 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
||||
doTest("compiler/testData/diagnostics/tests/smartCasts/thisWithLabelAsReceiverPart.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/smartCasts/inference")
|
||||
public static class Inference extends AbstractDiagnosticsTestWithEagerResolve {
|
||||
public void testAllFilesPresentInInference() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/smartCasts/inference"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("intersectionTypes.kt")
|
||||
public void testIntersectionTypes() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/smartCasts/inference/intersectionTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt1355.kt")
|
||||
public void testKt1355() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt1355.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt2746.kt")
|
||||
public void testKt2746() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt2746.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt2851.kt")
|
||||
public void testKt2851() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt2851.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Test innerSuite() {
|
||||
TestSuite suite = new TestSuite("SmartCasts");
|
||||
suite.addTestSuite(SmartCasts.class);
|
||||
suite.addTestSuite(Inference.class);
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/substitutions")
|
||||
@@ -5345,7 +5380,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
||||
suite.addTestSuite(Scopes.class);
|
||||
suite.addTestSuite(SenselessComparison.class);
|
||||
suite.addTestSuite(Shadowing.class);
|
||||
suite.addTestSuite(SmartCasts.class);
|
||||
suite.addTest(SmartCasts.innerSuite());
|
||||
suite.addTestSuite(Substitutions.class);
|
||||
suite.addTestSuite(Subtyping.class);
|
||||
suite.addTestSuite(ThisAndSuper.class);
|
||||
|
||||
Reference in New Issue
Block a user