[FIR] KT-37453: Type argument mapping

#KT-37453 Fixed
This commit is contained in:
simon.ogorodnik
2020-03-06 20:55:23 +03:00
parent 6a1e35389c
commit 4844a90788
11 changed files with 104 additions and 30 deletions
@@ -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()
@@ -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) {
@@ -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
}
}
@@ -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!>{}()<!>
}
@@ -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>()
}
@@ -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>()
@@ -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>
@@ -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)}