[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 scope = symbol.fir.unsubstitutedScope(session, scopeSession)
val className = symbol.classId.shortClassName val className = symbol.classId.shortClassName
val callInfo = CallInfo( val callInfo = CallInfo(
CallKind.Function, CallKind.DelegatingConstructorCall,
className, className,
explicitReceiver = null, explicitReceiver = null,
delegatedConstructorCall.argumentList, delegatedConstructorCall.argumentList,
@@ -322,7 +322,9 @@ class FirCallResolver(
scope.processFunctionsByName(className) { scope.processFunctionsByName(className) {
if (it is FirConstructorSymbol) { 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) return callResolver.selectCandidateFromGivenCandidates(delegatedConstructorCall, className, candidates)
@@ -10,6 +10,7 @@ enum class CallKind(vararg resolutionSequence: ResolutionStage) {
CheckVisibility, CheckVisibility,
DiscriminateSynthetics, DiscriminateSynthetics,
CheckExplicitReceiverConsistency, CheckExplicitReceiverConsistency,
NoTypeArguments,
CreateFreshTypeVariableSubstitutorStage, CreateFreshTypeVariableSubstitutorStage,
CheckReceivers.Dispatch, CheckReceivers.Dispatch,
CheckReceivers.Extension, CheckReceivers.Extension,
@@ -17,6 +18,7 @@ enum class CallKind(vararg resolutionSequence: ResolutionStage) {
), ),
SyntheticSelect( SyntheticSelect(
MapArguments, MapArguments,
NoTypeArguments,
CreateFreshTypeVariableSubstitutorStage, CreateFreshTypeVariableSubstitutorStage,
CheckArguments, CheckArguments,
EagerResolveOfCallableReferences EagerResolveOfCallableReferences
@@ -26,6 +28,7 @@ enum class CallKind(vararg resolutionSequence: ResolutionStage) {
DiscriminateSynthetics, DiscriminateSynthetics,
MapArguments, MapArguments,
CheckExplicitReceiverConsistency, CheckExplicitReceiverConsistency,
MapTypeArguments,
CreateFreshTypeVariableSubstitutorStage, CreateFreshTypeVariableSubstitutorStage,
CheckReceivers.Dispatch, CheckReceivers.Dispatch,
CheckReceivers.Extension, CheckReceivers.Extension,
@@ -33,14 +36,26 @@ enum class CallKind(vararg resolutionSequence: ResolutionStage) {
EagerResolveOfCallableReferences, EagerResolveOfCallableReferences,
CheckLowPriorityInOverloadResolution CheckLowPriorityInOverloadResolution
), ),
DelegatingConstructorCall(
CheckVisibility,
MapArguments,
CheckExplicitReceiverConsistency,
CreateFreshTypeVariableSubstitutorStage,
CheckReceivers.Dispatch,
CheckReceivers.Extension,
CheckArguments,
EagerResolveOfCallableReferences
),
CallableReference( CallableReference(
CheckVisibility, CheckVisibility,
DiscriminateSynthetics, DiscriminateSynthetics,
NoTypeArguments,
CreateFreshTypeVariableSubstitutorStage, CreateFreshTypeVariableSubstitutorStage,
CheckCallableReferenceExpectedType CheckCallableReferenceExpectedType
), ),
SyntheticIdForCallableReferencesResolution( SyntheticIdForCallableReferencesResolution(
MapArguments, MapArguments,
NoTypeArguments,
CreateFreshTypeVariableSubstitutorStage, CreateFreshTypeVariableSubstitutorStage,
CheckArguments, CheckArguments,
EagerResolveOfCallableReferences EagerResolveOfCallableReferences
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile 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.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.FirArgumentList import org.jetbrains.kotlin.fir.expressions.FirArgumentList
import org.jetbrains.kotlin.fir.expressions.FirEmptyArgumentList import org.jetbrains.kotlin.fir.expressions.FirEmptyArgumentList
@@ -61,7 +62,7 @@ data class CallInfo(
) )
fun replaceWithVariableAccess(): CallInfo = fun replaceWithVariableAccess(): CallInfo =
copy(callKind = CallKind.VariableAccess, argumentList = FirEmptyArgumentList) copy(callKind = CallKind.VariableAccess, typeArguments = emptyList(), argumentList = FirEmptyArgumentList)
fun replaceExplicitReceiver(explicitReceiver: FirExpression?): CallInfo = fun replaceExplicitReceiver(explicitReceiver: FirExpression?): CallInfo =
copy(explicitReceiver = explicitReceiver) copy(explicitReceiver = explicitReceiver)
@@ -112,6 +113,7 @@ class Candidate(
var usesSAM: Boolean = false var usesSAM: Boolean = false
var argumentMapping: Map<FirExpression, FirValueParameter>? = null var argumentMapping: Map<FirExpression, FirValueParameter>? = null
lateinit var typeArgumentMapping: TypeArgumentMapping
val postponedAtoms = mutableListOf<PostponedResolvedAtomMarker>() val postponedAtoms = mutableListOf<PostponedResolvedAtomMarker>()
val diagnostics: MutableList<ResolutionDiagnostic> = mutableListOf() val diagnostics: MutableList<ResolutionDiagnostic> = mutableListOf()
@@ -36,10 +36,11 @@ internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
return return
} }
// optimization // optimization
// if (resolvedCall.typeArgumentMappingByOriginal == NoExplicitArguments && knownTypeParametersResultingSubstitutor == null) { if (candidate.typeArgumentMapping == TypeArgumentMapping.NoExplicitArguments /*&& knownTypeParametersResultingSubstitutor == null*/) {
// return return
// } }
val typeParameters = declaration.typeParameters val typeParameters = declaration.typeParameters
for (index in typeParameters.indices) { 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 (val typeArgument = candidate.typeArgumentMapping[index]) {
//
when (typeArgument) {
is FirTypeProjectionWithVariance -> csBuilder.addEqualityConstraint( is FirTypeProjectionWithVariance -> csBuilder.addEqualityConstraint(
freshVariable.defaultType, freshVariable.defaultType,
typeArgument.typeRef.coneTypeUnsafe(), typeArgument.typeRef.coneTypeUnsafe(),
@@ -69,7 +68,7 @@ internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
is FirStarProjection -> csBuilder.addEqualityConstraint( is FirStarProjection -> csBuilder.addEqualityConstraint(
freshVariable.defaultType, freshVariable.defaultType,
typeParameter.bounds.firstOrNull()?.coneTypeUnsafe() 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 SimpleConstraintSystemConstraintPosition
) )
else -> assert(typeArgument == FirTypePlaceholderProjection) { 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 -> { is FirSuperReference -> {
// TODO: unresolved supertype // TODO: unresolved supertype
val supertype = reference.superTypeRef.coneTypeSafe<ConeClassLikeType>() ?: return delegatedConstructorCall.compose() 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 expandedSupertype = supertype.fullyExpandedType(session)
val lookupTag = expandedSupertype.lookupTag val symbol =
if (lookupTag is ConeClassLookupTagWithFixedSymbol) { expandedSupertype.lookupTag.toSymbol(session) as? FirClassSymbol<*> ?: return delegatedConstructorCall.compose()
lookupTag.symbol val classTypeParametersCount = (symbol.fir as? FirTypeParametersOwner)?.typeParameters?.size ?: 0
} else { typeArguments = expandedSupertype.typeArguments
// TODO: support locals .takeLast(classTypeParametersCount) // Hack for KT-37525
symbolProvider.getSymbolByLookupTag(lookupTag) ?: return delegatedConstructorCall.compose() .takeIf { it.isNotEmpty() }
} as FirClassSymbol<*> ?.map { it.toFirTypeProjection() }
?: emptyList()
symbol
} }
else -> return delegatedConstructorCall.compose() else -> return delegatedConstructorCall.compose()
} }
@@ -78,7 +78,7 @@ fun test() {
"sd".<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)()<!> "sd".<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)()<!>
val i : Int? = null val i : Int? = null
i.<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)()<!>; i.<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)()<!>;
{}<Int>() <!INAPPLICABLE_CANDIDATE!>{}<Int>()<!>
1?.<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)()<!> 1?.<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)()<!>
1.<!UNRESOLVED_REFERENCE!>{}()<!> 1.<!UNRESOLVED_REFERENCE!>{}()<!>
} }
@@ -5,12 +5,12 @@ fun myFun(i : String) {}
fun myFun(i : Int) {} fun myFun(i : Int) {}
fun test1() { fun test1() {
myFun<Int>(3) <!INAPPLICABLE_CANDIDATE!>myFun<!><Int>(3)
<!INAPPLICABLE_CANDIDATE!>myFun<!><String>('a') <!INAPPLICABLE_CANDIDATE!>myFun<!><String>('a')
} }
fun test2() { fun test2() {
val m0 = java.util.HashMap() val m0 = java.util.HashMap()
val m1 = java.util.HashMap<String, String, String>() val m1 = java.util.<!INAPPLICABLE_CANDIDATE!>HashMap<!><String, String, String>()
val m2 = java.util.HashMap<String>() val m2 = java.util.<!INAPPLICABLE_CANDIDATE!>HashMap<!><String>()
} }
@@ -7,4 +7,4 @@ class Outer {
fun nested() = Outer.Nested<Int>() fun nested() = Outer.Nested<Int>()
fun noArguments() = Outer.Nested() fun noArguments() = Outer.Nested()
fun noArgumentsExpectedType(): Outer.Nested<String> = 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> typealias PR<T1, T2> = Pair<T2, T1>
val test0 = P(1, 2) 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 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 test0p2 = P2(1, 1)
val test0p2a = P2(1, "") val test0p2a = P2(1, "")
val test1p2 = P2<Int>(1, 1) val test1p2 = P2<Int>(1, 1)
val test2p2 = P2<Int, Int>(1, 1) val test2p2 = <!INAPPLICABLE_CANDIDATE!>P2<!><Int, Int>(1, 1)
val test3p2 = P2<Int, Int, Int>(1, 1) val test3p2 = <!INAPPLICABLE_CANDIDATE!>P2<!><Int, Int, Int>(1, 1)
val test0pr = PR(1, "") val test0pr = PR(1, "")
val test1pr = <!INAPPLICABLE_CANDIDATE!>PR<!><Int>(1, "") val test1pr = <!INAPPLICABLE_CANDIDATE!>PR<!><Int>(1, "")
@@ -32,7 +32,7 @@ typealias N<T> = Num<T>
val testN0 = N("") val testN0 = N("")
val testN1 = N<Int>(1) val testN1 = N<Int>(1)
val testN1a = N<String>("") 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) class MyPair<T1 : CharSequence, T2 : Number>(val string: T1, val number: T2)
typealias MP<T1> = MyPair<String, T1> typealias MP<T1> = MyPair<String, T1>
@@ -24,4 +24,4 @@ val test1 = R { }
val test2 = C<String> { s -> println(s.length) } val test2 = C<String> { s -> println(s.length) }
val test3 = CStr { s -> <!AMBIGUITY!>println<!>(s.<!UNRESOLVED_REFERENCE!>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 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)}