diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/memberScopeOfCaptured.kt b/compiler/testData/diagnostics/tests/inference/capturedTypes/memberScopeOfCaptured.kt new file mode 100644 index 00000000000..08aada3de83 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/memberScopeOfCaptured.kt @@ -0,0 +1,11 @@ +// !CHECK_TYPE + +class A { + fun foo(): T = null!! +} + +fun A.bar(): A = this + +fun baz(x: A) { + x.bar().foo() checkType { _() } // See KT-10448 +} diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/memberScopeOfCaptured.txt b/compiler/testData/diagnostics/tests/inference/capturedTypes/memberScopeOfCaptured.txt new file mode 100644 index 00000000000..b69825e578c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/memberScopeOfCaptured.txt @@ -0,0 +1,12 @@ +package + +public fun baz(/*0*/ x: A): kotlin.Unit +public fun A.bar(): A + +public final class A { + public constructor A() + 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 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index a59dac91724..12074d84893 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -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"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/CapturedTypeApproximation.kt b/core/descriptors/src/org/jetbrains/kotlin/types/CapturedTypeApproximation.kt index 5943fb5bb48..56ddbafafe0 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/CapturedTypeApproximation.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/CapturedTypeApproximation.kt @@ -116,10 +116,8 @@ public fun approximateCapturedTypes(type: KotlinType): ApproximationBounds): 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 { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt index f8708070911..9e8edd10e97 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt @@ -114,6 +114,43 @@ public fun KotlinType.computeNewSubstitution( return composedSubstitution } +public fun KotlinType.replace( + newArguments: List, + 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 diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java index 14237c15fd2..4eb64f46bd0 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java @@ -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 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 add(bar: Bar): Foo }' R shouldn't be substituted in the scope - TypeSubstitution substitutionFilteringTypeParameters = new DelegatedTypeSubstitution(substitution) { - private final Collection 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); } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt index 26a52cf8736..8b1703c8c22 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt @@ -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 { - val declarationDescriptor = getConstructor().getDeclarationDescriptor() - if (declarationDescriptor is TypeParameterDescriptor) return listOf(declarationDescriptor) - - val flexibility = getCapability(javaClass()) - 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 { - val result = LinkedHashSet() - 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 { - // 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)