[FIR JS] Generate dynamic FIRs via DynamicScope

This commit is contained in:
Mikhail Glukhikh
2022-03-24 13:53:27 +03:00
committed by teamcity
parent 5e97a36680
commit eaa77b5af6
11 changed files with 222 additions and 6 deletions
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedClassIndex
import org.jetbrains.kotlin.fir.scopes.FirOverrideService
import org.jetbrains.kotlin.fir.scopes.FirPlatformClassMapper
import org.jetbrains.kotlin.fir.scopes.impl.FirDeclaredMemberScopeProvider
import org.jetbrains.kotlin.fir.scopes.impl.FirDynamicMembersStorage
import org.jetbrains.kotlin.fir.scopes.impl.FirIntersectionOverrideStorage
import org.jetbrains.kotlin.fir.scopes.impl.FirSubstitutionOverrideStorage
import org.jetbrains.kotlin.fir.symbols.FirPhaseManager
@@ -66,6 +67,7 @@ fun FirSession.registerCommonComponents(languageVersionSettings: LanguageVersion
register(FirIntersectionOverrideStorage::class, FirIntersectionOverrideStorage(this))
register(FirSamConstructorStorage::class, FirSamConstructorStorage(this))
register(FirOverrideService::class, FirOverrideService(this))
register(FirDynamicMembersStorage::class, FirDynamicMembersStorage(this))
}
@OptIn(SessionConfiguration::class)
@@ -14,10 +14,7 @@ import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
import org.jetbrains.kotlin.fir.scopes.FirUnstableSmartcastTypeScope
import org.jetbrains.kotlin.fir.scopes.impl.FirScopeWithFakeOverrideTypeCalculator
import org.jetbrains.kotlin.fir.scopes.impl.FirStandardOverrideChecker
import org.jetbrains.kotlin.fir.scopes.impl.FirTypeIntersectionScope
import org.jetbrains.kotlin.fir.scopes.impl.getOrBuildScopeForIntegerConstantOperatorType
import org.jetbrains.kotlin.fir.scopes.impl.*
import org.jetbrains.kotlin.fir.scopes.scopeForClass
import org.jetbrains.kotlin.fir.symbols.ensureResolved
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
@@ -81,6 +78,7 @@ private fun ConeKotlinType.scope(useSiteSession: FirSession, scopeSession: Scope
}
}
is ConeRawType -> lowerBound.scope(useSiteSession, scopeSession, requiredPhase)
is ConeDynamicType -> useSiteSession.dynamicMembersStorage.getDynamicScopeFor(scopeSession)
is ConeFlexibleType -> lowerBound.scope(useSiteSession, scopeSession, requiredPhase)
is ConeIntersectionType -> FirTypeIntersectionScope.prepareIntersectionScope(
useSiteSession,
@@ -0,0 +1,189 @@
/*
* Copyright 2010-2022 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.scopes.impl
import org.jetbrains.kotlin.builtins.StandardNames.DYNAMIC_FQ_NAME
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.caches.FirCache
import org.jetbrains.kotlin.fir.caches.createCache
import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.builder.*
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.expressions.FirOperationNameConventions
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.scope
import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeDynamicType
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.create
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
@RequiresOptIn(message = "Please, don't create FirDynamicScope-s manually")
annotation class FirDynamicScopeConstructor
class FirDynamicScope @FirDynamicScopeConstructor constructor(
private val session: FirSession,
private val scopeSession: ScopeSession,
) : FirTypeScope() {
override fun processDirectOverriddenFunctionsWithBaseScope(
functionSymbol: FirNamedFunctionSymbol,
processor: (FirNamedFunctionSymbol, FirTypeScope) -> ProcessorAction
): ProcessorAction = ProcessorAction.NEXT
override fun processDirectOverriddenPropertiesWithBaseScope(
propertySymbol: FirPropertySymbol,
processor: (FirPropertySymbol, FirTypeScope) -> ProcessorAction
): ProcessorAction = ProcessorAction.NEXT
override fun getCallableNames(): Set<Name> = emptySet()
override fun getClassifierNames(): Set<Name> = emptySet()
private val anyTypeScope by lazy {
session.builtinTypes.anyType.type.scope(session, scopeSession, FakeOverrideTypeCalculator.DoNothing)
}
override fun processFunctionsByName(
name: Name,
processor: (FirNamedFunctionSymbol) -> Unit
) {
var foundMemberInAny = false
anyTypeScope?.processFunctionsByName(name) {
foundMemberInAny = true
processor(it)
}
if (foundMemberInAny) {
return
}
session.dynamicMembersStorage.functionsCacheByName.getValue(name, null).also {
processor(it.symbol)
}
}
override fun processPropertiesByName(
name: Name,
processor: (FirVariableSymbol<*>) -> Unit
) {
var foundMemberInAny = false
anyTypeScope?.processPropertiesByName(name) {
foundMemberInAny = true
processor(it)
}
if (foundMemberInAny) {
return
}
session.dynamicMembersStorage.propertiesCacheByName.getValue(name, null).also {
processor(it.symbol)
}
}
}
class FirDynamicMembersStorage(val session: FirSession) : FirSessionComponent {
private val cachesFactory = session.firCachesFactory
@OptIn(FirDynamicScopeConstructor::class)
private val dynamicScopeCacheByScope: FirCache<ScopeSession, FirDynamicScope, Nothing?> =
cachesFactory.createCache { it -> FirDynamicScope(session, it) }
fun getDynamicScopeFor(scopeSession: ScopeSession) = dynamicScopeCacheByScope.getValue(scopeSession, null)
val functionsCacheByName: FirCache<Name, FirSimpleFunction, Nothing?> =
cachesFactory.createCache { name -> buildPseudoFunctionByName(name) }
val propertiesCacheByName: FirCache<Name, FirProperty, Nothing?> =
cachesFactory.createCache { name -> buildPseudoPropertyByName(name) }
private val dynamicTypeRef = buildResolvedTypeRef {
type = ConeDynamicType.create(session)
}
private val anyArrayTypeRef = buildResolvedTypeRef {
type = ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(StandardClassIds.Array),
arrayOf(session.builtinTypes.nullableAnyType.coneType),
isNullable = false
)
}
private fun buildPseudoFunctionByName(name: Name) = buildSimpleFunction {
status = FirResolvedDeclarationStatusImpl(
Visibilities.Public,
Modality.FINAL,
EffectiveVisibility.Public,
).apply {
isInfix = true
isOperator = true
}
this.name = name
this.symbol = FirNamedFunctionSymbol(CallableId(DYNAMIC_FQ_NAME, this.name))
moduleData = session.moduleData
origin = FirDeclarationOrigin.DynamicScope
resolvePhase = FirResolvePhase.BODY_RESOLVE
returnTypeRef = if (name in FirOperationNameConventions.ASSIGNMENT_NAMES) {
session.builtinTypes.unitType
} else {
dynamicTypeRef
}
val parameter = buildValueParameter {
moduleData = session.moduleData
origin = FirDeclarationOrigin.DynamicScope
returnTypeRef = anyArrayTypeRef
this.name = Name.identifier("args")
this.symbol = FirValueParameterSymbol(this.name)
isCrossinline = false
isNoinline = false
isVararg = true
}
valueParameters.add(parameter)
}
private fun buildPseudoPropertyByName(name: Name) = buildProperty {
this.name = name
this.symbol = FirPropertySymbol(CallableId(DYNAMIC_FQ_NAME, this.name))
status = FirResolvedDeclarationStatusImpl(
Visibilities.Public,
Modality.FINAL,
EffectiveVisibility.Public,
)
moduleData = session.moduleData
origin = FirDeclarationOrigin.DynamicScope
resolvePhase = FirResolvePhase.BODY_RESOLVE
returnTypeRef = dynamicTypeRef
isVar = true
isLocal = false
}
}
val FirSession.dynamicMembersStorage: FirDynamicMembersStorage by FirSession.sessionComponentAccessor()
@@ -522,6 +522,7 @@ fun FirFunction.getAsForbiddenNamedArgumentsTarget(session: FirSession): Forbidd
}
}
FirDeclarationOrigin.Synthetic -> null
FirDeclarationOrigin.DynamicScope -> null
FirDeclarationOrigin.RenamedForOverride -> null
FirDeclarationOrigin.WrappedIntegerOperator -> null
is FirDeclarationOrigin.Plugin -> null // TODO: figure out what to do with plugin generated functions
@@ -20,6 +20,7 @@ sealed class CallKind(vararg resolutionSequence: ResolutionStage) {
CheckDslScopeViolation,
CheckLowPriorityInOverloadResolution,
PostponedVariablesInitializerResolutionStage,
LowerPriorityIfDynamic,
ConstraintSystemForks,
CheckIncompatibleTypeVariableUpperBounds,
)
@@ -53,6 +54,7 @@ sealed class CallKind(vararg resolutionSequence: ResolutionStage) {
EagerResolveOfCallableReferences,
CheckLowPriorityInOverloadResolution,
PostponedVariablesInitializerResolutionStage,
LowerPriorityIfDynamic,
ConstraintSystemForks,
CheckIncompatibleTypeVariableUpperBounds,
)
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
@@ -79,7 +80,11 @@ fun BodyResolveComponents.mapArguments(
// If this is an indexed access set operator, it could have default values or a vararg parameter in the middle.
// For proper argument mapping, wrap the last one, which is supposed to be the updated value, as a named argument.
val isIndexedSetOperator = function is FirSimpleFunction && function.isOperator && function.name == OperatorNameConventions.SET
val isIndexedSetOperator = function is FirSimpleFunction
&& function.isOperator
&& function.name == OperatorNameConventions.SET
&& function.origin !is FirDeclarationOrigin.DynamicScope
if (isIndexedSetOperator &&
function.valueParameters.any { it.defaultValue != null || it.isVararg }
) {
@@ -644,6 +644,14 @@ internal object CheckDeprecatedSinceKotlin : ResolutionStage() {
}
}
internal object LowerPriorityIfDynamic : ResolutionStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
if (candidate.symbol.origin is FirDeclarationOrigin.DynamicScope) {
candidate.addDiagnostic(LowerPriorityForDynamic)
}
}
}
internal object ConstraintSystemForks : ResolutionStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
if (candidate.system.hasContradiction) return
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRefsOwner
import org.jetbrains.kotlin.fir.types.FirTypeProjection
import org.jetbrains.kotlin.fir.types.builder.buildPlaceholderProjection
@@ -33,7 +35,11 @@ internal object MapTypeArguments : ResolutionStage() {
val owner = candidate.symbol.fir as FirTypeParameterRefsOwner
if (typeArguments.size == owner.typeParameters.size || callInfo.callKind == CallKind.DelegatingConstructorCall) {
if (
typeArguments.size == owner.typeParameters.size ||
callInfo.callKind == CallKind.DelegatingConstructorCall ||
(owner as? FirDeclaration)?.origin is FirDeclarationOrigin.DynamicScope
) {
candidate.typeArgumentMapping = TypeArgumentMapping.Mapped(typeArguments)
} else {
candidate.typeArgumentMapping = TypeArgumentMapping.Mapped(emptyList())
@@ -89,6 +89,8 @@ class UnsafeCall(val actualType: ConeKotlinType) : ResolutionDiagnostic(UNSAFE_C
object LowerPriorityToPreserveCompatibilityDiagnostic : ResolutionDiagnostic(RESOLVED_NEED_PRESERVE_COMPATIBILITY)
object LowerPriorityForDynamic : ResolutionDiagnostic(RESOLVED_LOW_PRIORITY)
object CandidateChosenUsingOverloadResolutionByLambdaAnnotation : ResolutionDiagnostic(RESOLVED)
class UnstableSmartCast(val argument: FirExpressionWithSmartcast, val targetType: ConeKotlinType, val isCastToNotNull: Boolean) :
@@ -12,6 +12,7 @@ sealed class FirDeclarationOrigin(private val displayName: String? = null, val f
object BuiltIns : FirDeclarationOrigin()
object Java : FirDeclarationOrigin()
object Synthetic : FirDeclarationOrigin()
object DynamicScope : FirDeclarationOrigin()
object SamConstructor : FirDeclarationOrigin()
object Enhancement : FirDeclarationOrigin()
object ImportedFromObject : FirDeclarationOrigin()
@@ -32,6 +32,8 @@ object StandardNames {
@JvmField val CONTEXT_FUNCTION_TYPE_PARAMETER_COUNT_NAME = Name.identifier("count")
@JvmField val DYNAMIC_FQ_NAME = FqName("<dynamic>")
@JvmField val COROUTINES_PACKAGE_FQ_NAME = FqName("kotlin.coroutines")
@JvmField val COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME = FqName("kotlin.coroutines.jvm.internal")