Fix JetType.equals(): flexible types are not equal to non-flexible ones, when we store them in a HashSet
This commit is contained in:
+6
-1
@@ -1081,7 +1081,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
JetType type = resolvedCall.getResultingDescriptor().getReturnType();
|
JetType type = resolvedCall.getResultingDescriptor().getReturnType();
|
||||||
if (type == null || rightType == null) return JetTypeInfo.create(null, dataFlowInfo);
|
if (type == null || rightType == null) return JetTypeInfo.create(null, dataFlowInfo);
|
||||||
|
|
||||||
return JetTypeInfo.create(TypeUtils.makeNullableAsSpecified(type, rightType.isNullable()), dataFlowInfo);
|
// Sometimes return type for special call for elvis operator might be nullable,
|
||||||
|
// but result is not nullable if the right type is not nullable
|
||||||
|
if (!TypeUtils.isNullableType(rightType) && TypeUtils.isNullableType(type)) {
|
||||||
|
type = TypeUtils.makeNotNullable(type);
|
||||||
|
}
|
||||||
|
return JetTypeInfo.create(type, dataFlowInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// FILE: p/J.java
|
||||||
|
package p;
|
||||||
|
|
||||||
|
public interface J {
|
||||||
|
public interface Super<T> {}
|
||||||
|
public interface Sub<T> extends Super<T> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: k.kt
|
||||||
|
|
||||||
|
import p.J.*
|
||||||
|
|
||||||
|
class Foo<T>: Sub<T> {
|
||||||
|
fun foo(): Super<T> {
|
||||||
|
return <!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>Foo<!>()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
internal final class Foo</*0*/ T> : p.J.Sub<T> {
|
||||||
|
public constructor Foo</*0*/ T>()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
internal final fun foo(): p.J.Super<T>
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// FILE: p/J.java
|
||||||
|
|
||||||
|
package p;
|
||||||
|
|
||||||
|
public class J {
|
||||||
|
public static J j() { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: k.kt
|
||||||
|
|
||||||
|
import p.*
|
||||||
|
|
||||||
|
fun foo(): J? = null
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val v = foo() ?: J.j()
|
||||||
|
if (v != null) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
internal fun foo(): p.J?
|
||||||
|
internal fun main(/*0*/ args: kotlin.Array<kotlin.String>): kotlin.Unit
|
||||||
@@ -4865,6 +4865,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("immutableArrayList.kt")
|
||||||
|
public void testImmutableArrayList() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/immutableArrayList.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inferInFunctionLiterals.kt")
|
@TestMetadata("inferInFunctionLiterals.kt")
|
||||||
public void testInferInFunctionLiterals() throws Exception {
|
public void testInferInFunctionLiterals() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/inferInFunctionLiterals.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/inferInFunctionLiterals.kt");
|
||||||
@@ -7799,6 +7805,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeOfElvis.kt")
|
||||||
|
public void testTypeOfElvis() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/commonSupertype/typeOfElvis.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/platformTypes/methodCall")
|
@TestMetadata("compiler/testData/diagnostics/tests/platformTypes/methodCall")
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.types.ErrorUtils;
|
|||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.LazyType;
|
import org.jetbrains.jet.lang.types.LazyType;
|
||||||
import org.jetbrains.jet.lang.types.TypeConstructor;
|
import org.jetbrains.jet.lang.types.TypeConstructor;
|
||||||
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -397,9 +398,9 @@ public class DescriptorUtils {
|
|||||||
|
|
||||||
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
|
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
|
||||||
return builtIns.isPrimitiveType(type) ||
|
return builtIns.isPrimitiveType(type) ||
|
||||||
builtIns.getStringType().equals(type) ||
|
JetTypeChecker.DEFAULT.equalTypes(builtIns.getStringType(), type) ||
|
||||||
builtIns.getNumber().getDefaultType().equals(type) ||
|
JetTypeChecker.DEFAULT.equalTypes(builtIns.getNumber().getDefaultType(), type) ||
|
||||||
builtIns.getAnyType().equals(type);
|
JetTypeChecker.DEFAULT.equalTypes(builtIns.getAnyType(), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean classCanHaveAbstractMembers(@NotNull ClassDescriptor classDescriptor) {
|
public static boolean classCanHaveAbstractMembers(@NotNull ClassDescriptor classDescriptor) {
|
||||||
|
|||||||
+2
-1
@@ -23,6 +23,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure;
|
import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure;
|
||||||
import org.jetbrains.jet.lang.types.checker.TypingConstraints;
|
import org.jetbrains.jet.lang.types.checker.TypingConstraints;
|
||||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||||
@@ -388,7 +389,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
|
|
||||||
// can be equal for the recursive invocations:
|
// can be equal for the recursive invocations:
|
||||||
// fun <T> foo(i: Int) : T { ... return foo(i); } => T <: T
|
// fun <T> foo(i: Int) : T { ... return foo(i); } => T <: T
|
||||||
if (subType.equals(superType)) return;
|
if (JetTypeChecker.DEFAULT.equalTypes(subType, superType)) return;
|
||||||
|
|
||||||
assert !isMyTypeVariable(subType) || !isMyTypeVariable(superType) :
|
assert !isMyTypeVariable(subType) || !isMyTypeVariable(superType) :
|
||||||
"The constraint shouldn't contain different type variables on both sides: " + subType + " <: " + superType;
|
"The constraint shouldn't contain different type variables on both sides: " + subType + " <: " + superType;
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public abstract class AbstractJetType implements JetType {
|
|||||||
|
|
||||||
JetType type = (JetType) obj;
|
JetType type = (JetType) obj;
|
||||||
|
|
||||||
return isNullable() == type.isNullable() && JetTypeChecker.DEFAULT.equalTypes(this, type);
|
return isNullable() == type.isNullable() && JetTypeChecker.FLEXIBLE_UNEQUAL_TO_INFLEXIBLE.equalTypes(this, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
|
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||||
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -77,7 +78,11 @@ public abstract class DelegatingType implements JetType {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
return getDelegate().equals(obj);
|
if (this == obj) return true;
|
||||||
|
if (!(obj instanceof JetType)) return false;
|
||||||
|
|
||||||
|
JetType type = (JetType) obj;
|
||||||
|
return JetTypeChecker.FLEXIBLE_UNEQUAL_TO_INFLEXIBLE.equalTypes(this, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -28,6 +28,13 @@ public class JetTypeChecker {
|
|||||||
|
|
||||||
public static final JetTypeChecker DEFAULT = new JetTypeChecker(new TypeCheckingProcedure(new TypeCheckerTypingConstraints()));
|
public static final JetTypeChecker DEFAULT = new JetTypeChecker(new TypeCheckingProcedure(new TypeCheckerTypingConstraints()));
|
||||||
|
|
||||||
|
public static final JetTypeChecker FLEXIBLE_UNEQUAL_TO_INFLEXIBLE = new JetTypeChecker(new TypeCheckingProcedure(new TypeCheckerTypingConstraints()) {
|
||||||
|
@Override
|
||||||
|
protected boolean heterogeneousEquivalence(JetType inflexibleType, JetType flexibleType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JetTypeChecker withAxioms(@NotNull final TypeConstructorEquality equalityAxioms) {
|
public static JetTypeChecker withAxioms(@NotNull final TypeConstructorEquality equalityAxioms) {
|
||||||
return new JetTypeChecker(new TypeCheckingProcedure(new TypeCheckerTypingConstraints() {
|
return new JetTypeChecker(new TypeCheckingProcedure(new TypeCheckerTypingConstraints() {
|
||||||
|
|||||||
+1
-1
@@ -118,7 +118,7 @@ public class TypeCheckingProcedure {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean heterogeneousEquivalence(JetType inflexibleType, JetType flexibleType) {
|
protected boolean heterogeneousEquivalence(JetType inflexibleType, JetType flexibleType) {
|
||||||
// This is to account for the case when we have Collection<X> vs (Mutable)Collection<X>! or K(java.util.Collection<? extends X>)
|
// This is to account for the case when we have Collection<X> vs (Mutable)Collection<X>! or K(java.util.Collection<? extends X>)
|
||||||
assert !TypesPackage.isFlexible(inflexibleType) : "Only inflexible types are allowed here: " + inflexibleType;
|
assert !TypesPackage.isFlexible(inflexibleType) : "Only inflexible types are allowed here: " + inflexibleType;
|
||||||
return isSubtypeOf(TypesPackage.flexibility(flexibleType).getLowerBound(), inflexibleType)
|
return isSubtypeOf(TypesPackage.flexibility(flexibleType).getLowerBound(), inflexibleType)
|
||||||
|
|||||||
Reference in New Issue
Block a user