[FIR] KT-37453: Type argument mapping
#KT-37453 Fixed
This commit is contained in:
@@ -306,7 +306,7 @@ class FirCallResolver(
|
||||
val scope = symbol.fir.unsubstitutedScope(session, scopeSession)
|
||||
val className = symbol.classId.shortClassName
|
||||
val callInfo = CallInfo(
|
||||
CallKind.Function,
|
||||
CallKind.DelegatingConstructorCall,
|
||||
className,
|
||||
explicitReceiver = null,
|
||||
delegatedConstructorCall.argumentList,
|
||||
@@ -322,7 +322,9 @@ class FirCallResolver(
|
||||
|
||||
scope.processFunctionsByName(className) {
|
||||
if (it is FirConstructorSymbol) {
|
||||
candidates += candidateFactory.createCandidate(it, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER)
|
||||
val candidate = candidateFactory.createCandidate(it, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER)
|
||||
candidate.typeArgumentMapping = TypeArgumentMapping.Mapped(typeArguments)
|
||||
candidates += candidate
|
||||
}
|
||||
}
|
||||
return callResolver.selectCandidateFromGivenCandidates(delegatedConstructorCall, className, candidates)
|
||||
|
||||
@@ -10,6 +10,7 @@ enum class CallKind(vararg resolutionSequence: ResolutionStage) {
|
||||
CheckVisibility,
|
||||
DiscriminateSynthetics,
|
||||
CheckExplicitReceiverConsistency,
|
||||
NoTypeArguments,
|
||||
CreateFreshTypeVariableSubstitutorStage,
|
||||
CheckReceivers.Dispatch,
|
||||
CheckReceivers.Extension,
|
||||
@@ -17,6 +18,7 @@ enum class CallKind(vararg resolutionSequence: ResolutionStage) {
|
||||
),
|
||||
SyntheticSelect(
|
||||
MapArguments,
|
||||
NoTypeArguments,
|
||||
CreateFreshTypeVariableSubstitutorStage,
|
||||
CheckArguments,
|
||||
EagerResolveOfCallableReferences
|
||||
@@ -26,6 +28,7 @@ enum class CallKind(vararg resolutionSequence: ResolutionStage) {
|
||||
DiscriminateSynthetics,
|
||||
MapArguments,
|
||||
CheckExplicitReceiverConsistency,
|
||||
MapTypeArguments,
|
||||
CreateFreshTypeVariableSubstitutorStage,
|
||||
CheckReceivers.Dispatch,
|
||||
CheckReceivers.Extension,
|
||||
@@ -33,14 +36,26 @@ enum class CallKind(vararg resolutionSequence: ResolutionStage) {
|
||||
EagerResolveOfCallableReferences,
|
||||
CheckLowPriorityInOverloadResolution
|
||||
),
|
||||
DelegatingConstructorCall(
|
||||
CheckVisibility,
|
||||
MapArguments,
|
||||
CheckExplicitReceiverConsistency,
|
||||
CreateFreshTypeVariableSubstitutorStage,
|
||||
CheckReceivers.Dispatch,
|
||||
CheckReceivers.Extension,
|
||||
CheckArguments,
|
||||
EagerResolveOfCallableReferences
|
||||
),
|
||||
CallableReference(
|
||||
CheckVisibility,
|
||||
DiscriminateSynthetics,
|
||||
NoTypeArguments,
|
||||
CreateFreshTypeVariableSubstitutorStage,
|
||||
CheckCallableReferenceExpectedType
|
||||
),
|
||||
SyntheticIdForCallableReferencesResolution(
|
||||
MapArguments,
|
||||
NoTypeArguments,
|
||||
CreateFreshTypeVariableSubstitutorStage,
|
||||
CheckArguments,
|
||||
EagerResolveOfCallableReferences
|
||||
|
||||
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirArgumentList
|
||||
import org.jetbrains.kotlin.fir.expressions.FirEmptyArgumentList
|
||||
@@ -61,7 +62,7 @@ data class CallInfo(
|
||||
)
|
||||
|
||||
fun replaceWithVariableAccess(): CallInfo =
|
||||
copy(callKind = CallKind.VariableAccess, argumentList = FirEmptyArgumentList)
|
||||
copy(callKind = CallKind.VariableAccess, typeArguments = emptyList(), argumentList = FirEmptyArgumentList)
|
||||
|
||||
fun replaceExplicitReceiver(explicitReceiver: FirExpression?): CallInfo =
|
||||
copy(explicitReceiver = explicitReceiver)
|
||||
@@ -112,6 +113,7 @@ class Candidate(
|
||||
var usesSAM: Boolean = false
|
||||
|
||||
var argumentMapping: Map<FirExpression, FirValueParameter>? = null
|
||||
lateinit var typeArgumentMapping: TypeArgumentMapping
|
||||
val postponedAtoms = mutableListOf<PostponedResolvedAtomMarker>()
|
||||
|
||||
val diagnostics: MutableList<ResolutionDiagnostic> = mutableListOf()
|
||||
|
||||
+7
-8
@@ -36,10 +36,11 @@ internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// optimization
|
||||
// if (resolvedCall.typeArgumentMappingByOriginal == NoExplicitArguments && knownTypeParametersResultingSubstitutor == null) {
|
||||
// return
|
||||
// }
|
||||
if (candidate.typeArgumentMapping == TypeArgumentMapping.NoExplicitArguments /*&& knownTypeParametersResultingSubstitutor == null*/) {
|
||||
return
|
||||
}
|
||||
|
||||
val typeParameters = declaration.typeParameters
|
||||
for (index in typeParameters.indices) {
|
||||
@@ -57,10 +58,8 @@ internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
|
||||
// }
|
||||
|
||||
|
||||
val typeArgument =
|
||||
callInfo.typeArguments.getOrElse(index) { FirTypePlaceholderProjection }//resolvedCall.typeArgumentMappingByOriginal.getTypeArgument(typeParameter)
|
||||
//
|
||||
when (typeArgument) {
|
||||
//
|
||||
when (val typeArgument = candidate.typeArgumentMapping[index]) {
|
||||
is FirTypeProjectionWithVariance -> csBuilder.addEqualityConstraint(
|
||||
freshVariable.defaultType,
|
||||
typeArgument.typeRef.coneTypeUnsafe(),
|
||||
@@ -69,7 +68,7 @@ internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
|
||||
is FirStarProjection -> csBuilder.addEqualityConstraint(
|
||||
freshVariable.defaultType,
|
||||
typeParameter.bounds.firstOrNull()?.coneTypeUnsafe()
|
||||
?: sink.components.session.builtinTypes.nullableAnyType.type, //StandardClassIds.Any(sink.components.session.firSymbolProvider).constructType(emptyArray(), true),
|
||||
?: sink.components.session.builtinTypes.nullableAnyType.type,
|
||||
SimpleConstraintSystemConstraintPosition
|
||||
)
|
||||
else -> assert(typeArgument == FirTypePlaceholderProjection) {
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.declarations.FirTypeParametersOwner
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirTypePlaceholderProjection
|
||||
|
||||
sealed class TypeArgumentMapping {
|
||||
|
||||
abstract operator fun get(typeParameterIndex: Int): FirTypeProjection
|
||||
|
||||
object NoExplicitArguments : TypeArgumentMapping() {
|
||||
override fun get(typeParameterIndex: Int): FirTypeProjection = FirTypePlaceholderProjection
|
||||
}
|
||||
|
||||
class Mapped(private val ordered: List<FirTypeProjection>) : TypeArgumentMapping() {
|
||||
override fun get(typeParameterIndex: Int): FirTypeProjection {
|
||||
return ordered.getOrElse(typeParameterIndex) { FirTypePlaceholderProjection }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal object MapTypeArguments : ResolutionStage() {
|
||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
val typeArguments = callInfo.typeArguments
|
||||
if (typeArguments.isEmpty()) {
|
||||
candidate.typeArgumentMapping = TypeArgumentMapping.NoExplicitArguments
|
||||
return
|
||||
}
|
||||
|
||||
val owner = candidate.symbol.fir as FirTypeParametersOwner
|
||||
|
||||
if (typeArguments.size == owner.typeParameters.size) {
|
||||
candidate.typeArgumentMapping = TypeArgumentMapping.Mapped(typeArguments)
|
||||
} else {
|
||||
sink.yieldApplicability(CandidateApplicability.INAPPLICABLE)
|
||||
candidate.typeArgumentMapping = TypeArgumentMapping.Mapped(emptyList())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object NoTypeArguments : ResolutionStage() {
|
||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
|
||||
if (callInfo.typeArguments.isNotEmpty()) {
|
||||
sink.yieldApplicability(CandidateApplicability.INAPPLICABLE)
|
||||
}
|
||||
candidate.typeArgumentMapping = TypeArgumentMapping.NoExplicitArguments
|
||||
}
|
||||
}
|
||||
+9
-8
@@ -599,15 +599,16 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) :
|
||||
is FirSuperReference -> {
|
||||
// TODO: unresolved supertype
|
||||
val supertype = reference.superTypeRef.coneTypeSafe<ConeClassLikeType>() ?: return delegatedConstructorCall.compose()
|
||||
typeArguments = supertype.typeArguments.takeIf { it.isNotEmpty() }?.map { it.toFirTypeProjection() } ?: emptyList()
|
||||
val expandedSupertype = supertype.fullyExpandedType(session)
|
||||
val lookupTag = expandedSupertype.lookupTag
|
||||
if (lookupTag is ConeClassLookupTagWithFixedSymbol) {
|
||||
lookupTag.symbol
|
||||
} else {
|
||||
// TODO: support locals
|
||||
symbolProvider.getSymbolByLookupTag(lookupTag) ?: return delegatedConstructorCall.compose()
|
||||
} as FirClassSymbol<*>
|
||||
val symbol =
|
||||
expandedSupertype.lookupTag.toSymbol(session) as? FirClassSymbol<*> ?: return delegatedConstructorCall.compose()
|
||||
val classTypeParametersCount = (symbol.fir as? FirTypeParametersOwner)?.typeParameters?.size ?: 0
|
||||
typeArguments = expandedSupertype.typeArguments
|
||||
.takeLast(classTypeParametersCount) // Hack for KT-37525
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.map { it.toFirTypeProjection() }
|
||||
?: emptyList()
|
||||
symbol
|
||||
}
|
||||
else -> return delegatedConstructorCall.compose()
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ fun test() {
|
||||
"sd".<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)()<!>
|
||||
val i : Int? = null
|
||||
i.<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)()<!>;
|
||||
{}<Int>()
|
||||
<!INAPPLICABLE_CANDIDATE!>{}<Int>()<!>
|
||||
1?.<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)()<!>
|
||||
1.<!UNRESOLVED_REFERENCE!>{}()<!>
|
||||
}
|
||||
|
||||
+3
-3
@@ -5,12 +5,12 @@ fun myFun(i : String) {}
|
||||
fun myFun(i : Int) {}
|
||||
|
||||
fun test1() {
|
||||
myFun<Int>(3)
|
||||
<!INAPPLICABLE_CANDIDATE!>myFun<!><Int>(3)
|
||||
<!INAPPLICABLE_CANDIDATE!>myFun<!><String>('a')
|
||||
}
|
||||
|
||||
fun test2() {
|
||||
val m0 = java.util.HashMap()
|
||||
val m1 = java.util.HashMap<String, String, String>()
|
||||
val m2 = java.util.HashMap<String>()
|
||||
val m1 = java.util.<!INAPPLICABLE_CANDIDATE!>HashMap<!><String, String, String>()
|
||||
val m2 = java.util.<!INAPPLICABLE_CANDIDATE!>HashMap<!><String>()
|
||||
}
|
||||
+1
-1
@@ -7,4 +7,4 @@ class Outer {
|
||||
fun nested() = Outer.Nested<Int>()
|
||||
fun noArguments() = Outer.Nested()
|
||||
fun noArgumentsExpectedType(): Outer.Nested<String> = Outer.Nested()
|
||||
fun manyArguments() = Outer.Nested<String, Int>()
|
||||
fun manyArguments() = Outer.<!INAPPLICABLE_CANDIDATE!>Nested<!><String, Int>()
|
||||
|
||||
Vendored
+5
-5
@@ -10,15 +10,15 @@ typealias P2<T> = Pair<T, T>
|
||||
typealias PR<T1, T2> = Pair<T2, T1>
|
||||
|
||||
val test0 = P(1, 2)
|
||||
val test1 = P<Int>(1, 2)
|
||||
val test1 = <!INAPPLICABLE_CANDIDATE!>P<!><Int>(1, 2)
|
||||
val test2 = P<Int, Int>(1, 2)
|
||||
val test3 = P<Int, Int, Int>(1, 2)
|
||||
val test3 = <!INAPPLICABLE_CANDIDATE!>P<!><Int, Int, Int>(1, 2)
|
||||
|
||||
val test0p2 = P2(1, 1)
|
||||
val test0p2a = P2(1, "")
|
||||
val test1p2 = P2<Int>(1, 1)
|
||||
val test2p2 = P2<Int, Int>(1, 1)
|
||||
val test3p2 = P2<Int, Int, Int>(1, 1)
|
||||
val test2p2 = <!INAPPLICABLE_CANDIDATE!>P2<!><Int, Int>(1, 1)
|
||||
val test3p2 = <!INAPPLICABLE_CANDIDATE!>P2<!><Int, Int, Int>(1, 1)
|
||||
|
||||
val test0pr = PR(1, "")
|
||||
val test1pr = <!INAPPLICABLE_CANDIDATE!>PR<!><Int>(1, "")
|
||||
@@ -32,7 +32,7 @@ typealias N<T> = Num<T>
|
||||
val testN0 = N("")
|
||||
val testN1 = N<Int>(1)
|
||||
val testN1a = N<String>("")
|
||||
val testN2 = N<Int, Int>(1)
|
||||
val testN2 = <!INAPPLICABLE_CANDIDATE!>N<!><Int, Int>(1)
|
||||
|
||||
class MyPair<T1 : CharSequence, T2 : Number>(val string: T1, val number: T2)
|
||||
typealias MP<T1> = MyPair<String, T1>
|
||||
|
||||
Vendored
+1
-1
@@ -24,4 +24,4 @@ val test1 = R { }
|
||||
val test2 = C<String> { s -> println(s.length) }
|
||||
val test3 = CStr { s -> <!AMBIGUITY!>println<!>(s.<!UNRESOLVED_REFERENCE!>length<!>) }
|
||||
val test4 = CStrList { ss -> <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>for (s in ss) { <!AMBIGUITY!>println<!>(s.<!UNRESOLVED_REFERENCE!>length<!>) }<!> }
|
||||
val test5 = C2<Int> { a, b -> val x: Int = a <!AMBIGUITY!>+<!> b; println(x)}
|
||||
val test5 = <!INAPPLICABLE_CANDIDATE!>C2<!><Int> { a, b -> val x: Int = a <!AMBIGUITY!>+<!> b; println(x)}
|
||||
|
||||
Reference in New Issue
Block a user