FIR: Support callable references outside of the calls

^KT-32725 In Progress
This commit is contained in:
Denis Zharkov
2019-10-23 14:10:30 +03:00
parent 152236d84a
commit fe8cd195aa
13 changed files with 113 additions and 19 deletions
@@ -17,4 +17,8 @@ object SyntheticCallableId {
FqName("_synthetic"), FqName("_synthetic"),
Name.identifier("TRY_CALL") Name.identifier("TRY_CALL")
) )
} val ID = CallableId(
FqName("_synthetic"),
Name.identifier("ID_CALL")
)
}
@@ -224,7 +224,7 @@ class FirCallResolver(
val callableReferenceAccess = resolvedCallableReferenceAtom.atom val callableReferenceAccess = resolvedCallableReferenceAtom.atom
val lhs = resolvedCallableReferenceAtom.lhs val lhs = resolvedCallableReferenceAtom.lhs
val coneSubstitutor = constraintSystemBuilder.buildCurrentSubstitutor() as ConeSubstitutor val coneSubstitutor = constraintSystemBuilder.buildCurrentSubstitutor() as ConeSubstitutor
val expectedType = resolvedCallableReferenceAtom.expectedType?.let(coneSubstitutor::substituteOrSelf) ?: return false val expectedType = resolvedCallableReferenceAtom.expectedType?.let(coneSubstitutor::substituteOrSelf)
val result = CandidateCollector(this, resolutionStageRunner) val result = CandidateCollector(this, resolutionStageRunner)
val consumer = val consumer =
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.calls.InferenceComponents import org.jetbrains.kotlin.fir.resolve.calls.InferenceComponents
import org.jetbrains.kotlin.fir.resolve.calls.ResolutionStageRunner import org.jetbrains.kotlin.fir.resolve.calls.ResolutionStageRunner
import org.jetbrains.kotlin.fir.resolve.transformers.FirSyntheticCallGenerator
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
import org.jetbrains.kotlin.fir.resolve.transformers.phasedFir import org.jetbrains.kotlin.fir.resolve.transformers.phasedFir
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
@@ -35,6 +36,7 @@ interface BodyResolveComponents : SessionHolder {
val samResolver: FirSamResolver val samResolver: FirSamResolver
val callResolver: FirCallResolver val callResolver: FirCallResolver
val doubleColonExpressionResolver: FirDoubleColonExpressionResolver val doubleColonExpressionResolver: FirDoubleColonExpressionResolver
val syntheticCallGenerator: FirSyntheticCallGenerator
val <D> AbstractFirBasedSymbol<D>.phasedFir: D where D : FirDeclaration, D : FirSymbolOwner<D> val <D> AbstractFirBasedSymbol<D>.phasedFir: D where D : FirDeclaration, D : FirSymbolOwner<D>
get() = phasedFir(session, FirResolvePhase.DECLARATIONS) get() = phasedFir(session, FirResolvePhase.DECLARATIONS)
@@ -20,6 +20,20 @@ sealed class CallKind {
) )
} }
/*
* Used for resolution of synthetic calls for resolving callable references
* beyond any calls like `val x = ::foo` (they're transformed to `val x = id(::foo)`)
* It's needed to avoid having different callable references resolution parts within calls and beyond them
*/
object SyntheticIdForCallableReferencesResolution : CallKind() {
override val resolutionSequence: List<ResolutionStage> = listOf(
MapArguments,
CreateFreshTypeVariableSubstitutorStage,
CheckArguments,
EagerResolveOfCallableReferences
)
}
object Function : CallKind() { object Function : CallKind() {
override val resolutionSequence: List<ResolutionStage> = listOf( override val resolutionSequence: List<ResolutionStage> = listOf(
CheckVisibility, CheckVisibility,
@@ -175,7 +175,7 @@ internal object EagerResolveOfCallableReferences : CheckerStage() {
internal object CheckCallableReferenceExpectedType : CheckerStage() { internal object CheckCallableReferenceExpectedType : CheckerStage() {
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
val outerCsBuilder = callInfo.outerCSBuilder ?: return val outerCsBuilder = callInfo.outerCSBuilder ?: return
val expectedType = callInfo.expectedType ?: return val expectedType = callInfo.expectedType
val candidateSymbol = candidate.symbol as? FirCallableSymbol<*> ?: return val candidateSymbol = candidate.symbol as? FirCallableSymbol<*> ?: return
val resultingReceiverType = when (callInfo.lhs) { val resultingReceiverType = when (callInfo.lhs) {
@@ -201,7 +201,9 @@ internal object CheckCallableReferenceExpectedType : CheckerStage() {
val position = SimpleConstraintSystemConstraintPosition //TODO val position = SimpleConstraintSystemConstraintPosition //TODO
addSubtypeConstraint(resultingType, expectedType, position) if (expectedType != null) {
addSubtypeConstraint(resultingType, expectedType, position)
}
val declarationReceiverType: ConeKotlinType? = val declarationReceiverType: ConeKotlinType? =
(fir as? FirCallableMemberDeclaration<*>)?.receiverTypeRef?.coneTypeSafe<ConeKotlinType>() (fir as? FirCallableMemberDeclaration<*>)?.receiverTypeRef?.coneTypeSafe<ConeKotlinType>()
@@ -14,12 +14,15 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl import org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirTypeParameterImpl import org.jetbrains.kotlin.fir.declarations.impl.FirTypeParameterImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirTryExpression import org.jetbrains.kotlin.fir.expressions.FirTryExpression
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl
import org.jetbrains.kotlin.fir.references.impl.FirStubReference import org.jetbrains.kotlin.fir.references.impl.FirStubReference
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.calls.* import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.inference.FirCallCompleter
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.CallableId
@@ -35,9 +38,13 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
class FirSyntheticCallGenerator(private val components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents) : BodyResolveComponents by components { class FirSyntheticCallGenerator(
private val components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents,
private val callCompleter: FirCallCompleter
) : BodyResolveComponents by components {
private val whenSelectFunction: FirSimpleFunctionImpl = generateSyntheticSelectFunction(SyntheticCallableId.WHEN) private val whenSelectFunction: FirSimpleFunctionImpl = generateSyntheticSelectFunction(SyntheticCallableId.WHEN)
private val trySelectFunction: FirSimpleFunctionImpl = generateSyntheticSelectFunction(SyntheticCallableId.TRY) private val trySelectFunction: FirSimpleFunctionImpl = generateSyntheticSelectFunction(SyntheticCallableId.TRY)
private val idFunction: FirSimpleFunctionImpl = generateSyntheticSelectFunction(SyntheticCallableId.ID)
fun generateCalleeForWhenExpression(whenExpression: FirWhenExpression): FirWhenExpression? { fun generateCalleeForWhenExpression(whenExpression: FirWhenExpression): FirWhenExpression? {
val stubReference = whenExpression.calleeReference val stubReference = whenExpression.calleeReference
@@ -77,12 +84,28 @@ class FirSyntheticCallGenerator(private val components: FirAbstractBodyResolveTr
return tryExpression.copy(calleeReference = reference) return tryExpression.copy(calleeReference = reference)
} }
fun resolveCallableReferenceWithSyntheticOuterCall(
callableReferenceAccess: FirCallableReferenceAccess,
expectedTypeRef: FirTypeRef?
): FirCallableReferenceAccess? {
val arguments = listOf(callableReferenceAccess)
val reference =
generateCalleeReferenceWithCandidate(
idFunction, arguments, SyntheticCallableId.ID.callableName, CallKind.SyntheticIdForCallableReferencesResolution
) ?: return null
val fakeCallElement = FirFunctionCallImpl(null).copy(calleeReference = reference, arguments = arguments)
return callCompleter.completeCall(fakeCallElement, expectedTypeRef).arguments[0] as FirCallableReferenceAccess?
}
private fun generateCalleeReferenceWithCandidate( private fun generateCalleeReferenceWithCandidate(
function: FirSimpleFunctionImpl, function: FirSimpleFunctionImpl,
arguments: List<FirExpression>, arguments: List<FirExpression>,
name: Name name: Name,
callKind: CallKind = CallKind.SyntheticSelect
): FirNamedReferenceWithCandidate? { ): FirNamedReferenceWithCandidate? {
val callInfo = generateCallInfo(arguments) val callInfo = generateCallInfo(arguments, callKind)
val candidate = generateCandidate(callInfo, function) val candidate = generateCandidate(callInfo, function)
val applicability = resolutionStageRunner.processCandidate(candidate) val applicability = resolutionStageRunner.processCandidate(candidate)
if (applicability <= CandidateApplicability.INAPPLICABLE) { if (applicability <= CandidateApplicability.INAPPLICABLE) {
@@ -100,8 +123,8 @@ class FirSyntheticCallGenerator(private val components: FirAbstractBodyResolveTr
explicitReceiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER explicitReceiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
) )
private fun generateCallInfo(arguments: List<FirExpression>) = CallInfo( private fun generateCallInfo(arguments: List<FirExpression>, callKind: CallKind) = CallInfo(
callKind = CallKind.SyntheticSelect, callKind = callKind,
explicitReceiver = null, explicitReceiver = null,
arguments = arguments, arguments = arguments,
isSafeCall = false, isSafeCall = false,
@@ -111,7 +134,7 @@ class FirSyntheticCallGenerator(private val components: FirAbstractBodyResolveTr
container = container container = container
) { it.resultType } ) { it.resultType }
private fun generateSyntheticSelectFunction(callableId: CallableId): FirSimpleFunctionImpl { private fun generateSyntheticSelectFunction(callableId: CallableId, isVararg: Boolean = true): FirSimpleFunctionImpl {
val functionSymbol = FirSyntheticFunctionSymbol(callableId) val functionSymbol = FirSyntheticFunctionSymbol(callableId)
val typeParameterSymbol = FirTypeParameterSymbol() val typeParameterSymbol = FirTypeParameterSymbol()
val typeParameter = FirTypeParameterImpl(null, session, Name.identifier("K"), typeParameterSymbol, Variance.INVARIANT, false) val typeParameter = FirTypeParameterImpl(null, session, Name.identifier("K"), typeParameterSymbol, Variance.INVARIANT, false)
@@ -123,7 +146,7 @@ class FirSyntheticCallGenerator(private val components: FirAbstractBodyResolveTr
return generateMemberFunction(session, functionSymbol, callableId.callableName, typeArgument.typeRef).apply { return generateMemberFunction(session, functionSymbol, callableId.callableName, typeArgument.typeRef).apply {
typeParameters += typeParameter typeParameters += typeParameter
valueParameters += argumentType.toValueParameter(session, "branches", isVararg = true) valueParameters += argumentType.toValueParameter(session, "branches", isVararg)
} }
} }
@@ -98,6 +98,7 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb
override val samResolver: FirSamResolver = FirSamResolverImpl(session, scopeSession) override val samResolver: FirSamResolver = FirSamResolverImpl(session, scopeSession)
val callCompleter: FirCallCompleter = FirCallCompleter(transformer, this) val callCompleter: FirCallCompleter = FirCallCompleter(transformer, this)
val dataFlowAnalyzer: FirDataFlowAnalyzer = FirDataFlowAnalyzer(this) val dataFlowAnalyzer: FirDataFlowAnalyzer = FirDataFlowAnalyzer(this)
override val syntheticCallGenerator: FirSyntheticCallGenerator = FirSyntheticCallGenerator(this, callCompleter)
internal var _container: FirDeclaration? = null internal var _container: FirDeclaration? = null
override var container: FirDeclaration override var container: FirDeclaration
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.fir.visitors.transformSingle
class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTransformer) : class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTransformer) :
FirPartialBodyResolveTransformer(transformer) { FirPartialBodyResolveTransformer(transformer) {
private val syntheticCallGenerator: FirSyntheticCallGenerator = FirSyntheticCallGenerator(components) private val syntheticCallGenerator: FirSyntheticCallGenerator get() = components.syntheticCallGenerator
private val whenExhaustivenessTransformer = FirWhenExhaustivenessTransformer(components) private val whenExhaustivenessTransformer = FirWhenExhaustivenessTransformer(components)
@@ -266,6 +266,15 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) :
else else
callableReferenceAccess callableReferenceAccess
if (data != null) {
val resolvedReference =
components.syntheticCallGenerator.resolveCallableReferenceWithSyntheticOuterCall(
callableReferenceAccess, data as? FirTypeRef
) ?: callableReferenceAccess
return resolvedReference.compose()
}
return callableReferenceAccessWithTransformedLHS.compose() return callableReferenceAccessWithTransformedLHS.compose()
} }
@@ -0,0 +1,14 @@
fun bar(x: String): Int = 1
fun bar(x: String): Double = 1
fun baz(x: String): Int = 1
fun <T, R> foobaz(x: T): R = TODO()
fun foo() {
val x: (String) -> Int = ::bar
val y = ::bar
val z = ::baz
val w: (String) -> Int = ::foobaz
::baz
}
@@ -0,0 +1,20 @@
FILE: beyoundCalls.kt
public final fun bar(x: R|kotlin/String|): R|kotlin/Int| {
^bar Int(1)
}
public final fun bar(x: R|kotlin/String|): R|kotlin/Double| {
^bar Int(1)
}
public final fun baz(x: R|kotlin/String|): R|kotlin/Int| {
^baz Int(1)
}
public final fun <T, R> foobaz(x: R|T|): R|R| {
^foobaz R|kotlin/TODO|()
}
public final fun foo(): R|kotlin/Unit| {
lval x: R|kotlin/Function1<kotlin/String, kotlin/Int>| = ::R|/bar|
lval y: <ERROR TYPE REF: No result type for initializer> = ::<Unresolved reference: bar>#
lval z: R|kotlin/reflect/KFunction1<kotlin/String, kotlin/Int>| = ::R|/baz|
lval w: R|kotlin/Function1<kotlin/String, kotlin/Int>| = ::R|/foobaz<kotlin/String, kotlin/Int>|
::R|/baz|
}
@@ -8,13 +8,13 @@ FILE: moreSpecificAmbiguousExtensions.kt
public final fun R|IB|.extFun(x: R|IA|): R|kotlin/Unit| { public final fun R|IB|.extFun(x: R|IA|): R|kotlin/Unit| {
} }
public final fun test(): R|kotlin/Unit| { public final fun test(): R|kotlin/Unit| {
lval extFun1: <ERROR TYPE REF: No result type for initializer> = Q|IA|::extFun# lval extFun1: R|kotlin/reflect/KFunction2<IA, IB, kotlin/Unit>| = Q|IA|::R|/extFun|
lval extFun2: <ERROR TYPE REF: No result type for initializer> = Q|IB|::extFun# lval extFun2: R|kotlin/reflect/KFunction2<IB, IB, kotlin/Unit>| = Q|IB|::R|/extFun|
} }
public final fun testWithExpectedType(): R|kotlin/Unit| { public final fun testWithExpectedType(): R|kotlin/Unit| {
lval extFun_AB_A: R|kotlin/Function2<IA, IB, kotlin/Unit>| = Q|IA|::extFun# lval extFun_AB_A: R|kotlin/Function2<IA, IB, kotlin/Unit>| = Q|IA|::R|/extFun|
lval extFun_AA_B: R|kotlin/Function2<IA, IA, kotlin/Unit>| = Q|IB|::extFun# lval extFun_AA_B: R|kotlin/Function2<IA, IA, kotlin/Unit>| = Q|IB|::R|/extFun|
lval extFun_BB_A: R|kotlin/Function2<IB, IB, kotlin/Unit>| = Q|IA|::extFun# lval extFun_BB_A: R|kotlin/Function2<IB, IB, kotlin/Unit>| = Q|IA|::R|/extFun|
lval extFun_BA_B: R|kotlin/Function2<IB, IA, kotlin/Unit>| = Q|IB|::extFun# lval extFun_BA_B: R|kotlin/Function2<IB, IA, kotlin/Unit>| = Q|IB|::R|/extFun|
lval extFun_BB_B: R|kotlin/Function2<IB, IB, kotlin/Unit>| = Q|IB|::extFun# lval extFun_BB_B: R|kotlin/Function2<IB, IB, kotlin/Unit>| = Q|IB|::R|/extFun|
} }
@@ -40,6 +40,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/diagnostics/callableReferences"), Pattern.compile("^(.+)\\.kt$"), true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/diagnostics/callableReferences"), Pattern.compile("^(.+)\\.kt$"), true);
} }
@TestMetadata("beyoundCalls.kt")
public void testBeyoundCalls() throws Exception {
runTest("compiler/fir/resolve/testData/diagnostics/callableReferences/beyoundCalls.kt");
}
@TestMetadata("companions.kt") @TestMetadata("companions.kt")
public void testCompanions() throws Exception { public void testCompanions() throws Exception {
runTest("compiler/fir/resolve/testData/diagnostics/callableReferences/companions.kt"); runTest("compiler/fir/resolve/testData/diagnostics/callableReferences/companions.kt");