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:
Denis Zharkov
2015-12-22 12:34:40 +03:00
parent 58caff3411
commit 365ff593f3
7 changed files with 71 additions and 63 deletions
@@ -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
}
@@ -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);
}
@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")
public void testNotApproximateWhenCopyDescriptors() throws Exception {
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 {
assert(getArguments().size() == newTypeArguments.size()) { "Incorrect type arguments $newTypeArguments" }
return KotlinTypeImpl.create(
getAnnotations(), getConstructor(), isMarkedNullable(), newTypeArguments.map { it.toTypeProjection() }, getMemberScope()
)
assert(arguments.size == newTypeArguments.size) { "Incorrect type arguments $newTypeArguments" }
return replace(newTypeArguments.map { it.toTypeProjection() })
}
private fun approximateProjection(typeArgument: TypeArgument): ApproximationBounds<TypeArgument> {
@@ -114,6 +114,43 @@ public fun KotlinType.computeNewSubstitution(
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 val first: 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.name.FqName;
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.typesApproximation.CapturedTypeApproximationKt;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -217,7 +215,7 @@ public class TypeSubstitutor {
TypeProjection originalProjection,
int recursionDepth
) throws SubstitutionException {
final KotlinType type = originalProjection.getType();
KotlinType type = originalProjection.getType();
Variance projectionKind = originalProjection.getProjectionKind();
if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
// substitution can't change type parameter
@@ -228,25 +226,8 @@ public class TypeSubstitutor {
List<TypeProjection> substitutedArguments = substituteTypeArguments(
type.getConstructor().getParameters(), type.getArguments(), recursionDepth);
// Only type parameters of the corresponding class (or captured type parameters of outer declaration) are substituted
// 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
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());
KotlinType substitutedType =
TypeSubstitutionKt.replace(type, substitutedArguments, substitution.filterAnnotations(type.getAnnotations()));
return new TypeProjectionImpl(projectionKind, substitutedType);
}
@@ -17,15 +17,11 @@
package org.jetbrains.kotlin.types.typeUtil
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.annotations.Annotations
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.utils.toReadOnlyList
import java.util.*
public enum class TypeNullability {
@@ -65,39 +61,6 @@ fun KotlinType?.isArrayOfNothing(): Boolean {
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)