FIR: Support callable references partially
^KT-32725 In Progress
This commit is contained in:
@@ -38,6 +38,7 @@ object StandardClassIds {
|
|||||||
val KProperty = "KProperty".reflectId()
|
val KProperty = "KProperty".reflectId()
|
||||||
|
|
||||||
fun byName(name: String) = name.baseId()
|
fun byName(name: String) = name.baseId()
|
||||||
|
fun reflectByName(name: String) = name.reflectId()
|
||||||
|
|
||||||
val primitiveArrayTypeByElementType: Map<ClassId, ClassId> = mutableMapOf<ClassId, ClassId>().apply {
|
val primitiveArrayTypeByElementType: Map<ClassId, ClassId> = mutableMapOf<ClassId, ClassId>().apply {
|
||||||
fun addPrimitive(id: ClassId) {
|
fun addPrimitive(id: ClassId) {
|
||||||
@@ -55,4 +56,4 @@ object StandardClassIds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val elementTypeByPrimitiveArrayType = primitiveArrayTypeByElementType.map { (k, v) -> v to k }.toMap()
|
val elementTypeByPrimitiveArrayType = primitiveArrayTypeByElementType.map { (k, v) -> v to k }.toMap()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ package org.jetbrains.kotlin.fir
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedQualifierImpl
|
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedQualifierImpl
|
||||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReference
|
||||||
@@ -18,8 +18,7 @@ import org.jetbrains.kotlin.fir.references.impl.FirBackingFieldReferenceImpl
|
|||||||
import org.jetbrains.kotlin.fir.references.impl.FirErrorNamedReferenceImpl
|
import org.jetbrains.kotlin.fir.references.impl.FirErrorNamedReferenceImpl
|
||||||
import org.jetbrains.kotlin.fir.references.impl.FirResolvedCallableReferenceImpl
|
import org.jetbrains.kotlin.fir.references.impl.FirResolvedCallableReferenceImpl
|
||||||
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.ImplicitReceiverStack
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.StoreNameReference
|
import org.jetbrains.kotlin.fir.resolve.transformers.StoreNameReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.StoreReceiver
|
import org.jetbrains.kotlin.fir.resolve.transformers.StoreReceiver
|
||||||
@@ -28,12 +27,17 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
|||||||
import org.jetbrains.kotlin.fir.resolve.transformers.phasedFir
|
import org.jetbrains.kotlin.fir.resolve.transformers.phasedFir
|
||||||
import org.jetbrains.kotlin.fir.resolve.typeForQualifier
|
import org.jetbrains.kotlin.fir.resolve.typeForQualifier
|
||||||
import org.jetbrains.kotlin.fir.resolve.typeFromCallee
|
import org.jetbrains.kotlin.fir.resolve.typeFromCallee
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.*
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
|
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
|
||||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
||||||
|
|
||||||
class FirCallResolver(
|
class FirCallResolver(
|
||||||
@@ -217,6 +221,88 @@ class FirCallResolver(
|
|||||||
return resultExpression
|
return resultExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun resolveCallableReference(callableReferenceAccess: FirCallableReferenceAccess, lhs: DoubleColonLHS?): FirCallableReferenceAccess {
|
||||||
|
val resultCollector = ReferencesCandidateCollector(this, resolutionStageRunner)
|
||||||
|
|
||||||
|
val consumer =
|
||||||
|
createCallableReferencesConsumerForLHS(
|
||||||
|
callableReferenceAccess, lhs, resultCollector
|
||||||
|
)
|
||||||
|
|
||||||
|
towerResolver.runResolver(consumer, implicitReceiverStack.receiversAsReversed())
|
||||||
|
|
||||||
|
val result = resultCollector.results.firstOrNull() ?: return callableReferenceAccess
|
||||||
|
|
||||||
|
val resultingType: ConeKotlinType = when (val fir = result.symbol.fir) {
|
||||||
|
is FirSimpleFunction -> createKFunctionType(fir, lhs)
|
||||||
|
is FirProperty -> createKPropertyType(fir)
|
||||||
|
else -> ConeKotlinErrorType("Unknown callable kind: ${fir::class}")
|
||||||
|
}
|
||||||
|
|
||||||
|
callableReferenceAccess.replaceTypeRef(FirResolvedTypeRefImpl(null, resultingType))
|
||||||
|
|
||||||
|
return callableReferenceAccess.transformCalleeReference(
|
||||||
|
StoreNameReference,
|
||||||
|
FirNamedReferenceWithCandidate(callableReferenceAccess.psi, callableReferenceAccess.calleeReference.name, result)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createKPropertyType(fir: FirProperty): ConeKotlinType {
|
||||||
|
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createKFunctionType(
|
||||||
|
function: FirSimpleFunction,
|
||||||
|
lhs: DoubleColonLHS?
|
||||||
|
): ConeKotlinType {
|
||||||
|
val receiverType = (lhs as? DoubleColonLHS.Type)?.type
|
||||||
|
val parameterTypes = function.valueParameters.map {
|
||||||
|
it.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: ConeKotlinErrorType("No type for parameter $it")
|
||||||
|
}
|
||||||
|
|
||||||
|
return createFunctionalType(
|
||||||
|
parameterTypes, receiverType = receiverType,
|
||||||
|
rawReturnType = function.returnTypeRef.coneTypeSafe() ?: ConeKotlinErrorType("No type for return type of $this")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCallableReferencesConsumerForLHS(
|
||||||
|
callableReferenceAccess: FirCallableReferenceAccess,
|
||||||
|
lhs: DoubleColonLHS?,
|
||||||
|
resultCollector: CandidateCollector
|
||||||
|
): TowerDataConsumer {
|
||||||
|
val name = callableReferenceAccess.calleeReference.name
|
||||||
|
|
||||||
|
return when (lhs) {
|
||||||
|
is DoubleColonLHS.Expression, null -> createCallableReferencesConsumerForReceiver(
|
||||||
|
name, resultCollector, callableReferenceAccess.explicitReceiver
|
||||||
|
)
|
||||||
|
is DoubleColonLHS.Type -> createCallableReferencesConsumerForReceiver(
|
||||||
|
name, resultCollector,
|
||||||
|
FirExpressionStub(callableReferenceAccess.psi).apply { replaceTypeRef(FirResolvedTypeRefImpl(null, lhs.type)) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCallableReferencesConsumerForReceiver(
|
||||||
|
name: Name,
|
||||||
|
resultCollector: CandidateCollector,
|
||||||
|
receiver: FirExpression?
|
||||||
|
): TowerDataConsumer {
|
||||||
|
val info = CallInfo(
|
||||||
|
CallKind.CallableReference,
|
||||||
|
receiver,
|
||||||
|
emptyList(),
|
||||||
|
false,
|
||||||
|
emptyList(),
|
||||||
|
session,
|
||||||
|
file,
|
||||||
|
transformer.components.container
|
||||||
|
) { it.resultType }
|
||||||
|
|
||||||
|
return createCallableReferencesConsumer(session, name, info, this, resultCollector)
|
||||||
|
}
|
||||||
|
|
||||||
private fun createResolvedNamedReference(
|
private fun createResolvedNamedReference(
|
||||||
namedReference: FirNamedReference,
|
namedReference: FirNamedReference,
|
||||||
candidates: Collection<Candidate>,
|
candidates: Collection<Candidate>,
|
||||||
|
|||||||
+157
@@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("DuplicatedCode")
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.resolve
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeStarProjection
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
||||||
|
|
||||||
|
sealed class DoubleColonLHS(val type: ConeKotlinType) {
|
||||||
|
/**
|
||||||
|
* [isObjectQualifier] is true iff the LHS of a callable reference is a qualified expression which references a named object.
|
||||||
|
* Note that such LHS can be treated both as a type and as an expression, so special handling may be required.
|
||||||
|
*
|
||||||
|
* For example, if `Obj` is an object:
|
||||||
|
*
|
||||||
|
* Obj::class // object qualifier
|
||||||
|
* test.Obj::class // object qualifier
|
||||||
|
* (Obj)::class // not an object qualifier (can only be treated as an expression, not as a type)
|
||||||
|
* { Obj }()::class // not an object qualifier
|
||||||
|
*/
|
||||||
|
class Expression(type: ConeKotlinType, val isObjectQualifier: Boolean) : DoubleColonLHS(type)
|
||||||
|
|
||||||
|
class Type(type: ConeKotlinType) : DoubleColonLHS(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns true if this expression has the form "A<B>" which means it's a type on the LHS of a double colon expression
|
||||||
|
internal val FirFunctionCall.hasExplicitValueArguments: Boolean
|
||||||
|
get() = true // TODO: hasExplicitArgumentList || hasExplicitLambdaArguments
|
||||||
|
|
||||||
|
class FirDoubleColonExpressionResolver(
|
||||||
|
private val session: FirSession
|
||||||
|
) {
|
||||||
|
|
||||||
|
// Returns true if the expression is not a call expression without value arguments (such as "A<B>") or a qualified expression
|
||||||
|
// which contains such call expression as one of its parts.
|
||||||
|
// In this case it's pointless to attempt to type check an expression on the LHS in "A<B>::class", since "A<B>" certainly means a type.
|
||||||
|
private fun FirExpression.canBeConsideredProperExpression(): Boolean {
|
||||||
|
return when {
|
||||||
|
this is FirQualifiedAccessExpression && explicitReceiver?.canBeConsideredProperExpression() != true -> false
|
||||||
|
this is FirFunctionCall && !hasExplicitValueArguments -> false
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FirExpression.canBeConsideredProperType(): Boolean {
|
||||||
|
return when {
|
||||||
|
this is FirFunctionCall &&
|
||||||
|
explicitReceiver?.canBeConsideredProperType() != false -> !hasExplicitValueArguments
|
||||||
|
this is FirQualifiedAccessExpression &&
|
||||||
|
explicitReceiver?.canBeConsideredProperType() != false &&
|
||||||
|
calleeReference is FirNamedReference -> true
|
||||||
|
this is FirResolvedQualifier -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun shouldTryResolveLHSAsExpression(expression: FirCallableReferenceAccess): Boolean {
|
||||||
|
val lhs = expression.explicitReceiver ?: return false
|
||||||
|
return lhs.canBeConsideredProperExpression() /* && !expression.hasQuestionMarks */
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun shouldTryResolveLHSAsType(expression: FirCallableReferenceAccess): Boolean {
|
||||||
|
val lhs = expression.explicitReceiver
|
||||||
|
return lhs != null && lhs.canBeConsideredProperType()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun resolveDoubleColonLHS(doubleColonExpression: FirCallableReferenceAccess): DoubleColonLHS? {
|
||||||
|
val resultForExpr = tryResolveLHS(doubleColonExpression, this::shouldTryResolveLHSAsExpression, this::resolveExpressionOnLHS)
|
||||||
|
if (resultForExpr != null && !resultForExpr.isObjectQualifier) {
|
||||||
|
return resultForExpr
|
||||||
|
}
|
||||||
|
|
||||||
|
val resultForType = tryResolveLHS(doubleColonExpression, this::shouldTryResolveLHSAsType) { expression ->
|
||||||
|
resolveTypeOnLHS(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultForType != null) {
|
||||||
|
if (resultForExpr != null && resultForType.type == resultForExpr.type) {
|
||||||
|
// If we skipped an object expression result before and the type result is the same, this means that
|
||||||
|
// there were no other classifier except that object that could win. We prefer to treat the LHS as an expression here,
|
||||||
|
// to have a bound callable reference / class literal
|
||||||
|
return resultForExpr
|
||||||
|
}
|
||||||
|
return resultForType
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the LHS could be resolved neither as an expression nor as a type, we should still type-check it to allow all diagnostics
|
||||||
|
// to be reported and references to be resolved. For that, we commit one of the applicable traces here, preferring the expression
|
||||||
|
return resultForExpr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns null if the LHS is definitely not an expression. Returns a non-null result if a resolution was attempted and led to
|
||||||
|
* either a successful result or not.
|
||||||
|
*/
|
||||||
|
private fun <T : DoubleColonLHS> tryResolveLHS(
|
||||||
|
doubleColonExpression: FirCallableReferenceAccess,
|
||||||
|
criterion: (FirCallableReferenceAccess) -> Boolean,
|
||||||
|
resolve: (FirExpression) -> T?
|
||||||
|
): T? {
|
||||||
|
val expression = doubleColonExpression.explicitReceiver ?: return null
|
||||||
|
|
||||||
|
if (!criterion(doubleColonExpression)) return null
|
||||||
|
|
||||||
|
return resolve(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resolveExpressionOnLHS(expression: FirExpression): DoubleColonLHS.Expression? {
|
||||||
|
val type = (expression.typeRef as? FirResolvedTypeRef)?.type ?: return null
|
||||||
|
|
||||||
|
if (expression is FirResolvedQualifier) {
|
||||||
|
val firClass = session.firSymbolProvider
|
||||||
|
.getClassLikeSymbolByFqName(expression.classId ?: return null)
|
||||||
|
?.fir as? FirRegularClass
|
||||||
|
?: return null
|
||||||
|
|
||||||
|
if (firClass.classKind == ClassKind.OBJECT) return DoubleColonLHS.Expression(type, isObjectQualifier = true)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return DoubleColonLHS.Expression(type, isObjectQualifier = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resolveTypeOnLHS(
|
||||||
|
expression: FirExpression
|
||||||
|
): DoubleColonLHS.Type? {
|
||||||
|
val resolvedExpression =
|
||||||
|
expression as? FirResolvedQualifier
|
||||||
|
?: return null
|
||||||
|
|
||||||
|
val firClass = session.firSymbolProvider
|
||||||
|
.getClassLikeSymbolByFqName(resolvedExpression.classId ?: return null)
|
||||||
|
// TODO: support type aliases
|
||||||
|
?.fir as? FirRegularClass
|
||||||
|
?: return null
|
||||||
|
|
||||||
|
val type = ConeClassTypeImpl(
|
||||||
|
firClass.symbol.toLookupTag(),
|
||||||
|
Array(firClass.typeParameters.size) { ConeStarProjection },
|
||||||
|
isNullable = false // TODO: Use org.jetbrains.kotlin.psi.KtDoubleColonExpression.getHasQuestionMarks
|
||||||
|
)
|
||||||
|
|
||||||
|
return DoubleColonLHS.Type(type)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -216,11 +216,13 @@ fun FirFunction<*>.constructFunctionalTypeRef(session: FirSession): FirResolvedT
|
|||||||
fun createFunctionalType(
|
fun createFunctionalType(
|
||||||
parameters: List<ConeKotlinType>,
|
parameters: List<ConeKotlinType>,
|
||||||
receiverType: ConeKotlinType?,
|
receiverType: ConeKotlinType?,
|
||||||
rawReturnType: ConeKotlinType
|
rawReturnType: ConeKotlinType,
|
||||||
|
isKFunctionType: Boolean = false
|
||||||
): ConeLookupTagBasedType {
|
): ConeLookupTagBasedType {
|
||||||
val receiverAndParameterTypes = listOfNotNull(receiverType) + parameters + listOf(rawReturnType)
|
val receiverAndParameterTypes = listOfNotNull(receiverType) + parameters + listOf(rawReturnType)
|
||||||
|
|
||||||
val functionalTypeId = StandardClassIds.byName("Function${receiverAndParameterTypes.size - 1}")
|
val postfix = "Function${receiverAndParameterTypes.size - 1}"
|
||||||
|
val functionalTypeId = if (isKFunctionType) StandardClassIds.reflectByName("K$postfix") else StandardClassIds.byName(postfix)
|
||||||
return ConeClassTypeImpl(ConeClassLikeLookupTagImpl(functionalTypeId), receiverAndParameterTypes.toTypedArray(), isNullable = false)
|
return ConeClassTypeImpl(ConeClassLikeLookupTagImpl(functionalTypeId), receiverAndParameterTypes.toTypedArray(), isNullable = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ fun resolveArgumentExpression(
|
|||||||
typeProvider
|
typeProvider
|
||||||
)
|
)
|
||||||
// TODO:!
|
// TODO:!
|
||||||
is FirCallableReferenceAccess -> Unit
|
is FirCallableReferenceAccess -> preprocessCallableReference(csBuilder, argument, expectedType, sink)
|
||||||
// NB: FirCallableReferenceAccess should be checked earlier
|
// NB: FirCallableReferenceAccess should be checked earlier
|
||||||
is FirQualifiedAccessExpression -> resolvePlainExpressionArgument(
|
is FirQualifiedAccessExpression -> resolvePlainExpressionArgument(
|
||||||
csBuilder,
|
csBuilder,
|
||||||
|
|||||||
@@ -43,4 +43,12 @@ sealed class CallKind {
|
|||||||
CheckReceivers.Extension
|
CheckReceivers.Extension
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object CallableReference : CallKind() {
|
||||||
|
override val resolutionSequence: List<ResolutionStage> = listOf(
|
||||||
|
CheckVisibility,
|
||||||
|
DiscriminateSynthetics,
|
||||||
|
CreateFreshTypeVariableSubstitutorStage
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,20 @@ open class CandidateCollector(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ReferencesCandidateCollector(components: BodyResolveComponents, resolutionStageRunner: ResolutionStageRunner) :
|
||||||
|
CandidateCollector(components, resolutionStageRunner) {
|
||||||
|
|
||||||
|
val results = mutableListOf<Candidate>()
|
||||||
|
|
||||||
|
override fun consumeCandidate(group: Int, candidate: Candidate): CandidateApplicability {
|
||||||
|
val applicability = resolutionStageRunner.processCandidate(candidate)
|
||||||
|
if (applicability >= CandidateApplicability.SYNTHETIC_RESOLVED) {
|
||||||
|
results.add(candidate)
|
||||||
|
}
|
||||||
|
return CandidateApplicability.SYNTHETIC_RESOLVED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Collects properties that potentially could be invoke receivers, like 'propertyName()',
|
// Collects properties that potentially could be invoke receivers, like 'propertyName()',
|
||||||
// and initiates further invoke resolution by adding property-bound invoke consumers
|
// and initiates further invoke resolution by adding property-bound invoke consumers
|
||||||
class InvokeReceiverCandidateCollector(
|
class InvokeReceiverCandidateCollector(
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ class CandidateFactory(
|
|||||||
|
|
||||||
fun PostponedArgumentsAnalyzer.Context.addSubsystemFromExpression(expression: FirExpression) {
|
fun PostponedArgumentsAnalyzer.Context.addSubsystemFromExpression(expression: FirExpression) {
|
||||||
when (expression) {
|
when (expression) {
|
||||||
is FirFunctionCall, is FirWhenExpression, is FirTryExpression -> (expression as FirResolvable).candidate()?.let { addOtherSystem(it.system.asReadOnlyStorage()) }
|
is FirFunctionCall, is FirWhenExpression, is FirTryExpression, is FirCallableReferenceAccess ->
|
||||||
|
(expression as FirResolvable).candidate()?.let { addOtherSystem(it.system.asReadOnlyStorage()) }
|
||||||
is FirWrappedArgumentExpression -> addSubsystemFromExpression(expression.expression)
|
is FirWrappedArgumentExpression -> addSubsystemFromExpression(expression.expression)
|
||||||
is FirBlock -> expression.returnExpressions().forEach { addSubsystemFromExpression(it) }
|
is FirBlock -> expression.returnExpressions().forEach { addSubsystemFromExpression(it) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,3 +136,19 @@ fun createSimpleConsumer(
|
|||||||
NoExplicitReceiverTowerDataConsumer(session, name, token, factory, resultCollector)
|
NoExplicitReceiverTowerDataConsumer(session, name, token, factory, resultCollector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createCallableReferencesConsumer(
|
||||||
|
session: FirSession,
|
||||||
|
name: Name,
|
||||||
|
callInfo: CallInfo,
|
||||||
|
bodyResolveComponents: BodyResolveComponents,
|
||||||
|
resultCollector: CandidateCollector
|
||||||
|
): TowerDataConsumer {
|
||||||
|
// TODO: Use SamePriorityConsumer
|
||||||
|
return PrioritizedTowerDataConsumer(
|
||||||
|
resultCollector,
|
||||||
|
createSimpleConsumer(session, name, TowerScopeLevel.Token.Functions, callInfo, bodyResolveComponents, resultCollector)
|
||||||
|
// TODO: Support properties
|
||||||
|
// , createSimpleConsumer(session, name, TowerScopeLevel.Token.Properties, callInfo, bodyResolveComponents, resultCollector)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
+18
-2
@@ -6,11 +6,14 @@
|
|||||||
package org.jetbrains.kotlin.fir.resolve.calls
|
package org.jetbrains.kotlin.fir.resolve.calls
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
|
||||||
import org.jetbrains.kotlin.fir.resolve.constructType
|
import org.jetbrains.kotlin.fir.resolve.constructType
|
||||||
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
|
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
|
||||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||||
import org.jetbrains.kotlin.fir.symbols.invoke
|
import org.jetbrains.kotlin.fir.symbols.invoke
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
@@ -42,6 +45,19 @@ fun preprocessLambdaArgument(
|
|||||||
acceptLambdaAtoms(resolvedArgument)
|
acceptLambdaAtoms(resolvedArgument)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun preprocessCallableReference(
|
||||||
|
csBuilder: ConstraintSystemBuilder,
|
||||||
|
argument: FirCallableReferenceAccess,
|
||||||
|
expectedType: ConeKotlinType,
|
||||||
|
sink: CheckerSink
|
||||||
|
) {
|
||||||
|
val type = argument.typeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
||||||
|
val candidate = argument.candidate() ?: return resolvePlainArgumentType(
|
||||||
|
csBuilder, type, expectedType, sink, isReceiver = false, isSafeCall = false
|
||||||
|
)
|
||||||
|
val argumentType = candidate.substitutor.substituteOrSelf(type)
|
||||||
|
resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver = false, isSafeCall = false)
|
||||||
|
}
|
||||||
|
|
||||||
val ConeKotlinType.isBuiltinFunctionalType: Boolean
|
val ConeKotlinType.isBuiltinFunctionalType: Boolean
|
||||||
get() {
|
get() {
|
||||||
@@ -77,14 +93,14 @@ private fun isFunctionalTypeWithReceiver(typeRef: FirTypeRef) =
|
|||||||
coneTypeSafe.lookupTag.classId.asString() == "kotlin/ExtensionFunctionType"
|
coneTypeSafe.lookupTag.classId.asString() == "kotlin/ExtensionFunctionType"
|
||||||
}
|
}
|
||||||
|
|
||||||
private val ConeKotlinType.returnType: ConeKotlinType?
|
val ConeKotlinType.returnType: ConeKotlinType?
|
||||||
get() {
|
get() {
|
||||||
require(this is ConeClassType)
|
require(this is ConeClassType)
|
||||||
val projection = typeArguments.last()
|
val projection = typeArguments.last()
|
||||||
return (projection as? ConeTypedProjection)?.type
|
return (projection as? ConeTypedProjection)?.type
|
||||||
}
|
}
|
||||||
|
|
||||||
private val ConeKotlinType.valueParameterTypes: List<ConeKotlinType?>
|
val ConeKotlinType.valueParameterTypes: List<ConeKotlinType?>
|
||||||
get() {
|
get() {
|
||||||
require(this is ConeClassType)
|
require(this is ConeClassType)
|
||||||
return typeArguments.dropLast(1).map {
|
return typeArguments.dropLast(1).map {
|
||||||
|
|||||||
+43
-5
@@ -10,6 +10,8 @@ import org.jetbrains.kotlin.fir.copy
|
|||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.references.impl.FirResolvedCallableReferenceImpl
|
import org.jetbrains.kotlin.fir.references.impl.FirResolvedCallableReferenceImpl
|
||||||
|
import org.jetbrains.kotlin.fir.references.impl.FirResolvedRealCallableReferenceImpl
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.candidate
|
import org.jetbrains.kotlin.fir.resolve.calls.candidate
|
||||||
import org.jetbrains.kotlin.fir.resolve.constructFunctionalTypeRef
|
import org.jetbrains.kotlin.fir.resolve.constructFunctionalTypeRef
|
||||||
@@ -58,6 +60,34 @@ class FirCallCompletionResultsWriterTransformer(
|
|||||||
).compose()
|
).compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun transformCallableReferenceAccess(
|
||||||
|
callableReferenceAccess: FirCallableReferenceAccess,
|
||||||
|
data: Nothing?
|
||||||
|
): CompositeTransformResult<FirStatement> {
|
||||||
|
|
||||||
|
val calleeReference =
|
||||||
|
callableReferenceAccess.calleeReference as? FirNamedReferenceWithCandidate ?: return callableReferenceAccess.compose()
|
||||||
|
|
||||||
|
val typeRef = callableReferenceAccess.typeRef as FirResolvedTypeRef
|
||||||
|
|
||||||
|
val initialType = calleeReference.candidate.substitutor.substituteOrSelf(typeRef.type)
|
||||||
|
val finalType = finalSubstitutor.substituteOrSelf(initialType)
|
||||||
|
|
||||||
|
val resultType = typeRef.withReplacedConeType(finalType)
|
||||||
|
callableReferenceAccess.replaceTypeRef(resultType)
|
||||||
|
|
||||||
|
return callableReferenceAccess.transformCalleeReference(
|
||||||
|
StoreCalleeReference,
|
||||||
|
FirResolvedRealCallableReferenceImpl(
|
||||||
|
calleeReference.psi,
|
||||||
|
calleeReference.name,
|
||||||
|
calleeReference.candidateSymbol
|
||||||
|
).apply {
|
||||||
|
inferredTypeArguments.addAll(computeTypeArguments(calleeReference.candidate))
|
||||||
|
}
|
||||||
|
).compose()
|
||||||
|
}
|
||||||
|
|
||||||
override fun transformVariableAssignment(
|
override fun transformVariableAssignment(
|
||||||
variableAssignment: FirVariableAssignment,
|
variableAssignment: FirVariableAssignment,
|
||||||
data: Nothing?
|
data: Nothing?
|
||||||
@@ -80,9 +110,7 @@ class FirCallCompletionResultsWriterTransformer(
|
|||||||
|
|
||||||
val subCandidate = calleeReference.candidate
|
val subCandidate = calleeReference.candidate
|
||||||
val declaration = subCandidate.symbol.phasedFir as FirCallableMemberDeclaration<*>
|
val declaration = subCandidate.symbol.phasedFir as FirCallableMemberDeclaration<*>
|
||||||
val newTypeParameters = declaration.typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) }
|
val typeArguments = computeTypeArguments(subCandidate)
|
||||||
.map { subCandidate.substitutor.substituteOrSelf(it) }
|
|
||||||
.map { finalSubstitutor.substituteOrSelf(it) }
|
|
||||||
.mapIndexed { index, type ->
|
.mapIndexed { index, type ->
|
||||||
when (val argument = functionCall.typeArguments.getOrNull(index)) {
|
when (val argument = functionCall.typeArguments.getOrNull(index)) {
|
||||||
is FirTypeProjectionWithVariance -> {
|
is FirTypeProjectionWithVariance -> {
|
||||||
@@ -119,7 +147,7 @@ class FirCallCompletionResultsWriterTransformer(
|
|||||||
|
|
||||||
return functionCall.copy(
|
return functionCall.copy(
|
||||||
resultType = resultType,
|
resultType = resultType,
|
||||||
typeArguments = newTypeParameters,
|
typeArguments = typeArguments,
|
||||||
calleeReference = FirResolvedCallableReferenceImpl(
|
calleeReference = FirResolvedCallableReferenceImpl(
|
||||||
calleeReference.psi,
|
calleeReference.psi,
|
||||||
calleeReference.name,
|
calleeReference.name,
|
||||||
@@ -131,6 +159,16 @@ class FirCallCompletionResultsWriterTransformer(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun computeTypeArguments(
|
||||||
|
candidate: Candidate
|
||||||
|
): List<ConeKotlinType> {
|
||||||
|
val declaration = candidate.symbol.phasedFir as? FirCallableMemberDeclaration<*> ?: return emptyList()
|
||||||
|
|
||||||
|
return declaration.typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) }
|
||||||
|
.map { candidate.substitutor.substituteOrSelf(it) }
|
||||||
|
.map { finalSubstitutor.substituteOrSelf(it) }
|
||||||
|
}
|
||||||
|
|
||||||
override fun transformAnonymousFunction(
|
override fun transformAnonymousFunction(
|
||||||
anonymousFunction: FirAnonymousFunction,
|
anonymousFunction: FirAnonymousFunction,
|
||||||
data: Nothing?
|
data: Nothing?
|
||||||
@@ -210,4 +248,4 @@ class FirCallCompletionResultsWriterTransformer(
|
|||||||
).compose()
|
).compose()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -77,6 +77,13 @@ open class FirBodyResolveTransformer(
|
|||||||
return expressionsTransformer.transformFunctionCall(functionCall, data)
|
return expressionsTransformer.transformFunctionCall(functionCall, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun transformCallableReferenceAccess(
|
||||||
|
callableReferenceAccess: FirCallableReferenceAccess,
|
||||||
|
data: Any?
|
||||||
|
): CompositeTransformResult<FirStatement> {
|
||||||
|
return expressionsTransformer.transformCallableReferenceAccess(callableReferenceAccess, data)
|
||||||
|
}
|
||||||
|
|
||||||
override fun transformBlock(block: FirBlock, data: Any?): CompositeTransformResult<FirStatement> {
|
override fun transformBlock(block: FirBlock, data: Any?): CompositeTransformResult<FirStatement> {
|
||||||
return expressionsTransformer.transformBlock(block, data)
|
return expressionsTransformer.transformBlock(block, data)
|
||||||
}
|
}
|
||||||
@@ -217,4 +224,4 @@ open class FirBodyResolveTransformer(
|
|||||||
val result = this.transform<FirElement, D>(transformer, data)
|
val result = this.transform<FirElement, D>(transformer, data)
|
||||||
require(result.single === this) { "become ${result.single}: `${result.single.render()}`, was ${this}: `${this.render()}`" }
|
require(result.single === this) { "become ${result.single}: `${result.single.render()}`, was ${this}: `${this.render()}`" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-5
@@ -14,13 +14,11 @@ import org.jetbrains.kotlin.fir.references.FirResolvedCallableReference
|
|||||||
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
||||||
import org.jetbrains.kotlin.fir.references.impl.FirExplicitThisReference
|
import org.jetbrains.kotlin.fir.references.impl.FirExplicitThisReference
|
||||||
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ConeInferenceContext
|
import org.jetbrains.kotlin.fir.resolve.calls.ConeInferenceContext
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.candidate
|
import org.jetbrains.kotlin.fir.resolve.calls.candidate
|
||||||
import org.jetbrains.kotlin.fir.resolve.constructType
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.InvocationKindTransformer
|
import org.jetbrains.kotlin.fir.resolve.transformers.InvocationKindTransformer
|
||||||
import org.jetbrains.kotlin.fir.resolve.typeFromCallee
|
import org.jetbrains.kotlin.fir.resolve.transformers.StoreReceiver
|
||||||
import org.jetbrains.kotlin.fir.resolve.withNullability
|
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
|
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
|
||||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||||
import org.jetbrains.kotlin.fir.symbols.invoke
|
import org.jetbrains.kotlin.fir.symbols.invoke
|
||||||
@@ -31,6 +29,7 @@ import org.jetbrains.kotlin.fir.types.impl.FirImplicitUnitTypeRef
|
|||||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||||
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
||||||
import org.jetbrains.kotlin.fir.visitors.compose
|
import org.jetbrains.kotlin.fir.visitors.compose
|
||||||
|
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|
||||||
@@ -43,6 +42,7 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) :
|
|||||||
implicitReceiverStack,
|
implicitReceiverStack,
|
||||||
qualifiedResolver
|
qualifiedResolver
|
||||||
)
|
)
|
||||||
|
private val doubleColonExpressionResolver: FirDoubleColonExpressionResolver = FirDoubleColonExpressionResolver(session)
|
||||||
|
|
||||||
private inline val builtinTypes: BuiltinTypes get() = session.builtinTypes
|
private inline val builtinTypes: BuiltinTypes get() = session.builtinTypes
|
||||||
|
|
||||||
@@ -253,6 +253,24 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) :
|
|||||||
return result.compose()
|
return result.compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun transformCallableReferenceAccess(
|
||||||
|
callableReferenceAccess: FirCallableReferenceAccess,
|
||||||
|
data: Any?
|
||||||
|
): CompositeTransformResult<FirStatement> {
|
||||||
|
val transformedLHS =
|
||||||
|
callableReferenceAccess.explicitReceiver?.transformSingle(this, noExpectedType)
|
||||||
|
|
||||||
|
val callableReferenceAccessWithTransformedLHS =
|
||||||
|
if (transformedLHS != null)
|
||||||
|
callableReferenceAccess.transformExplicitReceiver(StoreReceiver, transformedLHS)
|
||||||
|
else
|
||||||
|
callableReferenceAccess
|
||||||
|
|
||||||
|
val lhsResult = doubleColonExpressionResolver.resolveDoubleColonLHS(callableReferenceAccessWithTransformedLHS)
|
||||||
|
|
||||||
|
return callResolver.resolveCallableReference(callableReferenceAccessWithTransformedLHS, lhsResult).compose()
|
||||||
|
}
|
||||||
|
|
||||||
override fun transformGetClassCall(getClassCall: FirGetClassCall, data: Any?): CompositeTransformResult<FirStatement> {
|
override fun transformGetClassCall(getClassCall: FirGetClassCall, data: Any?): CompositeTransformResult<FirStatement> {
|
||||||
val transformedGetClassCall = transformExpression(getClassCall, data).single as FirGetClassCall
|
val transformedGetClassCall = transformExpression(getClassCall, data).single as FirGetClassCall
|
||||||
val kClassSymbol = ClassId.fromString("kotlin/reflect/KClass")(session.firSymbolProvider)
|
val kClassSymbol = ClassId.fromString("kotlin/reflect/KClass")(session.firSymbolProvider)
|
||||||
@@ -349,4 +367,4 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) :
|
|||||||
internal fun <T> storeTypeFromCallee(access: T) where T : FirQualifiedAccess, T : FirExpression {
|
internal fun <T> storeTypeFromCallee(access: T) where T : FirQualifiedAccess, T : FirExpression {
|
||||||
access.resultType = callCompleter.typeFromCallee(access)
|
access.resultType = callCompleter.typeFromCallee(access)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
fun <T, E> foo(x: (T) -> E) {}
|
||||||
|
fun <T, E> foo2(x: (A, T) -> E) {}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
fun baz(x: String): Int = null!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(x: String): Int = null!!
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
foo(::bar)
|
||||||
|
foo(A()::baz)
|
||||||
|
foo2(A::baz)
|
||||||
|
}
|
||||||
Vendored
+39
@@ -0,0 +1,39 @@
|
|||||||
|
FILE: inferenceFromCallableReferenceType.kt
|
||||||
|
public final fun <T, E> foo(x: R|kotlin/Function1<T, E>|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final fun <T, E> foo2(x: R|kotlin/Function2<A, T, E>|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final class A : R|kotlin/Any| {
|
||||||
|
public constructor(): R|A| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun baz(x: R|kotlin/String|): R|kotlin/Int| {
|
||||||
|
^baz when (lval <bangbang>: R|kotlin/Nothing?| = Null(null)) {
|
||||||
|
==($subj$, Null(null)) -> {
|
||||||
|
throw R|kotlin/KotlinNullPointerException.KotlinNullPointerException|()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
R|<local>/<bangbang>|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun bar(x: R|kotlin/String|): R|kotlin/Int| {
|
||||||
|
^bar when (lval <bangbang>: R|kotlin/Nothing?| = Null(null)) {
|
||||||
|
==($subj$, Null(null)) -> {
|
||||||
|
throw R|kotlin/KotlinNullPointerException.KotlinNullPointerException|()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
R|<local>/<bangbang>|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun main(): R|kotlin/Unit| {
|
||||||
|
R|/foo|<R|kotlin/String|, R|kotlin/Int|>(::R|/bar|)
|
||||||
|
R|/foo|<R|kotlin/String|, R|kotlin/Int|>(R|/A.A|()::R|/A.baz|)
|
||||||
|
R|/foo2|<R|kotlin/String|, R|kotlin/Int|>(Q|A|::R|/A.baz|)
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
fun foo(x: (String) -> Int) {}
|
||||||
|
fun foo2(x: (A, String) -> Int) {}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
fun <T, E> baz(x: T): E = null!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T, E> bar(x: T): E = null!!
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
foo(::bar)
|
||||||
|
foo(A()::baz)
|
||||||
|
foo2(A::baz)
|
||||||
|
}
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
FILE: inferenceFromExpectedType.kt
|
||||||
|
public final fun foo(x: R|kotlin/Function1<kotlin/String, kotlin/Int>|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final fun foo2(x: R|kotlin/Function2<A, kotlin/String, kotlin/Int>|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final class A : R|kotlin/Any| {
|
||||||
|
public constructor(): R|A| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun <T, E> baz(x: R|T|): R|E| {
|
||||||
|
^baz when (lval <bangbang>: R|kotlin/Nothing?| = Null(null)) {
|
||||||
|
==($subj$, Null(null)) -> {
|
||||||
|
throw R|kotlin/KotlinNullPointerException.KotlinNullPointerException|()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
R|<local>/<bangbang>|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun <T, E> bar(x: R|T|): R|E| {
|
||||||
|
^bar when (lval <bangbang>: R|kotlin/Nothing?| = Null(null)) {
|
||||||
|
==($subj$, Null(null)) -> {
|
||||||
|
throw R|kotlin/KotlinNullPointerException.KotlinNullPointerException|()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
R|<local>/<bangbang>|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun main(): R|kotlin/Unit| {
|
||||||
|
R|/foo|(::R|/bar<kotlin/String, kotlin/Int>|)
|
||||||
|
R|/foo|(R|/A.A|()::R|/A.baz<kotlin/String, kotlin/Int>|)
|
||||||
|
R|/foo2|(Q|A|::R|/A.baz<kotlin/String, kotlin/Int>|)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
fun bar(x: String): Int {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(x: (A, String) -> Int) {}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
foo(A::bar)
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
FILE: simpleClassReceiver.kt
|
||||||
|
public final class A : R|kotlin/Any| {
|
||||||
|
public constructor(): R|A| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun bar(x: R|kotlin/String|): R|kotlin/Int| {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun foo(x: R|kotlin/Function2<A, kotlin/String, kotlin/Int>|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final fun main(): R|kotlin/Unit| {
|
||||||
|
R|/foo|(Q|A|::R|/A.bar|)
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
class A {
|
||||||
|
fun bar(x: String): Int {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(x: (String) -> Int) {}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val a = A()
|
||||||
|
foo(a::bar)
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
FILE: simpleExpressionReceiver.kt
|
||||||
|
public final class A : R|kotlin/Any| {
|
||||||
|
public constructor(): R|A| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun bar(x: R|kotlin/String|): R|kotlin/Int| {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun foo(x: R|kotlin/Function1<kotlin/String, kotlin/Int>|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final fun main(): R|kotlin/Unit| {
|
||||||
|
lval a: R|A| = R|/A.A|()
|
||||||
|
R|/foo|(R|<local>/a|::R|/A.bar|)
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
fun foo(x: (String) -> Int) {}
|
||||||
|
|
||||||
|
fun bar(x: String): Int {}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
foo(::bar)
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
FILE: simpleNoReceiver.kt
|
||||||
|
public final fun foo(x: R|kotlin/Function1<kotlin/String, kotlin/Int>|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final fun bar(x: R|kotlin/String|): R|kotlin/Int| {
|
||||||
|
}
|
||||||
|
public final fun main(): R|kotlin/Unit| {
|
||||||
|
R|/foo|(::R|/bar|)
|
||||||
|
}
|
||||||
+38
@@ -28,6 +28,44 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/fir/resolve/testData/diagnostics/callableReferences")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class CallableReferences extends AbstractFirDiagnosticsTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInCallableReferences() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/diagnostics/callableReferences"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inferenceFromCallableReferenceType.kt")
|
||||||
|
public void testInferenceFromCallableReferenceType() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/diagnostics/callableReferences/inferenceFromCallableReferenceType.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inferenceFromExpectedType.kt")
|
||||||
|
public void testInferenceFromExpectedType() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/diagnostics/callableReferences/inferenceFromExpectedType.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simpleClassReceiver.kt")
|
||||||
|
public void testSimpleClassReceiver() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/diagnostics/callableReferences/simpleClassReceiver.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simpleExpressionReceiver.kt")
|
||||||
|
public void testSimpleExpressionReceiver() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/diagnostics/callableReferences/simpleExpressionReceiver.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simpleNoReceiver.kt")
|
||||||
|
public void testSimpleNoReceiver() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/diagnostics/callableReferences/simpleNoReceiver.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/fir/resolve/testData/diagnostics/j+k")
|
@TestMetadata("compiler/fir/resolve/testData/diagnostics/j+k")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -90,6 +90,16 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun List<ConeKotlinType>.renderTypesSeparated() {
|
||||||
|
for ((index, element) in this.withIndex()) {
|
||||||
|
if (index > 0) {
|
||||||
|
print(", ")
|
||||||
|
}
|
||||||
|
print(element.render())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun List<FirValueParameter>.renderParameters() {
|
private fun List<FirValueParameter>.renderParameters() {
|
||||||
print("(")
|
print("(")
|
||||||
renderSeparated()
|
renderSeparated()
|
||||||
@@ -806,6 +816,18 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
|||||||
}
|
}
|
||||||
val symbol = resolvedCallableReference.resolvedSymbol
|
val symbol = resolvedCallableReference.resolvedSymbol
|
||||||
print(symbol.render())
|
print(symbol.render())
|
||||||
|
|
||||||
|
|
||||||
|
if (resolvedCallableReference is FirResolvedRealCallableReference) {
|
||||||
|
if (resolvedCallableReference.inferredTypeArguments.isNotEmpty()) {
|
||||||
|
print("<")
|
||||||
|
|
||||||
|
resolvedCallableReference.inferredTypeArguments.renderTypesSeparated()
|
||||||
|
|
||||||
|
print(">")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isFakeOverride) {
|
if (isFakeOverride) {
|
||||||
when (symbol) {
|
when (symbol) {
|
||||||
is FirNamedFunctionSymbol -> {
|
is FirNamedFunctionSymbol -> {
|
||||||
@@ -822,6 +844,10 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
|||||||
print("|")
|
print("|")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitResolvedRealCallableReference(resolvedRealCallableReference: FirResolvedRealCallableReference) {
|
||||||
|
visitResolvedCallableReference(resolvedRealCallableReference)
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitThisReference(thisReference: FirThisReference) {
|
override fun visitThisReference(thisReference: FirThisReference) {
|
||||||
print("this")
|
print("this")
|
||||||
val labelName = thisReference.labelName
|
val labelName = thisReference.labelName
|
||||||
|
|||||||
Reference in New Issue
Block a user