Extract and normalize member scope calculation
Basically it's wrong to use original types' member scope as a worker for SubstitutionScope. Member scope should always be determined by type constructor's default one and substitution/arguments #KT-10448 Fixed
This commit is contained in:
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// !CHECK_TYPE
|
||||||
|
|
||||||
|
class A<T> {
|
||||||
|
fun foo(): T = null!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <E> A<E>.bar(): A<in E> = this
|
||||||
|
|
||||||
|
fun baz(x: A<out CharSequence>) {
|
||||||
|
x.bar().foo() checkType { _<Any?>() } // See KT-10448
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun baz(/*0*/ x: A<out kotlin.CharSequence>): kotlin.Unit
|
||||||
|
public fun </*0*/ E> A<E>.bar(): A<in E>
|
||||||
|
|
||||||
|
public final class A</*0*/ T> {
|
||||||
|
public constructor A</*0*/ T>()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public final fun foo(): T
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -7997,6 +7997,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("memberScopeOfCaptured.kt")
|
||||||
|
public void testMemberScopeOfCaptured() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/memberScopeOfCaptured.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("notApproximateWhenCopyDescriptors.kt")
|
@TestMetadata("notApproximateWhenCopyDescriptors.kt")
|
||||||
public void testNotApproximateWhenCopyDescriptors() throws Exception {
|
public void testNotApproximateWhenCopyDescriptors() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/notApproximateWhenCopyDescriptors.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/notApproximateWhenCopyDescriptors.kt");
|
||||||
|
|||||||
@@ -116,10 +116,8 @@ public fun approximateCapturedTypes(type: KotlinType): ApproximationBounds<Kotli
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun KotlinType.replaceTypeArguments(newTypeArguments: List<TypeArgument>): KotlinType {
|
private fun KotlinType.replaceTypeArguments(newTypeArguments: List<TypeArgument>): KotlinType {
|
||||||
assert(getArguments().size() == newTypeArguments.size()) { "Incorrect type arguments $newTypeArguments" }
|
assert(arguments.size == newTypeArguments.size) { "Incorrect type arguments $newTypeArguments" }
|
||||||
return KotlinTypeImpl.create(
|
return replace(newTypeArguments.map { it.toTypeProjection() })
|
||||||
getAnnotations(), getConstructor(), isMarkedNullable(), newTypeArguments.map { it.toTypeProjection() }, getMemberScope()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun approximateProjection(typeArgument: TypeArgument): ApproximationBounds<TypeArgument> {
|
private fun approximateProjection(typeArgument: TypeArgument): ApproximationBounds<TypeArgument> {
|
||||||
|
|||||||
@@ -114,6 +114,43 @@ public fun KotlinType.computeNewSubstitution(
|
|||||||
return composedSubstitution
|
return composedSubstitution
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun KotlinType.replace(
|
||||||
|
newArguments: List<TypeProjection>,
|
||||||
|
annotations: Annotations = this@replace.annotations
|
||||||
|
): KotlinType {
|
||||||
|
if (newArguments.isEmpty() && annotations === this.annotations) return this
|
||||||
|
|
||||||
|
if (newArguments.isEmpty()) {
|
||||||
|
return KotlinTypeImpl.create(
|
||||||
|
annotations,
|
||||||
|
constructor,
|
||||||
|
isMarkedNullable,
|
||||||
|
arguments,
|
||||||
|
substitution,
|
||||||
|
memberScope,
|
||||||
|
capabilities
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val newSubstitution = computeNewSubstitution(constructor, newArguments)
|
||||||
|
|
||||||
|
val declarationDescriptor = constructor.declarationDescriptor
|
||||||
|
val newScope =
|
||||||
|
if (declarationDescriptor is ClassDescriptor)
|
||||||
|
declarationDescriptor.getMemberScope(newSubstitution)
|
||||||
|
else ErrorUtils.createErrorScope("Unexpected declaration descriptor for type constructor: $constructor")
|
||||||
|
|
||||||
|
return KotlinTypeImpl.create(
|
||||||
|
annotations,
|
||||||
|
constructor,
|
||||||
|
isMarkedNullable,
|
||||||
|
newArguments,
|
||||||
|
newSubstitution,
|
||||||
|
newScope,
|
||||||
|
capabilities
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private class CompositeTypeSubstitution(
|
private class CompositeTypeSubstitution(
|
||||||
private val first: TypeSubstitution,
|
private val first: TypeSubstitution,
|
||||||
private val second: TypeSubstitution
|
private val second: TypeSubstitution
|
||||||
|
|||||||
@@ -26,12 +26,10 @@ import org.jetbrains.kotlin.descriptors.annotations.CompositeAnnotations;
|
|||||||
import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations;
|
import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructorKt;
|
import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructorKt;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.SubstitutingScope;
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
||||||
import org.jetbrains.kotlin.types.typesApproximation.CapturedTypeApproximationKt;
|
import org.jetbrains.kotlin.types.typesApproximation.CapturedTypeApproximationKt;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -217,7 +215,7 @@ public class TypeSubstitutor {
|
|||||||
TypeProjection originalProjection,
|
TypeProjection originalProjection,
|
||||||
int recursionDepth
|
int recursionDepth
|
||||||
) throws SubstitutionException {
|
) throws SubstitutionException {
|
||||||
final KotlinType type = originalProjection.getType();
|
KotlinType type = originalProjection.getType();
|
||||||
Variance projectionKind = originalProjection.getProjectionKind();
|
Variance projectionKind = originalProjection.getProjectionKind();
|
||||||
if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
|
if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
|
||||||
// substitution can't change type parameter
|
// substitution can't change type parameter
|
||||||
@@ -228,25 +226,8 @@ public class TypeSubstitutor {
|
|||||||
List<TypeProjection> substitutedArguments = substituteTypeArguments(
|
List<TypeProjection> substitutedArguments = substituteTypeArguments(
|
||||||
type.getConstructor().getParameters(), type.getArguments(), recursionDepth);
|
type.getConstructor().getParameters(), type.getArguments(), recursionDepth);
|
||||||
|
|
||||||
// Only type parameters of the corresponding class (or captured type parameters of outer declaration) are substituted
|
KotlinType substitutedType =
|
||||||
// e.g. for return type Foo of 'add(..)' in 'class Foo { fun <R> add(bar: Bar<R>): Foo }' R shouldn't be substituted in the scope
|
TypeSubstitutionKt.replace(type, substitutedArguments, substitution.filterAnnotations(type.getAnnotations()));
|
||||||
TypeSubstitution substitutionFilteringTypeParameters = new DelegatedTypeSubstitution(substitution) {
|
|
||||||
private final Collection<TypeConstructor> containedOrCapturedTypeParameters =
|
|
||||||
TypeUtilsKt.getContainedAndCapturedTypeParameterConstructors(type);
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public TypeProjection get(@NotNull KotlinType key) {
|
|
||||||
return containedOrCapturedTypeParameters.contains(key.getConstructor()) ? substitution.get(key) : null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
KotlinType substitutedType = KotlinTypeImpl.create(substitution.filterAnnotations(type.getAnnotations()), // Old annotations. This is questionable
|
|
||||||
type.getConstructor(), // The same constructor
|
|
||||||
type.isMarkedNullable(), // Same nullability
|
|
||||||
substitutedArguments,
|
|
||||||
substitutionFilteringTypeParameters,
|
|
||||||
new SubstitutingScope(type.getMemberScope(), create(substitutionFilteringTypeParameters)),
|
|
||||||
type.getCapabilities());
|
|
||||||
return new TypeProjectionImpl(projectionKind, substitutedType);
|
return new TypeProjectionImpl(projectionKind, substitutedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,15 +17,11 @@
|
|||||||
package org.jetbrains.kotlin.types.typeUtil
|
package org.jetbrains.kotlin.types.typeUtil
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
import org.jetbrains.kotlin.utils.toReadOnlyList
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
public enum class TypeNullability {
|
public enum class TypeNullability {
|
||||||
@@ -65,39 +61,6 @@ fun KotlinType?.isArrayOfNothing(): Boolean {
|
|||||||
return typeArg != null && KotlinBuiltIns.isNothingOrNullableNothing(typeArg)
|
return typeArg != null && KotlinBuiltIns.isNothingOrNullableNothing(typeArg)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KotlinType.getContainedTypeParameters(): Collection<TypeParameterDescriptor> {
|
|
||||||
val declarationDescriptor = getConstructor().getDeclarationDescriptor()
|
|
||||||
if (declarationDescriptor is TypeParameterDescriptor) return listOf(declarationDescriptor)
|
|
||||||
|
|
||||||
val flexibility = getCapability(javaClass<Flexibility>())
|
|
||||||
if (flexibility != null) {
|
|
||||||
return flexibility.lowerBound.getContainedTypeParameters() + flexibility.upperBound.getContainedTypeParameters()
|
|
||||||
}
|
|
||||||
return getArguments().filter { !it.isStarProjection() }.map { it.getType() }.flatMap { it.getContainedTypeParameters() }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun DeclarationDescriptor.getCapturedTypeParameters(): Collection<TypeParameterDescriptor> {
|
|
||||||
val result = LinkedHashSet<TypeParameterDescriptor>()
|
|
||||||
val containingDeclaration = this.getContainingDeclaration()
|
|
||||||
|
|
||||||
if (containingDeclaration is ClassDescriptor) {
|
|
||||||
result.addAll(containingDeclaration.getDefaultType().getContainedTypeParameters())
|
|
||||||
}
|
|
||||||
else if (containingDeclaration is CallableDescriptor) {
|
|
||||||
result.addAll(containingDeclaration.getTypeParameters())
|
|
||||||
}
|
|
||||||
if (containingDeclaration != null) {
|
|
||||||
result.addAll(containingDeclaration.getCapturedTypeParameters())
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
public fun KotlinType.getContainedAndCapturedTypeParameterConstructors(): Collection<TypeConstructor> {
|
|
||||||
// todo type arguments (instead of type parameters) of the type of outer class must be considered; KT-6325
|
|
||||||
val capturedTypeParameters = getConstructor().getDeclarationDescriptor()?.getCapturedTypeParameters() ?: emptyList()
|
|
||||||
val typeParameters = getContainedTypeParameters() + capturedTypeParameters
|
|
||||||
return typeParameters.map { it.getTypeConstructor() }.toReadOnlyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
public fun KotlinType.isSubtypeOf(superType: KotlinType): Boolean = KotlinTypeChecker.DEFAULT.isSubtypeOf(this, superType)
|
public fun KotlinType.isSubtypeOf(superType: KotlinType): Boolean = KotlinTypeChecker.DEFAULT.isSubtypeOf(this, superType)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user