Filtering error types and accounting for platform types when computing intersections

KT-6508 Build impossible because of NoSuchElementException

 #KT-6508 Fixed
This commit is contained in:
Andrey Breslav
2014-12-25 14:45:50 +03:00
parent 2d1891c63f
commit 42113b5e58
8 changed files with 87 additions and 3 deletions
@@ -0,0 +1,11 @@
// !EXPLICIT_FLEXIBLE_TYPES
fun foo(
p1: ft<MutableMap<Int, String>, Map<Int, String>?>,
p2: Map<Int, String>
) = p1 == p2
fun foo(
p1: ft<String, String?>,
p2: String
) = p1 == p2
@@ -0,0 +1,4 @@
package
internal fun foo(/*0*/ p1: kotlin.(Mutable)Map<kotlin.Int, kotlin.String>!, /*1*/ p2: kotlin.Map<kotlin.Int, kotlin.String>): kotlin.Boolean
internal fun foo(/*0*/ p1: kotlin.String!, /*1*/ p2: kotlin.String): kotlin.Boolean
@@ -0,0 +1,24 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION
// FILE: foo/View.java
package foo;
public class View {}
// FILE: foo/TextView.java
package foo;
public class TextView extends View {}
// FILE: k.kt
import foo.View
//import foo.TextView
fun String.gah(view:View ?) {
if (view is <!UNRESOLVED_REFERENCE!>TextView<!>)
<!DEBUG_INFO_SMARTCAST!>view<!>
else <!UNRESOLVED_REFERENCE!>TextView<!>() as foo.TextView
}
@@ -0,0 +1,3 @@
package
internal fun kotlin.String.gah(/*0*/ view: foo.View?): kotlin.Unit
@@ -8043,7 +8043,7 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
@TestMetadata("compiler/testData/diagnostics/tests/platformTypes")
@TestDataPath("$PROJECT_ROOT")
@InnerTestClasses({PlatformTypes.CommonSupertype.class, PlatformTypes.MethodCall.class})
@InnerTestClasses({PlatformTypes.CommonSupertype.class, PlatformTypes.Intersection.class, PlatformTypes.MethodCall.class})
@RunWith(JUnit3RunnerWithInners.class)
public static class PlatformTypes extends AbstractJetDiagnosticsTest {
public void testAllFilesPresentInPlatformTypes() throws Exception {
@@ -8185,6 +8185,21 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
}
}
@TestMetadata("compiler/testData/diagnostics/tests/platformTypes/intersection")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Intersection extends AbstractJetDiagnosticsTest {
public void testAllFilesPresentInIntersection() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/platformTypes/intersection"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("map.kt")
public void testMap() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/intersection/map.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/diagnostics/tests/platformTypes/methodCall")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -8953,6 +8968,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("kt6508.kt")
public void testKt6508() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/regressions/kt6508.kt");
doTest(fileName);
}
@TestMetadata("kt688.kt")
public void testKt688() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/regressions/kt688.kt");
@@ -30,6 +30,8 @@ public class IntersectionTypeConstructor extends AnnotatedImpl implements TypeCo
public IntersectionTypeConstructor(Annotations annotations, Collection<JetType> typesToIntersect) {
super(annotations);
assert !typesToIntersect.isEmpty() : "Attempt to create an empty intersection";
this.intersectedTypes = new LinkedHashSet<JetType>(typesToIntersect);
this.hashCode = intersectedTypes.hashCode();
}
@@ -172,6 +172,8 @@ public class TypeUtils {
boolean nothingTypePresent = false;
List<JetType> nullabilityStripped = new ArrayList<JetType>(types.size());
for (JetType type : types) {
if (type.isError()) continue;
nothingTypePresent |= KotlinBuiltIns.isNothingOrNullableNothing(type);
allNullable &= type.isMarkedNullable();
nullabilityStripped.add(makeNotNullable(type));
@@ -181,6 +183,11 @@ public class TypeUtils {
return allNullable ? KotlinBuiltIns.getInstance().getNullableNothingType() : KotlinBuiltIns.getInstance().getNothingType();
}
if (nullabilityStripped.isEmpty()) {
// All types were errors
return ErrorUtils.createErrorType("Intersection of errors types: " + types);
}
// Now we remove types that have subtypes in the list
List<JetType> resultingTypes = new ArrayList<JetType>();
outer:
@@ -213,11 +220,23 @@ public class TypeUtils {
resultingTypes.add(type);
}
if (resultingTypes.isEmpty()) {
// If we ended up here, it means that all types from `nullabilityStripped` were excluded by the code above
// most likely, this is because they are all semantically interchangeable (e.g. List<Foo>! and List<Foo>),
// in that case, we can safely select the best representative out of that set and return it
// TODO: maybe return the most specific among the types that are subtypes to all others in the `nullabilityStripped`?
// TODO: e.g. among {Int, Int?, Int!}, return `Int` (now it returns `Int!`).
JetType bestRepresentative = TypesPackage.singleBestRepresentative(nullabilityStripped);
if (bestRepresentative == null) {
throw new AssertionError("Empty intersection for types " + types);
}
return makeNullableAsSpecified(bestRepresentative, allNullable);
}
if (resultingTypes.size() == 1) {
return makeNullableAsSpecified(resultingTypes.get(0), allNullable);
}
TypeConstructor constructor = new IntersectionTypeConstructor(Annotations.EMPTY, resultingTypes);
JetScope[] scopes = new JetScope[resultingTypes.size()];
@@ -67,7 +67,7 @@ public fun JetType.isNullabilityFlexible(): Boolean {
}
// This function is intended primarily for sets: since JetType.equals() represents _syntactical_ equality of types,
// whereas JetTypeChecker.DEFAULT.equalsTypes() represents semantical equality
// whereas JetTypeChecker.DEFAULT.equalsTypes() represents semantic equality
// A set of types (e.g. exact bounds etc) may contain, for example, X, X? and X!
// These are not equal syntactically (by JetType.equals()), but X! is _compatible_ with others as exact bounds,
// moreover, X! is a better fit.