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)
|
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 {
|
fun FirClass<*>.buildDefaultUseSiteMemberScope(useSiteSession: FirSession, builder: ScopeSession): FirScope {
|
||||||
return builder.getOrBuild(symbol, USE_SITE) {
|
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.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
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.FirImportImpl
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedImportImpl
|
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.expressions.FirResolvedQualifier
|
||||||
import org.jetbrains.kotlin.fir.resolve.*
|
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.resolve.transformers.ReturnTypeCalculatorWithJump
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
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.scopes.impl.FirExplicitSimpleImportingScope
|
||||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
|
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||||
@@ -357,11 +361,19 @@ private fun processConstructors(
|
|||||||
try {
|
try {
|
||||||
if (matchedSymbol != null) {
|
if (matchedSymbol != null) {
|
||||||
val scope = when (matchedSymbol) {
|
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)
|
is FirClassSymbol -> matchedSymbol.buildUseSiteMemberScope(session, scopeSession)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val constructorName = when (matchedSymbol) {
|
val constructorName = when (matchedSymbol) {
|
||||||
is FirTypeAliasSymbol -> finalExpansionName(matchedSymbol, session) ?: return ProcessorAction.NEXT
|
is FirTypeAliasSymbol -> finalExpansionName(matchedSymbol, session) ?: return ProcessorAction.NEXT
|
||||||
is FirClassSymbol -> name
|
is FirClassSymbol -> name
|
||||||
@@ -381,3 +393,85 @@ private fun processConstructors(
|
|||||||
throw RuntimeException("While processing constructors", e)
|
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");
|
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")
|
@TestMetadata("hashSet.kt")
|
||||||
public void testHashSet() throws Exception {
|
public void testHashSet() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/hashSet.kt");
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/hashSet.kt");
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ open class FirNamedFunctionSymbol(
|
|||||||
) : FirFunctionSymbol<FirSimpleFunction>(callableId)
|
) : FirFunctionSymbol<FirSimpleFunction>(callableId)
|
||||||
|
|
||||||
class FirConstructorSymbol(
|
class FirConstructorSymbol(
|
||||||
callableId: CallableId
|
callableId: CallableId,
|
||||||
|
override val overriddenSymbol: FirConstructorSymbol? = null
|
||||||
) : FirFunctionSymbol<FirConstructor>(callableId)
|
) : FirFunctionSymbol<FirConstructor>(callableId)
|
||||||
|
|
||||||
class FirAccessorSymbol(
|
class FirAccessorSymbol(
|
||||||
@@ -49,4 +50,4 @@ class FirAnonymousFunctionSymbol : FirFunctionWithoutNameSymbol<FirAnonymousFunc
|
|||||||
|
|
||||||
class FirPropertyAccessorSymbol : FirFunctionWithoutNameSymbol<FirPropertyAccessor>(Name.identifier("accessor"))
|
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
|
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
|
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>
|
<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: K>: K1 of <root>.plus
|
||||||
<class: V>: V1 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
|
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