diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt index 277b9591173..c3bd97d0ede 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt @@ -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, 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 new file mode 100644 index 00000000000..6beee51d0b3 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt @@ -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() + val typeAliasSymbol = expandedType.lookupTag.toSymbol(session)?.safeAs() + + 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().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 +): 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() + .let(substitutor::substituteOrNull) + ?.let { FirResolvedTypeRefImpl(source, it) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerLevels.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerLevels.kt index 180d548d19c..9f82693a518 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerLevels.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerLevels.kt @@ -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() - val typeAliasSymbol = expandedType.lookupTag.toSymbol(session)?.safeAs() - - 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().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 -): 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() - .let(substitutor::substituteOrNull) - ?.let { FirResolvedTypeRefImpl(source, it) }