Optimize type checking for common cases

- Type equality for simple constructors (no arguments)
- Subtyping on final classes
This commit is contained in:
Denis Zharkov
2017-09-28 18:57:53 +03:00
parent e519095e9e
commit bca53e6c1c
5 changed files with 32 additions and 6 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ package localObjects {
~x~val x : Int ~x~val x : Int
} }
class Foo { open class Foo {
~foo()~fun foo() : Int ~foo()~fun foo() : Int
} }
+1 -1
View File
@@ -1,6 +1,6 @@
package toplevelObjectDeclarations package toplevelObjectDeclarations
class Foo(y : Int) { open class Foo(y : Int) {
~foo()~open fun foo() : Int = 1 ~foo()~open fun foo() : Int = 1
} }
@@ -40,7 +40,7 @@ fun f_plus(): Int {
1 `contains`!in x 1 `contains`!in x
} }
~Foo~class Foo { open ~Foo~class Foo {
~set1~fun set(i : Int, val1 : String) {} ~set1~fun set(i : Int, val1 : String) {}
~get1~fun get(i : Int) : Int {} ~get1~fun get(i : Int) : Int {}
~get2~fun get(i : Int, j : Int) : String {} ~get2~fun get(i : Int, j : Int) : String {}
@@ -92,4 +92,4 @@ fun testUnitIncDec() {
var x = UnitIncDec() var x = UnitIncDec()
x`uinc`++ x`uinc`++
x`udec`-- x`udec`--
} }
@@ -346,7 +346,7 @@ public class TypeUtils {
} }
public static boolean equalTypes(@NotNull KotlinType a, @NotNull KotlinType b) { public static boolean equalTypes(@NotNull KotlinType a, @NotNull KotlinType b) {
return KotlinTypeChecker.DEFAULT.isSubtypeOf(a, b) && KotlinTypeChecker.DEFAULT.isSubtypeOf(b, a); return KotlinTypeChecker.DEFAULT.equalTypes(a, b);
} }
public static boolean dependsOnTypeParameters(@NotNull KotlinType type, @NotNull Collection<TypeParameterDescriptor> typeParameters) { public static boolean dependsOnTypeParameters(@NotNull KotlinType type, @NotNull Collection<TypeParameterDescriptor> typeParameters) {
@@ -18,7 +18,9 @@ package org.jetbrains.kotlin.types.checker
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
import org.jetbrains.kotlin.descriptors.isFinalClass
import org.jetbrains.kotlin.resolve.calls.inference.CapturedType import org.jetbrains.kotlin.resolve.calls.inference.CapturedType
import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructor import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructor
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
@@ -29,6 +31,7 @@ import org.jetbrains.kotlin.types.checker.TypeCheckerContext.SupertypesPolicy
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object StrictEqualityTypeChecker { object StrictEqualityTypeChecker {
/** /**
@@ -91,9 +94,24 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
fun TypeCheckerContext.equalTypes(a: UnwrappedType, b: UnwrappedType): Boolean { fun TypeCheckerContext.equalTypes(a: UnwrappedType, b: UnwrappedType): Boolean {
if (a === b) return true if (a === b) return true
if (isCommonDenotableType(a) && isCommonDenotableType(b)) {
if (!areEqualTypeConstructors(a.constructor, b.constructor)) return false
if (a.arguments.isEmpty()) {
if (a.hasFlexibleNullability() || b.hasFlexibleNullability()) return true
return a.isMarkedNullable == b.isMarkedNullable
}
}
return isSubtypeOf(a, b) && isSubtypeOf(b, a) return isSubtypeOf(a, b) && isSubtypeOf(b, a)
} }
private fun KotlinType.hasFlexibleNullability() =
lowerIfFlexible().isMarkedNullable != upperIfFlexible().isMarkedNullable
private fun isCommonDenotableType(type: KotlinType) =
type.constructor.isDenotable && !type.isDynamic() && type.lowerIfFlexible().constructor == type.upperIfFlexible().constructor
fun TypeCheckerContext.isSubtypeOf(subType: UnwrappedType, superType: UnwrappedType): Boolean { fun TypeCheckerContext.isSubtypeOf(subType: UnwrappedType, superType: UnwrappedType): Boolean {
val newSubType = transformToNewType(subType) val newSubType = transformToNewType(subType)
val newSuperType = transformToNewType(superType) val newSuperType = transformToNewType(superType)
@@ -266,6 +284,12 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
baseType: SimpleType, baseType: SimpleType,
constructor: TypeConstructor constructor: TypeConstructor
): List<SimpleType> { ): List<SimpleType> {
if (constructor.declarationDescriptor.safeAs<ClassDescriptor>()?.isCommonFinalClass == true) {
return if (areEqualTypeConstructors(baseType.constructor, constructor))
listOf(captureFromArguments(baseType, CaptureStatus.FOR_SUBTYPING) ?: baseType)
else
emptyList()
}
var result: MutableList<SimpleType>? = null var result: MutableList<SimpleType>? = null
@@ -293,6 +317,9 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
return result ?: emptyList() return result ?: emptyList()
} }
private val ClassDescriptor.isCommonFinalClass: Boolean
get() = isFinalClass && kind != ClassKind.ENUM_ENTRY
/** /**
* If we have several paths to some interface, we should prefer pure kotlin path. * If we have several paths to some interface, we should prefer pure kotlin path.
* Example: * Example:
@@ -357,7 +384,6 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
} }
object NullabilityChecker { object NullabilityChecker {
// this method checks only nullability // this method checks only nullability