FIR: Leave functions type parameters in subsituting scope

This commit is contained in:
Denis Zharkov
2019-11-22 16:09:54 +03:00
parent b5ef063b0f
commit f68929fe74
11 changed files with 221 additions and 27 deletions
@@ -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<FirTypeParameterSymbol, ConeKotlinType>):
return ConeSubstitutorByMap(substitution)
}
class ConeSubstitutorByMap(val substitution: Map<FirTypeParameterSymbol, ConeKotlinType>) : 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<FirTypeParameterSymbol, ConeKotlinType>) : AbstractConeSubstitutor() {
override fun substituteType(type: ConeKotlinType): ConeKotlinType? {
if (type !is ConeTypeParameterType) return null
return makeNullableIfNeed(type.isMarkedNullable, substitution[type.lookupTag.symbol])
@@ -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<ConeKotlinType>()
val newReceiverType = receiverType?.substitute()
val returnType = typeCalculator.tryCalculateReturnType(member).type
val newReturnType = returnType.substitute()
val newParameterTypes = member.valueParameters.map {
it.returnTypeRef.coneTypeUnsafe<ConeKotlinType>().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<ConeKotlinType>()
val newReceiverType = receiverType?.substitute(newSubstitutor)
val returnType = typeCalculator.tryCalculateReturnType(member).type
val newReturnType = returnType.substitute(newSubstitutor)
val newParameterTypes = member.valueParameters.map {
it.returnTypeRef.coneTypeUnsafe<ConeKotlinType>().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<FirTypeParameterImpl>,
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<ConeKotlinType>()
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<ConeKotlinType?>? = null
newParameterTypes: List<ConeKotlinType?>? = null,
newTypeParameters: List<FirTypeParameter>? = 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<ConeKotlinType?>? = null
newParameterTypes: List<ConeKotlinType?>? = null,
newTypeParameters: List<FirTypeParameter>? = 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
}
@@ -0,0 +1,14 @@
interface Ext<M : Message<M>, T>
interface Message<M : Message<M>> {
fun <T> ext(e: Ext<M, T>): T
}
class MyMessage : Message<MyMessage>
class MyExt : Ext<MyMessage, String>
fun <M : Message<M>, T> Message<M>.extF(e: Ext<M, T>): T = ext(e)
fun foo(m: MyMessage, e: MyExt) {
m.ext(e)
m.extF(e)
}
@@ -0,0 +1,26 @@
FILE: protobufExt.kt
public abstract interface Ext<M : R|Message<M>|, T> : R|kotlin/Any| {
}
public abstract interface Message<M : R|Message<M>|> : R|kotlin/Any| {
public abstract fun <T> ext(e: R|Ext<M, T>|): R|T|
}
public final class MyMessage : R|Message<MyMessage>| {
public constructor(): R|MyMessage| {
super<R|kotlin/Any|>()
}
}
public final class MyExt : R|Ext<MyMessage, kotlin/String>| {
public constructor(): R|MyExt| {
super<R|kotlin/Any|>()
}
}
public final fun <M : R|Message<M>|, T> R|Message<M>|.extF(e: R|Ext<M, T>|): R|T| {
^extF this@R|/Message|.R|FakeOverride</Message.ext: R|T|>|<R|T|>(R|<local>/e|)
}
public final fun foo(m: R|MyMessage|, e: R|MyExt|): R|kotlin/Unit| {
R|<local>/m|.R|FakeOverride</Message.ext: R|T|>|<R|kotlin/String|>(R|<local>/e|)
R|<local>/m|.R|/extF|<R|MyMessage|, R|kotlin/String|>(R|<local>/e|)
}
@@ -0,0 +1,14 @@
interface I<F> {
fun <T : Comparable<T>> f(t: List<T>, f: List<F>): Any// T = D, List<D> == List<D>
}
abstract class Base<E> {
fun <D : Comparable<D>> f(t: List<D>, e: List<E>) {}
}
class C : Base<String>(), I<String>
fun f(list: List<Int>, s: List<String>) {
C().f(list, s)
}
@@ -0,0 +1,23 @@
FILE: supertypeGenerics.kt
public abstract interface I<F> : R|kotlin/Any| {
public abstract fun <T : R|kotlin/Comparable<T>|> f(t: R|kotlin/collections/List<T>|, f: R|kotlin/collections/List<F>|): R|kotlin/Any|
}
public abstract class Base<E> : R|kotlin/Any| {
public constructor<E>(): R|Base<E>| {
super<R|kotlin/Any|>()
}
public final fun <D : R|kotlin/Comparable<D>|> f(t: R|kotlin/collections/List<D>|, e: R|kotlin/collections/List<E>|): R|kotlin/Unit| {
}
}
public final class C : R|Base<kotlin/String>|, R|I<kotlin/String>| {
public constructor(): R|C| {
super<R|Base<kotlin/String>|>()
}
}
public final fun f(list: R|kotlin/collections/List<kotlin/Int>|, s: R|kotlin/collections/List<kotlin/String>|): R|kotlin/Unit| {
R|/C.C|().R|FakeOverride</Base.f: R|kotlin/Unit|>|<R|kotlin/Int|>(R|<local>/list|, R|<local>/s|)
}
@@ -0,0 +1,14 @@
class Out<out T>
interface X : Out<String>
abstract class Base<E> {
fun <D : Out<E>> f(t: MutableList<D>, e: MutableList<E>) {}
}
class C : Base<CharSequence>()
fun f(list: MutableList<X>, s: MutableList<CharSequence>) {
C().f(list, s)
C().<!INAPPLICABLE_CANDIDATE!>f<!>(s, list)
}
@@ -0,0 +1,28 @@
FILE: supertypeGenericsComplex.kt
public final class Out<out T> : R|kotlin/Any| {
public constructor<T>(): R|Out<T>| {
super<R|kotlin/Any|>()
}
}
public abstract interface X : R|Out<kotlin/String>| {
}
public abstract class Base<E> : R|kotlin/Any| {
public constructor<E>(): R|Base<E>| {
super<R|kotlin/Any|>()
}
public final fun <D : R|Out<E>|> f(t: R|kotlin/collections/MutableList<D>|, e: R|kotlin/collections/MutableList<E>|): R|kotlin/Unit| {
}
}
public final class C : R|Base<kotlin/CharSequence>| {
public constructor(): R|C| {
super<R|Base<kotlin/CharSequence>|>()
}
}
public final fun f(list: R|kotlin/collections/MutableList<X>|, s: R|kotlin/collections/MutableList<kotlin/CharSequence>|): R|kotlin/Unit| {
R|/C.C|().R|FakeOverride</Base.f: R|kotlin/Unit|>|<R|X|>(R|<local>/list|, R|<local>/s|)
R|/C.C|().<Inapplicable(INAPPLICABLE): [/Base.f]>#(R|<local>/s|, R|<local>/list|)
}
@@ -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");
@@ -46,12 +46,13 @@ FILE fqName:<root> fileName:/delegatedMembers.kt
overridden:
public abstract fun <get-bar> (): kotlin.Int declared in <root>.IBase
$this: VALUE_PARAMETER name:<this> type:<root>.Test
FUN FAKE_OVERRIDE name:qux visibility:public modality:ABSTRACT <> ($this:<root>.IBase, t:TT of <root>.Test, x:X of <root>.IBase.qux) returnType:kotlin.Unit [fake_override]
FUN FAKE_OVERRIDE name:qux visibility:public modality:ABSTRACT <X> ($this:<root>.IBase, t:TT of <root>.Test, x:X of <root>.Test.qux) returnType:kotlin.Unit [fake_override]
overridden:
public abstract fun qux <X> (t: T of <root>.IBase, x: X of <root>.IBase.qux): kotlin.Unit declared in <root>.IBase
TYPE_PARAMETER name:X index:0 variance: superTypes:[kotlin.Any?]
$this: VALUE_PARAMETER name:<this> type:<root>.IBase
VALUE_PARAMETER name:t index:0 type:TT of <root>.Test
VALUE_PARAMETER name:x index:1 type:X of <root>.IBase.qux
VALUE_PARAMETER name:x index:1 type:X of <root>.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
@@ -137,11 +137,12 @@ FILE fqName:<root> fileName:/useImportedMember.kt
overridden:
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN FAKE_OVERRIDE name:fromInterface visibility:public modality:OPEN <> ($this:<root>.I, $receiver:T of <root>.I.fromInterface) returnType:T of <root>.I.fromInterface [fake_override]
FUN FAKE_OVERRIDE name:fromInterface visibility:public modality:OPEN <T> ($this:<root>.I, $receiver:T of <root>.C.fromInterface) returnType:T of <root>.C.fromInterface [fake_override]
overridden:
public open fun fromInterface <T> (): T of <root>.I.fromInterface declared in <root>.I
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?]
$this: VALUE_PARAMETER name:<this> type:<root>.I
$receiver: VALUE_PARAMETER name:<this> type:T of <root>.I.fromInterface
$receiver: VALUE_PARAMETER name:<this> type:T of <root>.C.fromInterface
FUN FAKE_OVERRIDE name:genericFromSuper visibility:public modality:OPEN <> ($this:<root>.I, g:kotlin.String) returnType:kotlin.String [fake_override]
overridden:
public open fun genericFromSuper (g: G of <root>.I): G of <root>.I declared in <root>.I