From e6ab38a5831aa61736961b2d4b6e19c83289d044 Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Thu, 18 Apr 2019 18:18:32 +0300 Subject: [PATCH] FIR: resolve constructors via type-aliases --- .../kotlin/fir/resolve/SupertypeUtils.kt | 18 +++--- .../org/jetbrains/kotlin/fir/scopes/Scopes.kt | 60 +++++++++++++++++++ .../scopes/impl/FirAbstractImportingScope.kt | 28 ++++----- .../impl/FirTopLevelDeclaredMemberScope.kt | 17 +++--- .../expresssions/typeAliasConstructor.kt | 13 ++++ .../expresssions/typeAliasConstructor.txt | 19 ++++++ .../fir/FirResolveTestCaseGenerated.java | 5 ++ 7 files changed, 130 insertions(+), 30 deletions(-) create mode 100644 compiler/fir/resolve/testData/resolve/expresssions/typeAliasConstructor.kt create mode 100644 compiler/fir/resolve/testData/resolve/expresssions/typeAliasConstructor.txt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt index 5d9c0f6c744..37ca1486136 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt @@ -7,10 +7,7 @@ package org.jetbrains.kotlin.fir.resolve import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.declarations.FirRegularClass -import org.jetbrains.kotlin.fir.declarations.classId -import org.jetbrains.kotlin.fir.declarations.expandedConeType -import org.jetbrains.kotlin.fir.declarations.superConeTypes +import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.impl.* import org.jetbrains.kotlin.fir.service @@ -59,6 +56,13 @@ fun FirRegularClass.buildUseSiteScope(useSiteSession: FirSession, builder: Scope return symbolProvider.getClassUseSiteMemberScope(this.classId, useSiteSession, builder)!! } +fun FirTypeAlias.buildUseSiteScope(useSiteSession: FirSession, builder: ScopeSession): FirScope? { + val type = expandedTypeRef.coneTypeUnsafe() + return type.scope(useSiteSession, builder)?.let { + type.wrapSubstitutionScopeIfNeed(useSiteSession, it, this, builder) + } +} + fun FirRegularClass.buildDefaultUseSiteScope(useSiteSession: FirSession, builder: ScopeSession): FirScope { return builder.getOrBuild(symbol, USE_SITE) { val superTypeScope = FirCompositeScope(mutableListOf()) @@ -81,13 +85,13 @@ fun FirRegularClass.buildDefaultUseSiteScope(useSiteSession: FirSession, builder private fun ConeClassLikeType.wrapSubstitutionScopeIfNeed( session: FirSession, useSiteScope: FirScope, - regularClass: FirRegularClass, + declaration: FirClassLikeDeclaration, builder: ScopeSession ): FirScope { if (this.typeArguments.isEmpty()) return useSiteScope - return builder.getOrBuild(regularClass.symbol, SubstitutionScopeKey(this)) { + return builder.getOrBuild(declaration.symbol, SubstitutionScopeKey(this)) { @Suppress("UNCHECKED_CAST") - val substitution = regularClass.typeParameters.zip(this.typeArguments) { typeParameter, typeArgument -> + val substitution = declaration.typeParameters.zip(this.typeArguments) { typeParameter, typeArgument -> typeParameter.symbol to (typeArgument as? ConeTypedProjection)?.type }.filter { (_, type) -> type != null }.toMap() as Map diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/Scopes.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/Scopes.kt index ab319d75c7d..a216105afd1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/Scopes.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/Scopes.kt @@ -7,7 +7,19 @@ package org.jetbrains.kotlin.fir.scopes import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.resolve.buildUseSiteScope +import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.scopes.impl.* +import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol +import org.jetbrains.kotlin.fir.symbols.ConeFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol +import org.jetbrains.kotlin.fir.types.ConeAbbreviatedType +import org.jetbrains.kotlin.fir.types.ConeClassLikeType +import org.jetbrains.kotlin.fir.types.coneTypeUnsafe +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.addToStdlib.safeAs fun MutableList.addImportingScopes(file: FirFile, session: FirSession) { this += listOf( @@ -24,3 +36,51 @@ fun MutableList.addImportingScopes(file: FirFile, session: FirSession) fun FirCompositeScope.addImportingScopes(file: FirFile, session: FirSession) { scopes.addImportingScopes(file, session) } + +private fun finalExpansionName(symbol: FirTypeAliasSymbol, session: FirSession): Name? { + val expandedType = symbol.fir.expandedTypeRef.coneTypeUnsafe() + return when (expandedType) { + is ConeAbbreviatedType -> + expandedType.abbreviationLookupTag.toSymbol(session)?.safeAs()?.let { + finalExpansionName(it, session) + } + else -> expandedType.lookupTag.classId.shortClassName + } + +} + +fun processConstructors( + matchedSymbol: ConeClassLikeSymbol?, + processor: (ConeFunctionSymbol) -> ProcessorAction, + session: FirSession, + scopeSession: ScopeSession, + name: Name +): ProcessorAction { + try { + if (matchedSymbol != null) { + val scope = when (matchedSymbol) { + is FirTypeAliasSymbol -> matchedSymbol.fir.buildUseSiteScope(session, scopeSession) + is FirClassSymbol -> matchedSymbol.fir.buildUseSiteScope(session, scopeSession) + else -> null + } + + + val constructorName = when (matchedSymbol) { + is FirTypeAliasSymbol -> finalExpansionName(matchedSymbol, session) ?: return ProcessorAction.NEXT + else -> 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) + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirAbstractImportingScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirAbstractImportingScope.kt index 911d6bc0a22..c0fb5a0a5f9 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirAbstractImportingScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirAbstractImportingScope.kt @@ -8,14 +8,10 @@ package org.jetbrains.kotlin.fir.scopes.impl import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirResolvedImport import org.jetbrains.kotlin.fir.resolve.ScopeSession -import org.jetbrains.kotlin.fir.resolve.buildUseSiteScope import org.jetbrains.kotlin.fir.resolve.calls.TowerScopeLevel import org.jetbrains.kotlin.fir.scopes.ProcessorAction -import org.jetbrains.kotlin.fir.symbols.CallableId -import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol -import org.jetbrains.kotlin.fir.symbols.ConeFunctionSymbol -import org.jetbrains.kotlin.fir.symbols.ConeVariableSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.scopes.processConstructors +import org.jetbrains.kotlin.fir.symbols.* import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.addToStdlib.cast @@ -55,18 +51,18 @@ abstract class FirAbstractImportingScope(session: FirSession, lookupInFir: Boole } } else { val matchedClass = provider.getClassLikeSymbolByFqName(ClassId(import.packageFqName, name)) - - if (matchedClass != null && matchedClass is FirClassSymbol) { - //TODO: why don't we use declared member scope at this point? - if (matchedClass.fir.buildUseSiteScope(session, scopeCache).processFunctionsByName( - name, - processor - ) == ProcessorAction.STOP - ) { - return ProcessorAction.STOP - } + if (processConstructors( + matchedClass, + processor, + session, + scopeCache, + name + ).stop() + ) { + return ProcessorAction.STOP } + val symbols = provider.getTopLevelCallableSymbols(callableId.packageName, callableId.callableName) for (symbol in symbols) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTopLevelDeclaredMemberScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTopLevelDeclaredMemberScope.kt index e034d2a4c96..5494a083c66 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTopLevelDeclaredMemberScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTopLevelDeclaredMemberScope.kt @@ -8,14 +8,13 @@ package org.jetbrains.kotlin.fir.scopes.impl import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.resolve.ScopeSession -import org.jetbrains.kotlin.fir.resolve.buildUseSiteScope import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.scopes.ProcessorAction.NEXT import org.jetbrains.kotlin.fir.scopes.ProcessorAction.STOP +import org.jetbrains.kotlin.fir.scopes.processConstructors import org.jetbrains.kotlin.fir.symbols.ConeFunctionSymbol import org.jetbrains.kotlin.fir.symbols.ConePropertySymbol import org.jetbrains.kotlin.fir.symbols.ConeVariableSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name @@ -29,11 +28,15 @@ class FirTopLevelDeclaredMemberScope( override fun processFunctionsByName(name: Name, processor: (ConeFunctionSymbol) -> ProcessorAction): ProcessorAction { val matchedClass = provider.getClassLikeSymbolByFqName(ClassId(packageFqName, name)) - if (matchedClass != null && matchedClass is FirClassSymbol) { - // TODO: why don't we use declared member scope at this point? - if (matchedClass.fir.buildUseSiteScope(session, ScopeSession()).processFunctionsByName(name, processor) == STOP) { - return STOP - } + if (processConstructors( + matchedClass, + processor, + session, + ScopeSession(), + name + ).stop() + ) { + return ProcessorAction.STOP } val symbols = provider.getTopLevelCallableSymbols(packageFqName, name) for (symbol in symbols) { diff --git a/compiler/fir/resolve/testData/resolve/expresssions/typeAliasConstructor.kt b/compiler/fir/resolve/testData/resolve/expresssions/typeAliasConstructor.kt new file mode 100644 index 00000000000..2d18419e40c --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/expresssions/typeAliasConstructor.kt @@ -0,0 +1,13 @@ +class A(i: Int) + +typealias AA = A + +class B(t: T) + +typealias BB = B + +fun main() { + val x = AA(1) + val y = BB("bb") +} + diff --git a/compiler/fir/resolve/testData/resolve/expresssions/typeAliasConstructor.txt b/compiler/fir/resolve/testData/resolve/expresssions/typeAliasConstructor.txt new file mode 100644 index 00000000000..b21677b1824 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/expresssions/typeAliasConstructor.txt @@ -0,0 +1,19 @@ +FILE: typeAliasConstructor.kt + public final class A : R|kotlin/Any| { + public constructor(i: R|kotlin/Int|): R|A| { + super() + } + + } + public final typealias AA = R|A| + public final class B : R|kotlin/Any| { + public constructor(t: R|T|): R|B| { + super() + } + + } + public final typealias BB = R|B| + public final fun main(): R|kotlin/Unit| { + lval x: R|A| = R|/A.A|(Int(1)) + lval y: = #(String(bb)) + } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java index a107bd121f8..e5145c51243 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java @@ -262,6 +262,11 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase { runTest("compiler/fir/resolve/testData/resolve/expresssions/this.kt"); } + @TestMetadata("typeAliasConstructor.kt") + public void testTypeAliasConstructor() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/expresssions/typeAliasConstructor.kt"); + } + @TestMetadata("vararg.kt") public void testVararg() throws Exception { runTest("compiler/fir/resolve/testData/resolve/expresssions/vararg.kt");