[FIR] Initialize outer type parameters for local classes

This commit is contained in:
Ivan Kochurkin
2021-09-15 19:28:02 +03:00
committed by TeamCityServer
parent 38820d3e41
commit e52a410599
39 changed files with 293 additions and 193 deletions
@@ -39,8 +39,8 @@ FILE: throwableSubclass.kt
}
public final fun foo(): R|kotlin/Unit| {
local final class Test7 : R|kotlin/Throwable| {
public constructor(): R|Test5.Test7| {
local final class Test7<T, B> : R|kotlin/Throwable| {
public constructor(): R|Test5.Test7<T, B>| {
super<R|kotlin/Throwable|>()
}
@@ -50,8 +50,8 @@ FILE: throwableSubclass.kt
}
public final fun <Z> topLevelFun(): R|kotlin/Unit| {
local final class Test8 : R|kotlin/Error| {
public constructor(): R|Test8| {
local final class Test8<Z> : R|kotlin/Error| {
public constructor(): R|Test8<Z>| {
super<R|kotlin/Error|>()
}
@@ -11345,6 +11345,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/generics/kt9985.kt");
}
@Test
@TestMetadata("localClassWithTypeArgumentFromFunction.kt")
public void testLocalClassWithTypeArgumentFromFunction() throws Exception {
runTest("compiler/testData/diagnostics/tests/generics/localClassWithTypeArgumentFromFunction.kt");
}
@Test
@TestMetadata("Projections.kt")
public void testProjections() throws Exception {
@@ -11345,6 +11345,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/generics/kt9985.kt");
}
@Test
@TestMetadata("localClassWithTypeArgumentFromFunction.kt")
public void testLocalClassWithTypeArgumentFromFunction() throws Exception {
runTest("compiler/testData/diagnostics/tests/generics/localClassWithTypeArgumentFromFunction.kt");
}
@Test
@TestMetadata("Projections.kt")
public void testProjections() throws Exception {
@@ -1102,6 +1102,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
}
val CASTS_AND_IS_CHECKS by object : DiagnosticGroup("Casts and is-checks") {
val CANNOT_CHECK_FOR_ERASED by error<PsiElement> {
parameter<ConeKotlinType>("type")
}
val USELESS_CAST by warning<KtBinaryExpressionWithTypeRHS>(PositioningStrategy.AS_TYPE)
val USELESS_IS_CHECK by warning<KtElement> {
parameter<Boolean>("compileTimeCheckResult")
@@ -590,6 +590,7 @@ object FirErrors {
val USELESS_ELVIS_RIGHT_IS_NULL by warning0<KtBinaryExpression>(SourceElementPositioningStrategies.USELESS_ELVIS)
// Casts and is-checks
val CANNOT_CHECK_FOR_ERASED by error1<PsiElement, ConeKotlinType>()
val USELESS_CAST by warning0<KtBinaryExpressionWithTypeRHS>(SourceElementPositioningStrategies.AS_TYPE)
val USELESS_IS_CHECK by warning1<KtElement, Boolean>()
val IS_ENUM_ENTRY by error0<KtTypeReference>()
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.resolve.isValidTypeParameterFromOuterClass
import org.jetbrains.kotlin.fir.resolve.isValidTypeParameterFromOuterDeclaration
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.toTypeProjections
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
@@ -47,7 +47,7 @@ object FirOuterClassArgumentsRequiredChecker : FirRegularClassChecker() {
for (index in typeArguments.size until typeParameters.size) {
val typeParameter = typeParameters[index]
if (!isValidTypeParameterFromOuterClass(typeParameter, declaration, context.session)) {
if (!isValidTypeParameterFromOuterDeclaration(typeParameter, declaration, context.session)) {
val outerClass = typeParameter.containingDeclarationSymbol as? FirRegularClassSymbol ?: break
reporter.reportOn(typeRef.source, FirErrors.OUTER_CLASS_ARGUMENTS_REQUIRED, outerClass, context)
break
@@ -26,7 +26,7 @@ object FirThrowableSubclassChecker : FirClassChecker() {
reporter.reportOn(declaration.typeParameters.firstOrNull()?.source, FirErrors.GENERIC_THROWABLE_SUBCLASS, context)
val source = when {
(declaration as? FirRegularClass)?.isInner == true -> declaration.source
(declaration as? FirRegularClass)?.let { it.isInner || it.isLocal } == true -> declaration.source
declaration is FirAnonymousObject -> (declaration.declarations.firstOrNull())?.source
else -> null
}
@@ -8,11 +8,13 @@ package org.jetbrains.kotlin.fir.scopes.impl
import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.persistentMapOf
import org.jetbrains.kotlin.builtins.StandardNames.BACKING_FIELD
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.FirVariable
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
@@ -24,29 +26,30 @@ import org.jetbrains.kotlin.name.Name
class FirLocalScope private constructor(
val properties: PersistentMap<Name, FirVariableSymbol<*>>,
val functions: PersistentMultimap<Name, FirNamedFunctionSymbol>,
val classes: PersistentMap<Name, FirRegularClassSymbol>
val classes: PersistentMap<Name, FirRegularClassSymbol>,
val useSiteSession: FirSession
) : FirContainingNamesAwareScope() {
constructor() : this(persistentMapOf(), PersistentMultimap(), persistentMapOf())
constructor(session: FirSession) : this(persistentMapOf(), PersistentMultimap(), persistentMapOf(), session)
fun storeClass(klass: FirRegularClass): FirLocalScope {
fun storeClass(klass: FirRegularClass, session: FirSession): FirLocalScope {
return FirLocalScope(
properties, functions, classes.put(klass.name, klass.symbol)
properties, functions, classes.put(klass.name, klass.symbol), session
)
}
fun storeFunction(function: FirSimpleFunction): FirLocalScope {
fun storeFunction(function: FirSimpleFunction, session: FirSession): FirLocalScope {
return FirLocalScope(
properties, functions.put(function.name, function.symbol), classes
properties, functions.put(function.name, function.symbol), classes, session
)
}
fun storeVariable(variable: FirVariable): FirLocalScope {
fun storeVariable(variable: FirVariable, session: FirSession): FirLocalScope {
return FirLocalScope(
properties.put(variable.name, variable.symbol), functions, classes
properties.put(variable.name, variable.symbol), functions, classes, session
)
}
fun storeBackingField(property: FirProperty): FirLocalScope {
fun storeBackingField(property: FirProperty, session: FirSession): FirLocalScope {
val enhancedProperties = property.backingField?.symbol?.let {
properties.put(BACKING_FIELD, it)
}
@@ -54,7 +57,8 @@ class FirLocalScope private constructor(
return FirLocalScope(
enhancedProperties ?: properties,
functions,
classes
classes,
session
)
}
@@ -74,7 +78,8 @@ class FirLocalScope private constructor(
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
val klass = classes[name]
if (klass != null) {
processor(klass, ConeSubstitutor.Empty)
val substitution = klass.typeParameterSymbols.associateWith { it.toConeType() }
processor(klass, ConeSubstitutorByMap(substitution, useSiteSession))
}
}
@@ -436,7 +436,7 @@ class DeclarationsConverter(
typeParameterList?.let { firTypeParameters += convertTypeParameters(it, typeConstraints, classSymbol) }
withCapturedTypeParameters(status.isInner, firTypeParameters) {
withCapturedTypeParameters(status.isInner || isLocal, firTypeParameters) {
buildRegularClass {
source = classNode.toFirSourceElement()
moduleData = baseModuleData
@@ -1044,7 +1044,7 @@ open class RawFirBuilder(
isExternal = classOrObject.hasModifier(EXTERNAL_KEYWORD)
}
withCapturedTypeParameters(status.isInner, listOf()) {
withCapturedTypeParameters(status.isInner || isLocal, listOf()) {
buildRegularClass {
source = classOrObject.toFirSourceElement()
moduleData = baseModuleData
@@ -1060,7 +1060,7 @@ open class RawFirBuilder(
context.appendOuterTypeParameters(ignoreLastLevel = true, typeParameters)
context.pushFirTypeParameters(
status.isInner,
status.isInner || isLocal,
typeParameters.subList(0, classOrObject.typeParameters.size)
)
@@ -49,8 +49,8 @@ class Context<T> {
val dispatchReceiverTypesStack = mutableListOf<ConeClassLikeType>()
var containerIsExpect: Boolean = false
fun pushFirTypeParameters(notNested: Boolean, parameters: List<FirTypeParameterRef>) {
capturedTypeParameters.add(StatusFirTypeParameterSymbolList(notNested, parameters.map { it.symbol }))
fun pushFirTypeParameters(isInnerOrLocal: Boolean, parameters: List<FirTypeParameterRef>) {
capturedTypeParameters.add(StatusFirTypeParameterSymbolList(isInnerOrLocal, parameters.map { it.symbol }))
}
fun popFirTypeParameters() {
@@ -68,7 +68,7 @@ class Context<T> {
}
}
if (!element.notNested) {
if (!element.isInnerOrLocal) {
break
}
}
@@ -119,5 +119,5 @@ class Context<T> {
}
}
data class StatusFirTypeParameterSymbolList(val notNested: Boolean, val list: List<FirTypeParameterSymbol> = listOf())
data class StatusFirTypeParameterSymbolList(val isInnerOrLocal: Boolean, val list: List<FirTypeParameterSymbol> = listOf())
}
@@ -466,20 +466,3 @@ fun FirFunction.getAsForbiddenNamedArgumentsTarget(session: FirSession): Forbidd
// org.jetbrains.kotlin.fir.serialization.FirElementSerializer.functionProto
// org.jetbrains.kotlin.fir.serialization.FirElementSerializer.constructorProto
fun FirFunction.getHasStableParameterNames(session: FirSession): Boolean = getAsForbiddenNamedArgumentsTarget(session) == null
fun FirClassLikeDeclaration.getActualTypeParametersCount(session: FirSession): Int {
var result = (if (this is FirTypeAlias) this.typeParameters else (this as FirClass).typeParameters).size
if (this is FirRegularClass && !isInner) {
return result
}
val containingClass = getContainingDeclaration(session) as? FirRegularClass
if (containingClass != null) {
result -= containingClass.typeParameters.size
}
return result
}
@@ -197,7 +197,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
symbol: FirBasedSymbol<*>?,
substitutor: ConeSubstitutor?,
areBareTypesAllowed: Boolean,
topDeclaration: FirRegularClass?,
topContainer: FirDeclaration?,
isOperandOfIsOperator: Boolean
): ConeKotlinType {
if (symbol == null || symbol !is FirClassifierSymbol<*>) {
@@ -240,14 +240,25 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
if (!isPossibleBareType) {
val actualSubstitutor = substitutor ?: ConeSubstitutor.Empty
val typeParameters = calculateTypeParameters(symbol)
val originalTypeParameters = collectTypeParameters(symbol)
val (typeParametersAlignedToQualifierParts, outerClasses) = getClassesAlignedToQualifierParts(symbol, qualifier, session)
val (typeParametersAlignedToQualifierParts, outerDeclarations) = getClassesAlignedToQualifierParts(
symbol,
qualifier,
session
)
for ((index, typeParameter) in typeParameters.withIndex()) {
val actualTypeParametersCount =
when (symbol) {
is FirTypeAliasSymbol ->
outerDeclarations.sumOf { it?.let { d -> getActualTypeParametersCount(d) } ?: 0 }
else -> (symbol as FirClassSymbol<*>).typeParameterSymbols.size
}
for ((typeParameterIndex, typeParameter) in originalTypeParameters.withIndex()) {
val (parameterClass, qualifierPartIndex) = typeParametersAlignedToQualifierParts[typeParameter.symbol] ?: continue
if (index < typeArgumentsCount) {
if (typeParameterIndex < typeArgumentsCount) {
// Check if type argument matches type parameter in respective qualifier part
val qualifierPartArgumentsCount = qualifier[qualifierPartIndex].typeArgumentList.typeArguments.size
createDiagnosticsIfExists(
@@ -261,12 +272,18 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
}
if (typeParameter !is FirOuterClassTypeParameterRef ||
isValidTypeParameterFromOuterClass(typeParameter.symbol, topDeclaration, session)
isValidTypeParameterFromOuterDeclaration(typeParameter.symbol, topContainer, session)
) {
val type = ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(typeParameter.symbol), isNullable = false)
val substituted = actualSubstitutor.substituteOrNull(type)
if (substituted == null) {
createDiagnosticsIfExists(parameterClass, qualifierPartIndex, symbol, typeRef)?.let { return it }
createDiagnosticsIfExists(
parameterClass,
qualifierPartIndex,
symbol,
typeRef,
qualifierPartArgumentsCount = null
)?.let { return it }
} else {
allTypeArguments.add(substituted)
}
@@ -276,15 +293,16 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
}
// Check rest type arguments
if (typeArgumentsCount > typeParameters.size) {
if (typeArgumentsCount > actualTypeParametersCount) {
for (index in qualifier.indices) {
if (qualifier[index].typeArgumentList.typeArguments.isNotEmpty()) {
val parameterClass = outerClasses.elementAtOrNull(index)
val parameterClass = outerDeclarations.elementAtOrNull(index)
createDiagnosticsIfExists(
parameterClass,
index,
symbol,
typeRef
typeRef,
qualifierPartArgumentsCount = null
)?.let { return it }
}
}
@@ -304,43 +322,43 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
}
}
private fun calculateTypeParameters(symbol: FirClassLikeSymbol<*>): List<FirTypeParameterRef> {
return if (symbol is FirTypeAliasSymbol) {
val typeAliasFir = symbol.fir
val typeAliasTypeParameters = typeAliasFir.typeParameters.toMutableList()
val fullyExpandedClass = typeAliasFir.fullyExpandedClass(session)
val newTypeParameters: MutableList<FirTypeParameterRef>
private fun collectTypeParameters(symbol: FirClassLikeSymbol<*>): List<FirTypeParameterRef> {
if (symbol is FirClassSymbol<*>) {
return symbol.fir.typeParameters
}
if (fullyExpandedClass != null) { // TODO: Should not be null, move to resolver?
val expandedTypeRef = typeAliasFir.expandedTypeRef
require(symbol is FirTypeAliasSymbol)
fun checkTypeArguments(typeArgument: ConeTypeProjection) {
when (typeArgument) {
is ConeTypeParameterType -> typeAliasTypeParameters.removeIf { it.symbol == typeArgument.lookupTag.symbol }
is ConeClassLikeType -> {
for (subTypeArgument in typeArgument.typeArguments) {
checkTypeArguments(subTypeArgument)
}
}
is ConeKotlinTypeProjection -> checkTypeArguments(typeArgument.type)
else -> {
val typeAliasFir = symbol.fir
val typeAliasTypeParameters = typeAliasFir.typeParameters.toMutableList()
val fullyExpandedClass = typeAliasFir.fullyExpandedClass(session)
val newTypeParameters = if (fullyExpandedClass != null) { // TODO: Should not be null, move to resolver?
val expandedTypeRef = typeAliasFir.expandedTypeRef
fun checkTypeArguments(typeArgument: ConeTypeProjection) {
when (typeArgument) {
is ConeTypeParameterType -> typeAliasTypeParameters.removeIf { it.symbol == typeArgument.lookupTag.symbol }
is ConeClassLikeType -> {
for (subTypeArgument in typeArgument.typeArguments) {
checkTypeArguments(subTypeArgument)
}
}
is ConeKotlinTypeProjection -> checkTypeArguments(typeArgument.type)
else -> {
}
}
checkTypeArguments(expandedTypeRef.coneType)
newTypeParameters = fullyExpandedClass.typeParameters.toMutableList()
} else {
newTypeParameters = mutableListOf()
}
for (typeParameter in typeAliasTypeParameters) {
newTypeParameters.add(typeParameter)
}
newTypeParameters
checkTypeArguments(expandedTypeRef.coneType)
fullyExpandedClass.typeParameters.toMutableList()
} else {
(symbol as FirClassSymbol<*>).fir.typeParameters
mutableListOf()
}
for (typeParameter in typeAliasTypeParameters) {
newTypeParameters.add(typeParameter)
}
return newTypeParameters
}
@OptIn(SymbolInternals::class)
@@ -373,8 +391,10 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
for (index in reversedOuterClasses.indices) {
currentClassLikeDeclaration = reversedOuterClasses[index]
val typeParameters = if (currentClassLikeDeclaration is FirTypeAlias) currentClassLikeDeclaration.typeParameters else
(currentClassLikeDeclaration as? FirClass)?.typeParameters
val typeParameters = when (currentClassLikeDeclaration) {
is FirTypeAlias -> currentClassLikeDeclaration.typeParameters
else -> (currentClassLikeDeclaration as? FirClass)?.typeParameters
}
if (currentClassLikeDeclaration != null && typeParameters != null) {
for (typeParameter in typeParameters) {
val typeParameterSymbol = typeParameter.symbol
@@ -404,10 +424,10 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
qualifierPartIndex: Int,
symbol: FirClassLikeSymbol<*>,
userTypeRef: FirUserTypeRef,
qualifierPartArgumentsCount: Int? = null
qualifierPartArgumentsCount: Int?
): ConeClassErrorType? {
// TODO: It should be TYPE_ARGUMENTS_NOT_ALLOWED diagnostics when parameterClass is null
val actualTypeParametersCount = (parameterClass ?: symbol.fir).getActualTypeParametersCount(session)
val actualTypeParametersCount = getActualTypeParametersCount(parameterClass ?: symbol.fir)
if (qualifierPartArgumentsCount == null || actualTypeParametersCount != qualifierPartArgumentsCount) {
val source = getTypeArgumentsOrNameSource(userTypeRef, qualifierPartIndex)
@@ -425,6 +445,11 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
return null
}
private fun getActualTypeParametersCount(element: FirClassLikeDeclaration): Int {
return (element as FirTypeParameterRefsOwner).typeParameters
.count { it !is FirOuterClassTypeParameterRef }
}
private fun getTypeArgumentsOrNameSource(typeRef: FirUserTypeRef, qualifierIndex: Int?): KtSourceElement? {
val qualifierPart = if (qualifierIndex != null) typeRef.qualifier.elementAtOrNull(qualifierIndex) else null
val typeArgumentsList = qualifierPart?.typeArgumentList
@@ -475,7 +500,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
symbol,
substitutor,
areBareTypesAllowed,
scopeClassDeclaration.containingDeclarations.lastOrNull(),
scopeClassDeclaration.topContainer ?: scopeClassDeclaration.containingDeclarations.lastOrNull(),
isOperandOfIsOperator
)
}
@@ -5,10 +5,11 @@
package org.jetbrains.kotlin.fir.resolve.transformers
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.scopes.FirScope
data class ScopeClassDeclaration(
val scopes: List<FirScope>,
val containingDeclarations: List<FirRegularClass>
val containingDeclarations: List<FirDeclaration>,
val topContainer: FirDeclaration? = null
)
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.PrivateForInline
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
@@ -211,8 +212,8 @@ class BodyResolveContext(
}
@PrivateForInline
fun storeFunction(function: FirSimpleFunction) {
updateLastScope { storeFunction(function) }
fun storeFunction(function: FirSimpleFunction, session: FirSession) {
updateLastScope { storeFunction(function, session) }
}
@PrivateForInline
@@ -251,8 +252,8 @@ class BodyResolveContext(
return FirMemberTypeParameterScope(this)
}
fun buildSecondaryConstructorParametersScope(constructor: FirConstructor): FirLocalScope =
constructor.valueParameters.fold(FirLocalScope()) { acc, param -> acc.storeVariable(param) }
fun buildSecondaryConstructorParametersScope(constructor: FirConstructor, session: FirSession): FirLocalScope =
constructor.valueParameters.fold(FirLocalScope(session)) { acc, param -> acc.storeVariable(param, session) }
@PrivateForInline
fun addInaccessibleImplicitReceiverValue(
@@ -272,8 +273,8 @@ class BodyResolveContext(
}
@PrivateForInline
private fun storeBackingField(property: FirProperty) {
updateLastScope { storeBackingField(property) }
private fun storeBackingField(property: FirProperty, session: FirSession) {
updateLastScope { storeBackingField(property, session) }
}
// ANALYSIS PUBLIC API
@@ -285,14 +286,14 @@ class BodyResolveContext(
towerDataContextsForClassParts.primaryConstructorAllParametersScope
@OptIn(PrivateForInline::class)
fun storeClassIfNotNested(klass: FirRegularClass) {
fun storeClassIfNotNested(klass: FirRegularClass, session: FirSession) {
if (containerIfAny is FirClass) return
updateLastScope { storeClass(klass) }
updateLastScope { storeClass(klass, session) }
}
@OptIn(PrivateForInline::class)
fun storeVariable(variable: FirVariable) {
updateLastScope { storeVariable(variable) }
fun storeVariable(variable: FirVariable, session: FirSession) {
updateLastScope { storeVariable(variable, session) }
}
@OptIn(PrivateForInline::class)
@@ -368,7 +369,7 @@ class BodyResolveContext(
forContracts: Boolean = false,
f: () -> T
): T {
storeClassIfNotNested(regularClass)
storeClassIfNotNested(regularClass, holder.session)
if (forContracts) {
return withTypeParametersOf(regularClass) {
withContainerClass(regularClass, f)
@@ -452,7 +453,7 @@ class BodyResolveContext(
val constructor = (owner as? FirRegularClass)?.declarations?.firstOrNull { it is FirConstructor } as? FirConstructor
val (primaryConstructorPureParametersScope, primaryConstructorAllParametersScope) =
if (constructor?.isPrimary == true) {
constructor.scopesWithPrimaryConstructorParameters(owner)
constructor.scopesWithPrimaryConstructorParameters(owner, holder.session)
} else {
null to null
}
@@ -473,16 +474,17 @@ class BodyResolveContext(
}
private fun FirConstructor.scopesWithPrimaryConstructorParameters(
ownerClass: FirClass
ownerClass: FirClass,
session: FirSession
): Pair<FirLocalScope, FirLocalScope> {
var parameterScope = FirLocalScope()
var allScope = FirLocalScope()
var parameterScope = FirLocalScope(session)
var allScope = FirLocalScope(session)
val properties = ownerClass.declarations.filterIsInstance<FirProperty>().associateBy { it.name }
for (parameter in valueParameters) {
allScope = allScope.storeVariable(parameter)
allScope = allScope.storeVariable(parameter, session)
val property = properties[parameter.name]
if (property?.source?.kind != KtFakeSourceElementKind.PropertyFromParameter) {
parameterScope = parameterScope.storeVariable(parameter)
parameterScope = parameterScope.storeVariable(parameter, session)
}
}
return parameterScope to allScope
@@ -491,10 +493,11 @@ class BodyResolveContext(
@OptIn(PrivateForInline::class)
inline fun <T> withSimpleFunction(
simpleFunction: FirSimpleFunction,
session: FirSession,
f: () -> T
): T {
if (containerIfAny !is FirClass) {
storeFunction(simpleFunction)
storeFunction(simpleFunction, session)
}
return withTypeParametersOf(simpleFunction) {
@@ -509,13 +512,13 @@ class BodyResolveContext(
f: () -> T
): T {
return withTowerDataCleanup {
addLocalScope(FirLocalScope())
addLocalScope(FirLocalScope(holder.session))
if (function is FirSimpleFunction) {
// Make all value parameters available in the local scope so that even one parameter that refers to another parameter,
// which may not be initialized yet, can be resolved. [FirFunctionParameterChecker] will detect and report an error
// if an uninitialized parameter is accessed by a preceding parameter.
for (parameter in function.valueParameters) {
storeVariable(parameter)
storeVariable(parameter, holder.session)
}
val receiverTypeRef = function.receiverTypeRef
withLabelAndReceiverType(function.name, function, receiverTypeRef?.coneType, holder, f)
@@ -528,6 +531,7 @@ class BodyResolveContext(
@OptIn(PrivateForInline::class)
fun <T> forConstructorBody(
constructor: FirConstructor,
session: FirSession,
f: () -> T
): T {
return if (constructor.isPrimary) {
@@ -542,7 +546,7 @@ class BodyResolveContext(
}
} else {
withTowerDataCleanup {
addLocalScope(buildSecondaryConstructorParametersScope(constructor))
addLocalScope(buildSecondaryConstructorParametersScope(constructor, session))
f()
}
}
@@ -562,7 +566,7 @@ class BodyResolveContext(
return f()
}
return withTowerDataCleanup {
addLocalScope(FirLocalScope())
addLocalScope(FirLocalScope(holder.session))
val receiverTypeRef = anonymousFunction.receiverTypeRef
val labelName = anonymousFunction.label?.name?.let { Name.identifier(it) }
withContainer(anonymousFunction) {
@@ -600,11 +604,12 @@ class BodyResolveContext(
@OptIn(PrivateForInline::class)
inline fun <T> withAnonymousInitializer(
anonymousInitializer: FirAnonymousInitializer,
session: FirSession,
f: () -> T
): T {
return withTowerDataCleanup {
getPrimaryConstructorPureParametersScope()?.let { addLocalScope(it) }
addLocalScope(FirLocalScope())
addLocalScope(FirLocalScope(session))
withContainer(anonymousInitializer, f)
}
}
@@ -612,10 +617,11 @@ class BodyResolveContext(
@OptIn(PrivateForInline::class)
inline fun <T> withValueParameter(
valueParameter: FirValueParameter,
session: FirSession,
f: () -> T
): T {
if (!valueParameter.name.isSpecial || valueParameter.name != UNDERSCORE_FOR_UNUSED_VAR) {
storeVariable(valueParameter)
storeVariable(valueParameter, session)
}
return withContainer(valueParameter, f)
}
@@ -641,17 +647,17 @@ class BodyResolveContext(
if (accessor is FirDefaultPropertyAccessor || accessor.body == null) {
return if (accessor.isGetter) withContainer(accessor, f)
else withTowerDataCleanup {
addLocalScope(FirLocalScope())
addLocalScope(FirLocalScope(holder.session))
withContainer(accessor, f)
}
}
return withTowerDataCleanup {
val receiverTypeRef = property.receiverTypeRef
addLocalScope(FirLocalScope())
addLocalScope(FirLocalScope(holder.session))
if (!forContracts && receiverTypeRef == null && property.returnTypeRef !is FirImplicitTypeRef &&
!property.isLocal && property.delegate == null
) {
storeBackingField(property)
storeBackingField(property, holder.session)
}
withContainer(accessor) {
withLabelAndReceiverType(property.name, property, receiverTypeRef?.coneType, holder, f)
@@ -731,8 +737,8 @@ class BodyResolveContext(
} else {
addInaccessibleImplicitReceiverValue(owningClass, holder)
withTowerDataCleanup {
addLocalScope(buildSecondaryConstructorParametersScope(constructor))
constructor.valueParameters.forEach { storeVariable(it) }
addLocalScope(buildSecondaryConstructorParametersScope(constructor, holder.session))
constructor.valueParameters.forEach { storeVariable(it, holder.session) }
f()
}
}
@@ -747,15 +753,15 @@ class BodyResolveContext(
towerDataContextForCallableReferences.remove(callableReferenceAccess)
}
fun <T> withWhenExpression(whenExpression: FirWhenExpression, f: () -> T): T {
fun <T> withWhenExpression(whenExpression: FirWhenExpression, session: FirSession, f: () -> T): T {
if (whenExpression.subjectVariable == null) return f()
return forBlock(f)
return forBlock(session, f)
}
@OptIn(PrivateForInline::class)
inline fun <T> forBlock(f: () -> T): T {
inline fun <T> forBlock(session: FirSession, f: () -> T): T {
return withTowerDataCleanup {
addLocalScope(FirLocalScope())
addLocalScope(FirLocalScope(session))
f()
}
}
@@ -70,7 +70,8 @@ open class FirBodyResolveTransformer(
typeRef,
ScopeClassDeclaration(
components.createCurrentScopeList(),
context.containingClassDeclarations
context.containingClassDeclarations,
context.containers.lastOrNull { it is FirTypeParameterRefsOwner && it !is FirAnonymousFunction }
)
)
}
@@ -41,7 +41,7 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran
override fun transformDoWhileLoop(doWhileLoop: FirDoWhileLoop, data: ResolutionMode): FirStatement {
// Do-while has a specific scope structure (its block and condition effectively share the scope)
return context.forBlock {
return context.forBlock(session) {
val context = ResolutionMode.ContextIndependent
doWhileLoop.also(dataFlowAnalyzer::enterDoWhileLoop)
.also {
@@ -61,7 +61,7 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran
}
whenExpression.annotations.forEach { it.accept(this, data) }
dataFlowAnalyzer.enterWhenExpression(whenExpression)
return context.withWhenExpression(whenExpression) with@{
return context.withWhenExpression(whenExpression, session) with@{
@Suppress("NAME_SHADOWING")
var whenExpression = whenExpression.transformSubject(transformer, ResolutionMode.ContextIndependent)
@@ -164,7 +164,7 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran
override fun transformCatch(catch: FirCatch, data: ResolutionMode): FirCatch {
dataFlowAnalyzer.enterCatchClause(catch)
catch.parameter.transformReturnTypeRef(transformer, ResolutionMode.ContextIndependent)
return context.forBlock {
return context.forBlock(session) {
catch.transformParameter(transformer, ResolutionMode.ContextIndependent)
catch.transformBlock(transformer, ResolutionMode.ContextDependent)
}.also { dataFlowAnalyzer.exitCatchClause(it) }
@@ -330,7 +330,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
variable.transformAccessors()
}
variable.transformOtherChildren(transformer, ResolutionMode.ContextIndependent)
context.storeVariable(variable)
context.storeVariable(variable, session)
dataFlowAnalyzer.exitLocalVariableDeclaration(variable, hadExplicitType)
return variable
}
@@ -540,7 +540,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
doTransformTypeParameters(simpleFunction)
val containingDeclaration = context.containerIfAny
return context.withSimpleFunction(simpleFunction) {
return context.withSimpleFunction(simpleFunction, session) {
// TODO: I think it worth creating something like runAllPhasesForLocalFunction
if (containingDeclaration != null && containingDeclaration !is FirClass) {
// For class members everything should be already prepared
@@ -635,7 +635,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
constructor.transformValueParameters(transformer, data)
}
constructor.transformDelegatedConstructor(transformer, data)
context.forConstructorBody(constructor) {
context.forConstructorBody(constructor, session) {
constructor.transformBody(transformer, data)
}
}
@@ -651,7 +651,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
): FirAnonymousInitializer {
if (implicitTypeOnly) return anonymousInitializer
dataFlowAnalyzer.enterInitBlock(anonymousInitializer)
return context.withAnonymousInitializer(anonymousInitializer) {
return context.withAnonymousInitializer(anonymousInitializer, session) {
val result =
transformDeclarationContent(anonymousInitializer, ResolutionMode.ContextIndependent) as FirAnonymousInitializer
val graph = dataFlowAnalyzer.exitInitBlock(result)
@@ -671,7 +671,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
}
dataFlowAnalyzer.enterValueParameter(valueParameter)
val result = context.withValueParameter(valueParameter) {
val result = context.withValueParameter(valueParameter, session) {
transformDeclarationContent(
valueParameter,
withExpectedType(valueParameter.returnTypeRef)
@@ -384,7 +384,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
}
override fun transformBlock(block: FirBlock, data: ResolutionMode): FirStatement {
context.forBlock {
context.forBlock(session) {
transformBlockInCurrentScope(block, data)
}
return block
@@ -22,7 +22,7 @@ fun <F : FirClassLikeDeclaration> F.runAllPhasesForLocalClass(
): F {
if (status is FirResolvedDeclarationStatus) return this
if (this is FirRegularClass) {
components.context.storeClassIfNotNested(this)
components.context.storeClassIfNotNested(this, components.session)
}
this.transformAnnotations(transformer, ResolutionMode.ContextIndependent)
val localClassesNavigationInfo = collectLocalClassesNavigationInfo()
@@ -71,7 +71,7 @@ open class FirContractResolveTransformer(
return simpleFunction
}
@Suppress("UNCHECKED_CAST")
return context.withSimpleFunction(simpleFunction) {
return context.withSimpleFunction(simpleFunction, session) {
context.forFunctionBody(simpleFunction, components) {
transformContractDescriptionOwner(simpleFunction)
}
@@ -129,7 +129,7 @@ open class FirContractResolveTransformer(
): T {
val valueParameters = owner.valueParameters
for (valueParameter in valueParameters) {
context.storeVariable(valueParameter)
context.storeVariable(valueParameter, session)
}
val contractCall = contractDescription.contractCall.transformSingle(transformer, ResolutionMode.ContextIndependent)
val resolvedId = contractCall.toResolvedCallableSymbol()?.callableId ?: return transformOwnerWithUnresolvedContract(owner)
@@ -32,31 +32,38 @@ fun FirClassLikeDeclaration.getContainingDeclaration(session: FirSession): FirCl
return null
}
fun isValidTypeParameterFromOuterClass(
fun isValidTypeParameterFromOuterDeclaration(
typeParameterSymbol: FirTypeParameterSymbol,
classDeclaration: FirRegularClass?,
declaration: FirDeclaration?,
session: FirSession
): Boolean {
if (classDeclaration == null) {
if (declaration == null) {
return true // Extra check is required because of classDeclaration will be resolved later
}
fun containsTypeParameter(currentClassDeclaration: FirRegularClass): Boolean {
if (currentClassDeclaration.typeParameters.any { it.symbol == typeParameterSymbol }) {
return true
}
for (superTypeRef in currentClassDeclaration.superTypeRefs) {
val superClassFir = superTypeRef.firClassLike(session)
if (superClassFir == null || superClassFir is FirRegularClass && containsTypeParameter(superClassFir)) {
fun containsTypeParameter(currentDeclaration: FirDeclaration?): Boolean {
if (currentDeclaration is FirTypeParameterRefsOwner) {
if (currentDeclaration.typeParameters.any { it.symbol == typeParameterSymbol }) {
return true
}
if (currentDeclaration is FirCallableDeclaration) {
val containingClassId = currentDeclaration.symbol.callableId.classId ?: return true
return containsTypeParameter(session.symbolProvider.getClassLikeSymbolByClassId(containingClassId)?.fir)
} else if (currentDeclaration is FirClass) {
for (superTypeRef in currentDeclaration.superTypeRefs) {
val superClassFir = superTypeRef.firClassLike(session)
if (superClassFir == null || superClassFir is FirRegularClass && containsTypeParameter(superClassFir)) {
return true
}
}
}
}
return false
}
return containsTypeParameter(classDeclaration)
return containsTypeParameter(declaration)
}
fun FirTypeRef.firClassLike(session: FirSession): FirClassLikeDeclaration? {