FIR: Substitute type alias constructors properly

This commit is contained in:
Denis Zharkov
2019-11-25 17:47:41 +03:00
parent f68929fe74
commit 3b7ad066fc
7 changed files with 126 additions and 14 deletions
@@ -73,13 +73,6 @@ fun FirClass<*>.buildUseSiteMemberScope(useSiteSession: FirSession, builder: Sco
return symbolProvider.getClassUseSiteMemberScope(classId, useSiteSession, builder)
}
fun FirTypeAlias.buildUseSiteMemberScope(useSiteSession: FirSession, builder: ScopeSession): FirScope? {
val type = expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>()
return type.scope(useSiteSession, builder)?.let {
type.wrapSubstitutionScopeIfNeed(useSiteSession, it, this, builder)
}
}
fun FirClass<*>.buildDefaultUseSiteMemberScope(useSiteSession: FirSession, builder: ScopeSession): FirScope {
return builder.getOrBuild(symbol, USE_SITE) {
@@ -8,10 +8,14 @@ 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.transformers.ReturnTypeCalculatorWithJump
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
@@ -19,8 +23,8 @@ 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.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
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
@@ -357,11 +361,19 @@ private fun processConstructors(
try {
if (matchedSymbol != null) {
val scope = when (matchedSymbol) {
is FirTypeAliasSymbol -> matchedSymbol.fir.buildUseSiteMemberScope(session, scopeSession)
is FirTypeAliasSymbol -> {
val type = matchedSymbol.fir.expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>().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
@@ -381,3 +393,85 @@ private fun processConstructors(
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<FirTypeParameter>
): 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<ConeKotlinType>()
.let(substitutor::substituteOrNull)
?.let { FirResolvedTypeRefImpl(source, it) }
@@ -0,0 +1,9 @@
typealias MyT<X> = HashMap<X, Int>
fun <X> MyT<X>.add(x: X, y: Int) {}
fun main() {
MyT<String>().apply {
add("1", 2)
}
}
@@ -0,0 +1,10 @@
FILE: hashMapTypeAlias.kt
public final typealias MyT<X> = R|kotlin/collections/HashMap<X, kotlin/Int>|
public final fun <X> R|MyT<X>|.add(x: R|X|, y: R|kotlin/Int|): R|kotlin/Unit| {
}
public final fun main(): R|kotlin/Unit| {
R|java/util/HashMap.HashMap|<R|kotlin/String|>().R|kotlin/apply|<R|java/util/HashMap<kotlin/String, kotlin/Int>|>(<L> = apply@fun R|java/util/HashMap<kotlin/String, kotlin/Int>|.<anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
this@R|special/anonymous|.R|/add|<R|kotlin/String|>(String(1), Int(2))
}
)
}
@@ -88,6 +88,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic
runTest("compiler/fir/resolve/testData/resolve/stdlib/functionX.kt");
}
@TestMetadata("hashMapTypeAlias.kt")
public void testHashMapTypeAlias() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/stdlib/hashMapTypeAlias.kt");
}
@TestMetadata("hashSet.kt")
public void testHashSet() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/stdlib/hashSet.kt");
@@ -28,7 +28,8 @@ open class FirNamedFunctionSymbol(
) : FirFunctionSymbol<FirSimpleFunction>(callableId)
class FirConstructorSymbol(
callableId: CallableId
callableId: CallableId,
override val overriddenSymbol: FirConstructorSymbol? = null
) : FirFunctionSymbol<FirConstructor>(callableId)
class FirAccessorSymbol(
@@ -49,4 +50,4 @@ class FirAnonymousFunctionSymbol : FirFunctionWithoutNameSymbol<FirAnonymousFunc
class FirPropertyAccessorSymbol : FirFunctionWithoutNameSymbol<FirPropertyAccessor>(Name.identifier("accessor"))
class FirErrorFunctionSymbol : FirFunctionWithoutNameSymbol<FirErrorFunction>(Name.identifier("error"))
class FirErrorFunctionSymbol : FirFunctionWithoutNameSymbol<FirErrorFunction>(Name.identifier("error"))
+1 -1
View File
@@ -18,7 +18,7 @@ FILE fqName:<root> fileName:/builtinMap.kt
if: CONST Boolean type=kotlin.Boolean value=true
then: CALL 'public final fun apply <T> (block: kotlin.Function1<T of kotlin.apply, kotlin.Unit>): T of kotlin.apply [inline] declared in kotlin' type=java.util.LinkedHashMap<K1 of <root>.plus, V1 of <root>.plus> origin=null
<T>: java.util.LinkedHashMap<K1 of <root>.plus, V1 of <root>.plus>
$receiver: CONSTRUCTOR_CALL 'public constructor <init> (p0: kotlin.collections.Map<out K of java.util.LinkedHashMap, out V of java.util.LinkedHashMap>?) declared in java.util.LinkedHashMap' type=java.util.LinkedHashMap<K1 of <root>.plus, V1 of <root>.plus> origin=null
$receiver: CONSTRUCTOR_CALL 'public constructor <init> (p0: kotlin.collections.Map<out K of <uninitialized parent>, out V of <uninitialized parent>>?) declared in java.util.LinkedHashMap' type=java.util.LinkedHashMap<K1 of <root>.plus, V1 of <root>.plus> origin=null
<class: K>: K1 of <root>.plus
<class: V>: V1 of <root>.plus
p0: GET_VAR '<this>: kotlin.collections.Map<out K1 of <root>.plus, V1 of <root>.plus> declared in <root>.plus' type=kotlin.collections.Map<out K1 of <root>.plus, V1 of <root>.plus> origin=null