[FIR] Properly detect callable reference type according conversions

This commit is contained in:
Dmitriy Novozhilov
2020-09-10 10:47:12 +03:00
parent ec93e5886a
commit 7f692be11e
15 changed files with 439 additions and 253 deletions
@@ -42,6 +42,7 @@ object StandardClassIds {
val String = "String".baseId()
val KProperty = "KProperty".reflectId()
val KMutableProperty = "KMutableProperty".reflectId()
val KProperty0 = "KProperty0".reflectId()
val KMutableProperty0 = "KMutableProperty0".reflectId()
val KProperty1 = "KProperty1".reflectId()
@@ -50,6 +51,7 @@ object StandardClassIds {
val KMutableProperty2 = "KMutableProperty2".reflectId()
val KFunction = "KFunction".reflectId()
val KClass = "KClass".reflectId()
val KCallable = "KCallable".reflectId()
val Comparable = "Comparable".baseId()
val Number = "Number".baseId()
@@ -0,0 +1,402 @@
/*
* 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.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.expressions.builder.buildNamedArgumentExpression
import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS
import org.jetbrains.kotlin.fir.resolve.createFunctionalType
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnsupportedCallableReferenceTarget
import org.jetbrains.kotlin.fir.resolve.inference.extractInputOutputTypesFromCallableReferenceExpectedType
import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.FirVisitor
import org.jetbrains.kotlin.resolve.calls.components.SuspendConversionStrategy
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
import org.jetbrains.kotlin.types.expressions.CoercionStrategy
internal object CheckCallableReferenceExpectedType : CheckerStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
val outerCsBuilder = callInfo.outerCSBuilder ?: return
val expectedType = callInfo.expectedType
if (candidate.symbol !is FirCallableSymbol<*>) return
val resultingReceiverType = when (callInfo.lhs) {
is DoubleColonLHS.Type -> callInfo.lhs.type.takeIf { callInfo.explicitReceiver !is FirResolvedQualifier }
else -> null
}
val fir: FirCallableDeclaration<*> = candidate.symbol.fir
val (rawResultingType, callableReferenceAdaptation) = buildReflectionType(fir, resultingReceiverType, callInfo, context)
val resultingType = candidate.substitutor.substituteOrSelf(rawResultingType)
if (callableReferenceAdaptation.needCompatibilityResolveForCallableReference()) {
sink.reportDiagnostic(LowerPriorityToPreserveCompatibilityDiagnostic)
}
candidate.resultingTypeForCallableReference = resultingType
candidate.usesSuspendConversion =
callableReferenceAdaptation?.suspendConversionStrategy == SuspendConversionStrategy.SUSPEND_CONVERSION
candidate.outerConstraintBuilderEffect = fun ConstraintSystemOperation.() {
addOtherSystem(candidate.system.asReadOnlyStorage())
val position = SimpleConstraintSystemConstraintPosition //TODO
if (expectedType != null) {
addSubtypeConstraint(resultingType, expectedType, position)
}
val declarationReceiverType: ConeKotlinType? =
(fir as? FirCallableMemberDeclaration<*>)?.receiverTypeRef?.coneType
?.let(candidate.substitutor::substituteOrSelf)
if (resultingReceiverType != null && declarationReceiverType != null) {
addSubtypeConstraint(resultingReceiverType, declarationReceiverType, position)
}
}
var isApplicable = true
outerCsBuilder.runTransaction {
candidate.outerConstraintBuilderEffect!!(this)
isApplicable = !hasContradiction
false
}
if (!isApplicable) {
sink.yieldDiagnostic(InapplicableCandidate)
}
}
}
/*
val resultingReceiverType = when (callInfo.lhs) {
is DoubleColonLHS.Type -> callInfo.lhs.type.takeIf { callInfo.explicitReceiver !is FirResolvedQualifier }
else -> null
}
*/
private fun buildReflectionType(
fir: FirCallableDeclaration<*>,
receiverType: ConeKotlinType?,
callInfo: CallInfo,
context: ResolutionContext
): Pair<ConeKotlinType, CallableReferenceAdaptation?> {
val returnTypeRef = context.bodyResolveComponents.returnTypeCalculator.tryCalculateReturnType(fir)
return when (fir) {
is FirFunction -> {
val unboundReferenceTarget = if (receiverType != null) 1 else 0
val callableReferenceAdaptation =
getCallableReferenceAdaptation(context.session, fir, callInfo.expectedType, unboundReferenceTarget)
val parameters = mutableListOf<ConeKotlinType>()
val returnType = callableReferenceAdaptation?.let {
parameters += it.argumentTypes
if (it.coercionStrategy == CoercionStrategy.COERCION_TO_UNIT) {
context.session.builtinTypes.unitType.type
} else {
returnTypeRef.coneType
}
} ?: returnTypeRef.coneType.also {
fir.valueParameters.mapTo(parameters) { it.returnTypeRef.coneType }
}
val isSuspend = (fir as? FirSimpleFunction)?.isSuspend == true ||
callableReferenceAdaptation?.suspendConversionStrategy == SuspendConversionStrategy.SUSPEND_CONVERSION
return createFunctionalType(
parameters,
receiverType = receiverType,
rawReturnType = returnType,
isKFunctionType = true,
isSuspend = isSuspend
) to callableReferenceAdaptation
}
is FirVariable -> createKPropertyType(fir, receiverType, returnTypeRef) to null
else -> ConeClassErrorType(ConeUnsupportedCallableReferenceTarget(fir)) to null
}
}
internal class CallableReferenceAdaptation(
val argumentTypes: Array<ConeKotlinType>,
val coercionStrategy: CoercionStrategy,
val defaults: Int,
val mappedArguments: Map<FirValueParameter, ResolvedCallArgument>,
val suspendConversionStrategy: SuspendConversionStrategy
)
private fun CallableReferenceAdaptation?.needCompatibilityResolveForCallableReference(): Boolean {
// KT-13934: check containing declaration for companion object
if (this == null) return false
return defaults != 0 ||
suspendConversionStrategy != SuspendConversionStrategy.NO_CONVERSION ||
coercionStrategy != CoercionStrategy.NO_COERCION ||
mappedArguments.values.any { it is ResolvedCallArgument.VarargArgument }
}
private fun getCallableReferenceAdaptation(
session: FirSession,
function: FirFunction<*>,
expectedType: ConeKotlinType?,
unboundReceiverCount: Int
): CallableReferenceAdaptation? {
if (expectedType == null) return null
// Do not adapt references against KCallable type as it's impossible to map defaults/vararg to absent parameters of KCallable
if (expectedType.isKCallableType()) return null
val (inputTypes, returnExpectedType) = extractInputOutputTypesFromCallableReferenceExpectedType(expectedType, session) ?: return null
val expectedArgumentsCount = inputTypes.size - unboundReceiverCount
if (expectedArgumentsCount < 0) return null
val fakeArguments = createFakeArgumentsForReference(function, expectedArgumentsCount, inputTypes, unboundReceiverCount)
val argumentMapping = mapArguments(fakeArguments, function)
if (argumentMapping.diagnostics.any { !it.applicability.isSuccess }) return null
/**
* (A, B, C) -> Unit
* fun foo(a: A, b: B = B(), vararg c: C)
*/
var defaults = 0
var varargMappingState = VarargMappingState.UNMAPPED
val mappedArguments = linkedMapOf<FirValueParameter, ResolvedCallArgument>()
val mappedVarargElements = linkedMapOf<FirValueParameter, MutableList<FirExpression>>()
val mappedArgumentTypes = arrayOfNulls<ConeKotlinType?>(fakeArguments.size)
for ((valueParameter, resolvedArgument) in argumentMapping.parameterToCallArgumentMap) {
for (fakeArgument in resolvedArgument.arguments) {
val index = fakeArgument.index
val substitutedParameter = function.valueParameters.getOrNull(function.indexOf(valueParameter)) ?: continue
val mappedArgument: ConeKotlinType?
if (substitutedParameter.isVararg) {
val (varargType, newVarargMappingState) = varargParameterTypeByExpectedParameter(
inputTypes[index + unboundReceiverCount],
substitutedParameter,
varargMappingState
)
varargMappingState = newVarargMappingState
mappedArgument = varargType
when (newVarargMappingState) {
VarargMappingState.MAPPED_WITH_ARRAY -> {
// If we've already mapped an argument to this value parameter, it'll always be a type mismatch.
mappedArguments[valueParameter] = ResolvedCallArgument.SimpleArgument(fakeArgument)
}
VarargMappingState.MAPPED_WITH_PLAIN_ARGS -> {
mappedVarargElements.getOrPut(valueParameter) { ArrayList() }.add(fakeArgument)
}
VarargMappingState.UNMAPPED -> {
}
}
} else {
mappedArgument = substitutedParameter.returnTypeRef.coneType
mappedArguments[valueParameter] = resolvedArgument
}
mappedArgumentTypes[index] = mappedArgument
}
if (resolvedArgument == ResolvedCallArgument.DefaultArgument) {
defaults++
mappedArguments[valueParameter] = resolvedArgument
}
}
if (mappedArgumentTypes.any { it == null }) return null
for ((valueParameter, varargElements) in mappedVarargElements) {
mappedArguments[valueParameter] = ResolvedCallArgument.VarargArgument(varargElements)
}
for (valueParameter in function.valueParameters) {
if (valueParameter.isVararg && valueParameter !in mappedArguments) {
mappedArguments[valueParameter] = ResolvedCallArgument.VarargArgument(emptyList())
}
}
val coercionStrategy = if (returnExpectedType.isUnit && !function.returnTypeRef.isUnit)
CoercionStrategy.COERCION_TO_UNIT
else
CoercionStrategy.NO_COERCION
val adaptedArguments = if (expectedType.isBaseTypeForNumberedReferenceTypes)
emptyMap()
else
mappedArguments
val suspendConversionStrategy = if ((function as? FirSimpleFunction)?.isSuspend != true && expectedType.isSuspendFunctionType(session))
SuspendConversionStrategy.SUSPEND_CONVERSION
else
SuspendConversionStrategy.NO_CONVERSION
@Suppress("UNCHECKED_CAST")
return CallableReferenceAdaptation(
mappedArgumentTypes as Array<ConeKotlinType>,
coercionStrategy,
defaults,
adaptedArguments,
suspendConversionStrategy
)
}
fun ConeKotlinType?.isPotentiallyArray(): Boolean =
this != null && (this.arrayElementType() != null || this is ConeTypeVariableType)
private fun varargParameterTypeByExpectedParameter(
expectedParameterType: ConeKotlinType,
substitutedParameter: FirValueParameter,
varargMappingState: VarargMappingState,
): Pair<ConeKotlinType?, VarargMappingState> {
val elementType = substitutedParameter.returnTypeRef.coneType.arrayElementType()
?: error("Vararg parameter $substitutedParameter does not have vararg type")
return when (varargMappingState) {
VarargMappingState.UNMAPPED -> {
if (expectedParameterType.isPotentiallyArray()) {
elementType.createOutArrayType() to VarargMappingState.MAPPED_WITH_ARRAY
} else {
elementType to VarargMappingState.MAPPED_WITH_PLAIN_ARGS
}
}
VarargMappingState.MAPPED_WITH_PLAIN_ARGS -> {
if (expectedParameterType.isPotentiallyArray())
null to VarargMappingState.MAPPED_WITH_PLAIN_ARGS
else
elementType to VarargMappingState.MAPPED_WITH_PLAIN_ARGS
}
VarargMappingState.MAPPED_WITH_ARRAY ->
null to VarargMappingState.MAPPED_WITH_ARRAY
}
}
private enum class VarargMappingState {
UNMAPPED, MAPPED_WITH_PLAIN_ARGS, MAPPED_WITH_ARRAY
}
private fun FirFunction<*>.indexOf(valueParameter: FirValueParameter): Int = valueParameters.indexOf(valueParameter)
private val ConeKotlinType.isUnit: Boolean
get() {
val type = this.lowerBoundIfFlexible()
if (type.isNullable) return false
val classId = type.classId ?: return false
return classId == StandardClassIds.Unit
}
private val ConeKotlinType.isBaseTypeForNumberedReferenceTypes: Boolean
get() {
val classId = lowerBoundIfFlexible().classId ?: return false
return when (classId) {
StandardClassIds.KProperty,
StandardClassIds.KMutableProperty,
StandardClassIds.KCallable -> true
else -> false
}
}
private val FirExpression.index: Int
get() = when (this) {
is FirNamedArgumentExpression -> expression.index
is FirFakeArgumentForCallableReference -> index
else -> throw IllegalArgumentException()
}
private fun createFakeArgumentsForReference(
function: FirFunction<*>,
expectedArgumentCount: Int,
inputTypes: List<ConeKotlinType>,
unboundReceiverCount: Int
): List<FirExpression> {
var afterVararg = false
var varargComponentType: ConeKotlinType? = null
var vararg = false
return (0 until expectedArgumentCount).map { index ->
val inputType = inputTypes.getOrNull(index + unboundReceiverCount)
if (vararg && varargComponentType != inputType) {
afterVararg = true
}
val valueParameter = function.valueParameters.getOrNull(index)
val name = if (afterVararg && valueParameter?.defaultValue != null)
valueParameter.name
else
null
if (valueParameter?.isVararg == true) {
varargComponentType = inputType
vararg = true
}
if (name != null) {
buildNamedArgumentExpression {
expression = FirFakeArgumentForCallableReference(index)
this.name = name
isSpread = false
}
} else {
FirFakeArgumentForCallableReference(index)
}
}
}
private class FirFakeArgumentForCallableReference(
val index: Int
) : FirExpression() {
override val source: FirSourceElement?
get() = null
override val typeRef: FirTypeRef
get() = error("should not be called")
override val annotations: List<FirAnnotationCall>
get() = error("should not be called")
override fun replaceTypeRef(newTypeRef: FirTypeRef) {
error("should not be called")
}
override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirNamedArgumentExpression {
error("should not be called")
}
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
error("should not be called")
}
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElement {
error("should not be called")
}
}
fun ConeKotlinType.isKCallableType(): Boolean {
return this.classId == StandardClassIds.KCallable
}
private fun createKPropertyType(
propertyOrField: FirVariable<*>,
receiverType: ConeKotlinType?,
returnTypeRef: FirResolvedTypeRef
): ConeKotlinType {
val propertyType = returnTypeRef.type
return org.jetbrains.kotlin.fir.resolve.createKPropertyType(
receiverType, propertyType, isMutable = propertyOrField.isVar
)
}
@@ -58,3 +58,5 @@ object HiddenCandidate : ResolutionDiagnostic(CandidateApplicability.HIDDEN)
object ResolvedWithLowPriority : ResolutionDiagnostic(CandidateApplicability.RESOLVED_LOW_PRIORITY)
object InapplicableWrongReceiver : ResolutionDiagnostic(CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER)
object LowerPriorityToPreserveCompatibilityDiagnostic : ResolutionDiagnostic(CandidateApplicability.RESOLVED_NEED_PRESERVE_COMPATIBILITY)
@@ -7,8 +7,6 @@ package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
@@ -24,8 +22,6 @@ import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
@@ -196,165 +192,6 @@ internal object EagerResolveOfCallableReferences : CheckerStage() {
}
}
internal object CheckCallableReferenceExpectedType : CheckerStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
val outerCsBuilder = callInfo.outerCSBuilder ?: return
val expectedType = callInfo.expectedType
if (candidate.symbol !is FirCallableSymbol<*>) return
val resultingReceiverType = when (callInfo.lhs) {
is DoubleColonLHS.Type -> callInfo.lhs.type.takeIf { callInfo.explicitReceiver !is FirResolvedQualifier }
else -> null
}
val fir: FirCallableDeclaration<*> = candidate.symbol.fir
val returnTypeRef = context.bodyResolveComponents.returnTypeCalculator.tryCalculateReturnType(fir)
// If the expected type is a suspend function type and the current argument of interest is a function reference, we need to do
// "suspend conversion." Here, during resolution, we bypass constraint system by making resulting type be KSuspendFunction.
// Then, during conversion, we need to create an adapter function and replace the function reference created here with an adapted
// callable reference.
// TODO: should refer to LanguageVersionSettings.SuspendConversion
val requireSuspendConversion = expectedType?.isSuspendFunctionType(callInfo.session) == true
val resultingType: ConeKotlinType = when (fir) {
is FirFunction -> callInfo.session.createAdaptedKFunctionType(
fir,
resultingReceiverType, returnTypeRef, expectedParameterTypes = expectedType?.typeArguments,
isSuspend = (fir as? FirSimpleFunction)?.isSuspend == true || requireSuspendConversion,
expectedReturnType = extractInputOutputTypesFromCallableReferenceExpectedType(expectedType, callInfo.session)?.outputType
)
is FirVariable<*> -> createKPropertyType(fir, resultingReceiverType, returnTypeRef)
else -> ConeKotlinErrorType(ConeSimpleDiagnostic("Unknown callable kind: ${fir::class}", DiagnosticKind.UnknownCallableKind))
}.let(candidate.substitutor::substituteOrSelf)
candidate.usesSuspendConversion = requireSuspendConversion
candidate.resultingTypeForCallableReference = resultingType
candidate.outerConstraintBuilderEffect = fun ConstraintSystemOperation.() {
addOtherSystem(candidate.system.asReadOnlyStorage())
val position = SimpleConstraintSystemConstraintPosition //TODO
if (expectedType != null) {
addSubtypeConstraint(resultingType, expectedType, position)
}
val declarationReceiverType: ConeKotlinType? =
(fir as? FirCallableMemberDeclaration<*>)?.receiverTypeRef?.coneType
?.let(candidate.substitutor::substituteOrSelf)
if (resultingReceiverType != null && declarationReceiverType != null) {
addSubtypeConstraint(resultingReceiverType, declarationReceiverType, position)
}
}
var isApplicable = true
outerCsBuilder.runTransaction {
candidate.outerConstraintBuilderEffect!!(this)
isApplicable = !hasContradiction
false
}
if (!isApplicable) {
sink.yieldDiagnostic(InapplicableCandidate)
}
}
}
private fun createKPropertyType(
propertyOrField: FirVariable<*>,
receiverType: ConeKotlinType?,
returnTypeRef: FirResolvedTypeRef
): ConeKotlinType {
val propertyType = returnTypeRef.type
return createKPropertyType(
receiverType, propertyType, isMutable = propertyOrField.isVar
)
}
private fun FirSession.createAdaptedKFunctionType(
function: FirFunction<*>,
receiverType: ConeKotlinType?,
returnTypeRef: FirResolvedTypeRef,
expectedParameterTypes: Array<out ConeTypeProjection>?,
isSuspend: Boolean,
expectedReturnType: ConeKotlinType?
): ConeKotlinType {
// The similar adaptations: defaults and coercion-to-unit happen at org.jetbrains.kotlin.resolve.calls.components.CallableReferencesCandidateFactory.getCallableReferenceAdaptation
val parameterTypes = mutableListOf<ConeKotlinType>()
val shift = if (receiverType != null) 1 else 0
val expectedParameterNumber =
if (expectedParameterTypes == null) null
// Drop the last one: return type, and the first one: receiver type, if needed
else expectedParameterTypes.size - 1 - shift
fun ConeKotlinType?.isPotentiallyArray(): Boolean =
this != null && (this.arrayElementType() != null || this is ConeTypeVariableType)
var lastVarargParameter: FirValueParameter? = null
for ((index, valueParameter) in function.valueParameters.withIndex()) {
// Update the last vararg parameter in preparation for adaptation.
if (valueParameter.isVararg) {
lastVarargParameter = valueParameter
}
// Pack value parameters until the expected parameter number is met.
if (expectedParameterNumber == null || index < expectedParameterNumber) {
// But, if the value parameter is vararg, make sure it matches with the expected parameter type.
if (expectedParameterTypes != null && valueParameter.isVararg) {
val expectedParameterType = (expectedParameterTypes[index + shift] as? ConeKotlinTypeProjection)?.type
if (!expectedParameterType.isPotentiallyArray()) {
// Expect an element. Will spread vararg parameter later.
continue
}
}
parameterTypes += valueParameter.returnTypeRef.coneType
continue
}
// After expected parameters are fulfilled, a value parameter which doesn't have a default value or isn't vararg should be added to
// the resulting type (so that it can reject incompatible function reference). In either case, we can't assume no actual arguments
// are given.
if (valueParameter.defaultValue == null && !valueParameter.isVararg) {
parameterTypes += valueParameter.returnTypeRef.coneType
}
}
// If a function with vararg is passed to a place where a spread of elements is expected, we can adapt the function reference to
// literally spread such vararg argument. E.g., foo(vararg xs: Char): String => bar(::foo) where bar(f: (Char, Char) -> String)
if (expectedParameterNumber != null &&
expectedParameterTypes != null &&
parameterTypes.size < expectedParameterNumber &&
lastVarargParameter != null
) {
val varargArrayType = lastVarargParameter.returnTypeRef.coneType
val varargElementType = varargArrayType.varargElementType()
val expectedParameterType = (expectedParameterTypes[parameterTypes.size + shift] as? ConeKotlinTypeProjection)?.type
// Expect an array or potentially array (i.e., type variable). Pass vararg parameter as-is.
if (expectedParameterType.isPotentiallyArray()) {
parameterTypes += varargArrayType
} else {
// Expect an element. Spread vararg parameter.
while (parameterTypes.size < expectedParameterNumber) {
parameterTypes += varargElementType
}
}
}
val returnType =
if (expectedReturnType != null && typeContext.run { expectedReturnType.isUnit() })
expectedReturnType
else
returnTypeRef.type
return createFunctionalType(
parameterTypes,
receiverType = receiverType,
rawReturnType = returnType,
isKFunctionType = true,
isSuspend = isSuspend
)
}
internal object DiscriminateSynthetics : CheckerStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
if (candidate.symbol is SyntheticSymbol) {
@@ -5,7 +5,9 @@
package org.jetbrains.kotlin.fir.resolve.diagnostics
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
@@ -80,6 +82,10 @@ class ConeInstanceAccessBeforeSuperCall(val target: String) : ConeDiagnostic() {
override val reason: String get() = "Cannot access ''${target}'' before superclass constructor has been called"
}
class ConeUnsupportedCallableReferenceTarget(val fir: FirCallableDeclaration<*>) : ConeDiagnostic() {
override val reason: String get() = "Unsupported declaration for callable reference: ${fir.render()}"
}
private fun describeSymbol(symbol: AbstractFirBasedSymbol<*>): String {
return when (symbol) {
is FirClassLikeSymbol<*> -> symbol.classId.asString()
@@ -7,6 +7,10 @@ package org.jetbrains.kotlin.fir.types
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
fun ConeKotlinType.createOutArrayType(nullable: Boolean = false): ConeKotlinType {
return ConeKotlinTypeProjectionOut(this).createArrayOf(nullable)
}
fun ConeTypeProjection.createArrayOf(nullable: Boolean = false): ConeKotlinType {
if (this is ConeKotlinTypeProjection) {
val type = type.lowerBoundIfFlexible()
@@ -0,0 +1,10 @@
/*
* 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.resolve.calls.components
enum class SuspendConversionStrategy {
SUSPEND_CONVERSION, NO_CONVERSION
}
@@ -88,10 +88,6 @@ class CallableReferenceAdaptation(
val suspendConversionStrategy: SuspendConversionStrategy
)
enum class SuspendConversionStrategy {
SUSPEND_CONVERSION, NO_CONVERSION
}
/**
* cases: class A {}, class B { companion object }, object C, enum class D { E }
* A::foo <-> Type
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// FILE: test.kt
fun checkNotEqual(x: Any, y: Any) {
@@ -26,5 +26,5 @@ fun test() {
<!UNRESOLVED_REFERENCE!>B::bas<!>
::fas
}
<!UNRESOLVED_REFERENCE!>::fas<!>
}
@@ -23,7 +23,7 @@ fun test() {
usePrimitiveIntArray(::intVararg)
<!INAPPLICABLE_CANDIDATE!>useIntArray<!>(<!UNRESOLVED_REFERENCE!>::intVararg<!>)
<!INAPPLICABLE_CANDIDATE!>useMixedStringArgs1<!>(<!UNRESOLVED_REFERENCE!>::stringVararg<!>)
useMixedStringArgs2(::stringVararg)
<!INAPPLICABLE_CANDIDATE!>useMixedStringArgs2<!>(<!UNRESOLVED_REFERENCE!>::stringVararg<!>)
<!INAPPLICABLE_CANDIDATE!>useMixedStringArgs3<!>(<!UNRESOLVED_REFERENCE!>::stringVararg<!>)
useTwoStringArrays(::stringVararg)
<!INAPPLICABLE_CANDIDATE!>useTwoStringArrays<!>(<!UNRESOLVED_REFERENCE!>::stringVararg<!>)
}
@@ -107,26 +107,26 @@ FILE fqName:<root> fileName:/caoWithAdaptationForSam.kt
BLOCK type=kotlin.Unit origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:<root>.A [val]
GET_OBJECT 'CLASS OBJECT name:A modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.A
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.reflect.KFunction0<kotlin.Int> [val]
FUNCTION_REFERENCE 'public final fun withVararg (vararg xs: kotlin.Int): kotlin.Int declared in <root>' type=kotlin.reflect.KFunction0<kotlin.Int> origin=null reflectionTarget=<same>
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.reflect.KFunction1<kotlin.IntArray, kotlin.Int> [val]
FUNCTION_REFERENCE 'public final fun withVararg (vararg xs: kotlin.Int): kotlin.Int declared in <root>' type=kotlin.reflect.KFunction1<kotlin.IntArray, kotlin.Int> origin=null reflectionTarget=<same>
ERROR_CALL 'Unresolved reference: <Inapplicable(INAPPLICABLE): /set>#' type=kotlin.Unit
GET_VAR 'val tmp_1: kotlin.reflect.KFunction0<kotlin.Int> [val] declared in <root>.test1' type=kotlin.reflect.KFunction0<kotlin.Int> origin=null
GET_VAR 'val tmp_1: kotlin.reflect.KFunction1<kotlin.IntArray, kotlin.Int> [val] declared in <root>.test1' type=kotlin.reflect.KFunction1<kotlin.IntArray, kotlin.Int> origin=null
CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: ERROR_CALL 'Unresolved reference: <Inapplicable(INAPPLICABLE): /get>#' type=kotlin.Int
GET_VAR 'val tmp_1: kotlin.reflect.KFunction0<kotlin.Int> [val] declared in <root>.test1' type=kotlin.reflect.KFunction0<kotlin.Int> origin=null
GET_VAR 'val tmp_1: kotlin.reflect.KFunction1<kotlin.IntArray, kotlin.Int> [val] declared in <root>.test1' type=kotlin.reflect.KFunction1<kotlin.IntArray, kotlin.Int> origin=null
other: CONST Int type=kotlin.Int value=1
FUN name:test2 visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
BLOCK type=kotlin.Unit origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_2 type:<root>.B [val]
GET_OBJECT 'CLASS OBJECT name:B modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.B
VAR IR_TEMPORARY_VARIABLE name:tmp_3 type:kotlin.reflect.KFunction0<kotlin.Int> [val]
FUNCTION_REFERENCE 'public final fun withVararg (vararg xs: kotlin.Int): kotlin.Int declared in <root>' type=kotlin.reflect.KFunction0<kotlin.Int> origin=null reflectionTarget=<same>
VAR IR_TEMPORARY_VARIABLE name:tmp_3 type:kotlin.reflect.KFunction1<kotlin.IntArray, kotlin.Int> [val]
FUNCTION_REFERENCE 'public final fun withVararg (vararg xs: kotlin.Int): kotlin.Int declared in <root>' type=kotlin.reflect.KFunction1<kotlin.IntArray, kotlin.Int> origin=null reflectionTarget=<same>
ERROR_CALL 'Unresolved reference: <Inapplicable(INAPPLICABLE): /set>#' type=kotlin.Unit
GET_VAR 'val tmp_3: kotlin.reflect.KFunction0<kotlin.Int> [val] declared in <root>.test2' type=kotlin.reflect.KFunction0<kotlin.Int> origin=null
GET_VAR 'val tmp_3: kotlin.reflect.KFunction1<kotlin.IntArray, kotlin.Int> [val] declared in <root>.test2' type=kotlin.reflect.KFunction1<kotlin.IntArray, kotlin.Int> origin=null
CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: ERROR_CALL 'Unresolved reference: <Inapplicable(INAPPLICABLE): /get>#' type=kotlin.Int
GET_VAR 'val tmp_3: kotlin.reflect.KFunction0<kotlin.Int> [val] declared in <root>.test2' type=kotlin.reflect.KFunction0<kotlin.Int> origin=null
GET_VAR 'val tmp_3: kotlin.reflect.KFunction1<kotlin.IntArray, kotlin.Int> [val] declared in <root>.test2' type=kotlin.reflect.KFunction1<kotlin.IntArray, kotlin.Int> origin=null
other: CONST Int type=kotlin.Int value=1
FUN name:test3 visibility:public modality:FINAL <> (fn:kotlin.Function1<kotlin.Int, kotlin.Unit>) returnType:kotlin.Unit
VALUE_PARAMETER name:fn index:0 type:kotlin.Function1<kotlin.Int, kotlin.Unit>
@@ -1,73 +0,0 @@
FILE fqName:<root> fileName:/funWithDefaultParametersAsKCallableStar.kt
FUN name:defaultsOnly visibility:public modality:FINAL <> (x:kotlin.String) returnType:kotlin.Int
VALUE_PARAMETER name:x index:0 type:kotlin.String
EXPRESSION_BODY
CONST String type=kotlin.String value=""
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun defaultsOnly (x: kotlin.String): kotlin.Int declared in <root>'
CONST Int type=kotlin.Int value=1
FUN name:regularAndDefaults visibility:public modality:FINAL <> (x1:kotlin.String, x2:kotlin.String) returnType:kotlin.Int
VALUE_PARAMETER name:x1 index:0 type:kotlin.String
VALUE_PARAMETER name:x2 index:1 type:kotlin.String
EXPRESSION_BODY
CONST String type=kotlin.String value=""
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun regularAndDefaults (x1: kotlin.String, x2: kotlin.String): kotlin.Int declared in <root>'
CONST Int type=kotlin.Int value=1
FUN name:varargs visibility:public modality:FINAL <> (xs:kotlin.Array<out kotlin.String>) returnType:kotlin.Int
VALUE_PARAMETER name:xs index:0 type:kotlin.Array<out kotlin.String> varargElementType:kotlin.String [vararg]
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun varargs (vararg xs: kotlin.String): kotlin.Int declared in <root>'
CONST Int type=kotlin.Int value=1
CLASS CLASS name:C modality:FINAL visibility:public superTypes:[kotlin.Any]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.C
CONSTRUCTOR visibility:public <> (x:kotlin.String) returnType:<root>.C [primary]
VALUE_PARAMETER name:x index:0 type:kotlin.String
EXPRESSION_BODY
CONST String type=kotlin.String value=""
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in kotlin.Any'
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:C modality:FINAL visibility:public superTypes:[kotlin.Any]'
PROPERTY name:x visibility:public modality:FINAL [val]
FIELD PROPERTY_BACKING_FIELD name:x type:kotlin.String visibility:private [final]
EXPRESSION_BODY
GET_VAR 'x: kotlin.String declared in <root>.C.<init>' type=kotlin.String origin=INITIALIZE_PROPERTY_FROM_PARAMETER
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-x> visibility:public modality:FINAL <> ($this:<root>.C) returnType:kotlin.String
correspondingProperty: PROPERTY name:x visibility:public modality:FINAL [val]
$this: VALUE_PARAMETER name:<this> type:<root>.C
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-x> (): kotlin.String declared in <root>.C'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:x type:kotlin.String visibility:private [final]' type=kotlin.String origin=null
receiver: GET_VAR '<this>: <root>.C declared in <root>.C.<get-x>' type=<root>.C origin=null
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
overridden:
public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
overridden:
public open fun hashCode (): kotlin.Int declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
overridden:
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN name:useKCallableStar visibility:public modality:FINAL <> (fn:kotlin.reflect.KCallable<*>) returnType:kotlin.Unit
VALUE_PARAMETER name:fn index:0 type:kotlin.reflect.KCallable<*>
BLOCK_BODY
FUN name:testDefaultsOnlyStar visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
CALL 'public final fun useKCallableStar (fn: kotlin.reflect.KCallable<*>): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
fn: FUNCTION_REFERENCE 'public final fun defaultsOnly (x: kotlin.String): kotlin.Int declared in <root>' type=kotlin.reflect.KFunction0<kotlin.Int> origin=null reflectionTarget=<same>
FUN name:testRegularAndDefaultsStar visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
CALL 'public final fun useKCallableStar (fn: kotlin.reflect.KCallable<*>): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
fn: FUNCTION_REFERENCE 'public final fun regularAndDefaults (x1: kotlin.String, x2: kotlin.String): kotlin.Int declared in <root>' type=kotlin.reflect.KFunction1<kotlin.String, kotlin.Int> origin=null reflectionTarget=<same>
FUN name:testVarargsStar visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
CALL 'public final fun useKCallableStar (fn: kotlin.reflect.KCallable<*>): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
fn: FUNCTION_REFERENCE 'public final fun varargs (vararg xs: kotlin.String): kotlin.Int declared in <root>' type=kotlin.reflect.KFunction0<kotlin.Int> origin=null reflectionTarget=<same>
FUN name:testCtorStar visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
CALL 'public final fun useKCallableStar (fn: kotlin.reflect.KCallable<*>): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
fn: FUNCTION_REFERENCE 'public constructor <init> (x: kotlin.String) [primary] declared in <root>.C' type=kotlin.reflect.KFunction0<<root>.C> origin=null reflectionTarget=<same>
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// WITH_REFLECT
import kotlin.reflect.KCallable