From 1ce4eca3a62972498c9018c7e2fc8900732a2464 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Mon, 13 Jul 2020 15:59:09 +0300 Subject: [PATCH] [FIR] Infer type arguments for captured parameters of inner classes KT-38992 --- .../invokeWithReceiverAndArgument.kt | 29 +++++++ .../invokeWithReceiverAndArgument.txt | 62 +++++++++++++++ ...ifiedSupertypeExtendedByOtherSupertype.txt | 20 ++--- .../resolve/typeParameterVsNested.txt | 18 ++--- .../types/capturedParametersOfInnerClasses.kt | 13 +++ .../capturedParametersOfInnerClasses.txt | 31 ++++++++ .../fir/FirDiagnosticsTestGenerated.java | 10 +++ ...DiagnosticsWithLightTreeTestGenerated.java | 10 +++ .../kotlin/fir/resolve/FirTypeResolver.kt | 5 +- .../kotlin/fir/resolve/ResolveUtils.kt | 17 +--- .../providers/impl/FirTypeResolverImpl.kt | 79 ++++++++++++++----- ...irAbstractTreeTransformerWithSuperTypes.kt | 33 +++++++- .../FirSpecificTypeResolverTransformer.kt | 19 ++++- .../FirExpressionsResolveTransformer.kt | 4 +- .../scopes/impl/FirNestedClassifierScope.kt | 14 +++- compiler/testData/codegen/box/ir/kt25405.kt | 2 - .../signatureOfDeepGenericInner.kt | 1 - .../genericSignature/signatureOfDeepInner.kt | 1 - .../signatureOfGenericInnerGenericOuter.kt | 1 - .../implicitArguments/fromSuperClasses.fir.kt | 4 +- .../fromSuperClassesLocal.fir.kt | 2 +- .../fromSuperClassesLocalInsideInner.fir.kt | 2 +- .../generics/innerClasses/innerTP.fir.kt | 8 +- .../innerClasses/qualifiedOuter.fir.kt | 2 +- .../tests/generics/innerClasses/simple.fir.kt | 6 +- .../generics/innerClasses/simpleIn.fir.kt | 6 +- .../substitutedMemberScope.fir.kt | 2 +- 27 files changed, 316 insertions(+), 85 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/resolve/callResolution/invokeWithReceiverAndArgument.kt create mode 100644 compiler/fir/analysis-tests/testData/resolve/callResolution/invokeWithReceiverAndArgument.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.kt create mode 100644 compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.txt diff --git a/compiler/fir/analysis-tests/testData/resolve/callResolution/invokeWithReceiverAndArgument.kt b/compiler/fir/analysis-tests/testData/resolve/callResolution/invokeWithReceiverAndArgument.kt new file mode 100644 index 00000000000..29e27786a03 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/callResolution/invokeWithReceiverAndArgument.kt @@ -0,0 +1,29 @@ +interface AbstractFirTreeBuilder + +class FirTreeBuilder : AbstractFirTreeBuilder + +abstract class AbstractBuilderConfigurator { + abstract class BuilderConfigurationContext + + inner class LeafBuilderConfigurationContext : BuilderConfigurationContext() +} + +class BuilderConfigurator : AbstractBuilderConfigurator() { + fun test(func: (LeafBuilderConfigurationContext) -> Unit) { + val context = LeafBuilderConfigurationContext() + func(context) + } +} + +class Outer { + inner class Inner + + fun foo(x: (Inner) -> Unit, y: Inner.() -> Unit) { + // each call reported as INAPPLICABLE because "Inner is not a subtype of Inner" + bar(Inner()) + x(Inner()) + Inner().y() + } + + fun bar(i: Inner) {} +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolve/callResolution/invokeWithReceiverAndArgument.txt b/compiler/fir/analysis-tests/testData/resolve/callResolution/invokeWithReceiverAndArgument.txt new file mode 100644 index 00000000000..ce527faf1de --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/callResolution/invokeWithReceiverAndArgument.txt @@ -0,0 +1,62 @@ +FILE: invokeWithReceiverAndArgument.kt + public abstract interface AbstractFirTreeBuilder : R|kotlin/Any| { + } + public final class FirTreeBuilder : R|AbstractFirTreeBuilder| { + public constructor(): R|FirTreeBuilder| { + super() + } + + } + public abstract class AbstractBuilderConfigurator : R|kotlin/Any| { + public constructor(): R|AbstractBuilderConfigurator| { + super() + } + + public abstract class BuilderConfigurationContext : R|kotlin/Any| { + public constructor(): R|AbstractBuilderConfigurator.BuilderConfigurationContext| { + super() + } + + } + + public final inner class LeafBuilderConfigurationContext : R|AbstractBuilderConfigurator.BuilderConfigurationContext| { + public constructor(): R|AbstractBuilderConfigurator.LeafBuilderConfigurationContext| { + super() + } + + } + + } + public final class BuilderConfigurator : R|AbstractBuilderConfigurator| { + public constructor(): R|BuilderConfigurator| { + super|>() + } + + public final fun test(func: R|(AbstractBuilderConfigurator.LeafBuilderConfigurationContext) -> kotlin/Unit|): R|kotlin/Unit| { + lval context: R|AbstractBuilderConfigurator.LeafBuilderConfigurationContext| = this@R|/BuilderConfigurator|.R|/AbstractBuilderConfigurator.LeafBuilderConfigurationContext.LeafBuilderConfigurationContext|() + R|/func|.R|FakeOverride|(R|/context|) + } + + } + public final class Outer : R|kotlin/Any| { + public constructor(): R|Outer| { + super() + } + + public final inner class Inner : R|kotlin/Any| { + public constructor(): R|Outer.Inner| { + super() + } + + } + + public final fun foo(x: R|(Outer.Inner) -> kotlin/Unit|, y: R|Outer.Inner.() -> kotlin/Unit|): R|kotlin/Unit| { + this@R|/Outer|.R|/Outer.bar|(this@R|/Outer|.R|/Outer.Inner.Inner|()) + R|/x|.R|FakeOverride|(this@R|/Outer|.R|/Outer.Inner.Inner|()) + R|/y|.R|FakeOverride|(this@R|/Outer|.R|/Outer.Inner.Inner|()) + } + + public final fun bar(i: R|Outer.Inner|): R|kotlin/Unit| { + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/qualifiedSupertypeExtendedByOtherSupertype.txt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/qualifiedSupertypeExtendedByOtherSupertype.txt index a4c129af390..b5c7c701130 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/qualifiedSupertypeExtendedByOtherSupertype.txt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/qualifiedSupertypeExtendedByOtherSupertype.txt @@ -23,11 +23,11 @@ FILE: qualifiedSupertypeExtendedByOtherSupertype.kt } public final fun test(): R|kotlin/Unit| { - this@R|/Test|.super.R|/IBase.foo|() - this@R|/Test|.super.R|/IBase.bar|() - this@R|/Test|.super.R|/IDerived.foo|() - this@R|/Test|.super.R|/IBase.bar|() - this@R|/Test|.super.R|/IDerived.qux|() + this@R|/Test|.super|>.R|/IBase.foo|() + this@R|/Test|.super|>.R|/IBase.bar|() + this@R|/Test|.super|>.R|/IDerived.foo|() + this@R|/Test|.super|>.R|/IBase.bar|() + this@R|/Test|.super|>.R|/IDerived.qux|() } } @@ -37,13 +37,13 @@ FILE: qualifiedSupertypeExtendedByOtherSupertype.kt } public final fun test(): R|kotlin/Unit| { - this@R|/Test2|.super.R|/IBase.foo|() - this@R|/Test2|.super.R|/IBase.bar|() + this@R|/Test2|.super|>.R|/IBase.foo|() + this@R|/Test2|.super|>.R|/IBase.bar|() this@R|/Test2|.super.R|/IBase.foo|() this@R|/Test2|.super.R|/IBase.bar|() - this@R|/Test2|.super.R|/IDerived.foo|() - this@R|/Test2|.super.R|/IBase.bar|() - this@R|/Test2|.super.R|/IDerived.qux|() + this@R|/Test2|.super|>.R|/IDerived.foo|() + this@R|/Test2|.super|>.R|/IBase.bar|() + this@R|/Test2|.super|>.R|/IDerived.qux|() } } diff --git a/compiler/fir/analysis-tests/testData/resolve/typeParameterVsNested.txt b/compiler/fir/analysis-tests/testData/resolve/typeParameterVsNested.txt index 0804e6ce389..2c547192089 100644 --- a/compiler/fir/analysis-tests/testData/resolve/typeParameterVsNested.txt +++ b/compiler/fir/analysis-tests/testData/resolve/typeParameterVsNested.txt @@ -13,20 +13,20 @@ FILE: typeParameterVsNested.kt } - public abstract val x: R|test/My.T| - public get(): R|test/My.T| + public abstract val x: R|test/My.T| + public get(): R|test/My.T| - public abstract fun foo(arg: R|test/My.T|): R|kotlin/Unit| + public abstract fun foo(arg: R|test/My.T|): R|kotlin/Unit| - public abstract val y: R|test/My.T| - public get(): R|test/My.T| + public abstract val y: R|test/My.T| + public get(): R|test/My.T| - public abstract val z: R|test/My.T| - public get(): R|test/My.T| + public abstract val z: R|test/My.T| + public get(): R|test/My.T| - public final class Some : R|test/My.T| { + public final class Some : R|test/My.T| { public constructor(): R|test/My.Some| { - super() + super|>() } } diff --git a/compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.kt b/compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.kt new file mode 100644 index 00000000000..f78eb42830c --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.kt @@ -0,0 +1,13 @@ +class A { + inner class B { + inner class C + + fun foo(c: C) {} + } + + fun foo(c: B.C) {} +} + +fun foo(c: A.B.C) {} + +fun foo(c: A.B.C) {} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.txt b/compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.txt new file mode 100644 index 00000000000..1a9af7518eb --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.txt @@ -0,0 +1,31 @@ +FILE: capturedParametersOfInnerClasses.kt + public final class A : R|kotlin/Any| { + public constructor(): R|A| { + super() + } + + public final inner class B : R|kotlin/Any| { + public constructor(): R|A.B| { + super() + } + + public final inner class C : R|kotlin/Any| { + public constructor(): R|A.B.C| { + super() + } + + } + + public final fun foo(c: R|A.B.C|): R|kotlin/Unit| { + } + + } + + public final fun foo(c: R|A.B.C|): R|kotlin/Unit| { + } + + } + public final fun foo(c: R|A.B.C|): R|kotlin/Unit| { + } + public final fun foo(c: R|A.B.C|): R|kotlin/Unit| { + } diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index 68961eeeeb1..75f5ad6fa94 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -644,6 +644,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/invokeAmbiguity.kt"); } + @TestMetadata("invokeWithReceiverAndArgument.kt") + public void testInvokeWithReceiverAndArgument() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/invokeWithReceiverAndArgument.kt"); + } + @TestMetadata("objectInvoke.kt") public void testObjectInvoke() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/objectInvoke.kt"); @@ -2352,6 +2357,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { public void testBareWithSubjectTypeAlias() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/types/bareWithSubjectTypeAlias.kt"); } + + @TestMetadata("capturedParametersOfInnerClasses.kt") + public void testCapturedParametersOfInnerClasses() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.kt"); + } } @TestMetadata("compiler/fir/analysis-tests/testData/resolve/visibility") diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java index 8d9eb1da43f..fff14b525d5 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java @@ -644,6 +644,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/invokeAmbiguity.kt"); } + @TestMetadata("invokeWithReceiverAndArgument.kt") + public void testInvokeWithReceiverAndArgument() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/invokeWithReceiverAndArgument.kt"); + } + @TestMetadata("objectInvoke.kt") public void testObjectInvoke() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/objectInvoke.kt"); @@ -2352,6 +2357,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos public void testBareWithSubjectTypeAlias() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/types/bareWithSubjectTypeAlias.kt"); } + + @TestMetadata("capturedParametersOfInnerClasses.kt") + public void testCapturedParametersOfInnerClasses() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.kt"); + } } @TestMetadata("compiler/fir/analysis-tests/testData/resolve/visibility") diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirTypeResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirTypeResolver.kt index bd2b80ae19b..dfa9af7ab94 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirTypeResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirTypeResolver.kt @@ -6,13 +6,12 @@ package org.jetbrains.kotlin.fir.resolve import org.jetbrains.kotlin.fir.FirSessionComponent +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.FirTypeRef -import org.jetbrains.kotlin.fir.types.FirUserTypeRef interface FirTypeResolver : FirSessionComponent { - fun resolveType(typeRef: FirTypeRef, scope: FirScope): ConeKotlinType - fun resolveToSymbol(typeRef: FirTypeRef, scope: FirScope): FirClassifierSymbol<*>? + fun resolveType(typeRef: FirTypeRef, scope: FirScope, areBareTypesAllowed: Boolean): ConeKotlinType } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index 14ede2c10d9..af25abf3e72 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.bindSymbolToLookupTag import org.jetbrains.kotlin.fir.resolve.providers.getSymbolByTypeRef import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType import org.jetbrains.kotlin.fir.scopes.impl.FirDeclaredMemberScopeProvider import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType @@ -191,21 +192,7 @@ fun FirClassifierSymbol<*>.constructType( fun FirClassifierSymbol<*>.constructType(parts: List, isNullable: Boolean): ConeKotlinType = constructType(parts.toTypeProjections(), isNullable) -fun FirClassifierSymbol<*>.constructType( - parts: List, - isNullable: Boolean, - symbolOriginSession: FirSession, - attributes: ConeAttributes = ConeAttributes.Empty -): ConeKotlinType = - constructType(parts.toTypeProjections(), isNullable, attributes) - .also { - val lookupTag = it.lookupTag - if (lookupTag is ConeClassLikeLookupTagImpl && this is FirClassLikeSymbol<*>) { - lookupTag.bindSymbolToLookupTag(symbolOriginSession.firSymbolProvider, this) - } - } - -private fun List.toTypeProjections(): Array = +fun List.toTypeProjections(): Array = asReversed().flatMap { it.typeArguments.map { typeArgument -> typeArgument.toConeTypeProjection() } }.toTypedArray() fun FirFunction<*>.constructFunctionalTypeRef(isSuspend: Boolean = false): FirResolvedTypeRef { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt index 3402b0d61c1..e3ed44807d6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt @@ -8,17 +8,15 @@ package org.jetbrains.kotlin.fir.resolve.providers.impl import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.render -import org.jetbrains.kotlin.fir.resolve.FirTypeResolver -import org.jetbrains.kotlin.fir.resolve.constructType -import org.jetbrains.kotlin.fir.resolve.firSymbolProvider -import org.jetbrains.kotlin.fir.resolve.qualifierResolver +import org.jetbrains.kotlin.fir.resolve.* +import org.jetbrains.kotlin.fir.resolve.providers.bindSymbolToLookupTag +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.scopes.FirScope -import org.jetbrains.kotlin.fir.scopes.processClassifiersByName -import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol +import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag +import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl +import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef import org.jetbrains.kotlin.name.ClassId @@ -40,18 +38,22 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver { } } - override fun resolveToSymbol( + private fun resolveToSymbol( typeRef: FirTypeRef, scope: FirScope - ): FirClassifierSymbol<*>? { + ): Pair?, ConeSubstitutor?> { return when (typeRef) { - is FirResolvedTypeRef -> typeRef.coneTypeSafe()?.lookupTag?.let(symbolProvider::getSymbolByLookupTag) + is FirResolvedTypeRef -> { + val resultSymbol = typeRef.coneTypeSafe()?.lookupTag?.let(symbolProvider::getSymbolByLookupTag) + resultSymbol to null + } is FirUserTypeRef -> { val qualifierResolver = session.qualifierResolver var resolvedSymbol: FirClassifierSymbol<*>? = null - scope.processClassifiersByName(typeRef.qualifier.first().name) { symbol -> - if (resolvedSymbol != null) return@processClassifiersByName + var substitutor: ConeSubstitutor? = null + scope.processClassifiersByNameWithSubstitution(typeRef.qualifier.first().name) { symbol, substitutorFromScope -> + if (resolvedSymbol != null) return@processClassifiersByNameWithSubstitution resolvedSymbol = when (symbol) { is FirClassLikeSymbol<*> -> { if (typeRef.qualifier.size == 1) { @@ -66,25 +68,56 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver { } else -> error("!") } + substitutor = substitutorFromScope } // TODO: Imports - resolvedSymbol ?: qualifierResolver.resolveSymbol(typeRef.qualifier) + val resultSymbol: FirClassifierSymbol<*>? = resolvedSymbol ?: qualifierResolver.resolveSymbol(typeRef.qualifier) + resultSymbol to substitutor } is FirImplicitBuiltinTypeRef -> { - resolveBuiltInQualified(typeRef.id, session) + resolveBuiltInQualified(typeRef.id, session) to null } - else -> null + else -> null to null } } - private fun resolveUserType(typeRef: FirUserTypeRef, symbol: FirClassifierSymbol<*>?): ConeKotlinType { + private fun resolveUserType( + typeRef: FirUserTypeRef, + symbol: FirClassifierSymbol<*>?, + substitutor: ConeSubstitutor?, + areBareTypesAllowed: Boolean + ): ConeKotlinType { if (symbol == null) { return ConeKotlinErrorType("Symbol not found, for `${typeRef.render()}`") } - return symbol.constructType(typeRef.qualifier, typeRef.isMarkedNullable, symbolOriginSession = session, typeRef.annotations.computeTypeAttributes()) + var typeArguments = typeRef.qualifier.toTypeProjections() + if (symbol is FirRegularClassSymbol) { + val isPossibleBareType = areBareTypesAllowed && typeArguments.isEmpty() + if (typeArguments.size != symbol.fir.typeParameters.size && !isPossibleBareType) { + @Suppress("NAME_SHADOWING") + val substitutor = substitutor ?: ConeSubstitutor.Empty + val n = symbol.fir.typeParameters.size - typeArguments.size + if (n < 0) { + typeArguments = (1..symbol.fir.typeParameters.size).map { ConeClassErrorType("Type arguments number mismatch") }.toTypedArray() + } else { + val argumentsFromOuterClassesAndParents = symbol.fir.typeParameters.takeLast(n).map { + val type = ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(it.symbol), isNullable = false) + substitutor.substituteOrNull(type) ?: ConeClassErrorType("Type argument not defined") + }.toTypedArray() + typeArguments += argumentsFromOuterClassesAndParents + } + } + } + return symbol.constructType(typeArguments, typeRef.isMarkedNullable, typeRef.annotations.computeTypeAttributes()) + .also { + val lookupTag = it.lookupTag + if (lookupTag is ConeClassLikeLookupTagImpl && symbol is FirClassLikeSymbol<*>) { + lookupTag.bindSymbolToLookupTag(session.firSymbolProvider, symbol) + } + } } private fun createFunctionalType(typeRef: FirFunctionTypeRef): ConeClassLikeType { @@ -108,13 +141,17 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver { override fun resolveType( typeRef: FirTypeRef, - scope: FirScope + scope: FirScope, + areBareTypesAllowed: Boolean ): ConeKotlinType { return when (typeRef) { is FirResolvedTypeRef -> typeRef.type - is FirUserTypeRef -> resolveUserType(typeRef, resolveToSymbol(typeRef, scope)) + is FirUserTypeRef -> { + val (symbol, substitutor) = resolveToSymbol(typeRef, scope) + resolveUserType(typeRef, symbol, substitutor, areBareTypesAllowed) + } is FirFunctionTypeRef -> createFunctionalType(typeRef) - is FirDelegatedTypeRef -> resolveType(typeRef.typeRef, scope) + is FirDelegatedTypeRef -> resolveType(typeRef.typeRef, scope, areBareTypesAllowed) is FirDynamicTypeRef -> ConeKotlinErrorType("Not supported: ${typeRef::class.simpleName}") else -> error("!") } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirAbstractTreeTransformerWithSuperTypes.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirAbstractTreeTransformerWithSuperTypes.kt index c8eed4ee89a..55bfeaabc5a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirAbstractTreeTransformerWithSuperTypes.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirAbstractTreeTransformerWithSuperTypes.kt @@ -10,13 +10,24 @@ import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.expressions.FirStatement +import org.jetbrains.kotlin.fir.resolve.firSymbolProvider import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes import org.jetbrains.kotlin.fir.resolve.providers.getNestedClassifierScope +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap +import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.scopes.FirCompositeScope import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope +import org.jetbrains.kotlin.fir.scopes.impl.FirNestedClassifierScope import org.jetbrains.kotlin.fir.scopes.impl.nestedClassifierScope +import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag +import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLookupTagWithFixedSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult +import org.jetbrains.kotlin.name.Name abstract class FirAbstractTreeTransformerWithSuperTypes( phase: FirResolvePhase @@ -43,8 +54,16 @@ abstract class FirAbstractTreeTransformerWithSuperTypes( // ? Is it Ok to use original file session here ? val superTypes = lookupSuperTypes(firClass, lookupInterfaces = false, deep = true, useSiteSession = session).asReversed() for (superType in superTypes) { - session.getNestedClassifierScope(superType.lookupTag)?.let { - scopes.add(it) + session.getNestedClassifierScope(superType.lookupTag)?.let { nestedClassifierScope -> + val klass = superType.lookupTag.toSymbol(session)?.fir as? FirRegularClass + val mapping = klass?.typeParameters?.map { it.symbol }?.zip(superType.typeArguments.map { it as ConeKotlinType })?.toMap() + val substitutor = mapping?.let { ConeSubstitutorByMap(it) } ?: ConeSubstitutor.Empty + val scope = if (nestedClassifierScope is FirNestedClassifierScope) { + FirNestedClassifierScopeWithSubstitution(nestedClassifierScope, substitutor) + } else { + nestedClassifierScope + } + scopes.add(scope) } } if (firClass is FirRegularClass) { @@ -67,3 +86,13 @@ abstract class FirAbstractTreeTransformerWithSuperTypes( } } } + +private class FirNestedClassifierScopeWithSubstitution( + private val scope: FirNestedClassifierScope, + private val substitutor: ConeSubstitutor +) : FirScope() { + override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) { + val matchedClass = scope.getClassifierByName(name) ?: return + processor(matchedClass, substitutor) + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt index 7262df1b1bb..9f491d3010a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.resolve.transformers import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.PrivateForInline import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.resolve.typeResolver import org.jetbrains.kotlin.fir.scopes.FirScope @@ -21,16 +22,30 @@ class FirSpecificTypeResolverTransformer( ) : FirAbstractTreeTransformer(phase = FirResolvePhase.SUPER_TYPES) { private val typeResolver = session.typeResolver + @set:PrivateForInline + var areBareTypesAllowed: Boolean = false + + @OptIn(PrivateForInline::class) + inline fun withAllowedBareTypes(block: () -> R): R { + val oldValue = areBareTypesAllowed + areBareTypesAllowed = true + return try { + block() + } finally { + areBareTypesAllowed = oldValue + } + } + override fun transformTypeRef(typeRef: FirTypeRef, data: FirScope): CompositeTransformResult { typeRef.transformChildren(this, data) - return transformType(typeRef, typeResolver.resolveType(typeRef, data)) + return transformType(typeRef, typeResolver.resolveType(typeRef, data, areBareTypesAllowed)) } override fun transformFunctionTypeRef(functionTypeRef: FirFunctionTypeRef, data: FirScope): CompositeTransformResult { functionTypeRef.transformChildren(this, data) return buildResolvedFunctionTypeRef { source = functionTypeRef.source - type = typeResolver.resolveType(functionTypeRef, data).takeIfAcceptable() ?: return functionTypeRef.compose() + type = typeResolver.resolveType(functionTypeRef, data, areBareTypesAllowed).takeIfAcceptable() ?: return functionTypeRef.compose() isMarkedNullable = functionTypeRef.isMarkedNullable isSuspend = functionTypeRef.isSuspend receiverTypeRef = functionTypeRef.receiverTypeRef diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index d1b2700dee8..205399c319f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -432,7 +432,9 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform typeOperatorCall: FirTypeOperatorCall, data: ResolutionMode, ): CompositeTransformResult { - val resolved = transformExpression(typeOperatorCall, ResolutionMode.ContextIndependent).single as FirTypeOperatorCall + val resolved = components.typeResolverTransformer.withAllowedBareTypes { + typeOperatorCall.transformConversionTypeRef(transformer, ResolutionMode.ContextIndependent) + }.transformOtherChildren(transformer, ResolutionMode.ContextIndependent) resolved.argumentList.transformArguments(integerLiteralTypeApproximator, null) val conversionTypeRef = resolved.conversionTypeRef.withTypeArgumentsForBareType(resolved.argument) resolved.transformChildren(object : FirDefaultTransformer() { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirNestedClassifierScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirNestedClassifierScope.kt index 8f61a1d635d..f3eed3ef56a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirNestedClassifierScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirNestedClassifierScope.kt @@ -7,10 +7,15 @@ package org.jetbrains.kotlin.fir.scopes.impl import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRef import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl import org.jetbrains.kotlin.name.Name class FirNestedClassifierScope(val klass: FirClass<*>) : FirScope() { @@ -31,6 +36,13 @@ class FirNestedClassifierScope(val klass: FirClass<*>) : FirScope() { processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit ) { val matchedClass = classIndex[name] ?: return - processor(matchedClass, ConeSubstitutor.Empty) + val substitution = klass.typeParameters.associate { + it.symbol to it.toConeType() + } + processor(matchedClass, ConeSubstitutorByMap(substitution)) } + + fun getClassifierByName(name: Name): FirRegularClassSymbol? = classIndex[name] } + +fun FirTypeParameterRef.toConeType(): ConeKotlinType = ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(symbol), isNullable = false) \ No newline at end of file diff --git a/compiler/testData/codegen/box/ir/kt25405.kt b/compiler/testData/codegen/box/ir/kt25405.kt index 1fb602beefc..485922deed7 100644 --- a/compiler/testData/codegen/box/ir/kt25405.kt +++ b/compiler/testData/codegen/box/ir/kt25405.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR - fun tableView(init: Table.() -> Unit) { Table().init() } diff --git a/compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepGenericInner.kt b/compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepGenericInner.kt index 0b92b98e3f1..f7f92e0ddd8 100644 --- a/compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepGenericInner.kt +++ b/compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepGenericInner.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // SKIP_JDK6 // TARGET_BACKEND: JVM // WITH_REFLECT diff --git a/compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepInner.kt b/compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepInner.kt index 8e1f92ea015..f884729ae43 100644 --- a/compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepInner.kt +++ b/compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepInner.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // SKIP_JDK6 // TARGET_BACKEND: JVM // WITH_REFLECT diff --git a/compiler/testData/codegen/box/reflection/genericSignature/signatureOfGenericInnerGenericOuter.kt b/compiler/testData/codegen/box/reflection/genericSignature/signatureOfGenericInnerGenericOuter.kt index bca8eef641b..ab6ebb820a1 100644 --- a/compiler/testData/codegen/box/reflection/genericSignature/signatureOfGenericInnerGenericOuter.kt +++ b/compiler/testData/codegen/box/reflection/genericSignature/signatureOfGenericInnerGenericOuter.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // SKIP_JDK6 // TARGET_BACKEND: JVM // WITH_REFLECT diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/fromSuperClasses.fir.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/fromSuperClasses.fir.kt index a8fa7ce8835..4b06fd6d4b4 100644 --- a/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/fromSuperClasses.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/fromSuperClasses.fir.kt @@ -19,8 +19,8 @@ class A : Outer() { } fun foo() { - Derived().foo() checkType { _.Inner>() } + Derived().foo() checkType { _.Inner>() } Derived().baz() checkType { _>() } - A.B().bar() checkType { _.Inner>() } + A.B().bar() checkType { _.Inner>() } A.B().x() checkType { _>() } } diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/fromSuperClassesLocal.fir.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/fromSuperClassesLocal.fir.kt index ffd67e920ab..f4db464a50c 100644 --- a/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/fromSuperClassesLocal.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/fromSuperClassesLocal.fir.kt @@ -50,6 +50,6 @@ fun test() { var y = noParameters() y = noParameters() - y().foo().a() checkType { _>() } + y().foo().a() checkType { _>() } y().bar() checkType { _>() } } diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/fromSuperClassesLocalInsideInner.fir.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/fromSuperClassesLocalInsideInner.fir.kt index 43541fe539a..0ac26948940 100644 --- a/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/fromSuperClassesLocalInsideInner.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/fromSuperClassesLocalInsideInner.fir.kt @@ -52,7 +52,7 @@ class Outer { var y = noParameters() y = noParameters() - y().foo().a() checkType { _>() } + y().foo().a() checkType { _>() } y().bar() checkType { _>() } } } diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/innerTP.fir.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/innerTP.fir.kt index 1d6143f5f48..f21b8a298e3 100644 --- a/compiler/testData/diagnostics/tests/generics/innerClasses/innerTP.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/innerTP.fir.kt @@ -14,7 +14,7 @@ class Outer { fun set(inner: Inner) {} fun inside() { - innerFactory().checkType { _>() } + innerFactory().checkType { _>() } } } @@ -34,9 +34,9 @@ fun main() { checkSubtype.Inner>(outer.bar()) checkSubtype.Inner>(outer.Inner()) - outer.set(outer.bar()) - outer.set(outer.Inner()) + outer.set(outer.bar()) + outer.set(outer.Inner()) val x: Outer.Inner = factoryString() - outer.set(x) + outer.set(x) } diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/qualifiedOuter.fir.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/qualifiedOuter.fir.kt index 890f42ddd21..e365762a123 100644 --- a/compiler/testData/diagnostics/tests/generics/innerClasses/qualifiedOuter.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/qualifiedOuter.fir.kt @@ -9,7 +9,7 @@ class Outer { x.checkType { _() } x.checkType { _.Inner>() } z.checkType { _() } - z.checkType { _.Inner>() } + z.checkType { _.Inner>() } inner = x } diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/simple.fir.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/simple.fir.kt index 5376811625e..50641cc1111 100644 --- a/compiler/testData/diagnostics/tests/generics/innerClasses/simple.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/simple.fir.kt @@ -28,9 +28,9 @@ fun main() { checkSubtype.Inner>(outer.bar()) checkSubtype.Inner>(outer.Inner()) - outer.set(outer.bar()) - outer.set(outer.Inner()) + outer.set(outer.bar()) + outer.set(outer.Inner()) val x: Outer.Inner = factoryString() - outer.set(x) + outer.set(x) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/simpleIn.fir.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/simpleIn.fir.kt index 641be62ce66..3f09cfe537b 100644 --- a/compiler/testData/diagnostics/tests/generics/innerClasses/simpleIn.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/simpleIn.fir.kt @@ -28,13 +28,13 @@ fun main() { checkSubtype.Inner>(outer.bar()) checkSubtype.Inner>(outer.Inner()) - outer.set(outer.bar()) - outer.set(outer.Inner()) + outer.set(outer.bar()) + outer.set(outer.Inner()) val x: Outer.Inner = factoryString() outer.set(x) val y: Outer.Inner = infer("") - outer.set(y) + outer.set(y) outer.set(infer("")) } diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/substitutedMemberScope.fir.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/substitutedMemberScope.fir.kt index af6d575ba72..235de26c5bc 100644 --- a/compiler/testData/diagnostics/tests/generics/innerClasses/substitutedMemberScope.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/substitutedMemberScope.fir.kt @@ -44,6 +44,6 @@ fun foo() { strInt.instance().Inner().checkType { _.Inner>() } - Outer().setInner(strInt) + Outer().setInner(strInt) Outer().setInner(strInt) }