diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt index 3428e7abc9f..f26e6cb5902 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt @@ -50,6 +50,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.TypeUtils.noExpectedType +import org.jetbrains.kotlin.types.checker.ErrorTypesAreEqualToAnything import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import java.util.* @@ -178,7 +179,7 @@ class CandidateResolver( // TODO: use constraint system to check if candidateKCallableType can be a subtype of expectedType val substituteDontCare = makeConstantSubstitutor(candidateTypeParameters, TypeUtils.DONT_CARE) val subTypeSubstituted = substituteDontCare.substitute(subType, Variance.INVARIANT) ?: return true - return KotlinTypeChecker.ERROR_TYPES_ARE_EQUAL_TO_ANYTHING.isSubtypeOf(subTypeSubstituted, superType) + return ErrorTypesAreEqualToAnything.isSubtypeOf(subTypeSubstituted, superType) } private fun CallCandidateResolutionContext<*>.checkVisibilityWithoutReceiver() = checkAndReport { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java b/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java index 106df7dcf9d..862a0391c64 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java @@ -132,14 +132,14 @@ public class TypeIntersector { return TypeUtils.makeNullableAsSpecified(resultingTypes.get(0), allNullable); } - TypeConstructor constructor = new IntersectionTypeConstructor(Annotations.Companion.getEMPTY(), resultingTypes); + IntersectionTypeConstructor constructor = new IntersectionTypeConstructor(resultingTypes); return KotlinTypeFactory.simpleType( Annotations.Companion.getEMPTY(), constructor, Collections.emptyList(), allNullable, - TypeIntersectionScope.create("member scope for intersection type " + constructor, resultingTypes) + constructor.createScopeForKotlinType() ); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/Utils.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/Utils.kt index e3fe5723ed9..e3b8b19293b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/Utils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/Utils.kt @@ -16,7 +16,7 @@ package org.jetbrains.kotlin.types -import org.jetbrains.kotlin.types.checker.KotlinTypeChecker +import org.jetbrains.kotlin.types.checker.ErrorTypesAreEqualToAnything /** * This is temporary hack for type intersector. @@ -33,7 +33,7 @@ internal fun hackForTypeIntersector(types: Collection): KotlinType? return types.firstOrNull { candidate -> types.all { - KotlinTypeChecker.ERROR_TYPES_ARE_EQUAL_TO_ANYTHING.isSubtypeOf(candidate, it) + ErrorTypesAreEqualToAnything.isSubtypeOf(candidate, it) } } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/subtyping/javaAndKotlinSuperType.kt b/compiler/testData/diagnostics/tests/subtyping/javaAndKotlinSuperType.kt new file mode 100644 index 00000000000..79c18cb27b3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/subtyping/javaAndKotlinSuperType.kt @@ -0,0 +1,42 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// FILE: A.java +public interface A { +} + +// FILE: B.java +public class B implements A { +} + +// FILE: 1.kt +class C: B() + +class D: B(), A +class E: B(), A + +fun eatAString(a: A) {} +fun eatAStringN(a: A) {} + +fun test(b: B, c: C, d: D, e: E) { + eatAString(b) + eatAString(c) + eatAString(d) + eatAString(e) + + eatAStringN(b) + eatAStringN(c) + eatAStringN(d) + eatAStringN(e) +} + +// FILE: 3.kt + +interface X : A +interface Y: X +interface Z: X + +class W: B(), Z + +fun test2(w: W) { + eatAString(w) + eatAStringN(w) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/subtyping/javaAndKotlinSuperType.txt b/compiler/testData/diagnostics/tests/subtyping/javaAndKotlinSuperType.txt new file mode 100644 index 00000000000..4aaf050657d --- /dev/null +++ b/compiler/testData/diagnostics/tests/subtyping/javaAndKotlinSuperType.txt @@ -0,0 +1,65 @@ +package + +public fun eatAString(/*0*/ a: A): kotlin.Unit +public fun eatAStringN(/*0*/ a: A): kotlin.Unit +public fun test(/*0*/ b: B, /*1*/ c: C, /*2*/ d: D, /*3*/ e: E): kotlin.Unit +public fun test2(/*0*/ w: W): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class B : A { + public constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class C : B { + public constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class D : B, A { + public constructor D() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class E : B, A { + public constructor E() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class W : B, Z { + public constructor W() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface X : A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Y : X { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Z : X { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 5f10cfe557f..cf0ff71016f 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -18921,6 +18921,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("javaAndKotlinSuperType.kt") + public void testJavaAndKotlinSuperType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/subtyping/javaAndKotlinSuperType.kt"); + doTest(fileName); + } + @TestMetadata("kt2069.kt") public void testKt2069() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/subtyping/kt2069.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/types/KotlinTypeCheckerTest.java b/compiler/tests/org/jetbrains/kotlin/types/KotlinTypeCheckerTest.java index 570831d8ba5..8f7b2c7495b 100644 --- a/compiler/tests/org/jetbrains/kotlin/types/KotlinTypeCheckerTest.java +++ b/compiler/tests/org/jetbrains/kotlin/types/KotlinTypeCheckerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -182,13 +182,13 @@ public class KotlinTypeCheckerTest extends KotlinTestWithEnvironment { assertCommonSupertype("Base_T", "Base_T", "Base_T"); assertCommonSupertype("Base_T", "Derived_T", "Base_T"); assertCommonSupertype("Base_T", "Derived_T", "Base_T"); - assertCommonSupertype("Base_T<*>", "Base_T", "Base_T<*>"); + assertCommonSupertype("Base_T", "Base_T", "Base_T<*>"); assertCommonSupertype("Base_T", "Base_T", "Base_T"); } public void testCommonSupertypesForRecursive() throws Exception { - assertCommonSupertype("Rec>>>>", "ARec", "BRec"); + assertCommonSupertype("Rec>>>>", "ARec", "BRec"); } public void testIntersect() throws Exception { diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/CapturedTypeConstructor.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/CapturedTypeConstructor.kt index 1ce53430d53..2eccd312cd8 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/CapturedTypeConstructor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/CapturedTypeConstructor.kt @@ -24,11 +24,14 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.Variance.IN_VARIANCE import org.jetbrains.kotlin.types.Variance.OUT_VARIANCE +import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor import org.jetbrains.kotlin.types.typeUtil.builtIns class CapturedTypeConstructor( val typeProjection: TypeProjection ): TypeConstructor { + var newTypeConstructor: NewCapturedTypeConstructor? = null + init { assert(typeProjection.projectionKind != Variance.INVARIANT) { "Only nontrivial projections can be captured, not: $typeProjection" @@ -59,8 +62,8 @@ class CapturedTypeConstructor( } class CapturedType( - private val typeProjection: TypeProjection, - override val constructor: TypeConstructor = CapturedTypeConstructor(typeProjection), + val typeProjection: TypeProjection, + override val constructor: CapturedTypeConstructor = CapturedTypeConstructor(typeProjection), override val isMarkedNullable: Boolean = false, override val annotations: Annotations = Annotations.EMPTY ): SimpleType(), SubtypingRepresentatives { diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/TypeIntersectionScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/TypeIntersectionScope.kt index 223755cb963..1b432c15306 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/TypeIntersectionScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/TypeIntersectionScope.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,7 +45,7 @@ class TypeIntersectionScope private constructor(override val workerScope: Chaine companion object { @JvmStatic - fun create(message: String, types: List): MemberScope { + fun create(message: String, types: Collection): MemberScope { val chainedScope = ChainedMemberScope(message, types.map { it.memberScope }) if (types.size <= 1) return chainedScope diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/IntersectionTypeConstructor.java b/core/descriptors/src/org/jetbrains/kotlin/types/IntersectionTypeConstructor.java index b45e4b5f337..92d0aa539c9 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/IntersectionTypeConstructor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/IntersectionTypeConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,15 +22,16 @@ import org.jetbrains.kotlin.descriptors.ClassifierDescriptor; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; import org.jetbrains.kotlin.descriptors.annotations.AnnotatedImpl; import org.jetbrains.kotlin.descriptors.annotations.Annotations; +import org.jetbrains.kotlin.resolve.scopes.MemberScope; +import org.jetbrains.kotlin.resolve.scopes.TypeIntersectionScope; import java.util.*; -public class IntersectionTypeConstructor extends AnnotatedImpl implements TypeConstructor { +public class IntersectionTypeConstructor implements TypeConstructor { private final Set intersectedTypes; private final int hashCode; - public IntersectionTypeConstructor(Annotations annotations, Collection typesToIntersect) { - super(annotations); + public IntersectionTypeConstructor(Collection typesToIntersect) { assert !typesToIntersect.isEmpty() : "Attempt to create an empty intersection"; this.intersectedTypes = new LinkedHashSet(typesToIntersect); @@ -49,6 +50,10 @@ public class IntersectionTypeConstructor extends AnnotatedImpl implements TypeCo return intersectedTypes; } + public MemberScope createScopeForKotlinType() { + return TypeIntersectionScope.create("member scope for intersection type " + this, intersectedTypes); + } + @Override public boolean isFinal() { return false; @@ -106,4 +111,9 @@ public class IntersectionTypeConstructor extends AnnotatedImpl implements TypeCo return hashCode; } + @NotNull + @Override + public Annotations getAnnotations() { + return Annotations.Companion.getEMPTY(); + } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/KotlinType.kt b/core/descriptors/src/org/jetbrains/kotlin/types/KotlinType.kt index 4ca109753c6..9c7736d2b55 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/KotlinType.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/KotlinType.kt @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRendererOptions import org.jetbrains.kotlin.resolve.scopes.MemberScope -import org.jetbrains.kotlin.types.checker.KotlinTypeChecker +import org.jetbrains.kotlin.types.checker.StrictEqualityTypeChecker /** * [KotlinType] has only two direct subclasses: [WrappedType] and [UnwrappedType]. @@ -63,7 +63,7 @@ sealed class KotlinType : Annotated { if (this === other) return true if (other !is KotlinType) return false - return isMarkedNullable == other.isMarkedNullable && KotlinTypeChecker.FLEXIBLE_UNEQUAL_TO_INFLEXIBLE.equalTypes(this, other) + return isMarkedNullable == other.isMarkedNullable && StrictEqualityTypeChecker.strictEqualTypes(unwrap(), other.unwrap()) } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/IntersectionType.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/IntersectionType.kt new file mode 100644 index 00000000000..01cfbc42956 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/IntersectionType.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.types.checker + +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.types.* + +fun intersectTypes(types: List): UnwrappedType { + when (types.size) { + 0 -> error("Expected some types") + 1 -> return types.single() + } + var hasFlexibleTypes = false + var hasErrorType = false + val lowerBounds = types.map { + hasErrorType = hasErrorType || it.isError + when (it) { + is SimpleType -> it + is FlexibleType -> { + hasFlexibleTypes = true + it.lowerBound + } + } + } + if (hasErrorType) { + return ErrorUtils.createErrorType("Intersection of error types: $types") + } + + if (!hasFlexibleTypes) { + return intersectTypes(lowerBounds) + } + + val upperBounds = types.map { it.upperIfFlexible() } + /** + * We should save this rules: + * - if for each type from types type is subtype of A, then intersectionType should be subtype of A + * - same for type B which is subtype of all types. + * + * Note: when we construct intersection type of dynamic(or Raw type) & other type, we can get non-dynamic type. // todo discuss + */ + return KotlinTypeFactory.flexibleType(intersectTypes(lowerBounds), intersectTypes(upperBounds)) +} + +// types.size >= 2 +// It is incorrect see to nullability here, because of KT-12684 +private fun intersectTypes(types: List): SimpleType { + val constructor = IntersectionTypeConstructor(types) + return KotlinTypeFactory.simpleType(Annotations.EMPTY, constructor, listOf(), false, constructor.createScopeForKotlinType()) +} + diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/KotlinTypeChecker.java b/core/descriptors/src/org/jetbrains/kotlin/types/checker/KotlinTypeChecker.java index 90f37d6f30e..a000066ae6a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/KotlinTypeChecker.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/KotlinTypeChecker.java @@ -26,22 +26,7 @@ public interface KotlinTypeChecker { boolean equals(@NotNull TypeConstructor a, @NotNull TypeConstructor b); } - KotlinTypeChecker DEFAULT = new KotlinTypeCheckerImpl(new TypeCheckingProcedure(new TypeCheckerProcedureCallbacksImpl())); - - KotlinTypeChecker ERROR_TYPES_ARE_EQUAL_TO_ANYTHING = new KotlinTypeCheckerImpl(new TypeCheckingProcedure(new TypeCheckerProcedureCallbacksImpl() { - @Override - public boolean assertEqualTypes(@NotNull KotlinType a, @NotNull KotlinType b, @NotNull TypeCheckingProcedure typeCheckingProcedure) { - return a.isError() || b.isError() || super.assertEqualTypes(a, b, typeCheckingProcedure); - } - })); - - KotlinTypeChecker FLEXIBLE_UNEQUAL_TO_INFLEXIBLE = new KotlinTypeCheckerImpl(new TypeCheckingProcedure(new TypeCheckerProcedureCallbacksImpl()) { - @Override - protected boolean heterogeneousEquivalence(KotlinType inflexibleType, KotlinType flexibleType) { - return false; - } - }); - + KotlinTypeChecker DEFAULT = NewKotlinTypeChecker.INSTANCE; boolean isSubtypeOf(@NotNull KotlinType subtype, @NotNull KotlinType supertype); boolean equalTypes(@NotNull KotlinType a, @NotNull KotlinType b); diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt new file mode 100644 index 00000000000..604ea5d9203 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt @@ -0,0 +1,123 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.types.checker + +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.ClassifierDescriptor +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.typeUtil.asTypeProjection +import org.jetbrains.kotlin.types.typeUtil.builtIns +import org.jetbrains.kotlin.utils.DO_NOTHING_2 + +fun captureFromArguments( + type: SimpleType, + status: CaptureStatus, + acceptNewCapturedType: ((argumentIndex: Int, NewCapturedType) -> Unit) = DO_NOTHING_2 +): SimpleType { + val arguments = type.arguments + if (arguments.all { it.projectionKind == Variance.INVARIANT }) return type + + val newArguments = arguments.mapIndexed { + index, projection -> + if (projection.projectionKind == Variance.INVARIANT) return@mapIndexed projection + + val lowerType = if (!projection.isStarProjection && projection.projectionKind == Variance.IN_VARIANCE) { + projection.type.unwrap() + } else null + + NewCapturedType(status, lowerType, projection).asTypeProjection() // todo optimization: do not create type projection + } + + val substitutor = TypeConstructorSubstitution.create(type.constructor, newArguments).buildSubstitutor() + for (index in arguments.indices) { + val oldProjection = arguments[index] + val newProjection = newArguments[index] + + if (oldProjection.projectionKind == Variance.INVARIANT) continue + var upperBounds = type.constructor.parameters[index].upperBounds.map { + NewKotlinTypeChecker.transformToNewType(substitutor.safeSubstitute(it, Variance.INVARIANT).unwrap()) + } + if (!oldProjection.isStarProjection && oldProjection.projectionKind == Variance.OUT_VARIANCE) { + upperBounds += NewKotlinTypeChecker.transformToNewType(oldProjection.type.unwrap()) + } + + val capturedType = newProjection.type as NewCapturedType + capturedType.constructor.initializeSupertypes(upperBounds) + acceptNewCapturedType(index, capturedType) + } + + return KotlinTypeFactory.simpleType(type.annotations, type.constructor, newArguments, type.isMarkedNullable) +} + +enum class CaptureStatus { + FOR_SUBTYPING, + FROM_EXPRESSION +} + +/** + * Now [lowerType] is not null only for in projections. + * Example: `Inv` For `in String` we create CapturedType with [lowerType] = String. + * + * TODO: interface D, D<*, List> -> D> + * We should set [lowerType] for Q as Number. For this we should use constraint system. + * + */ +class NewCapturedType( + val captureStatus: CaptureStatus, + override val constructor: NewCapturedTypeConstructor, + val lowerType: UnwrappedType?, + override val annotations: Annotations = Annotations.EMPTY, + override val isMarkedNullable: Boolean = false +): SimpleType() { + + constructor(captureStatus: CaptureStatus, lowerType: UnwrappedType?, projection: TypeProjection): this(captureStatus, NewCapturedTypeConstructor(projection), lowerType) + + override val arguments: List get() = listOf() + override val memberScope: MemberScope // todo what about foo().bar() where foo() return captured type? + get() = ErrorUtils.createErrorScope("No member resolution should be done on captured type!", true) + override val isError: Boolean get() = false + + override fun replaceAnnotations(newAnnotations: Annotations) = + NewCapturedType(captureStatus, constructor, lowerType, newAnnotations, isMarkedNullable) + + override fun makeNullableAsSpecified(newNullability: Boolean) = + NewCapturedType(captureStatus, constructor, lowerType, annotations, newNullability) +} + +class NewCapturedTypeConstructor(val projection: TypeProjection, private var supertypes: List? = null) : TypeConstructor { + fun initializeSupertypes(supertypes: List) { + assert(this.supertypes == null) { + "Already initialized! oldValue = ${this.supertypes}, newValue = $supertypes" + } + this.supertypes = supertypes + } + + override fun getSupertypes() = supertypes ?: emptyList() + override fun getParameters(): List = emptyList() + + override fun isFinal() = false + override fun isDenotable() = false + override fun getDeclarationDescriptor(): ClassifierDescriptor? = null + override fun getBuiltIns(): KotlinBuiltIns = projection.type.builtIns + override val annotations: Annotations get() = Annotations.EMPTY + + override fun toString() = "CapturedType($projection)" + +} \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt new file mode 100644 index 00000000000..68d8bf1d9ae --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt @@ -0,0 +1,397 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.types.checker + +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor +import org.jetbrains.kotlin.resolve.calls.inference.CapturedType +import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.checker.TypeCheckerContext.SupertypesPolicy +import org.jetbrains.kotlin.types.typeUtil.asTypeProjection +import org.jetbrains.kotlin.types.typeUtil.makeNullable +import org.jetbrains.kotlin.utils.SmartList +import org.jetbrains.kotlin.utils.addToStdlib.check + +object StrictEqualityTypeChecker { + /** + * String! != String & A != A, also A != A + * also A<*> != A + * different error types non-equals even errorTypeEqualToAnything + */ + fun strictEqualTypes(a: UnwrappedType, b: UnwrappedType): Boolean { + if (a === b) return true + + if (a is SimpleType && b is SimpleType) return strictEqualTypes(a, b) + if (a is FlexibleType && b is FlexibleType) { + return strictEqualTypes(a.lowerBound, b.lowerBound) && + strictEqualTypes(a.upperBound, b.upperBound) + } + return false + } + + fun strictEqualTypes(a: SimpleType, b: SimpleType): Boolean { + if (a.isMarkedNullable != b.isMarkedNullable + || a.constructor != b.constructor + || a.arguments.size != b.arguments.size + ) { + return false + } + for (i in a.arguments.indices) { + val aArg = a.arguments[i] + val bArg = b.arguments[i] + if (aArg.isStarProjection != bArg.isStarProjection) return false + + // both non-star + if (!aArg.isStarProjection) { + if (aArg.projectionKind != bArg.projectionKind) return false + if (!strictEqualTypes(aArg.type.unwrap(), bArg.type.unwrap())) return false + } + } + return true + } + +} + +object ErrorTypesAreEqualToAnything : KotlinTypeChecker { + override fun isSubtypeOf(subtype: KotlinType, supertype: KotlinType): Boolean = + NewKotlinTypeChecker.run { TypeCheckerContext(true).isSubtypeOf(subtype.unwrap(), supertype.unwrap()) } + + override fun equalTypes(a: KotlinType, b: KotlinType): Boolean = + NewKotlinTypeChecker.run { TypeCheckerContext(true).equalTypes(a.unwrap(), b.unwrap()) } +} + +object NewKotlinTypeChecker : KotlinTypeChecker { + override fun isSubtypeOf(subtype: KotlinType, supertype: KotlinType): Boolean = + TypeCheckerContext(true).run { isSubtypeOf(subtype.unwrap(), supertype.unwrap()) } // todo fix flag errorTypeEqualsToAnything + override fun equalTypes(a: KotlinType, b: KotlinType): Boolean = + TypeCheckerContext(false).run { equalTypes(a.unwrap(), b.unwrap()) } + + fun TypeCheckerContext.equalTypes(a: UnwrappedType, b: UnwrappedType): Boolean { + if (a === b) return true + + return isSubtypeOf(a, b) && isSubtypeOf(b, a) + } + + fun TypeCheckerContext.isSubtypeOf(subType: UnwrappedType, superType: UnwrappedType) = + isSubtypeOf(subType.lowerIfFlexible(), superType.upperIfFlexible()) + + fun TypeCheckerContext.isSubtypeOf(subType: SimpleType, superType: SimpleType): Boolean { + return isSubtypeOfForNewTypes(transformToNewType(subType), transformToNewType(superType)) + } + + fun transformToNewType(type: SimpleType): SimpleType { + if (type is CapturedType) { + val lowerType = type.typeProjection.check { it.projectionKind == Variance.IN_VARIANCE }?.type?.unwrap() + + // it is incorrect calculate this type directly because of recursive star projections + if (type.constructor.newTypeConstructor == null) { + type.constructor.newTypeConstructor = NewCapturedTypeConstructor(type.typeProjection, type.constructor.supertypes.map { it.unwrap() }) + } + val newCapturedType = NewCapturedType(CaptureStatus.FOR_SUBTYPING, type.constructor.newTypeConstructor!!, + lowerType, type.annotations, type.isMarkedNullable) + return newCapturedType + } + + if (type.constructor is IntersectionTypeConstructor && type.isMarkedNullable) { + val newSuperTypes = type.constructor.supertypes.map { it.makeNullable() } + val newConstructor = IntersectionTypeConstructor(newSuperTypes) + return KotlinTypeFactory.simpleType(type.annotations, newConstructor, listOf(), false, newConstructor.createScopeForKotlinType()) + } + + if (type.constructor is IntegerValueTypeConstructor) { + val newConstructor = IntersectionTypeConstructor(type.constructor.supertypes.map { TypeUtils.makeNullableAsSpecified(it, type.isMarkedNullable) }) + return KotlinTypeFactory.simpleType(type.annotations, newConstructor, listOf(), false, type.memberScope) + } + + return type + } + + fun transformToNewType(type: UnwrappedType): UnwrappedType = + when (type) { + is SimpleType -> transformToNewType(type) + is FlexibleType -> { + val newLower = transformToNewType(type.lowerBound) + val newUpper = transformToNewType(type.upperBound) + if (newLower !== type.lowerBound || newUpper !== type.upperBound) { + KotlinTypeFactory.flexibleType(newLower, newUpper) + } + else { + type + } + } + } + + private fun TypeCheckerContext.isSubtypeOfForNewTypes(subType: SimpleType, superType: SimpleType): Boolean { + if (isSubtypeByExternalRule(subType, superType)) return true // todo: do not call this for T? <: String? + + if (subType.isError || superType.isError) { + if (errorTypeEqualsToAnything) return true + + if (subType.isMarkedNullable && !superType.isMarkedNullable) return false + + return StrictEqualityTypeChecker.strictEqualTypes(subType.makeNullableAsSpecified(false), superType.makeNullableAsSpecified(false)) + } + + if (superType is NewCapturedType && superType.lowerType != null && isSubtypeOf(subType, superType.lowerType)) return true + + (superType.constructor as? IntersectionTypeConstructor)?.let { + assert(!superType.isMarkedNullable) { "Intersection type should not be marked nullable!: $superType" } + return it.supertypes.all { isSubtypeOf(subType, it.unwrap()) } + } + + return isSubtypeOfForSingleClassifierType(subType, superType) + } + + private fun TypeCheckerContext.hasNothingSupertype(type: SimpleType) = // todo add tests + anySupertype(type, KotlinBuiltIns::isNothingOrNullableNothing) { + if (it.isClassType) { + SupertypesPolicy.None + } + else { + SupertypesPolicy.LowerIfFlexible + } + } + + private fun TypeCheckerContext.isSubtypeOfForSingleClassifierType(subType: SimpleType, superType: SimpleType): Boolean { + assert(subType.isSingleClassifierType || subType.isIntersectionType) { "Not singleClassifierType and not intersection subType: $subType" } + assert(superType.isSingleClassifierType) { "Not singleClassifierType superType: $superType" } + + if (!NullabilityChecker.isPossibleSubtype(this, subType, superType)) return false + + val superConstructor = superType.constructor + val supertypesWithSameConstructor = findCorrespondingSupertypes(subType, superConstructor) + when (supertypesWithSameConstructor.size) { + 0 -> return hasNothingSupertype(subType) // todo Nothing & Array <: Array + 1 -> return isSubtypeForSameConstructor(supertypesWithSameConstructor.first().arguments, superType) + + else -> { // at least 2 supertypes with same constructors. Such case is rare + if (supertypesWithSameConstructor.any { isSubtypeForSameConstructor(it.arguments, superType) }) return true + + val newArguments = superConstructor.parameters.mapIndexed { index, parameterDescriptor -> + val allProjections = supertypesWithSameConstructor.map { + it.arguments.getOrNull(index)?.check { it.projectionKind == Variance.INVARIANT }?.type?.unwrap() + ?: error("Incorrect type: $it, subType: $subType, superType: $superType") + } + + // todo discuss + intersectTypes(allProjections).asTypeProjection() + } + + return isSubtypeForSameConstructor(newArguments, superType) + } + } + } + + // nullability was checked earlier via nullabilityChecker + private fun TypeCheckerContext.findCorrespondingSupertypes( + baseType: SimpleType, + constructor: TypeConstructor + ): List { + fun TypeCheckerContext.collectAndFilter(classType: SimpleType, constructor: TypeConstructor) = + selectOnlyPureKotlinSupertypes(collectAllSupertypesWithGivenTypeConstructor(classType, constructor)) + + if (baseType.isClassType) { + return collectAndFilter(baseType, constructor) + } + + // i.e. superType is not a classType + if (constructor !is ClassDescriptor) { + return collectAllSupertypesWithGivenTypeConstructor(baseType, constructor) + } + + // todo add tests + val classTypeSupertypes = SmartList() + anySupertype(baseType, { false }) { + if (it.isClassType) { + classTypeSupertypes.add(it) + SupertypesPolicy.None + } + else { + SupertypesPolicy.LowerIfFlexible + } + } + + return classTypeSupertypes.flatMap { collectAndFilter(it, constructor) } + } + + private fun TypeCheckerContext.collectAllSupertypesWithGivenTypeConstructor( + baseType: SimpleType, + constructor: TypeConstructor + ): List { + + var result: MutableList? = null + + anySupertype(baseType, { false }) { + val current = captureFromArguments(it, CaptureStatus.FOR_SUBTYPING) + + if (current.constructor == constructor) { + if (result == null) { + result = SmartList() + } + result!!.add(current) + + SupertypesPolicy.None + } + else if (current.arguments.isEmpty()) { + SupertypesPolicy.LowerIfFlexible + } + else { + SupertypesPolicy.LowerIfFlexibleWithCustomSubstitutor(TypeConstructorSubstitution.create(current).buildSubstitutor()) + } + } + + return result ?: emptyList() + } + + /** + * If we have several paths to some interface, we should prefer pure kotlin path. + * Example: + * + * class MyList : AbstractList(), MutableList + * + * We should see `String` in `get` function and others, also MyList is not subtype of MutableList + * + * More tests: javaAndKotlinSuperType & purelyImplementedCollection folder + */ + private fun selectOnlyPureKotlinSupertypes(supertypes: List): List { + if (supertypes.size < 2) return supertypes + + val allPureSupertypes = supertypes.filter { it.arguments.all { !it.type.isFlexible() } } + if (allPureSupertypes.isNotEmpty()) { + return allPureSupertypes + } + else { + return supertypes + } + } + + private fun effectiveVariance(declared: Variance, useSite: Variance): Variance? { + if (declared == Variance.INVARIANT) return useSite + if (useSite == Variance.INVARIANT) return declared + + // both not INVARIANT + if (declared == useSite) return declared + + // composite In with Out + return null + } + + private fun TypeCheckerContext.isSubtypeForSameConstructor( + capturedSubArguments: List, + superType: SimpleType + ): Boolean { + val parameters = superType.constructor.parameters + + for (index in parameters.indices) { + val superProjection = superType.arguments[index] // todo error index + if (superProjection.isStarProjection) continue // A <: A<*> + + val superArgumentType = superProjection.type.unwrap() + val subArgumentType = capturedSubArguments[index].let { + assert(it.projectionKind == Variance.INVARIANT) { "Incorrect sub argument: $it" } + it.type.unwrap() + } + + val variance = effectiveVariance(parameters[index].variance, superProjection.projectionKind) + ?: return errorTypeEqualsToAnything // todo exception? + + val correctArgument = runWithArgumentsSettings(subArgumentType) { + when (variance) { + Variance.INVARIANT -> equalTypes(subArgumentType, superArgumentType) + Variance.OUT_VARIANCE -> isSubtypeOf(subArgumentType, superArgumentType) + Variance.IN_VARIANCE -> isSubtypeOf(superArgumentType, subArgumentType) + } + } + if (!correctArgument) return false + } + return true + } + +} + + +object NullabilityChecker { + + // this method checks only nullability + fun isPossibleSubtype(context: TypeCheckerContext, subType: SimpleType, superType: SimpleType): Boolean = + context.runIsPossibleSubtype(subType, superType) + + private fun TypeCheckerContext.runIsPossibleSubtype(subType: SimpleType, superType: SimpleType): Boolean { + // it makes for case String? & Any <: String + assert(subType.isIntersectionType || subType.isSingleClassifierType) {"Not singleClassifierType superType: $superType"} + assert(superType.isSingleClassifierType) {"Not singleClassifierType superType: $superType"} + + // superType is actually nullable + if (superType.isMarkedNullable) return true + + // i.e. subType is not-nullable + if (hasNotNullSupertype(subType, SupertypesPolicy.LowerIfFlexible)) return true + + // i.e subType hasn't not-null supertype, but superType has + if (hasNotNullSupertype(superType, SupertypesPolicy.UpperIfFlexible)) return false + + // both superType and subType hasn't not-null supertype. + + /** + * If we still don't know, it means, that superType is not classType, for example -- type parameter. + * + * For captured types with lower bound this function can give to you false result. Example: + * class A, A => \exist Q : Number <: Q. A + * isPossibleSubtype(Number, Q) = false. + * Such cases should be taken in to account in [NewKotlinTypeChecker.isSubtypeOf] (same for intersection types) + */ + + // classType cannot has special type in supertype list + if (subType.isClassType) return false + + return hasPathByNotMarkedNullableNodes(subType, superType.constructor) + } + + private fun TypeCheckerContext.hasNotNullSupertype(type: SimpleType, supertypesPolicy: SupertypesPolicy) = + anySupertype(type, { it.isClassType && !it.isMarkedNullable }) { + if (it.isMarkedNullable) SupertypesPolicy.None else supertypesPolicy + } + + private fun TypeCheckerContext.hasPathByNotMarkedNullableNodes(start: SimpleType, end: TypeConstructor) = + anySupertype(start, { !it.isMarkedNullable && it.constructor == end }) { + if (it.isMarkedNullable) SupertypesPolicy.None else SupertypesPolicy.LowerIfFlexible + } + +} + +/** + * ClassType means that type constructor for this type is type for real class or interface + */ +private val SimpleType.isClassType: Boolean get() = constructor.declarationDescriptor is ClassDescriptor + +/** + * SingleClassifierType is one of the following types: + * - classType + * - type for type parameter + * - captured type + * + * Such types can contains error types in our arguments, but type constructor isn't errorTypeConstructor + */ +private val SimpleType.isSingleClassifierType: Boolean + get() = !isError && + constructor.declarationDescriptor !is TypeAliasDescriptor && + (constructor.declarationDescriptor != null || this is CapturedType || this is NewCapturedType) + +private val SimpleType.isIntersectionType: Boolean + get() = constructor is IntersectionTypeConstructor \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/TypeCheckerContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/TypeCheckerContext.kt new file mode 100644 index 00000000000..7da03ea34e1 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/TypeCheckerContext.kt @@ -0,0 +1,116 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.types.checker + +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.utils.SmartSet +import org.jetbrains.kotlin.utils.addToStdlib.check +import java.util.* + +open class TypeCheckerContext(val errorTypeEqualsToAnything: Boolean) { + protected var argumentsDepth = 0 + + private var supertypesLocked = false + private var supertypesDeque: ArrayDeque? = null + private var supertypesSet: MutableSet? = null + + open fun isSubtypeByExternalRule(subType: SimpleType, superType: SimpleType) = false + + inline fun runWithArgumentsSettings(subArgument: UnwrappedType, f: TypeCheckerContext.() -> T): T { + if (argumentsDepth > 100) { + error("Arguments depth is too high. Some related argument: $subArgument") + } + + argumentsDepth++ + val result = f() + argumentsDepth-- + return result + } + + private fun initialize() { + assert(!supertypesLocked) + supertypesLocked = true + + if (supertypesDeque == null) { + supertypesDeque = ArrayDeque() + } + if (supertypesSet == null) { + supertypesSet = SmartSet.create() + } + } + + private fun clear() { + supertypesDeque!!.clear() + supertypesSet!!.clear() + supertypesLocked = false + } + + internal fun anySupertype( + start: SimpleType, + predicate: (SimpleType) -> Boolean, + supertypesPolicy: (SimpleType) -> SupertypesPolicy + ): Boolean { + initialize() + + val deque = supertypesDeque!! + val visitedSupertypes = supertypesSet!! + + deque.push(start) + while (deque.isNotEmpty()) { + if (visitedSupertypes.size > 1000) { + error("Too many supertypes for type: $start. Supertypes = ${visitedSupertypes.joinToString()}") + } + val current = deque.pop() + + if (!visitedSupertypes.add(current)) { + continue + } + + if (predicate(current)) { + clear() + return true + } + + val policy = supertypesPolicy(current).check { it != SupertypesPolicy.None } ?: continue + for (supertype in current.constructor.supertypes) deque.add(policy.transformType(supertype)) + } + + clear() + return false + } + + internal sealed class SupertypesPolicy { + abstract fun transformType(type: KotlinType): SimpleType + + object None : SupertypesPolicy() { + override fun transformType(type: KotlinType) = throw UnsupportedOperationException("Should not be called") + } + + object UpperIfFlexible : SupertypesPolicy() { + override fun transformType(type: KotlinType) = type.upperIfFlexible() + } + + object LowerIfFlexible : SupertypesPolicy() { + override fun transformType(type: KotlinType) = type.lowerIfFlexible() + } + + class LowerIfFlexibleWithCustomSubstitutor(val substitutor: TypeSubstitutor): SupertypesPolicy() { + override fun transformType(type: KotlinType) = + substitutor.safeSubstitute(type.lowerIfFlexible(), Variance.INVARIANT).asSimpleType() + } + } +} \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/flexibleTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/types/flexibleTypes.kt index 3edc1fe9e2b..9ef7d82e2d2 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/flexibleTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/flexibleTypes.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRendererOptions +import org.jetbrains.kotlin.types.checker.ErrorTypesAreEqualToAnything import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.typeUtil.builtIns @@ -49,7 +50,7 @@ fun Collection.singleBestRepresentative(): KotlinType? { other -> // We consider error types equal to anything here, so that intersections like // {Array, Array<[ERROR]>} work correctly - candidate == other || KotlinTypeChecker.ERROR_TYPES_ARE_EQUAL_TO_ANYTHING.equalTypes(candidate, other) + candidate == other || ErrorTypesAreEqualToAnything.equalTypes(candidate, other) } } } diff --git a/core/util.runtime/src/org/jetbrains/kotlin/utils/functions.kt b/core/util.runtime/src/org/jetbrains/kotlin/utils/functions.kt index cf3b793995f..8b720b882e5 100644 --- a/core/util.runtime/src/org/jetbrains/kotlin/utils/functions.kt +++ b/core/util.runtime/src/org/jetbrains/kotlin/utils/functions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ private val ALWAYS_NULL: (Any?) -> Any? = { null } fun alwaysNull(): (T) -> R? = ALWAYS_NULL as (T) -> R? val DO_NOTHING: (Any?) -> Unit = { } +val DO_NOTHING_2: (Any?, Any?) -> Unit = { x, y -> } val DO_NOTHING_3: (Any?, Any?, Any?) -> Unit = { x, y, z -> } fun doNothing(): (T) -> Unit = DO_NOTHING diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt index 9b83ce0f7d4..7f1a89fbcac 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.CallHandle import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind import org.jetbrains.kotlin.types.* -import org.jetbrains.kotlin.types.checker.KotlinTypeChecker +import org.jetbrains.kotlin.types.checker.StrictEqualityTypeChecker import org.jetbrains.kotlin.types.typeUtil.* import java.util.* @@ -53,7 +53,7 @@ fun FuzzyType.presentationType(): KotlinType { for ((argument, typeParameter) in type.arguments.zip(type.constructor.parameters)) { if (argument.projectionKind == Variance.INVARIANT) { val equalToFreeParameter = freeParameters.firstOrNull { - KotlinTypeChecker.FLEXIBLE_UNEQUAL_TO_INFLEXIBLE.equalTypes(it.defaultType, argument.type) + StrictEqualityTypeChecker.strictEqualTypes(it.defaultType, argument.type.unwrap()) } ?: continue map[equalToFreeParameter.typeConstructor] = createProjection(typeParameter.defaultType, Variance.INVARIANT, null) @@ -186,7 +186,7 @@ fun TypeSubstitution.hasConflictWith(other: TypeSubstitution, freeParameters: Co val type = parameter.defaultType val substituted1 = this[type] ?: return@any false val substituted2 = other[type] ?: return@any false - !KotlinTypeChecker.FLEXIBLE_UNEQUAL_TO_INFLEXIBLE.equalTypes(substituted1.type, substituted2.type) || substituted1.projectionKind != substituted2.projectionKind + !StrictEqualityTypeChecker.strictEqualTypes(substituted1.type.unwrap(), substituted2.type.unwrap()) || substituted1.projectionKind != substituted2.projectionKind } } diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/DynamicTypeDeserializer.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/DynamicTypeDeserializer.kt index c3a24b123ee..a8dcf56b792 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/DynamicTypeDeserializer.kt +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/DynamicTypeDeserializer.kt @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializ import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.SimpleType -import org.jetbrains.kotlin.types.checker.KotlinTypeChecker +import org.jetbrains.kotlin.types.checker.StrictEqualityTypeChecker import org.jetbrains.kotlin.types.createDynamicType import org.jetbrains.kotlin.types.typeUtil.builtIns @@ -30,8 +30,8 @@ object DynamicTypeDeserializer : FlexibleTypeDeserializer { override fun create(proto: ProtoBuf.Type, flexibleId: String, lowerBound: SimpleType, upperBound: SimpleType): KotlinType { if (flexibleId != id) return ErrorUtils.createErrorType("Unexpected id: $flexibleId. ($lowerBound..$upperBound)") - if (KotlinTypeChecker.FLEXIBLE_UNEQUAL_TO_INFLEXIBLE.equalTypes(lowerBound, lowerBound.builtIns.nothingType) && - KotlinTypeChecker.FLEXIBLE_UNEQUAL_TO_INFLEXIBLE.equalTypes(upperBound, upperBound.builtIns.nullableAnyType)) { + if (StrictEqualityTypeChecker.strictEqualTypes(lowerBound, lowerBound.builtIns.nothingType) && + StrictEqualityTypeChecker.strictEqualTypes(upperBound, upperBound.builtIns.nullableAnyType)) { return createDynamicType(lowerBound.builtIns) } else {