FIR: Move constructor processing parts to a separate file

This commit is contained in:
Denis Zharkov
2019-11-27 11:56:35 +03:00
parent bf68e85a5c
commit fbe7db5471
3 changed files with 219 additions and 203 deletions
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirTypeParameterImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticFunctionSymbol
import org.jetbrains.kotlin.fir.resolve.calls.SAM_PARAMETER_NAME
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.symbols.CallableId
@@ -38,6 +37,7 @@ interface FirSamResolver : FirSessionComponent {
}
private val NULL_STUB = Any()
val SAM_PARAMETER_NAME = Name.identifier("block")
class FirSamResolverImpl(
private val firSession: FirSession,
@@ -0,0 +1,215 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.resolve.calls
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirConstructorImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal fun FirScope.processFunctionsAndConstructorsByName(
name: Name,
session: FirSession,
bodyResolveComponents: BodyResolveComponents,
processor: (FirCallableSymbol<*>) -> ProcessorAction
): ProcessorAction {
val matchedClassSymbol = getFirstClassifierOrNull(name) as? FirClassLikeSymbol<*>
if (processConstructors(
matchedClassSymbol,
processor,
session,
bodyResolveComponents.scopeSession,
name
).stop()
) {
return ProcessorAction.STOP
}
if (processSyntheticConstructors(
matchedClassSymbol,
processor,
bodyResolveComponents
).stop()
) {
return ProcessorAction.STOP
}
return processFunctionsByName(name) {
if (it is FirConstructorSymbol) ProcessorAction.NEXT
else processor(it)
}
}
private fun FirScope.getFirstClassifierOrNull(name: Name): FirClassifierSymbol<*>? {
var result: FirClassifierSymbol<*>? = null
processClassifiersByName(name) {
result = it
ProcessorAction.STOP
}
return result
}
private fun finalExpansionName(symbol: FirTypeAliasSymbol, session: FirSession): Name? {
val expandedType = symbol.fir.expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>()
val typeAliasSymbol = expandedType.lookupTag.toSymbol(session)?.safeAs<FirTypeAliasSymbol>()
return if (typeAliasSymbol != null)
finalExpansionName(typeAliasSymbol, session)
else
expandedType.lookupTag.classId.shortClassName
}
private fun processSyntheticConstructors(
matchedSymbol: FirClassLikeSymbol<*>?,
processor: (FirFunctionSymbol<*>) -> ProcessorAction,
bodyResolveComponents: BodyResolveComponents
): ProcessorAction {
if (matchedSymbol == null) return ProcessorAction.NEXT
if (matchedSymbol !is FirRegularClassSymbol) return ProcessorAction.NEXT
val function = bodyResolveComponents.samResolver.getSamConstructor(matchedSymbol.fir) ?: return ProcessorAction.NEXT
return processor(function.symbol)
}
private fun processConstructors(
matchedSymbol: FirClassLikeSymbol<*>?,
processor: (FirFunctionSymbol<*>) -> ProcessorAction,
session: FirSession,
scopeSession: ScopeSession,
name: Name
): ProcessorAction {
try {
if (matchedSymbol != null) {
val scope = when (matchedSymbol) {
is FirTypeAliasSymbol -> {
val type = matchedSymbol.fir.expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>().fullyExpandedType(session)
val basicScope = type.scope(session, scopeSession)
if (basicScope != null && type.typeArguments.isNotEmpty()) {
prepareSubstitutingScopeForTypeAliasConstructors(
matchedSymbol, type, session, basicScope
) ?: return ProcessorAction.STOP
} else basicScope
}
is FirClassSymbol -> matchedSymbol.buildUseSiteMemberScope(session, scopeSession)
}
val constructorName = when (matchedSymbol) {
is FirTypeAliasSymbol -> finalExpansionName(matchedSymbol, session) ?: return ProcessorAction.NEXT
is FirClassSymbol -> name
}
//TODO: why don't we use declared member scope at this point?
if (scope != null && scope.processFunctionsByName(
constructorName,
processor
) == ProcessorAction.STOP
) {
return ProcessorAction.STOP
}
}
return ProcessorAction.NEXT
} catch (e: Throwable) {
throw RuntimeException("While processing constructors", e)
}
}
private class TypeAliasConstructorsSubstitutingScope(
private val typeAliasSymbol: FirTypeAliasSymbol,
private val substitutor: ConeSubstitutor,
private val delegatingScope: FirScope
) : FirScope() {
override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> ProcessorAction): ProcessorAction {
return delegatingScope.processFunctionsByName(name) {
val toProcess = if (it is FirConstructorSymbol) {
it.fir.createTypeAliasConstructor(substitutor, typeAliasSymbol.fir.typeParameters).symbol
} else {
it
}
processor(toProcess)
}
}
}
private fun prepareSubstitutingScopeForTypeAliasConstructors(
typeAliasSymbol: FirTypeAliasSymbol,
expandedType: ConeClassLikeType,
session: FirSession,
delegatingScope: FirScope
): FirScope? {
val expandedClass = expandedType.lookupTag.toSymbol(session)?.fir as? FirRegularClass ?: return null
val resultingTypeArguments = expandedType.typeArguments.map {
// We don't know how to handle cases like yet
// typealias A = ArrayList<*>()
it as? ConeKotlinType ?: return null
}
val substitutor = substitutorByMap(
expandedClass.typeParameters.map { it.symbol }.zip(resultingTypeArguments).toMap()
);
return TypeAliasConstructorsSubstitutingScope(typeAliasSymbol, substitutor, delegatingScope)
}
private fun FirConstructor.createTypeAliasConstructor(
substitutor: ConeSubstitutor,
typeParameters: List<FirTypeParameter>
): FirConstructor {
val newReturnTypeRef = returnTypeRef.substitute(substitutor)
val newParameterTypeRefs = valueParameters.map { valueParameter ->
valueParameter.returnTypeRef.substitute(substitutor)
}
if (newReturnTypeRef == null && newParameterTypeRefs.all { it == null }) return this
return FirConstructorImpl(
source, session, newReturnTypeRef ?: returnTypeRef, receiverTypeRef, status,
FirConstructorSymbol(symbol.callableId, overriddenSymbol = symbol)
).apply {
resolvePhase = this@createTypeAliasConstructor.resolvePhase
valueParameters += this@createTypeAliasConstructor.valueParameters.zip(
newParameterTypeRefs
) { valueParameter, newTypeRef ->
with(valueParameter) {
FirValueParameterImpl(
source,
session,
newTypeRef ?: returnTypeRef,
name,
FirVariableSymbol(valueParameter.symbol.callableId),
defaultValue,
isCrossinline,
isNoinline,
isVararg
)
}
}
this.typeParameters += typeParameters
}
}
private fun FirTypeRef.substitute(substitutor: ConeSubstitutor): FirResolvedTypeRef? =
coneTypeUnsafe<ConeKotlinType>()
.let(substitutor::substituteOrNull)
?.let { FirResolvedTypeRefImpl(source, it) }
@@ -8,26 +8,21 @@ package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirConstructorImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirImportImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedImportImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractImportingScope
import org.jetbrains.kotlin.fir.scopes.impl.FirExplicitSimpleImportingScope
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
interface TowerScopeLevel {
@@ -282,197 +277,3 @@ fun FirCallableDeclaration<*>.dispatchReceiverValue(session: FirSession): ClassD
}
private fun FirCallableSymbol<*>.hasExtensionReceiver(): Boolean = this.fir.receiverTypeRef != null
private fun FirScope.processFunctionsAndConstructorsByName(
name: Name,
session: FirSession,
bodyResolveComponents: BodyResolveComponents,
processor: (FirCallableSymbol<*>) -> ProcessorAction
): ProcessorAction {
val matchedClassSymbol = getFirstClassifierOrNull(name) as? FirClassLikeSymbol<*>
if (processConstructors(
matchedClassSymbol,
processor,
session,
bodyResolveComponents.scopeSession,
name
).stop()
) {
return ProcessorAction.STOP
}
if (processSyntheticConstructors(
matchedClassSymbol,
processor,
bodyResolveComponents
).stop()
) {
return ProcessorAction.STOP
}
return processFunctionsByName(name) {
if (it is FirConstructorSymbol) ProcessorAction.NEXT
else processor(it)
}
}
private fun FirScope.getFirstClassifierOrNull(name: Name): FirClassifierSymbol<*>? {
var result: FirClassifierSymbol<*>? = null
processClassifiersByName(name) {
result = it
ProcessorAction.STOP
}
return result
}
private fun finalExpansionName(symbol: FirTypeAliasSymbol, session: FirSession): Name? {
val expandedType = symbol.fir.expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>()
val typeAliasSymbol = expandedType.lookupTag.toSymbol(session)?.safeAs<FirTypeAliasSymbol>()
return if (typeAliasSymbol != null)
finalExpansionName(typeAliasSymbol, session)
else
expandedType.lookupTag.classId.shortClassName
}
val SAM_PARAMETER_NAME = Name.identifier("block")
private fun processSyntheticConstructors(
matchedSymbol: FirClassLikeSymbol<*>?,
processor: (FirFunctionSymbol<*>) -> ProcessorAction,
bodyResolveComponents: BodyResolveComponents
): ProcessorAction {
if (matchedSymbol == null) return ProcessorAction.NEXT
if (matchedSymbol !is FirRegularClassSymbol) return ProcessorAction.NEXT
val function = bodyResolveComponents.samResolver.getSamConstructor(matchedSymbol.fir) ?: return ProcessorAction.NEXT
return processor(function.symbol)
}
private fun processConstructors(
matchedSymbol: FirClassLikeSymbol<*>?,
processor: (FirFunctionSymbol<*>) -> ProcessorAction,
session: FirSession,
scopeSession: ScopeSession,
name: Name
): ProcessorAction {
try {
if (matchedSymbol != null) {
val scope = when (matchedSymbol) {
is FirTypeAliasSymbol -> {
val type = matchedSymbol.fir.expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>().fullyExpandedType(session)
val basicScope = type.scope(session, scopeSession)
if (basicScope != null && type.typeArguments.isNotEmpty()) {
prepareSubstitutingScopeForTypeAliasConstructors(
matchedSymbol, type, session, basicScope
) ?: return ProcessorAction.STOP
} else basicScope
}
is FirClassSymbol -> matchedSymbol.buildUseSiteMemberScope(session, scopeSession)
}
val constructorName = when (matchedSymbol) {
is FirTypeAliasSymbol -> finalExpansionName(matchedSymbol, session) ?: return ProcessorAction.NEXT
is FirClassSymbol -> name
}
//TODO: why don't we use declared member scope at this point?
if (scope != null && scope.processFunctionsByName(
constructorName,
processor
) == ProcessorAction.STOP
) {
return ProcessorAction.STOP
}
}
return ProcessorAction.NEXT
} catch (e: Throwable) {
throw RuntimeException("While processing constructors", e)
}
}
private class TypeAliasConstructorsSubstitutingScope(
private val typeAliasSymbol: FirTypeAliasSymbol,
private val substitutor: ConeSubstitutor,
private val delegatingScope: FirScope
) : FirScope() {
override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> ProcessorAction): ProcessorAction {
return delegatingScope.processFunctionsByName(name) {
val toProcess = if (it is FirConstructorSymbol) {
it.fir.createTypeAliasConstructor(substitutor, typeAliasSymbol.fir.typeParameters).symbol
} else {
it
}
processor(toProcess)
}
}
}
private fun prepareSubstitutingScopeForTypeAliasConstructors(
typeAliasSymbol: FirTypeAliasSymbol,
expandedType: ConeClassLikeType,
session: FirSession,
delegatingScope: FirScope
): FirScope? {
val expandedClass = expandedType.lookupTag.toSymbol(session)?.fir as? FirRegularClass ?: return null
val resultingTypeArguments = expandedType.typeArguments.map {
// We don't know how to handle cases like yet
// typealias A = ArrayList<*>()
it as? ConeKotlinType ?: return null
}
val substitutor = substitutorByMap(
expandedClass.typeParameters.map { it.symbol }.zip(resultingTypeArguments).toMap()
);
return TypeAliasConstructorsSubstitutingScope(typeAliasSymbol, substitutor, delegatingScope)
}
private fun FirConstructor.createTypeAliasConstructor(
substitutor: ConeSubstitutor,
typeParameters: List<FirTypeParameter>
): FirConstructor {
val newReturnTypeRef = returnTypeRef.substitute(substitutor)
val newParameterTypeRefs = valueParameters.map { valueParameter ->
valueParameter.returnTypeRef.substitute(substitutor)
}
if (newReturnTypeRef == null && newParameterTypeRefs.all { it == null }) return this
return FirConstructorImpl(
source, session, newReturnTypeRef ?: returnTypeRef, receiverTypeRef, status,
FirConstructorSymbol(symbol.callableId, overriddenSymbol = symbol)
).apply {
resolvePhase = this@createTypeAliasConstructor.resolvePhase
valueParameters += this@createTypeAliasConstructor.valueParameters.zip(
newParameterTypeRefs
) { valueParameter, newTypeRef ->
with(valueParameter) {
FirValueParameterImpl(
source,
session,
newTypeRef ?: returnTypeRef,
name,
FirVariableSymbol(valueParameter.symbol.callableId),
defaultValue,
isCrossinline,
isNoinline,
isVararg
)
}
}
this.typeParameters += typeParameters
}
}
private fun FirTypeRef.substitute(substitutor: ConeSubstitutor): FirResolvedTypeRef? =
coneTypeUnsafe<ConeKotlinType>()
.let(substitutor::substituteOrNull)
?.let { FirResolvedTypeRefImpl(source, it) }