Optimize type checking for common cases
- Type equality for simple constructors (no arguments) - Subtyping on final classes
This commit is contained in:
+1
-1
@@ -3,7 +3,7 @@ package localObjects {
|
||||
~x~val x : Int
|
||||
}
|
||||
|
||||
class Foo {
|
||||
open class Foo {
|
||||
~foo()~fun foo() : Int
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package toplevelObjectDeclarations
|
||||
|
||||
class Foo(y : Int) {
|
||||
open class Foo(y : Int) {
|
||||
~foo()~open fun foo() : Int = 1
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ fun f_plus(): Int {
|
||||
1 `contains`!in x
|
||||
}
|
||||
|
||||
~Foo~class Foo {
|
||||
open ~Foo~class Foo {
|
||||
~set1~fun set(i : Int, val1 : String) {}
|
||||
~get1~fun get(i : Int) : Int {}
|
||||
~get2~fun get(i : Int, j : Int) : String {}
|
||||
@@ -92,4 +92,4 @@ fun testUnitIncDec() {
|
||||
var x = UnitIncDec()
|
||||
x`uinc`++
|
||||
x`udec`--
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +346,7 @@ public class TypeUtils {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -18,7 +18,9 @@ package org.jetbrains.kotlin.types.checker
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
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.CapturedTypeConstructor
|
||||
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.makeNullable
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
object StrictEqualityTypeChecker {
|
||||
/**
|
||||
@@ -91,9 +94,24 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
|
||||
fun TypeCheckerContext.equalTypes(a: UnwrappedType, b: UnwrappedType): Boolean {
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
val newSubType = transformToNewType(subType)
|
||||
val newSuperType = transformToNewType(superType)
|
||||
@@ -266,6 +284,12 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
|
||||
baseType: SimpleType,
|
||||
constructor: TypeConstructor
|
||||
): 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
|
||||
|
||||
@@ -293,6 +317,9 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
|
||||
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.
|
||||
* Example:
|
||||
@@ -357,7 +384,6 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
|
||||
|
||||
}
|
||||
|
||||
|
||||
object NullabilityChecker {
|
||||
|
||||
// this method checks only nullability
|
||||
|
||||
Reference in New Issue
Block a user