Introduce new type checker.
This commit is contained in:
@@ -50,6 +50,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver
|
|||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.TypeUtils.noExpectedType
|
import org.jetbrains.kotlin.types.TypeUtils.noExpectedType
|
||||||
|
import org.jetbrains.kotlin.types.checker.ErrorTypesAreEqualToAnything
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -178,7 +179,7 @@ class CandidateResolver(
|
|||||||
// TODO: use constraint system to check if candidateKCallableType can be a subtype of expectedType
|
// TODO: use constraint system to check if candidateKCallableType can be a subtype of expectedType
|
||||||
val substituteDontCare = makeConstantSubstitutor(candidateTypeParameters, TypeUtils.DONT_CARE)
|
val substituteDontCare = makeConstantSubstitutor(candidateTypeParameters, TypeUtils.DONT_CARE)
|
||||||
val subTypeSubstituted = substituteDontCare.substitute(subType, Variance.INVARIANT) ?: return true
|
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 {
|
private fun CallCandidateResolutionContext<*>.checkVisibilityWithoutReceiver() = checkAndReport {
|
||||||
|
|||||||
@@ -132,14 +132,14 @@ public class TypeIntersector {
|
|||||||
return TypeUtils.makeNullableAsSpecified(resultingTypes.get(0), allNullable);
|
return TypeUtils.makeNullableAsSpecified(resultingTypes.get(0), allNullable);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeConstructor constructor = new IntersectionTypeConstructor(Annotations.Companion.getEMPTY(), resultingTypes);
|
IntersectionTypeConstructor constructor = new IntersectionTypeConstructor(resultingTypes);
|
||||||
|
|
||||||
return KotlinTypeFactory.simpleType(
|
return KotlinTypeFactory.simpleType(
|
||||||
Annotations.Companion.getEMPTY(),
|
Annotations.Companion.getEMPTY(),
|
||||||
constructor,
|
constructor,
|
||||||
Collections.<TypeProjection>emptyList(),
|
Collections.<TypeProjection>emptyList(),
|
||||||
allNullable,
|
allNullable,
|
||||||
TypeIntersectionScope.create("member scope for intersection type " + constructor, resultingTypes)
|
constructor.createScopeForKotlinType()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.types
|
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.
|
* This is temporary hack for type intersector.
|
||||||
@@ -33,7 +33,7 @@ internal fun hackForTypeIntersector(types: Collection<KotlinType>): KotlinType?
|
|||||||
|
|
||||||
return types.firstOrNull { candidate ->
|
return types.firstOrNull { candidate ->
|
||||||
types.all {
|
types.all {
|
||||||
KotlinTypeChecker.ERROR_TYPES_ARE_EQUAL_TO_ANYTHING.isSubtypeOf(candidate, it)
|
ErrorTypesAreEqualToAnything.isSubtypeOf(candidate, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
// FILE: A.java
|
||||||
|
public interface A<T> {
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: B.java
|
||||||
|
public class B implements A<String> {
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: 1.kt
|
||||||
|
class C: B()
|
||||||
|
|
||||||
|
class D: B(), A<String>
|
||||||
|
class E: B(), A<String?>
|
||||||
|
|
||||||
|
fun eatAString(a: A<String>) {}
|
||||||
|
fun eatAStringN(a: A<String?>) {}
|
||||||
|
|
||||||
|
fun test(b: B, c: C, d: D, e: E) {
|
||||||
|
eatAString(b)
|
||||||
|
eatAString(c)
|
||||||
|
eatAString(d)
|
||||||
|
eatAString(<!TYPE_MISMATCH!>e<!>)
|
||||||
|
|
||||||
|
eatAStringN(b)
|
||||||
|
eatAStringN(c)
|
||||||
|
eatAStringN(<!TYPE_MISMATCH!>d<!>)
|
||||||
|
eatAStringN(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: 3.kt
|
||||||
|
|
||||||
|
interface X : A<String>
|
||||||
|
interface Y: X
|
||||||
|
interface Z: X
|
||||||
|
|
||||||
|
class W: B(), Z
|
||||||
|
|
||||||
|
fun test2(w: W) {
|
||||||
|
eatAString(w)
|
||||||
|
eatAStringN(<!TYPE_MISMATCH!>w<!>)
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun eatAString(/*0*/ a: A<kotlin.String>): kotlin.Unit
|
||||||
|
public fun eatAStringN(/*0*/ a: A<kotlin.String?>): 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</*0*/ T : kotlin.Any!> {
|
||||||
|
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<kotlin.String!> {
|
||||||
|
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<kotlin.String> {
|
||||||
|
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<kotlin.String?> {
|
||||||
|
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<kotlin.String> {
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -18921,6 +18921,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("kt2069.kt")
|
||||||
public void testKt2069() throws Exception {
|
public void testKt2069() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/subtyping/kt2069.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/subtyping/kt2069.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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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<in Int>", "Base_T<Int>", "Base_T<in Int>");
|
assertCommonSupertype("Base_T<in Int>", "Base_T<Int>", "Base_T<in Int>");
|
||||||
assertCommonSupertype("Base_T<in Int>", "Derived_T<Int>", "Base_T<in Int>");
|
assertCommonSupertype("Base_T<in Int>", "Derived_T<Int>", "Base_T<in Int>");
|
||||||
assertCommonSupertype("Base_T<in Int>", "Derived_T<in Int>", "Base_T<Int>");
|
assertCommonSupertype("Base_T<in Int>", "Derived_T<in Int>", "Base_T<Int>");
|
||||||
assertCommonSupertype("Base_T<*>", "Base_T<Int>", "Base_T<*>");
|
assertCommonSupertype("Base_T<out Any?>", "Base_T<Int>", "Base_T<*>");
|
||||||
|
|
||||||
assertCommonSupertype("Base_T<out Parent>", "Base_T<A>", "Base_T<B>");
|
assertCommonSupertype("Base_T<out Parent>", "Base_T<A>", "Base_T<B>");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCommonSupertypesForRecursive() throws Exception {
|
public void testCommonSupertypesForRecursive() throws Exception {
|
||||||
assertCommonSupertype("Rec<out Rec<out Rec<out Rec<out Rec<out Any?>>>>>", "ARec", "BRec");
|
assertCommonSupertype("Rec<out Rec<out Rec<out Rec<out Rec<*>>>>>", "ARec", "BRec");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testIntersect() throws Exception {
|
public void testIntersect() throws Exception {
|
||||||
|
|||||||
+5
-2
@@ -24,11 +24,14 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
|||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.Variance.IN_VARIANCE
|
import org.jetbrains.kotlin.types.Variance.IN_VARIANCE
|
||||||
import org.jetbrains.kotlin.types.Variance.OUT_VARIANCE
|
import org.jetbrains.kotlin.types.Variance.OUT_VARIANCE
|
||||||
|
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
|
||||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
|
|
||||||
class CapturedTypeConstructor(
|
class CapturedTypeConstructor(
|
||||||
val typeProjection: TypeProjection
|
val typeProjection: TypeProjection
|
||||||
): TypeConstructor {
|
): TypeConstructor {
|
||||||
|
var newTypeConstructor: NewCapturedTypeConstructor? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
assert(typeProjection.projectionKind != Variance.INVARIANT) {
|
assert(typeProjection.projectionKind != Variance.INVARIANT) {
|
||||||
"Only nontrivial projections can be captured, not: $typeProjection"
|
"Only nontrivial projections can be captured, not: $typeProjection"
|
||||||
@@ -59,8 +62,8 @@ class CapturedTypeConstructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CapturedType(
|
class CapturedType(
|
||||||
private val typeProjection: TypeProjection,
|
val typeProjection: TypeProjection,
|
||||||
override val constructor: TypeConstructor = CapturedTypeConstructor(typeProjection),
|
override val constructor: CapturedTypeConstructor = CapturedTypeConstructor(typeProjection),
|
||||||
override val isMarkedNullable: Boolean = false,
|
override val isMarkedNullable: Boolean = false,
|
||||||
override val annotations: Annotations = Annotations.EMPTY
|
override val annotations: Annotations = Annotations.EMPTY
|
||||||
): SimpleType(), SubtypingRepresentatives {
|
): SimpleType(), SubtypingRepresentatives {
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun create(message: String, types: List<KotlinType>): MemberScope {
|
fun create(message: String, types: Collection<KotlinType>): MemberScope {
|
||||||
val chainedScope = ChainedMemberScope(message, types.map { it.memberScope })
|
val chainedScope = ChainedMemberScope(message, types.map { it.memberScope })
|
||||||
if (types.size <= 1) return chainedScope
|
if (types.size <= 1) return chainedScope
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.TypeParameterDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotatedImpl;
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotatedImpl;
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.TypeIntersectionScope;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class IntersectionTypeConstructor extends AnnotatedImpl implements TypeConstructor {
|
public class IntersectionTypeConstructor implements TypeConstructor {
|
||||||
private final Set<KotlinType> intersectedTypes;
|
private final Set<KotlinType> intersectedTypes;
|
||||||
private final int hashCode;
|
private final int hashCode;
|
||||||
|
|
||||||
public IntersectionTypeConstructor(Annotations annotations, Collection<KotlinType> typesToIntersect) {
|
public IntersectionTypeConstructor(Collection<KotlinType> typesToIntersect) {
|
||||||
super(annotations);
|
|
||||||
assert !typesToIntersect.isEmpty() : "Attempt to create an empty intersection";
|
assert !typesToIntersect.isEmpty() : "Attempt to create an empty intersection";
|
||||||
|
|
||||||
this.intersectedTypes = new LinkedHashSet<KotlinType>(typesToIntersect);
|
this.intersectedTypes = new LinkedHashSet<KotlinType>(typesToIntersect);
|
||||||
@@ -49,6 +50,10 @@ public class IntersectionTypeConstructor extends AnnotatedImpl implements TypeCo
|
|||||||
return intersectedTypes;
|
return intersectedTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MemberScope createScopeForKotlinType() {
|
||||||
|
return TypeIntersectionScope.create("member scope for intersection type " + this, intersectedTypes);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFinal() {
|
public boolean isFinal() {
|
||||||
return false;
|
return false;
|
||||||
@@ -106,4 +111,9 @@ public class IntersectionTypeConstructor extends AnnotatedImpl implements TypeCo
|
|||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Annotations getAnnotations() {
|
||||||
|
return Annotations.Companion.getEMPTY();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
|||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRendererOptions
|
import org.jetbrains.kotlin.renderer.DescriptorRendererOptions
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
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].
|
* [KotlinType] has only two direct subclasses: [WrappedType] and [UnwrappedType].
|
||||||
@@ -63,7 +63,7 @@ sealed class KotlinType : Annotated {
|
|||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other !is KotlinType) return false
|
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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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>): 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>): SimpleType {
|
||||||
|
val constructor = IntersectionTypeConstructor(types)
|
||||||
|
return KotlinTypeFactory.simpleType(Annotations.EMPTY, constructor, listOf(), false, constructor.createScopeForKotlinType())
|
||||||
|
}
|
||||||
|
|
||||||
@@ -26,22 +26,7 @@ public interface KotlinTypeChecker {
|
|||||||
boolean equals(@NotNull TypeConstructor a, @NotNull TypeConstructor b);
|
boolean equals(@NotNull TypeConstructor a, @NotNull TypeConstructor b);
|
||||||
}
|
}
|
||||||
|
|
||||||
KotlinTypeChecker DEFAULT = new KotlinTypeCheckerImpl(new TypeCheckingProcedure(new TypeCheckerProcedureCallbacksImpl()));
|
KotlinTypeChecker DEFAULT = NewKotlinTypeChecker.INSTANCE;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
boolean isSubtypeOf(@NotNull KotlinType subtype, @NotNull KotlinType supertype);
|
boolean isSubtypeOf(@NotNull KotlinType subtype, @NotNull KotlinType supertype);
|
||||||
boolean equalTypes(@NotNull KotlinType a, @NotNull KotlinType b);
|
boolean equalTypes(@NotNull KotlinType a, @NotNull KotlinType b);
|
||||||
|
|||||||
@@ -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<in String>` For `in String` we create CapturedType with [lowerType] = String.
|
||||||
|
*
|
||||||
|
* TODO: interface D<T, S: List<T>, D<*, List<Number>> -> D<Q, List<Number>>
|
||||||
|
* 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<TypeProjection> 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<UnwrappedType>? = null) : TypeConstructor {
|
||||||
|
fun initializeSupertypes(supertypes: List<UnwrappedType>) {
|
||||||
|
assert(this.supertypes == null) {
|
||||||
|
"Already initialized! oldValue = ${this.supertypes}, newValue = $supertypes"
|
||||||
|
}
|
||||||
|
this.supertypes = supertypes
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSupertypes() = supertypes ?: emptyList()
|
||||||
|
override fun getParameters(): List<TypeParameterDescriptor> = 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)"
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<String!> != A<String>, also A<in Nothing> != A<out Any?>
|
||||||
|
* also A<*> != A<out Any?>
|
||||||
|
* 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<Number> <: Array<String>
|
||||||
|
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<SimpleType> {
|
||||||
|
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<SimpleType>()
|
||||||
|
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<SimpleType> {
|
||||||
|
|
||||||
|
var result: MutableList<SimpleType>? = 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<String>(), MutableList<String>
|
||||||
|
*
|
||||||
|
* We should see `String` in `get` function and others, also MyList is not subtype of MutableList<String?>
|
||||||
|
*
|
||||||
|
* More tests: javaAndKotlinSuperType & purelyImplementedCollection folder
|
||||||
|
*/
|
||||||
|
private fun selectOnlyPureKotlinSupertypes(supertypes: List<SimpleType>): List<SimpleType> {
|
||||||
|
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<TypeProjection>,
|
||||||
|
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<B> <: 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<T>, A<in Number> => \exist Q : Number <: Q. A<Q>
|
||||||
|
* 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
|
||||||
@@ -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<SimpleType>? = null
|
||||||
|
private var supertypesSet: MutableSet<SimpleType>? = null
|
||||||
|
|
||||||
|
open fun isSubtypeByExternalRule(subType: SimpleType, superType: SimpleType) = false
|
||||||
|
|
||||||
|
inline fun <T> 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRendererOptions
|
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.checker.KotlinTypeChecker
|
||||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ fun Collection<KotlinType>.singleBestRepresentative(): KotlinType? {
|
|||||||
other ->
|
other ->
|
||||||
// We consider error types equal to anything here, so that intersections like
|
// We consider error types equal to anything here, so that intersections like
|
||||||
// {Array<String>, Array<[ERROR]>} work correctly
|
// {Array<String>, Array<[ERROR]>} work correctly
|
||||||
candidate == other || KotlinTypeChecker.ERROR_TYPES_ARE_EQUAL_TO_ANYTHING.equalTypes(candidate, other)
|
candidate == other || ErrorTypesAreEqualToAnything.equalTypes(candidate, other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 <T, R: Any> alwaysNull(): (T) -> R? = ALWAYS_NULL as (T) -> R?
|
fun <T, R: Any> alwaysNull(): (T) -> R? = ALWAYS_NULL as (T) -> R?
|
||||||
|
|
||||||
val DO_NOTHING: (Any?) -> Unit = { }
|
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 -> }
|
val DO_NOTHING_3: (Any?, Any?, Any?) -> Unit = { x, y, z -> }
|
||||||
|
|
||||||
fun <T> doNothing(): (T) -> Unit = DO_NOTHING
|
fun <T> doNothing(): (T) -> Unit = DO_NOTHING
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.ConstraintSystemBuilderImpl
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind
|
||||||
import org.jetbrains.kotlin.types.*
|
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 org.jetbrains.kotlin.types.typeUtil.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ fun FuzzyType.presentationType(): KotlinType {
|
|||||||
for ((argument, typeParameter) in type.arguments.zip(type.constructor.parameters)) {
|
for ((argument, typeParameter) in type.arguments.zip(type.constructor.parameters)) {
|
||||||
if (argument.projectionKind == Variance.INVARIANT) {
|
if (argument.projectionKind == Variance.INVARIANT) {
|
||||||
val equalToFreeParameter = freeParameters.firstOrNull {
|
val equalToFreeParameter = freeParameters.firstOrNull {
|
||||||
KotlinTypeChecker.FLEXIBLE_UNEQUAL_TO_INFLEXIBLE.equalTypes(it.defaultType, argument.type)
|
StrictEqualityTypeChecker.strictEqualTypes(it.defaultType, argument.type.unwrap())
|
||||||
} ?: continue
|
} ?: continue
|
||||||
|
|
||||||
map[equalToFreeParameter.typeConstructor] = createProjection(typeParameter.defaultType, Variance.INVARIANT, null)
|
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 type = parameter.defaultType
|
||||||
val substituted1 = this[type] ?: return@any false
|
val substituted1 = this[type] ?: return@any false
|
||||||
val substituted2 = other[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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializ
|
|||||||
import org.jetbrains.kotlin.types.ErrorUtils
|
import org.jetbrains.kotlin.types.ErrorUtils
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.SimpleType
|
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.createDynamicType
|
||||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
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 {
|
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 (flexibleId != id) return ErrorUtils.createErrorType("Unexpected id: $flexibleId. ($lowerBound..$upperBound)")
|
||||||
if (KotlinTypeChecker.FLEXIBLE_UNEQUAL_TO_INFLEXIBLE.equalTypes(lowerBound, lowerBound.builtIns.nothingType) &&
|
if (StrictEqualityTypeChecker.strictEqualTypes(lowerBound, lowerBound.builtIns.nothingType) &&
|
||||||
KotlinTypeChecker.FLEXIBLE_UNEQUAL_TO_INFLEXIBLE.equalTypes(upperBound, upperBound.builtIns.nullableAnyType)) {
|
StrictEqualityTypeChecker.strictEqualTypes(upperBound, upperBound.builtIns.nullableAnyType)) {
|
||||||
return createDynamicType(lowerBound.builtIns)
|
return createDynamicType(lowerBound.builtIns)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
Reference in New Issue
Block a user