diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt index 4d0018934a6..7cb91f22f7a 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt @@ -42,7 +42,7 @@ import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedSymbolError import org.jetbrains.kotlin.fir.resolve.getContainingClass import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeParameterBasedTypeVariable -import org.jetbrains.kotlin.fir.resolve.originalConstructorIfTypeAlias +import org.jetbrains.kotlin.fir.scopes.impl.originalConstructorIfTypeAlias import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirDeprecationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirDeprecationChecker.kt index 90c62240c1b..8ddebcfe789 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirDeprecationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirDeprecationChecker.kt @@ -26,7 +26,7 @@ import org.jetbrains.kotlin.fir.expressions.calleeReference import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.references.resolved import org.jetbrains.kotlin.fir.resolve.firClassLike -import org.jetbrains.kotlin.fir.resolve.typeAliasForConstructor +import org.jetbrains.kotlin.fir.scopes.impl.typeAliasForConstructor import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedExpressionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedExpressionChecker.kt index 6a19d995548..9d278b6ce2c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedExpressionChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedExpressionChecker.kt @@ -14,7 +14,7 @@ import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableWrongReceiver import org.jetbrains.kotlin.fir.resolve.fullyExpandedType -import org.jetbrains.kotlin.fir.resolve.isTypeAliasedConstructor +import org.jetbrains.kotlin.fir.scopes.impl.isTypeAliasedConstructor import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt index 04758aec39e..29d6f7152de 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt @@ -37,6 +37,7 @@ import org.jetbrains.kotlin.fir.resolve.providers.FirProvider import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope +import org.jetbrains.kotlin.fir.scopes.impl.originalConstructorIfTypeAlias import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.* diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt index b9186bb2ea6..34922de03d0 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt @@ -27,6 +27,8 @@ import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.approximateDeclarationType import org.jetbrains.kotlin.fir.scopes.getDeclaredConstructors +import org.jetbrains.kotlin.fir.scopes.impl.originalConstructorIfTypeAlias +import org.jetbrains.kotlin.fir.scopes.impl.typeAliasForConstructor import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/TypeAliasConstructorsSubstitutingScope.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/TypeAliasConstructorsSubstitutingScope.kt new file mode 100644 index 00000000000..87d19490ae8 --- /dev/null +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/TypeAliasConstructorsSubstitutingScope.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2010-2023 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.fir.declarations.FirConstructor +import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataKey +import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataRegistry +import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin +import org.jetbrains.kotlin.fir.declarations.builder.buildConstructedClassTypeParameterRef +import org.jetbrains.kotlin.fir.declarations.builder.buildConstructorCopy +import org.jetbrains.kotlin.fir.declarations.builder.buildReceiverParameter +import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol +import org.jetbrains.kotlin.fir.types.ConeClassLikeType +import org.jetbrains.kotlin.fir.types.withReplacedConeType + +private object TypeAliasConstructorKey : FirDeclarationDataKey() + +var FirConstructor.originalConstructorIfTypeAlias: FirConstructor? by FirDeclarationDataRegistry.data(TypeAliasConstructorKey) +val FirConstructorSymbol.isTypeAliasedConstructor: Boolean + get() = fir.originalConstructorIfTypeAlias != null + +private object TypeAliasForConstructorKey : FirDeclarationDataKey() + +var FirConstructor.typeAliasForConstructor: FirTypeAliasSymbol? by FirDeclarationDataRegistry.data(TypeAliasForConstructorKey) +val FirConstructorSymbol.typeAliasForConstructor: FirTypeAliasSymbol? + get() = fir.typeAliasForConstructor + +class TypeAliasConstructorsSubstitutingScope( + private val typeAliasSymbol: FirTypeAliasSymbol, + private val delegatingScope: FirScope, + private val outerType: ConeClassLikeType?, +) : FirScope() { + + override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) { + delegatingScope.processDeclaredConstructors wrapper@{ originalConstructorSymbol -> + val typeParameters = typeAliasSymbol.fir.typeParameters + + processor( + buildConstructorCopy(originalConstructorSymbol.fir) { + symbol = FirConstructorSymbol(originalConstructorSymbol.callableId) + origin = FirDeclarationOrigin.Synthetic.TypeAliasConstructor + + this.typeParameters.clear() + typeParameters.mapTo(this.typeParameters) { buildConstructedClassTypeParameterRef { symbol = it.symbol } } + + if (outerType != null) { + // If the matched symbol is a type alias, and the expanded type is a nested class, e.g., + // + // class Outer { + // inner class Inner + // } + // typealias OI = Outer.Inner + // fun foo() { Outer().OI() } + // + // the chances are that `processor` belongs to [ScopeTowerLevel] (to resolve type aliases at top-level), which treats + // the explicit receiver (`Outer()`) as an extension receiver, whereas the constructor of the nested class may regard + // the same explicit receiver as a dispatch receiver (hence inconsistent receiver). + // Here, we add a copy of the nested class constructor, along with the outer type as an extension receiver, so that it + // can be seen as if resolving: + // + // fun Outer.OI(): OI = ... + // + // + receiverParameter = originalConstructorSymbol.fir.returnTypeRef.withReplacedConeType(outerType).let { + buildReceiverParameter { + typeRef = it + } + } + } + + }.apply { + originalConstructorIfTypeAlias = originalConstructorSymbol.fir + typeAliasForConstructor = typeAliasSymbol + }.symbol + ) + } + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index 82f15b88c78..e11e718e9d2 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBod import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirExpressionsResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType import org.jetbrains.kotlin.fir.resolve.transformers.doesResolutionResultOverrideOtherToPreserveCompatibility +import org.jetbrains.kotlin.fir.scopes.impl.originalConstructorIfTypeAlias import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirOuterClassManager.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirOuterClassManager.kt index d898f36e43c..35c94ca5ba0 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirOuterClassManager.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirOuterClassManager.kt @@ -6,14 +6,10 @@ package org.jetbrains.kotlin.fir.resolve import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.declarations.FirTypeParameter -import org.jetbrains.kotlin.fir.declarations.utils.isInner import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.types.ConeClassLikeType -import org.jetbrains.kotlin.fir.types.constructType class FirOuterClassManager( private val session: FirSession, @@ -29,19 +25,6 @@ class FirOuterClassManager( return symbolProvider.getClassLikeSymbolByClassId(outerClassId) } - fun outerType(classLikeType: ConeClassLikeType): ConeClassLikeType? { - val fullyExpandedType = classLikeType.fullyExpandedType(session) - - val symbol = fullyExpandedType.lookupTag.toSymbol(session) ?: return null - - if (symbol is FirRegularClassSymbol && !symbol.fir.isInner) return null - - val containingSymbol = outerClass(symbol) ?: return null - val currentTypeArgumentsNumber = (symbol as? FirRegularClassSymbol)?.fir?.typeParameters?.count { it is FirTypeParameter } ?: 0 - - return containingSymbol.constructType( - fullyExpandedType.typeArguments.drop(currentTypeArgumentsNumber).toTypedArray(), - isNullable = false - ) - } + fun outerType(classLikeType: ConeClassLikeType): ConeClassLikeType? = + outerType(classLikeType, session, ::outerClass) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt index 8f00e028865..e3b04000476 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt @@ -8,22 +8,18 @@ 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.builder.buildConstructedClassTypeParameterRef -import org.jetbrains.kotlin.fir.declarations.builder.buildConstructorCopy -import org.jetbrains.kotlin.fir.declarations.builder.buildReceiverParameter import org.jetbrains.kotlin.fir.declarations.utils.isInner -import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.scopes.impl.TypeAliasConstructorsSubstitutingScope import org.jetbrains.kotlin.fir.scopes.processClassifiersByName import org.jetbrains.kotlin.fir.scopes.scopeForClass import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.coneTypeUnsafe -import org.jetbrains.kotlin.fir.types.withReplacedConeType import org.jetbrains.kotlin.fir.visibilityChecker import org.jetbrains.kotlin.fir.whileAnalysing import org.jetbrains.kotlin.name.Name @@ -215,55 +211,3 @@ private fun processConstructors( } } } - -private class TypeAliasConstructorsSubstitutingScope( - private val typeAliasSymbol: FirTypeAliasSymbol, - private val delegatingScope: FirScope, - private val outerType: ConeClassLikeType?, -) : FirScope() { - - override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) { - delegatingScope.processDeclaredConstructors wrapper@{ originalConstructorSymbol -> - val typeParameters = typeAliasSymbol.fir.typeParameters - - processor( - buildConstructorCopy(originalConstructorSymbol.fir) { - symbol = FirConstructorSymbol(originalConstructorSymbol.callableId) - origin = FirDeclarationOrigin.Synthetic.TypeAliasConstructor - - this.typeParameters.clear() - typeParameters.mapTo(this.typeParameters) { buildConstructedClassTypeParameterRef { symbol = it.symbol } } - - if (outerType != null) { - // If the matched symbol is a type alias, and the expanded type is a nested class, e.g., - // - // class Outer { - // inner class Inner - // } - // typealias OI = Outer.Inner - // fun foo() { Outer().OI() } - // - // the chances are that `processor` belongs to [ScopeTowerLevel] (to resolve type aliases at top-level), which treats - // the explicit receiver (`Outer()`) as an extension receiver, whereas the constructor of the nested class may regard - // the same explicit receiver as a dispatch receiver (hence inconsistent receiver). - // Here, we add a copy of the nested class constructor, along with the outer type as an extension receiver, so that it - // can be seen as if resolving: - // - // fun Outer.OI(): OI = ... - // - // - receiverParameter = originalConstructorSymbol.fir.returnTypeRef.withReplacedConeType(outerType).let { - buildReceiverParameter { - typeRef = it - } - } - } - - }.apply { - originalConstructorIfTypeAlias = originalConstructorSymbol.fir - typeAliasForConstructor = typeAliasSymbol - }.symbol - ) - } - } -} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt index 59825d33310..519dfbc7add 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt @@ -25,10 +25,10 @@ import org.jetbrains.kotlin.fir.resolve.inference.csBuilder import org.jetbrains.kotlin.fir.resolve.inference.hasBuilderInferenceAnnotation import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExplicitTypeParameterConstraintPosition import org.jetbrains.kotlin.fir.resolve.toSymbol -import org.jetbrains.kotlin.fir.resolve.typeAliasForConstructor import org.jetbrains.kotlin.fir.scopes.FirTypeScope import org.jetbrains.kotlin.fir.scopes.FirUnstableSmartcastTypeScope import org.jetbrains.kotlin.fir.scopes.ProcessorAction +import org.jetbrains.kotlin.fir.scopes.impl.typeAliasForConstructor import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/DeclarationUtils.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/DeclarationUtils.kt index f845bd762d9..425a217e498 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/DeclarationUtils.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/DeclarationUtils.kt @@ -8,13 +8,11 @@ package org.jetbrains.kotlin.fir.resolve import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.containingClassForLocalAttr import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.utils.isInner import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.resolve.dfa.RealVariable import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider -import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol -import org.jetbrains.kotlin.fir.symbols.impl.LookupTagInternals +import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.name.ClassId @@ -82,20 +80,6 @@ fun FirTypeRef.firClassLike(session: FirSession): FirClassLikeDeclaration? { fun List.toTypeProjections(): Array = asReversed().flatMap { it.typeArgumentList.typeArguments.map { typeArgument -> typeArgument.toConeTypeProjection() } }.toTypedArray() -private object TypeAliasConstructorKey : FirDeclarationDataKey() - -var FirConstructor.originalConstructorIfTypeAlias: FirConstructor? by FirDeclarationDataRegistry.data(TypeAliasConstructorKey) - -val FirConstructorSymbol.isTypeAliasedConstructor: Boolean - get() = fir.originalConstructorIfTypeAlias != null - -private object TypeAliasForConstructorKey : FirDeclarationDataKey() - -var FirConstructor.typeAliasForConstructor: FirTypeAliasSymbol? by FirDeclarationDataRegistry.data(TypeAliasForConstructorKey) - -val FirConstructorSymbol.typeAliasForConstructor: FirTypeAliasSymbol? - get() = fir.typeAliasForConstructor - interface FirCodeFragmentContext { val towerDataContext: FirTowerDataContext val smartCasts: Map> @@ -104,3 +88,30 @@ interface FirCodeFragmentContext { private object CodeFragmentContextDataKey : FirDeclarationDataKey() var FirCodeFragment.codeFragmentContext: FirCodeFragmentContext? by FirDeclarationDataRegistry.data(CodeFragmentContextDataKey) + +/** + * If `classLikeType` is an inner class, + * then this function returns a type representing + * only the "outer" part of `classLikeType`: + * the part with the outer classes and their + * type arguments. Returns `null` otherwise. + */ +inline fun outerType( + classLikeType: ConeClassLikeType, + session: FirSession, + outerClass: (FirClassLikeSymbol<*>) -> FirClassLikeSymbol<*>?, +): ConeClassLikeType? { + val fullyExpandedType = classLikeType.fullyExpandedType(session) + + val symbol = fullyExpandedType.lookupTag.toSymbol(session) ?: return null + + if (symbol is FirRegularClassSymbol && !symbol.fir.isInner) return null + + val containingSymbol = outerClass(symbol) ?: return null + val currentTypeArgumentsNumber = (symbol as? FirRegularClassSymbol)?.fir?.typeParameters?.count { it is FirTypeParameter } ?: 0 + + return containingSymbol.constructType( + fullyExpandedType.typeArguments.drop(currentTypeArgumentsNumber).toTypedArray(), + isNullable = false + ) +}