From 4844a907887776d631051bb53783390876feac2c Mon Sep 17 00:00:00 2001 From: "simon.ogorodnik" Date: Fri, 6 Mar 2020 20:55:23 +0300 Subject: [PATCH] [FIR] KT-37453: Type argument mapping #KT-37453 Fixed --- .../jetbrains/kotlin/fir/FirCallResolver.kt | 6 +- .../kotlin/fir/resolve/calls/CallKind.kt | 15 +++++ .../kotlin/fir/resolve/calls/Candidate.kt | 4 +- ...CreateFreshTypeVariableSubstitutorStage.kt | 15 +++-- .../fir/resolve/calls/TypeArgumentMapping.kt | 55 +++++++++++++++++++ .../FirExpressionsResolveTransformer.kt | 17 +++--- .../tests/FunctionCalleeExpressions.fir.kt | 2 +- ...rongNumberOfTypeArgumentsDiagnostic.fir.kt | 6 +- .../genericNestedClass.fir.kt | 2 +- ...erOfArgumentsInTypeAliasConstructor.fir.kt | 10 ++-- .../typeAliasSamAdapterConstructors2.fir.kt | 2 +- 11 files changed, 104 insertions(+), 30 deletions(-) create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TypeArgumentMapping.kt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index 73786eec704..f4f9a57f531 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -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) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallKind.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallKind.kt index 8a8f360efc6..0ccc674cb3a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallKind.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallKind.kt @@ -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 diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt index fd1dd9e7109..b50d049f445 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt @@ -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? = null + lateinit var typeArgumentMapping: TypeArgumentMapping val postponedAtoms = mutableListOf() val diagnostics: MutableList = mutableListOf() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt index ba3e4fafe70..093085fdf60 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt @@ -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) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TypeArgumentMapping.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TypeArgumentMapping.kt new file mode 100644 index 00000000000..e975d4dffcd --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TypeArgumentMapping.kt @@ -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) : 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 + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index 8bba1c16e62..401501dd462 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -599,15 +599,16 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) : is FirSuperReference -> { // TODO: unresolved supertype val supertype = reference.superTypeRef.coneTypeSafe() ?: 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() } diff --git a/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt b/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt index f0c9784cb3f..5d8592d2732 100644 --- a/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt +++ b/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt @@ -78,7 +78,7 @@ fun test() { "sd".(fun Int.() = 1)() val i : Int? = null i.(fun Int.() = 1)(); - {}() + {}() 1?.(fun Int.() = 1)() 1.{}() } diff --git a/compiler/testData/diagnostics/tests/generics/wrongNumberOfTypeArgumentsDiagnostic.fir.kt b/compiler/testData/diagnostics/tests/generics/wrongNumberOfTypeArgumentsDiagnostic.fir.kt index ca978f6d492..6a1b212e577 100644 --- a/compiler/testData/diagnostics/tests/generics/wrongNumberOfTypeArgumentsDiagnostic.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/wrongNumberOfTypeArgumentsDiagnostic.fir.kt @@ -5,12 +5,12 @@ fun myFun(i : String) {} fun myFun(i : Int) {} fun test1() { - myFun(3) + myFun(3) myFun('a') } fun test2() { val m0 = java.util.HashMap() - val m1 = java.util.HashMap() - val m2 = java.util.HashMap() + val m1 = java.util.HashMap() + val m2 = java.util.HashMap() } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inner/qualifiedExpression/genericNestedClass.fir.kt b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/genericNestedClass.fir.kt index 6ae7ed32c08..70d9d0e3c08 100644 --- a/compiler/testData/diagnostics/tests/inner/qualifiedExpression/genericNestedClass.fir.kt +++ b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/genericNestedClass.fir.kt @@ -7,4 +7,4 @@ class Outer { fun nested() = Outer.Nested() fun noArguments() = Outer.Nested() fun noArgumentsExpectedType(): Outer.Nested = Outer.Nested() -fun manyArguments() = Outer.Nested() +fun manyArguments() = Outer.Nested() diff --git a/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.fir.kt b/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.fir.kt index 4a15293d85c..ec180d9b570 100644 --- a/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.fir.kt +++ b/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.fir.kt @@ -10,15 +10,15 @@ typealias P2 = Pair typealias PR = Pair val test0 = P(1, 2) -val test1 = P(1, 2) +val test1 = P(1, 2) val test2 = P(1, 2) -val test3 = P(1, 2) +val test3 = P(1, 2) val test0p2 = P2(1, 1) val test0p2a = P2(1, "") val test1p2 = P2(1, 1) -val test2p2 = P2(1, 1) -val test3p2 = P2(1, 1) +val test2p2 = P2(1, 1) +val test3p2 = P2(1, 1) val test0pr = PR(1, "") val test1pr = PR(1, "") @@ -32,7 +32,7 @@ typealias N = Num val testN0 = N("") val testN1 = N(1) val testN1a = N("") -val testN2 = N(1) +val testN2 = N(1) class MyPair(val string: T1, val number: T2) typealias MP = MyPair diff --git a/compiler/testData/diagnostics/testsWithStdLib/typealias/typeAliasSamAdapterConstructors2.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/typealias/typeAliasSamAdapterConstructors2.fir.kt index a1d989f3161..b353439a94d 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/typealias/typeAliasSamAdapterConstructors2.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/typealias/typeAliasSamAdapterConstructors2.fir.kt @@ -24,4 +24,4 @@ val test1 = R { } val test2 = C { s -> println(s.length) } val test3 = CStr { s -> println(s.length) } val test4 = CStrList { ss -> for (s in ss) { println(s.length) } } -val test5 = C2 { a, b -> val x: Int = a + b; println(x)} +val test5 = C2 { a, b -> val x: Int = a + b; println(x)}