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:
@@ -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")
|
@TestMetadata("compiler/testData/diagnostics/tests/platformTypes")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@InnerTestClasses({PlatformTypes.CommonSupertype.class, PlatformTypes.MethodCall.class})
|
@InnerTestClasses({PlatformTypes.CommonSupertype.class, PlatformTypes.Intersection.class, PlatformTypes.MethodCall.class})
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public static class PlatformTypes extends AbstractJetDiagnosticsTest {
|
public static class PlatformTypes extends AbstractJetDiagnosticsTest {
|
||||||
public void testAllFilesPresentInPlatformTypes() throws Exception {
|
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")
|
@TestMetadata("compiler/testData/diagnostics/tests/platformTypes/methodCall")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
@@ -8953,6 +8968,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("kt688.kt")
|
||||||
public void testKt688() throws Exception {
|
public void testKt688() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/regressions/kt688.kt");
|
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) {
|
public IntersectionTypeConstructor(Annotations annotations, Collection<JetType> typesToIntersect) {
|
||||||
super(annotations);
|
super(annotations);
|
||||||
|
assert !typesToIntersect.isEmpty() : "Attempt to create an empty intersection";
|
||||||
|
|
||||||
this.intersectedTypes = new LinkedHashSet<JetType>(typesToIntersect);
|
this.intersectedTypes = new LinkedHashSet<JetType>(typesToIntersect);
|
||||||
this.hashCode = intersectedTypes.hashCode();
|
this.hashCode = intersectedTypes.hashCode();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,6 +172,8 @@ public class TypeUtils {
|
|||||||
boolean nothingTypePresent = false;
|
boolean nothingTypePresent = false;
|
||||||
List<JetType> nullabilityStripped = new ArrayList<JetType>(types.size());
|
List<JetType> nullabilityStripped = new ArrayList<JetType>(types.size());
|
||||||
for (JetType type : types) {
|
for (JetType type : types) {
|
||||||
|
if (type.isError()) continue;
|
||||||
|
|
||||||
nothingTypePresent |= KotlinBuiltIns.isNothingOrNullableNothing(type);
|
nothingTypePresent |= KotlinBuiltIns.isNothingOrNullableNothing(type);
|
||||||
allNullable &= type.isMarkedNullable();
|
allNullable &= type.isMarkedNullable();
|
||||||
nullabilityStripped.add(makeNotNullable(type));
|
nullabilityStripped.add(makeNotNullable(type));
|
||||||
@@ -181,6 +183,11 @@ public class TypeUtils {
|
|||||||
return allNullable ? KotlinBuiltIns.getInstance().getNullableNothingType() : KotlinBuiltIns.getInstance().getNothingType();
|
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
|
// Now we remove types that have subtypes in the list
|
||||||
List<JetType> resultingTypes = new ArrayList<JetType>();
|
List<JetType> resultingTypes = new ArrayList<JetType>();
|
||||||
outer:
|
outer:
|
||||||
@@ -213,11 +220,23 @@ public class TypeUtils {
|
|||||||
resultingTypes.add(type);
|
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) {
|
if (resultingTypes.size() == 1) {
|
||||||
return makeNullableAsSpecified(resultingTypes.get(0), allNullable);
|
return makeNullableAsSpecified(resultingTypes.get(0), allNullable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TypeConstructor constructor = new IntersectionTypeConstructor(Annotations.EMPTY, resultingTypes);
|
TypeConstructor constructor = new IntersectionTypeConstructor(Annotations.EMPTY, resultingTypes);
|
||||||
|
|
||||||
JetScope[] scopes = new JetScope[resultingTypes.size()];
|
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,
|
// 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!
|
// 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,
|
// These are not equal syntactically (by JetType.equals()), but X! is _compatible_ with others as exact bounds,
|
||||||
// moreover, X! is a better fit.
|
// moreover, X! is a better fit.
|
||||||
|
|||||||
Reference in New Issue
Block a user