FIR: Substitute type alias constructors properly
This commit is contained in:
@@ -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))
|
||||
}
|
||||
)
|
||||
}
|
||||
Generated
+5
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user