From f68929fe74d984d8f18363c5f4fa16f2dd45c07c Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 22 Nov 2019 16:09:54 +0300 Subject: [PATCH] FIR: Leave functions type parameters in subsituting scope --- .../resolve/substitution/ConeSubstitutor.kt | 14 +-- .../scopes/impl/FirClassSubstitutionScope.kt | 90 +++++++++++++++---- .../testData/resolve/overrides/protobufExt.kt | 14 +++ .../resolve/overrides/protobufExt.txt | 26 ++++++ .../resolve/overrides/supertypeGenerics.kt | 14 +++ .../resolve/overrides/supertypeGenerics.txt | 23 +++++ .../overrides/supertypeGenericsComplex.kt | 14 +++ .../overrides/supertypeGenericsComplex.txt | 28 ++++++ .../fir/FirDiagnosticsTestGenerated.java | 15 ++++ .../parameters/delegatedMembers.fir.txt | 5 +- .../expressions/useImportedMember.fir.txt | 5 +- 11 files changed, 221 insertions(+), 27 deletions(-) create mode 100644 compiler/fir/resolve/testData/resolve/overrides/protobufExt.kt create mode 100644 compiler/fir/resolve/testData/resolve/overrides/protobufExt.txt create mode 100644 compiler/fir/resolve/testData/resolve/overrides/supertypeGenerics.kt create mode 100644 compiler/fir/resolve/testData/resolve/overrides/supertypeGenerics.txt create mode 100644 compiler/fir/resolve/testData/resolve/overrides/supertypeGenericsComplex.kt create mode 100644 compiler/fir/resolve/testData/resolve/overrides/supertypeGenericsComplex.txt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/ConeSubstitutor.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/ConeSubstitutor.kt index 7278b953125..b6aa79c5e8b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/ConeSubstitutor.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/ConeSubstitutor.kt @@ -13,7 +13,7 @@ import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker abstract class ConeSubstitutor : TypeSubstitutorMarker { - abstract fun substituteOrSelf(type: ConeKotlinType): ConeKotlinType + open fun substituteOrSelf(type: ConeKotlinType): ConeKotlinType = substituteOrNull(type) ?: type abstract fun substituteOrNull(type: ConeKotlinType): ConeKotlinType? object Empty : ConeSubstitutor() { @@ -55,10 +55,6 @@ abstract class AbstractConeSubstitutor : ConeSubstitutor() { return type?.withNullability(ConeNullability.NULLABLE) } - override fun substituteOrSelf(type: ConeKotlinType): ConeKotlinType { - return substituteOrNull(type) ?: type - } - override fun substituteOrNull(type: ConeKotlinType): ConeKotlinType? { val newType = substituteType(type) return (newType ?: type.substituteRecursive()) @@ -143,8 +139,14 @@ fun substitutorByMap(substitution: Map): return ConeSubstitutorByMap(substitution) } -class ConeSubstitutorByMap(val substitution: Map) : AbstractConeSubstitutor() { +class ChainedSubstitutor(private val first: ConeSubstitutor, private val second: ConeSubstitutor) : ConeSubstitutor() { + override fun substituteOrNull(type: ConeKotlinType): ConeKotlinType? { + first.substituteOrNull(type)?.let { return second.substituteOrSelf(it) } + return second.substituteOrNull(type) + } +} +class ConeSubstitutorByMap(val substitution: Map) : AbstractConeSubstitutor() { override fun substituteType(type: ConeKotlinType): ConeKotlinType? { if (type !is ConeTypeParameterType) return null return makeNullableIfNeed(type.isMarkedNullable, substitution[type.lookupTag.symbol]) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt index 7e0f35e6004..66918611476 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt @@ -9,11 +9,11 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirField import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction -import org.jetbrains.kotlin.fir.declarations.impl.FirFieldImpl -import org.jetbrains.kotlin.fir.declarations.impl.FirPropertyImpl -import org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl -import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl +import org.jetbrains.kotlin.fir.declarations.FirTypeParameter +import org.jetbrains.kotlin.fir.declarations.impl.* import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorWithJump import org.jetbrains.kotlin.fir.scopes.FirScope @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.fir.types.coneTypeUnsafe +import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl import org.jetbrains.kotlin.name.Name @@ -83,6 +84,10 @@ class FirClassSubstitutionScope( return substitutor.substituteOrNull(this) } + private fun ConeKotlinType.substitute(substitutor: ConeSubstitutor): ConeKotlinType? { + return substitutor.substituteOrNull(this) + } + private fun createFakeOverrideFunction(original: FirFunctionSymbol<*>): FirFunctionSymbol<*> { val member = when (original) { is FirNamedFunctionSymbol -> original.fir @@ -90,21 +95,66 @@ class FirClassSubstitutionScope( else -> throw AssertionError("Should not be here") } - val receiverType = member.receiverTypeRef?.coneTypeUnsafe() - val newReceiverType = receiverType?.substitute() - - val returnType = typeCalculator.tryCalculateReturnType(member).type - val newReturnType = returnType.substitute() - - val newParameterTypes = member.valueParameters.map { - it.returnTypeRef.coneTypeUnsafe().substitute() + val newTypeParameters = member.typeParameters.map { originalParameter -> + FirTypeParameterImpl( + originalParameter.source, originalParameter.session, originalParameter.name, + FirTypeParameterSymbol(), originalParameter.variance, originalParameter.isReified + ).apply { + annotations += originalParameter.annotations + } } - if (newReceiverType == null && newReturnType == null && newParameterTypes.all { it == null }) { + val newSubstitutor = + if (member.typeParameters.isEmpty()) + substitutor + else { + val substitutionMapForNewParameters = member.typeParameters.zip(newTypeParameters).map { + Pair(it.first.symbol, ConeTypeParameterTypeImpl(it.second.symbol.toLookupTag(), isNullable = false)) + }.toMap() + ChainedSubstitutor(substitutor, substitutorByMap(substitutionMapForNewParameters)) + } + + val wereChangesInTypeParameters = fillBoundsForTypeParameters(newTypeParameters, member, newSubstitutor) + + val receiverType = member.receiverTypeRef?.coneTypeUnsafe() + val newReceiverType = receiverType?.substitute(newSubstitutor) + + val returnType = typeCalculator.tryCalculateReturnType(member).type + val newReturnType = returnType.substitute(newSubstitutor) + + val newParameterTypes = member.valueParameters.map { + it.returnTypeRef.coneTypeUnsafe().substitute(newSubstitutor) + } + + if (newReceiverType == null && newReturnType == null && newParameterTypes.all { it == null } && !wereChangesInTypeParameters) { return original } - return createFakeOverrideFunction(session, member, original, newReceiverType, newReturnType, newParameterTypes) + return createFakeOverrideFunction( + session, member, original, newReceiverType, newReturnType, newParameterTypes, newTypeParameters + ) + } + + private fun fillBoundsForTypeParameters( + newTypeParameters: List, + member: FirSimpleFunction, + newSubstitutor: ConeSubstitutor + ): Boolean { + var wereChangesInTypeParameters = false + for ((newTypeParameter, oldTypeParameter) in newTypeParameters.zip(member.typeParameters)) { + for (boundTypeRef in oldTypeParameter.bounds) { + val typeForBound = boundTypeRef.coneTypeUnsafe() + val substitutedBound = typeForBound.substitute(newSubstitutor) + if (substitutedBound == null) { + newTypeParameter.bounds += boundTypeRef + } else { + newTypeParameter.bounds += FirResolvedTypeRefImpl(boundTypeRef.source, substitutedBound) + wereChangesInTypeParameters = true + } + } + } + + return wereChangesInTypeParameters } private fun createFakeOverrideProperty(original: FirPropertySymbol): FirPropertySymbol { @@ -156,7 +206,8 @@ class FirClassSubstitutionScope( baseFunction: FirSimpleFunction, newReceiverType: ConeKotlinType? = null, newReturnType: ConeKotlinType? = null, - newParameterTypes: List? = null + newParameterTypes: List? = null, + newTypeParameters: List? = null ): FirSimpleFunction { return with(baseFunction) { // TODO: consider using here some light-weight functions instead of pseudo-real FirMemberFunctionImpl @@ -188,6 +239,8 @@ class FirClassSubstitutionScope( ) } } + + typeParameters += newTypeParameters ?: baseFunction.typeParameters } } } @@ -198,10 +251,13 @@ class FirClassSubstitutionScope( baseSymbol: FirNamedFunctionSymbol, newReceiverType: ConeKotlinType? = null, newReturnType: ConeKotlinType? = null, - newParameterTypes: List? = null + newParameterTypes: List? = null, + newTypeParameters: List? = null ): FirNamedFunctionSymbol { val symbol = FirNamedFunctionSymbol(baseSymbol.callableId, true, baseSymbol) - createFakeOverrideFunction(symbol, session, baseFunction, newReceiverType, newReturnType, newParameterTypes) + createFakeOverrideFunction( + symbol, session, baseFunction, newReceiverType, newReturnType, newParameterTypes, newTypeParameters + ) return symbol } diff --git a/compiler/fir/resolve/testData/resolve/overrides/protobufExt.kt b/compiler/fir/resolve/testData/resolve/overrides/protobufExt.kt new file mode 100644 index 00000000000..7571147ad3c --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/overrides/protobufExt.kt @@ -0,0 +1,14 @@ +interface Ext, T> +interface Message> { + fun ext(e: Ext): T +} + +class MyMessage : Message +class MyExt : Ext + +fun , T> Message.extF(e: Ext): T = ext(e) + +fun foo(m: MyMessage, e: MyExt) { + m.ext(e) + m.extF(e) +} diff --git a/compiler/fir/resolve/testData/resolve/overrides/protobufExt.txt b/compiler/fir/resolve/testData/resolve/overrides/protobufExt.txt new file mode 100644 index 00000000000..252522dec22 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/overrides/protobufExt.txt @@ -0,0 +1,26 @@ +FILE: protobufExt.kt + public abstract interface Ext|, T> : R|kotlin/Any| { + } + public abstract interface Message|> : R|kotlin/Any| { + public abstract fun ext(e: R|Ext|): R|T| + + } + public final class MyMessage : R|Message| { + public constructor(): R|MyMessage| { + super() + } + + } + public final class MyExt : R|Ext| { + public constructor(): R|MyExt| { + super() + } + + } + public final fun |, T> R|Message|.extF(e: R|Ext|): R|T| { + ^extF this@R|/Message|.R|FakeOverride|(R|/e|) + } + public final fun foo(m: R|MyMessage|, e: R|MyExt|): R|kotlin/Unit| { + R|/m|.R|FakeOverride|(R|/e|) + R|/m|.R|/extF|(R|/e|) + } diff --git a/compiler/fir/resolve/testData/resolve/overrides/supertypeGenerics.kt b/compiler/fir/resolve/testData/resolve/overrides/supertypeGenerics.kt new file mode 100644 index 00000000000..d7c5b36b975 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/overrides/supertypeGenerics.kt @@ -0,0 +1,14 @@ +interface I { + fun > f(t: List, f: List): Any// T = D, List == List +} + +abstract class Base { + fun > f(t: List, e: List) {} +} + + +class C : Base(), I + +fun f(list: List, s: List) { + C().f(list, s) +} diff --git a/compiler/fir/resolve/testData/resolve/overrides/supertypeGenerics.txt b/compiler/fir/resolve/testData/resolve/overrides/supertypeGenerics.txt new file mode 100644 index 00000000000..f10ddd67a1e --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/overrides/supertypeGenerics.txt @@ -0,0 +1,23 @@ +FILE: supertypeGenerics.kt + public abstract interface I : R|kotlin/Any| { + public abstract fun |> f(t: R|kotlin/collections/List|, f: R|kotlin/collections/List|): R|kotlin/Any| + + } + public abstract class Base : R|kotlin/Any| { + public constructor(): R|Base| { + super() + } + + public final fun |> f(t: R|kotlin/collections/List|, e: R|kotlin/collections/List|): R|kotlin/Unit| { + } + + } + public final class C : R|Base|, R|I| { + public constructor(): R|C| { + super|>() + } + + } + public final fun f(list: R|kotlin/collections/List|, s: R|kotlin/collections/List|): R|kotlin/Unit| { + R|/C.C|().R|FakeOverride|(R|/list|, R|/s|) + } diff --git a/compiler/fir/resolve/testData/resolve/overrides/supertypeGenericsComplex.kt b/compiler/fir/resolve/testData/resolve/overrides/supertypeGenericsComplex.kt new file mode 100644 index 00000000000..e86b3873732 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/overrides/supertypeGenericsComplex.kt @@ -0,0 +1,14 @@ +class Out + +interface X : Out + +abstract class Base { + fun > f(t: MutableList, e: MutableList) {} +} + +class C : Base() + +fun f(list: MutableList, s: MutableList) { + C().f(list, s) + C().f(s, list) +} diff --git a/compiler/fir/resolve/testData/resolve/overrides/supertypeGenericsComplex.txt b/compiler/fir/resolve/testData/resolve/overrides/supertypeGenericsComplex.txt new file mode 100644 index 00000000000..d106668beb1 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/overrides/supertypeGenericsComplex.txt @@ -0,0 +1,28 @@ +FILE: supertypeGenericsComplex.kt + public final class Out : R|kotlin/Any| { + public constructor(): R|Out| { + super() + } + + } + public abstract interface X : R|Out| { + } + public abstract class Base : R|kotlin/Any| { + public constructor(): R|Base| { + super() + } + + public final fun |> f(t: R|kotlin/collections/MutableList|, e: R|kotlin/collections/MutableList|): R|kotlin/Unit| { + } + + } + public final class C : R|Base| { + public constructor(): R|C| { + super|>() + } + + } + public final fun f(list: R|kotlin/collections/MutableList|, s: R|kotlin/collections/MutableList|): R|kotlin/Unit| { + R|/C.C|().R|FakeOverride|(R|/list|, R|/s|) + R|/C.C|().#(R|/s|, R|/list|) + } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index cb4c378b08b..2824b1abb03 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -825,6 +825,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { runTest("compiler/fir/resolve/testData/resolve/overrides/generics.kt"); } + @TestMetadata("protobufExt.kt") + public void testProtobufExt() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/overrides/protobufExt.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/fir/resolve/testData/resolve/overrides/simple.kt"); @@ -835,6 +840,16 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { runTest("compiler/fir/resolve/testData/resolve/overrides/simpleFakeOverride.kt"); } + @TestMetadata("supertypeGenerics.kt") + public void testSupertypeGenerics() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/overrides/supertypeGenerics.kt"); + } + + @TestMetadata("supertypeGenericsComplex.kt") + public void testSupertypeGenericsComplex() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/overrides/supertypeGenericsComplex.kt"); + } + @TestMetadata("three.kt") public void testThree() throws Exception { runTest("compiler/fir/resolve/testData/resolve/overrides/three.kt"); diff --git a/compiler/testData/ir/irText/declarations/parameters/delegatedMembers.fir.txt b/compiler/testData/ir/irText/declarations/parameters/delegatedMembers.fir.txt index 496e02a2c11..4c91f17dc05 100644 --- a/compiler/testData/ir/irText/declarations/parameters/delegatedMembers.fir.txt +++ b/compiler/testData/ir/irText/declarations/parameters/delegatedMembers.fir.txt @@ -46,12 +46,13 @@ FILE fqName: fileName:/delegatedMembers.kt overridden: public abstract fun (): kotlin.Int declared in .IBase $this: VALUE_PARAMETER name: type:.Test - FUN FAKE_OVERRIDE name:qux visibility:public modality:ABSTRACT <> ($this:.IBase, t:TT of .Test, x:X of .IBase.qux) returnType:kotlin.Unit [fake_override] + FUN FAKE_OVERRIDE name:qux visibility:public modality:ABSTRACT ($this:.IBase, t:TT of .Test, x:X of .Test.qux) returnType:kotlin.Unit [fake_override] overridden: public abstract fun qux (t: T of .IBase, x: X of .IBase.qux): kotlin.Unit declared in .IBase + TYPE_PARAMETER name:X index:0 variance: superTypes:[kotlin.Any?] $this: VALUE_PARAMETER name: type:.IBase VALUE_PARAMETER name:t index:0 type:TT of .Test - VALUE_PARAMETER name:x index:1 type:X of .IBase.qux + VALUE_PARAMETER name:x index:1 type:X of .Test.qux FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override] overridden: public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.Any diff --git a/compiler/testData/ir/irText/expressions/useImportedMember.fir.txt b/compiler/testData/ir/irText/expressions/useImportedMember.fir.txt index 8beb91e7d61..2a72cb717a9 100644 --- a/compiler/testData/ir/irText/expressions/useImportedMember.fir.txt +++ b/compiler/testData/ir/irText/expressions/useImportedMember.fir.txt @@ -137,11 +137,12 @@ FILE fqName: fileName:/useImportedMember.kt overridden: public open fun toString (): kotlin.String declared in kotlin.Any $this: VALUE_PARAMETER name: type:kotlin.Any - FUN FAKE_OVERRIDE name:fromInterface visibility:public modality:OPEN <> ($this:.I, $receiver:T of .I.fromInterface) returnType:T of .I.fromInterface [fake_override] + FUN FAKE_OVERRIDE name:fromInterface visibility:public modality:OPEN ($this:.I, $receiver:T of .C.fromInterface) returnType:T of .C.fromInterface [fake_override] overridden: public open fun fromInterface (): T of .I.fromInterface declared in .I + TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] $this: VALUE_PARAMETER name: type:.I - $receiver: VALUE_PARAMETER name: type:T of .I.fromInterface + $receiver: VALUE_PARAMETER name: type:T of .C.fromInterface FUN FAKE_OVERRIDE name:genericFromSuper visibility:public modality:OPEN <> ($this:.I, g:kotlin.String) returnType:kotlin.String [fake_override] overridden: public open fun genericFromSuper (g: G of .I): G of .I declared in .I