Implement fake override mapping for functions

Related to KT-29636
This commit is contained in:
Simon Ogorodnik
2019-01-31 19:34:52 +03:00
committed by Mikhail Glukhikh
parent 1f5e89cd32
commit 0e3fecf614
11 changed files with 330 additions and 63 deletions
@@ -26,23 +26,30 @@ object StarProjection : ConeKotlinTypeProjection() {
get() = ProjectionKind.STAR
}
class ConeKotlinTypeProjectionIn(val type: ConeKotlinType) : ConeKotlinTypeProjection() {
interface ConeTypedProjection {
val type: ConeKotlinType
}
class ConeKotlinTypeProjectionIn(override val type: ConeKotlinType) : ConeKotlinTypeProjection(), ConeTypedProjection {
override val kind: ProjectionKind
get() = ProjectionKind.IN
}
class ConeKotlinTypeProjectionOut(val type: ConeKotlinType) : ConeKotlinTypeProjection() {
class ConeKotlinTypeProjectionOut(override val type: ConeKotlinType) : ConeKotlinTypeProjection(), ConeTypedProjection {
override val kind: ProjectionKind
get() = ProjectionKind.OUT
}
// We assume type IS an invariant type projection to prevent additional wrapper here
// (more exactly, invariant type projection contains type)
sealed class ConeKotlinType : ConeKotlinTypeProjection() {
sealed class ConeKotlinType : ConeKotlinTypeProjection(), ConeTypedProjection {
override val kind: ProjectionKind
get() = ProjectionKind.INVARIANT
abstract val typeArguments: Array<out ConeKotlinTypeProjection>
override val type: ConeKotlinType
get() = this
}
class ConeKotlinErrorType(val reason: String) : ConeKotlinType() {
@@ -14,15 +14,17 @@ import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.ProcessorAction.NEXT
import org.jetbrains.kotlin.fir.scopes.impl.FirClassDeclaredMemberScope
import org.jetbrains.kotlin.fir.scopes.impl.FirClassUseSiteScope
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
import org.jetbrains.kotlin.fir.scopes.impl.FirTopLevelDeclaredMemberScope
import org.jetbrains.kotlin.fir.scopes.impl.*
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeTypedProjection
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
import org.jetbrains.kotlin.fir.visitors.compose
@@ -35,6 +37,21 @@ class FirAccessResolveTransformer : FirAbstractTreeTransformerWithSuperTypes(rev
}
}
private fun ConeClassLikeType.buildSubstitutionScope(
useSiteSession: FirSession,
unsubstituted: FirScope,
regularClass: FirRegularClass
): FirClassSubstitutionScope? {
if (this.typeArguments.isEmpty()) return null
@Suppress("UNCHECKED_CAST")
val substitution = regularClass.typeParameters.zip(this.typeArguments) { typeParameter, typeArgument ->
typeParameter.symbol to (typeArgument as? ConeTypedProjection)?.type
}.filter { (_, type) -> type != null }.toMap() as Map<ConeTypeParameterSymbol, ConeKotlinType>
return FirClassSubstitutionScope(useSiteSession, unsubstituted, substitution, true)
}
private fun FirRegularClass.buildUseSiteScope(useSiteSession: FirSession = session): FirClassUseSiteScope {
val superTypeScope = FirCompositeScope(mutableListOf())
val declaredScope = FirClassDeclaredMemberScope(this, useSiteSession)
@@ -43,7 +60,8 @@ class FirAccessResolveTransformer : FirAbstractTreeTransformerWithSuperTypes(rev
if (useSiteSuperType is ConeClassErrorType) return@mapNotNullTo null
val symbol = useSiteSuperType.symbol
if (symbol is FirClassSymbol) {
symbol.fir.buildUseSiteScope(useSiteSession)
val scope = symbol.fir.buildUseSiteScope(useSiteSession)
useSiteSuperType.buildSubstitutionScope(useSiteSession, scope, symbol.fir) ?: scope
} else {
null
}
@@ -58,10 +76,10 @@ class FirAccessResolveTransformer : FirAbstractTreeTransformerWithSuperTypes(rev
}
}
var lookupFunctions = false
var lookupProperties = false
private var lookupFunctions = false
private var lookupProperties = false
inline fun <T> withNewSettings(block: () -> T): T {
private inline fun <T> withNewSettings(block: () -> T): T {
val prevFunctions = lookupFunctions
val prevProperties = lookupProperties
val result = block()
@@ -0,0 +1,149 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirNamedFunction
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirMemberFunctionImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.symbols.*
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeAbbreviatedTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeImpl
import org.jetbrains.kotlin.name.Name
class FirClassSubstitutionScope(
session: FirSession,
private val unsubstituted: FirScope,
private val substitution: Map<ConeTypeParameterSymbol, ConeKotlinType>,
lookupInFir: Boolean
) : FirAbstractProviderBasedScope(session, lookupInFir) {
val fakeOverrides = mutableMapOf<ConeCallableSymbol, ConeCallableSymbol>()
private fun wrapProjection(old: ConeKotlinTypeProjection, newType: ConeKotlinType): ConeKotlinTypeProjection {
return when (old) {
is StarProjection -> old
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(newType)
is ConeKotlinTypeProjectionOut -> ConeKotlinTypeProjectionOut(newType)
is ConeKotlinType -> newType
else -> old
}
}
private fun ConeKotlinType.substitute(): ConeKotlinType? {
if (this is ConeTypeParameterType) return substitution[this]
val newArguments by lazy { arrayOfNulls<ConeKotlinTypeProjection>(typeArguments.size) }
var initialized = false
for ((index, typeArgument) in this.typeArguments.withIndex()) {
val type = (typeArgument as? ConeTypedProjection)?.type ?: continue
val newType = type.substitute()
if (newType != null) {
initialized = true
newArguments[index] = wrapProjection(typeArgument, newType)
}
}
if (initialized) {
for ((index, typeArgument) in this.typeArguments.withIndex()) {
if (newArguments[index] == null) {
newArguments[index] = typeArgument
}
}
@Suppress("UNCHECKED_CAST")
return when (this) {
is ConeKotlinErrorType -> error("Trying to substitute arguments for error type")
is ConeTypeParameterType -> error("Trying to substitute arguments for type parameter")
is ConeClassTypeImpl -> ConeClassTypeImpl(symbol, newArguments as Array<ConeKotlinTypeProjection>)
is ConeAbbreviatedTypeImpl -> ConeAbbreviatedTypeImpl(
abbreviationSymbol,
newArguments as Array<ConeKotlinTypeProjection>,
directExpansion.substitute() as? ConeClassLikeType ?: directExpansion
)
is ConeFunctionType -> TODO("Substitute function type properly")
is ConeClassLikeType -> error("Unknown class-like type to substitute: $this, ${this::class}")
}
}
return null
}
override fun processFunctionsByName(name: Name, processor: (ConeFunctionSymbol) -> ProcessorAction): ProcessorAction {
unsubstituted.processFunctionsByName(name) process@{ original ->
val function = fakeOverrides.getOrPut(original) { createFakeOverride(original, name) }
processor(function as ConeFunctionSymbol)
}
return super.processFunctionsByName(name, processor)
}
override fun processPropertiesByName(name: Name, processor: (ConePropertySymbol) -> ProcessorAction): ProcessorAction {
return unsubstituted.processPropertiesByName(name, processor)
}
private fun createFakeOverride(
original: ConeFunctionSymbol,
name: Name
): FirFunctionSymbol {
val member = (original as FirBasedSymbol<*>).fir as? FirNamedFunction ?: error("Can't fake override for $original")
val receiverType = member.receiverType?.coneTypeUnsafe()
val newReceiverType = receiverType?.substitute()
val returnType = member.returnType.coneTypeUnsafe()
val newReturnType = returnType.substitute()
val newParameterTypes = member.valueParameters.map {
it.returnType.coneTypeUnsafe().substitute()
}
val symbol = FirFunctionSymbol(original.callableId, true)
with(member) {
// TODO: consider using here some light-weight functions instead of pseudo-real FirMemberFunctionImpl
// As second alternative, we can invent some light-weight kind of FirRegularClass
FirMemberFunctionImpl(
session,
psi,
symbol,
name,
member.receiverType?.withReplacedConeType(newReceiverType),
member.returnType.withReplacedConeType(newReturnType)
).apply {
status = member.status as FirDeclarationStatusImpl
valueParameters += member.valueParameters.zip(newParameterTypes) { valueParameter, newType ->
with(valueParameter) {
FirValueParameterImpl(
session, psi,
name, this.returnType.withReplacedConeType(newType),
defaultValue, isCrossinline, isNoinline, isVararg
)
}
}
}
}
return symbol
}
}
fun FirType.withReplacedConeType(newType: ConeKotlinType?): FirResolvedType {
require(this is FirResolvedType)
if (newType == null) return this
return FirResolvedTypeImpl(
session, psi, newType,
isNullable,
annotations
)
}
@@ -0,0 +1,15 @@
open class A<T> {
fun foo(t: T): T {
return t
}
}
class Some
class B : A<Some>() {
fun test() {
foo(Some())
}
}
@@ -0,0 +1,21 @@
FILE: simpleFakeOverride.kt
<T> public open class A {
public constructor(): super<R|kotlin/Any|>()
public final function foo(t: R|T|): R|T| {
return@@@foo <Unresolved name: t>#
}
}
public final class Some {
public constructor(): super<R|kotlin/Any|>()
}
public final class B : R|A<Some>| {
public constructor(): super<R|A<Some>|>()
public final function test(): R|kotlin/Unit| {
R|FakeOverride</A.foo>|(<Unresolved name: Some>#())
}
}
@@ -259,6 +259,11 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
public void testSimple() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/overrides/simple.kt");
}
@TestMetadata("simpleFakeOverride.kt")
public void testSimpleFakeOverride() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/overrides/simpleFakeOverride.kt");
}
}
@TestMetadata("compiler/fir/resolve/testData/resolve/references")
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.*
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinType
@@ -697,7 +698,15 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
override fun visitResolvedCallableReference(resolvedCallableReference: FirResolvedCallableReference) {
print("R|")
val isFakeOverride = (resolvedCallableReference.callableSymbol as? FirFunctionSymbol)?.isFakeOverride == true
if (isFakeOverride) {
print("FakeOverride<")
}
print(resolvedCallableReference.callableSymbol.callableId)
if (isFakeOverride) {
print(">")
}
print("|")
}
@@ -17,25 +17,47 @@ import org.jetbrains.kotlin.fir.types.FirType
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.name.Name
abstract class FirAbstractCallableMember(
session: FirSession,
psi: PsiElement?,
final override val symbol: FirBasedSymbol<FirCallableMember>,
name: Name,
visibility: Visibility,
modality: Modality?,
isExpect: Boolean,
isActual: Boolean,
isOverride: Boolean,
final override var receiverType: FirType?,
final override var returnType: FirType
) : FirAbstractMemberDeclaration(session, psi, name, visibility, modality, isExpect, isActual), FirCallableMember {
abstract class FirAbstractCallableMember : FirAbstractMemberDeclaration, FirCallableMember {
init {
final override val symbol: FirBasedSymbol<FirCallableMember>
final override var receiverType: FirType?
final override var returnType: FirType
constructor(
session: FirSession,
psi: PsiElement?,
symbol: FirBasedSymbol<FirCallableMember>,
name: Name,
receiverType: FirType?,
returnType: FirType
) : super(session, psi, name) {
this.symbol = symbol
symbol.bind(this)
this.receiverType = receiverType
this.returnType = returnType
}
constructor(
session: FirSession,
psi: PsiElement?,
symbol: FirBasedSymbol<FirCallableMember>,
name: Name,
visibility: Visibility,
modality: Modality?,
isExpect: Boolean,
isActual: Boolean,
isOverride: Boolean,
receiverType: FirType?,
returnType: FirType
) : super(session, psi, name, visibility, modality, isExpect, isActual) {
this.symbol = symbol
symbol.bind(this)
this.receiverType = receiverType
this.returnType = returnType
status.isOverride = isOverride
}
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElement {
receiverType = receiverType?.transformSingle(transformer, data)
returnType = returnType.transformSingle(transformer, data)
@@ -20,23 +20,31 @@ import org.jetbrains.kotlin.name.Name
abstract class FirAbstractMemberDeclaration(
session: FirSession,
psi: PsiElement?,
name: Name,
visibility: Visibility,
modality: Modality?,
isExpect: Boolean,
isActual: Boolean
name: Name
) : FirAbstractNamedAnnotatedDeclaration(session, psi, name), FirMemberDeclaration {
final override val typeParameters = mutableListOf<FirTypeParameter>()
final override var status = FirDeclarationStatusImpl(
session,
visibility,
modality
).apply {
this.isExpect = isExpect
this.isActual = isActual
constructor(
session: FirSession,
psi: PsiElement?,
name: Name,
visibility: Visibility,
modality: Modality?,
isExpect: Boolean,
isActual: Boolean
) : this(session, psi, name) {
this.status = FirDeclarationStatusImpl(
session,
visibility,
modality
).apply {
this.isExpect = isExpect
this.isActual = isActual
}
}
final override val typeParameters: MutableList<FirTypeParameter> = mutableListOf()
final override lateinit var status: FirDeclarationStatusImpl
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElement {
typeParameters.transformInplace(transformer, data)
status = status.transformSingle(transformer, data)
@@ -20,29 +20,39 @@ import org.jetbrains.kotlin.fir.types.FirType
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.name.Name
class FirMemberFunctionImpl(
session: FirSession,
psi: PsiElement?,
symbol: FirFunctionSymbol,
name: Name,
visibility: Visibility,
modality: Modality?,
isExpect: Boolean,
isActual: Boolean,
isOverride: Boolean,
isOperator: Boolean,
isInfix: Boolean,
isInline: Boolean,
isTailRec: Boolean,
isExternal: Boolean,
isSuspend: Boolean,
receiverType: FirType?,
returnType: FirType
) : FirAbstractCallableMember(
session, psi, symbol, name, visibility, modality,
isExpect, isActual, isOverride, receiverType, returnType
), FirNamedFunction, FirModifiableFunction {
init {
class FirMemberFunctionImpl : FirAbstractCallableMember, FirNamedFunction, FirModifiableFunction {
constructor(
session: FirSession,
psi: PsiElement?,
symbol: FirFunctionSymbol,
name: Name,
receiverType: FirType?,
returnType: FirType
) : super(session, psi, symbol, name, receiverType, returnType)
constructor(
session: FirSession,
psi: PsiElement?,
symbol: FirFunctionSymbol,
name: Name,
visibility: Visibility,
modality: Modality?,
isExpect: Boolean,
isActual: Boolean,
isOverride: Boolean,
isOperator: Boolean,
isInfix: Boolean,
isInline: Boolean,
isTailRec: Boolean,
isExternal: Boolean,
isSuspend: Boolean,
receiverType: FirType?,
returnType: FirType
) : super(
session, psi, symbol, name, visibility, modality,
isExpect, isActual, isOverride, receiverType, returnType
) {
status.isOperator = isOperator
status.isInfix = isInfix
status.isInline = isInline
@@ -11,7 +11,10 @@ import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.ConeFunctionSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
class FirFunctionSymbol(override val callableId: CallableId) : ConeFunctionSymbol, AbstractFirBasedSymbol<FirCallableMember>() {
class FirFunctionSymbol(
override val callableId: CallableId,
val isFakeOverride: Boolean = false
) : ConeFunctionSymbol, AbstractFirBasedSymbol<FirCallableMember>() {
override val parameters: List<ConeKotlinType>
get() = emptyList()
}