Expand ConeTypeContext, implement FIR type inference & related checkers
This commit is contained in:
committed by
Mikhail Glukhikh
parent
f1eb66819b
commit
1dae135840
@@ -123,8 +123,9 @@ class ConeFlexibleType(val lowerBound: ConeLookupTagBasedType, val upperBound: C
|
|||||||
get() = lowerBound.nullability.takeIf { it == upperBound.nullability } ?: ConeNullability.UNKNOWN
|
get() = lowerBound.nullability.takeIf { it == upperBound.nullability } ?: ConeNullability.UNKNOWN
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConeCapturedTypeConstructor(val projection: ConeKotlinTypeProjection) : TypeConstructorMarker {
|
class ConeCapturedTypeConstructor(val projection: ConeKotlinTypeProjection, var supertypes: List<ConeKotlinType>? = null) :
|
||||||
var supertypes: List<ConeKotlinType>? = null
|
TypeConstructorMarker {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConeCapturedType(
|
class ConeCapturedType(
|
||||||
@@ -144,3 +145,17 @@ class ConeCapturedType(
|
|||||||
override val typeArguments: Array<out ConeKotlinTypeProjection>
|
override val typeArguments: Array<out ConeKotlinTypeProjection>
|
||||||
get() = emptyArray()
|
get() = emptyArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ConeTypeVariableType(
|
||||||
|
override val nullability: ConeNullability,
|
||||||
|
override val lookupTag: ConeClassifierLookupTag
|
||||||
|
) : ConeLookupTagBasedType() {
|
||||||
|
override val typeArguments: Array<out ConeKotlinTypeProjection> get() = emptyArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConeDefinitelyNotNullType(val original: ConeKotlinType): ConeKotlinType(), DefinitelyNotNullTypeMarker {
|
||||||
|
override val typeArguments: Array<out ConeKotlinTypeProjection>
|
||||||
|
get() = original.typeArguments
|
||||||
|
override val nullability: ConeNullability
|
||||||
|
get() = ConeNullability.NOT_NULL
|
||||||
|
}
|
||||||
@@ -55,6 +55,7 @@ fun ConeKotlinType.toIrType(session: FirSession, declarationStorage: Fir2IrDecla
|
|||||||
upperBound.toIrType(session, declarationStorage)
|
upperBound.toIrType(session, declarationStorage)
|
||||||
}
|
}
|
||||||
is ConeCapturedType -> TODO()
|
is ConeCapturedType -> TODO()
|
||||||
|
is ConeDefinitelyNotNullType -> TODO()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +103,7 @@ fun FirReference.toSymbol(declarationStorage: Fir2IrDeclarationStorage): IrSymbo
|
|||||||
|
|
||||||
fun FirNamedReference.toSymbol(declarationStorage: Fir2IrDeclarationStorage): IrSymbol? {
|
fun FirNamedReference.toSymbol(declarationStorage: Fir2IrDeclarationStorage): IrSymbol? {
|
||||||
if (this is FirResolvedCallableReference) {
|
if (this is FirResolvedCallableReference) {
|
||||||
when (val callableSymbol = this.callableSymbol) {
|
when (val callableSymbol = this.coneSymbol) {
|
||||||
is FirFunctionSymbol -> return callableSymbol.toFunctionSymbol(declarationStorage)
|
is FirFunctionSymbol -> return callableSymbol.toFunctionSymbol(declarationStorage)
|
||||||
is FirPropertySymbol -> return callableSymbol.toPropertySymbol(declarationStorage)
|
is FirPropertySymbol -> return callableSymbol.toPropertySymbol(declarationStorage)
|
||||||
is FirVariableSymbol -> return callableSymbol.toValueSymbol(declarationStorage)
|
is FirVariableSymbol -> return callableSymbol.toValueSymbol(declarationStorage)
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
|
|
||||||
|
fun FirFunctionCall.copy(
|
||||||
|
annotations: List<FirAnnotationCall> = this.annotations,
|
||||||
|
arguments: List<FirExpression> = this.arguments,
|
||||||
|
calleeReference: FirNamedReference = this.calleeReference,
|
||||||
|
explicitReceiver: FirExpression? = this.explicitReceiver,
|
||||||
|
psi: PsiElement? = this.psi,
|
||||||
|
safe: Boolean = this.safe,
|
||||||
|
session: FirSession = this.session,
|
||||||
|
typeArguments: List<FirTypeProjection> = this.typeArguments,
|
||||||
|
resultType: FirTypeRef = this.typeRef
|
||||||
|
): FirFunctionCall {
|
||||||
|
return FirFunctionCallImpl(
|
||||||
|
session, psi, safe
|
||||||
|
).apply {
|
||||||
|
this.annotations.addAll(annotations)
|
||||||
|
this.arguments.addAll(arguments)
|
||||||
|
this.calleeReference = calleeReference
|
||||||
|
this.explicitReceiver = explicitReceiver
|
||||||
|
this.typeArguments.addAll(typeArguments)
|
||||||
|
this.typeRef = resultType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ fun ConeClassifierLookupTag.toSymbol(useSiteSession: FirSession): ConeClassifier
|
|||||||
when (this) {
|
when (this) {
|
||||||
is ConeClassLikeLookupTag -> toSymbol(useSiteSession)
|
is ConeClassLikeLookupTag -> toSymbol(useSiteSession)
|
||||||
is ConeTypeParameterSymbol -> this
|
is ConeTypeParameterSymbol -> this
|
||||||
else -> error("sealed")
|
else -> error("sealed ${this::class}")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ConeClassLikeLookupTag.constructClassType(typeArguments: Array<ConeKotlinTypeProjection>, isNullable: Boolean): ConeLookupTagBasedType {
|
fun ConeClassLikeLookupTag.constructClassType(typeArguments: Array<ConeKotlinTypeProjection>, isNullable: Boolean): ConeLookupTagBasedType {
|
||||||
@@ -116,7 +116,8 @@ fun <T : ConeKotlinType> T.withNullability(nullability: ConeNullability): T {
|
|||||||
is ConeFunctionTypeImpl -> ConeFunctionTypeImpl(receiverType, parameterTypes, returnType, lookupTag, nullability.isNullable) as T
|
is ConeFunctionTypeImpl -> ConeFunctionTypeImpl(receiverType, parameterTypes, returnType, lookupTag, nullability.isNullable) as T
|
||||||
is ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable) as T
|
is ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable) as T
|
||||||
is ConeFlexibleType -> ConeFlexibleType(lowerBound.withNullability(nullability), upperBound.withNullability(nullability)) as T
|
is ConeFlexibleType -> ConeFlexibleType(lowerBound.withNullability(nullability), upperBound.withNullability(nullability)) as T
|
||||||
else -> TODO("FIX KOTLIN COMPILER")
|
is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag) as T
|
||||||
|
else -> error("sealed: ${this::class}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.resolve.calls
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.withNullability
|
||||||
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||||
|
|
||||||
|
|
||||||
|
fun resolveArgumentExpression(
|
||||||
|
/*
|
||||||
|
csBuilder: ConstraintSystemBuilder,
|
||||||
|
argument: KotlinCallArgument,
|
||||||
|
expectedType: UnwrappedType?,
|
||||||
|
diagnosticsHolder: KotlinDiagnosticsHolder,
|
||||||
|
isReceiver: Boolean
|
||||||
|
*/
|
||||||
|
csBuilder: ConstraintSystemBuilder,
|
||||||
|
argument: FirExpression,
|
||||||
|
expectedType: ConeKotlinType,
|
||||||
|
sink: CheckerSink,
|
||||||
|
isReceiver: Boolean,
|
||||||
|
typeProvider: (FirExpression) -> FirTypeRef?
|
||||||
|
) {
|
||||||
|
return when (argument) {
|
||||||
|
is FirQualifiedAccessExpression, is FirFunctionCall -> checkPlainExpressionArgument(csBuilder, argument, expectedType, sink, isReceiver, typeProvider)
|
||||||
|
// TODO:!
|
||||||
|
is FirAnonymousFunction -> Unit
|
||||||
|
// TODO:!
|
||||||
|
is FirCallableReferenceAccess -> Unit
|
||||||
|
// TODO:!
|
||||||
|
//TODO: Collection literal
|
||||||
|
else -> checkPlainExpressionArgument(csBuilder, argument, expectedType, sink, isReceiver, typeProvider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkPlainExpressionArgument(
|
||||||
|
csBuilder: ConstraintSystemBuilder,
|
||||||
|
argument: FirExpression,
|
||||||
|
expectedType: ConeKotlinType?,
|
||||||
|
sink: CheckerSink,
|
||||||
|
isReceiver: Boolean,
|
||||||
|
typeProvider: (FirExpression) -> FirTypeRef?
|
||||||
|
) {
|
||||||
|
if (expectedType == null) return
|
||||||
|
val argumentType = typeProvider(argument)?.coneTypeSafe<ConeKotlinType>() ?: return
|
||||||
|
|
||||||
|
val position = SimpleConstraintSystemConstraintPosition //TODO
|
||||||
|
|
||||||
|
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) {
|
||||||
|
if (!isReceiver) {
|
||||||
|
csBuilder.addSubtypeConstraint(argumentType, expectedType, position)
|
||||||
|
}
|
||||||
|
val nullableExpectedType = expectedType.withNullability(ConeNullability.NULLABLE)
|
||||||
|
if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, nullableExpectedType, position)) {
|
||||||
|
sink.reportApplicability(CandidateApplicability.WRONG_RECEIVER) // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Candidate.resolveArgument(
|
||||||
|
argument: FirExpression,
|
||||||
|
parameter: FirValueParameter,
|
||||||
|
isReceiver: Boolean,
|
||||||
|
typeProvider: (FirExpression) -> FirTypeRef?,
|
||||||
|
sink: CheckerSink
|
||||||
|
) {
|
||||||
|
|
||||||
|
val expectedType = prepareExpectedType(argument, parameter)
|
||||||
|
resolveArgumentExpression(this.system.getBuilder(), argument, expectedType, sink, isReceiver, typeProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Candidate.prepareExpectedType(argument: FirExpression, parameter: FirValueParameter): ConeKotlinType {
|
||||||
|
val expectedType = argument.getExpectedType(parameter/*, LanguageVersionSettings*/)
|
||||||
|
return this.substitutor.substituteOrSelf(expectedType)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun FirExpression.getExpectedType(parameter: FirValueParameter/*, languageVersionSettings: LanguageVersionSettings*/) =
|
||||||
|
// if (this.isSpread || this.isArrayAssignedAsNamedArgumentInAnnotation(parameter, languageVersionSettings)) {
|
||||||
|
// parameter.type.unwrap()
|
||||||
|
// } else {
|
||||||
|
parameter.returnTypeRef.coneTypeUnsafe()//?.varargElementType?.unwrap() ?: parameter.type.unwrap()
|
||||||
|
// }
|
||||||
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.renderWithType
|
|||||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||||
import org.jetbrains.kotlin.fir.resolve.scope
|
import org.jetbrains.kotlin.fir.resolve.scope
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
|
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
@@ -22,14 +23,22 @@ import org.jetbrains.kotlin.fir.symbols.*
|
|||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CallInfo(
|
class CallInfo(
|
||||||
val variableAccess: Boolean,
|
val callKind: CallKind,
|
||||||
|
|
||||||
val explicitReceiver: FirExpression?,
|
val explicitReceiver: FirExpression?,
|
||||||
val argumentCount: Int
|
|
||||||
|
val arguments: List<FirExpression>,
|
||||||
|
val typeArguments: List<FirTypeProjection>,
|
||||||
|
|
||||||
|
val typeProvider: (FirExpression) -> FirTypeRef?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -50,11 +59,20 @@ class CheckerSinkImpl : CheckerSink {
|
|||||||
class Candidate(
|
class Candidate(
|
||||||
val symbol: ConeSymbol,
|
val symbol: ConeSymbol,
|
||||||
val receiverKind: ExplicitReceiverKind,
|
val receiverKind: ExplicitReceiverKind,
|
||||||
val callKind: CallKind
|
private val inferenceComponents: InferenceComponents,
|
||||||
)
|
private val baseSystem: ConstraintStorage
|
||||||
|
) {
|
||||||
|
val system by lazy {
|
||||||
|
val system = inferenceComponents.createConstraintSystem()
|
||||||
|
system.addOtherSystem(baseSystem)
|
||||||
|
system
|
||||||
|
}
|
||||||
|
lateinit var substitutor: ConeSubstitutor
|
||||||
|
}
|
||||||
|
|
||||||
sealed class CallKind {
|
sealed class CallKind {
|
||||||
abstract fun sequence(): List<ResolutionStage>
|
abstract fun sequence(): List<ResolutionStage>
|
||||||
|
|
||||||
object Function : CallKind() {
|
object Function : CallKind() {
|
||||||
override fun sequence(): List<ResolutionStage> {
|
override fun sequence(): List<ResolutionStage> {
|
||||||
return functionCallResolutionSequence()
|
return functionCallResolutionSequence()
|
||||||
@@ -177,19 +195,31 @@ abstract class TowerDataConsumer {
|
|||||||
fun createVariableConsumer(
|
fun createVariableConsumer(
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
name: Name,
|
name: Name,
|
||||||
explicitReceiver: FirExpression?,
|
callInfo: CallInfo,
|
||||||
explicitReceiverType: FirTypeRef?
|
inferenceComponents: InferenceComponents
|
||||||
): TowerDataConsumer {
|
): TowerDataConsumer {
|
||||||
return createSimpleConsumer(session, name, TowerScopeLevel.Token.Properties, explicitReceiver, explicitReceiverType, CallKind.VariableAccess)
|
return createSimpleConsumer(
|
||||||
|
session,
|
||||||
|
name,
|
||||||
|
TowerScopeLevel.Token.Properties,
|
||||||
|
callInfo,
|
||||||
|
inferenceComponents
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createFunctionConsumer(
|
fun createFunctionConsumer(
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
name: Name,
|
name: Name,
|
||||||
explicitReceiver: FirExpression?,
|
callInfo: CallInfo,
|
||||||
explicitReceiverType: FirTypeRef?
|
inferenceComponents: InferenceComponents
|
||||||
): TowerDataConsumer {
|
): TowerDataConsumer {
|
||||||
return createSimpleConsumer(session, name, TowerScopeLevel.Token.Functions, explicitReceiver, explicitReceiverType, CallKind.Function)
|
return createSimpleConsumer(
|
||||||
|
session,
|
||||||
|
name,
|
||||||
|
TowerScopeLevel.Token.Functions,
|
||||||
|
callInfo,
|
||||||
|
inferenceComponents
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -197,18 +227,24 @@ fun createSimpleConsumer(
|
|||||||
session: FirSession,
|
session: FirSession,
|
||||||
name: Name,
|
name: Name,
|
||||||
token: TowerScopeLevel.Token<*>,
|
token: TowerScopeLevel.Token<*>,
|
||||||
explicitReceiver: FirExpression?,
|
callInfo: CallInfo,
|
||||||
explicitReceiverType: FirTypeRef?,
|
inferenceComponents: InferenceComponents
|
||||||
callKind: CallKind
|
|
||||||
): TowerDataConsumer {
|
): TowerDataConsumer {
|
||||||
return if (explicitReceiver != null) {
|
val factory = CandidateFactory(inferenceComponents, callInfo)
|
||||||
ExplicitReceiverTowerDataConsumer(session, name, token, object : ReceiverValueWithPossibleTypes {
|
return if (callInfo.explicitReceiver != null) {
|
||||||
override val type: ConeKotlinType
|
ExplicitReceiverTowerDataConsumer(
|
||||||
get() = explicitReceiverType?.coneTypeSafe()
|
session,
|
||||||
?: ConeKotlinErrorType("No type calculated for: ${explicitReceiver.renderWithType()}") // TODO: assert here
|
name,
|
||||||
}, callKind)
|
token,
|
||||||
|
object : ReceiverValueWithPossibleTypes {
|
||||||
|
override val type: ConeKotlinType
|
||||||
|
get() = callInfo.typeProvider(callInfo.explicitReceiver)?.coneTypeSafe()
|
||||||
|
?: ConeKotlinErrorType("No type calculated for: ${callInfo.explicitReceiver.renderWithType()}") // TODO: assert here
|
||||||
|
},
|
||||||
|
factory
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
NoExplicitReceiverTowerDataConsumer(session, name, token, callKind)
|
NoExplicitReceiverTowerDataConsumer(session, name, token, factory)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +253,7 @@ class ExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
|||||||
val name: Name,
|
val name: Name,
|
||||||
val token: TowerScopeLevel.Token<T>,
|
val token: TowerScopeLevel.Token<T>,
|
||||||
val explicitReceiver: ReceiverValueWithPossibleTypes,
|
val explicitReceiver: ReceiverValueWithPossibleTypes,
|
||||||
val callKind: CallKind
|
val candidateFactory: CandidateFactory
|
||||||
) : TowerDataConsumer() {
|
) : TowerDataConsumer() {
|
||||||
|
|
||||||
var groupId = 0
|
var groupId = 0
|
||||||
@@ -237,7 +273,14 @@ class ExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
|||||||
null,
|
null,
|
||||||
object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||||
override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction {
|
override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction {
|
||||||
resultCollector.consumeCandidate(groupId, Candidate(symbol, ExplicitReceiverKind.DISPATCH_RECEIVER, callKind))
|
resultCollector.consumeCandidate(
|
||||||
|
groupId,
|
||||||
|
candidateFactory.createCandidate(
|
||||||
|
symbol,
|
||||||
|
boundDispatchReceiver,
|
||||||
|
ExplicitReceiverKind.DISPATCH_RECEIVER
|
||||||
|
)
|
||||||
|
)
|
||||||
return ProcessorAction.NEXT
|
return ProcessorAction.NEXT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,7 +292,14 @@ class ExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
|||||||
explicitReceiver,
|
explicitReceiver,
|
||||||
object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||||
override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction {
|
override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction {
|
||||||
resultCollector.consumeCandidate(groupId, Candidate(symbol, ExplicitReceiverKind.EXTENSION_RECEIVER, callKind))
|
resultCollector.consumeCandidate(
|
||||||
|
groupId,
|
||||||
|
candidateFactory.createCandidate(
|
||||||
|
symbol,
|
||||||
|
boundDispatchReceiver,
|
||||||
|
ExplicitReceiverKind.EXTENSION_RECEIVER
|
||||||
|
)
|
||||||
|
)
|
||||||
return ProcessorAction.NEXT
|
return ProcessorAction.NEXT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -263,7 +313,7 @@ class NoExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
|||||||
val session: FirSession,
|
val session: FirSession,
|
||||||
val name: Name,
|
val name: Name,
|
||||||
val token: TowerScopeLevel.Token<T>,
|
val token: TowerScopeLevel.Token<T>,
|
||||||
val callKind: CallKind
|
val candidateFactory: CandidateFactory
|
||||||
) : TowerDataConsumer() {
|
) : TowerDataConsumer() {
|
||||||
var groupId = 0
|
var groupId = 0
|
||||||
|
|
||||||
@@ -284,7 +334,10 @@ class NoExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
|||||||
null,
|
null,
|
||||||
object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||||
override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction {
|
override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction {
|
||||||
resultCollector.consumeCandidate(groupId, Candidate(symbol, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, callKind))
|
resultCollector.consumeCandidate(
|
||||||
|
groupId,
|
||||||
|
candidateFactory.createCandidate(symbol, boundDispatchReceiver, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER)
|
||||||
|
)
|
||||||
return ProcessorAction.NEXT
|
return ProcessorAction.NEXT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,7 +403,7 @@ class CandidateCollector(val callInfo: CallInfo) {
|
|||||||
val sink = CheckerSinkImpl()
|
val sink = CheckerSinkImpl()
|
||||||
|
|
||||||
|
|
||||||
candidate.callKind.sequence().forEach {
|
callInfo.callKind.sequence().forEach {
|
||||||
it.check(candidate, sink, callInfo)
|
it.check(candidate, sink, callInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,9 +427,9 @@ class CandidateCollector(val callInfo: CallInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun successCandidates(): List<ConeSymbol> {
|
fun bestCandidates(): List<Candidate> {
|
||||||
if (groupNumbers.isEmpty()) return emptyList()
|
if (groupNumbers.isEmpty()) return emptyList()
|
||||||
val result = mutableListOf<ConeSymbol>()
|
val result = mutableListOf<Candidate>()
|
||||||
var bestGroup = groupNumbers.first()
|
var bestGroup = groupNumbers.first()
|
||||||
for ((index, candidate) in candidates.withIndex()) {
|
for ((index, candidate) in candidates.withIndex()) {
|
||||||
val group = groupNumbers[index]
|
val group = groupNumbers[index]
|
||||||
@@ -385,7 +438,7 @@ class CandidateCollector(val callInfo: CallInfo) {
|
|||||||
result.clear()
|
result.clear()
|
||||||
}
|
}
|
||||||
if (bestGroup == group) {
|
if (bestGroup == group) {
|
||||||
result.add(candidate.symbol)
|
result.add(candidate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.expressions.FirExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
|
|
||||||
|
class CandidateFactory(
|
||||||
|
val inferenceComponents: InferenceComponents,
|
||||||
|
callInfo: CallInfo
|
||||||
|
) {
|
||||||
|
|
||||||
|
val baseSystem: ConstraintStorage
|
||||||
|
|
||||||
|
init {
|
||||||
|
val system = inferenceComponents.createConstraintSystem()
|
||||||
|
callInfo.arguments.forEach {
|
||||||
|
system.addSubsystemFromExpression(it)
|
||||||
|
}
|
||||||
|
baseSystem = system.asReadOnlyStorage()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createCandidate(
|
||||||
|
symbol: ConeSymbol,
|
||||||
|
boundDispatchReceiver: ReceiverValueWithPossibleTypes?,
|
||||||
|
explicitReceiverKind: ExplicitReceiverKind
|
||||||
|
): Candidate {
|
||||||
|
return Candidate(symbol, explicitReceiverKind, inferenceComponents, baseSystem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PostponedArgumentsAnalyzer.Context.addSubsystemFromExpression(expression: FirExpression) {
|
||||||
|
when (expression) {
|
||||||
|
is FirFunctionCall -> expression.candidate()?.let { addOtherSystem(it.system.asReadOnlyStorage()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun FirFunctionCall.candidate(): Candidate? {
|
||||||
|
val callee = this.calleeReference
|
||||||
|
return when (callee) {
|
||||||
|
is FirNamedReferenceWithCandidate -> return callee.candidate
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
+308
@@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.resolve.FirSymbolProvider
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.constructType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.withArguments
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.withNullability
|
||||||
|
import org.jetbrains.kotlin.fir.service
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeClassifierSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.invoke
|
||||||
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
||||||
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
|
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
|
||||||
|
import org.jetbrains.kotlin.types.model.*
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||||
|
|
||||||
|
interface ConeInferenceContext : TypeSystemInferenceExtensionContext,
|
||||||
|
ConeTypeContext {
|
||||||
|
|
||||||
|
val symbolProvider: FirSymbolProvider get() = session.service()
|
||||||
|
|
||||||
|
override fun nullableNothingType(): SimpleTypeMarker {
|
||||||
|
return StandardClassIds.Nothing(symbolProvider).constructType(emptyArray(), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun nullableAnyType(): SimpleTypeMarker {
|
||||||
|
return StandardClassIds.Any(symbolProvider).constructType(emptyArray(), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun nothingType(): SimpleTypeMarker {
|
||||||
|
return StandardClassIds.Nothing(symbolProvider).constructType(emptyArray(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createFlexibleType(lowerBound: SimpleTypeMarker, upperBound: SimpleTypeMarker): KotlinTypeMarker {
|
||||||
|
require(lowerBound is ConeLookupTagBasedType)
|
||||||
|
require(upperBound is ConeLookupTagBasedType)
|
||||||
|
|
||||||
|
return ConeFlexibleType(lowerBound, upperBound)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createSimpleType(
|
||||||
|
constructor: TypeConstructorMarker,
|
||||||
|
arguments: List<TypeArgumentMarker>,
|
||||||
|
nullable: Boolean
|
||||||
|
): SimpleTypeMarker {
|
||||||
|
require(constructor is ConeClassifierSymbol)
|
||||||
|
when (constructor) {
|
||||||
|
is ConeClassLikeSymbol -> return ConeClassTypeImpl(
|
||||||
|
constructor.toLookupTag(),
|
||||||
|
arguments.cast(),
|
||||||
|
nullable
|
||||||
|
)
|
||||||
|
else -> error("!")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createTypeArgument(type: KotlinTypeMarker, variance: TypeVariance): TypeArgumentMarker {
|
||||||
|
require(type is ConeKotlinType)
|
||||||
|
return when (variance) {
|
||||||
|
TypeVariance.INV -> type
|
||||||
|
TypeVariance.IN -> ConeKotlinTypeProjectionIn(type)
|
||||||
|
TypeVariance.OUT -> ConeKotlinTypeProjectionOut(type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createStarProjection(typeParameter: TypeParameterMarker): TypeArgumentMarker {
|
||||||
|
return ConeStarProjection
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newBaseTypeCheckerContext(errorTypesEqualToAnything: Boolean): AbstractTypeCheckerContext {
|
||||||
|
return ConeTypeCheckerContext(errorTypesEqualToAnything, session)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun KotlinTypeMarker.canHaveUndefinedNullability(): Boolean {
|
||||||
|
require(this is ConeKotlinType)
|
||||||
|
return this is ConeCapturedType /*|| this is ConeTypeVariable // TODO */
|
||||||
|
|| this is ConeTypeParameterType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ConeKotlinType.typeDepthSimple(): Int {
|
||||||
|
// if (this is TypeUtils.SpecialType) return 0 // TODO: WTF?
|
||||||
|
|
||||||
|
val maxInArguments = this.typeArguments.asSequence().map {
|
||||||
|
if (it.isStarProjection()) 1 else it.getType().typeDepth()
|
||||||
|
}.max() ?: 0
|
||||||
|
|
||||||
|
return maxInArguments + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun SimpleTypeMarker.typeDepth(): Int {
|
||||||
|
require(this is ConeKotlinType)
|
||||||
|
return this.typeDepthSimple()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun KotlinTypeMarker.typeDepth(): Int {
|
||||||
|
require(this is ConeKotlinType)
|
||||||
|
return when (this) {
|
||||||
|
is ConeFlexibleType -> Math.max(lowerBound.typeDepthSimple(), upperBound.typeDepthSimple())
|
||||||
|
else -> typeDepthSimple()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun KotlinTypeMarker.contains(predicate: (KotlinTypeMarker) -> Boolean): Boolean {
|
||||||
|
return this.containsInternal(predicate)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KotlinTypeMarker?.containsInternal(
|
||||||
|
predicate: (KotlinTypeMarker) -> Boolean,
|
||||||
|
visited: HashSet<KotlinTypeMarker> = hashSetOf()
|
||||||
|
): Boolean {
|
||||||
|
if (this == null) return false
|
||||||
|
if (this in visited) return false
|
||||||
|
visited += this
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO:?
|
||||||
|
UnwrappedType unwrappedType = type.unwrap();
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (predicate(this)) return true
|
||||||
|
|
||||||
|
val flexibleType = this.asFlexibleType()
|
||||||
|
if (flexibleType != null
|
||||||
|
&& (flexibleType.lowerBound().containsInternal(predicate, visited)
|
||||||
|
|| flexibleType.upperBound().containsInternal(predicate, visited))
|
||||||
|
) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (this is DefinitelyNotNullTypeMarker
|
||||||
|
&& this.original().containsInternal(predicate, visited)
|
||||||
|
) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
TODO:
|
||||||
|
|
||||||
|
TypeConstructor typeConstructor = type.getConstructor();
|
||||||
|
if (typeConstructor instanceof IntersectionTypeConstructor) {
|
||||||
|
IntersectionTypeConstructor intersectionTypeConstructor = (IntersectionTypeConstructor) typeConstructor;
|
||||||
|
for (KotlinType supertype : intersectionTypeConstructor.getSupertypes()) {
|
||||||
|
if (contains(supertype, isSpecialType, visited)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
val simpleType = this.asSimpleType() ?: return false
|
||||||
|
repeat(simpleType.argumentsCount()) { index ->
|
||||||
|
val argument = simpleType.getArgument(index)
|
||||||
|
if (!argument.isStarProjection() && argument.getType().containsInternal(predicate, visited)) return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun TypeConstructorMarker.isUnitTypeConstructor(): Boolean {
|
||||||
|
return this is ConeClassLikeSymbol && this.classId == StandardClassIds.Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun Collection<KotlinTypeMarker>.singleBestRepresentative(): KotlinTypeMarker? {
|
||||||
|
if (this.size == 1) return this.first()
|
||||||
|
|
||||||
|
val context = newBaseTypeCheckerContext(true)
|
||||||
|
return this.firstOrNull { candidate ->
|
||||||
|
this.all { other ->
|
||||||
|
// We consider error types equal to anything here, so that intersections like
|
||||||
|
// {Array<String>, Array<[ERROR]>} work correctly
|
||||||
|
candidate == other || AbstractTypeChecker.equalTypes(context, candidate, other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun KotlinTypeMarker.isUnit(): Boolean {
|
||||||
|
require(this is ConeKotlinType)
|
||||||
|
return this.typeConstructor().isUnitTypeConstructor() && !this.isNullable
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun KotlinTypeMarker.withNullability(nullable: Boolean): KotlinTypeMarker {
|
||||||
|
require(this is ConeKotlinType)
|
||||||
|
return this.withNullability(ConeNullability.create(nullable))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun KotlinTypeMarker.makeDefinitelyNotNullOrNotNull(): KotlinTypeMarker {
|
||||||
|
return this.withNullability(false) //TODO("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun SimpleTypeMarker.makeSimpleTypeDefinitelyNotNullOrNotNull(): SimpleTypeMarker {
|
||||||
|
return this.withNullability(false) //TODO("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createCapturedType(
|
||||||
|
constructorProjection: TypeArgumentMarker,
|
||||||
|
constructorSupertypes: List<KotlinTypeMarker>,
|
||||||
|
lowerType: KotlinTypeMarker?,
|
||||||
|
captureStatus: CaptureStatus
|
||||||
|
): CapturedTypeMarker {
|
||||||
|
require(lowerType is ConeKotlinType?)
|
||||||
|
require(constructorProjection is ConeKotlinTypeProjection)
|
||||||
|
return ConeCapturedType(
|
||||||
|
captureStatus,
|
||||||
|
lowerType,
|
||||||
|
constructor = ConeCapturedTypeConstructor(constructorProjection, constructorSupertypes.cast())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createStubType(typeVariable: TypeVariableMarker): StubTypeMarker {
|
||||||
|
TODO("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun KotlinTypeMarker.removeAnnotations(): KotlinTypeMarker {
|
||||||
|
return this // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun SimpleTypeMarker.replaceArguments(newArguments: List<TypeArgumentMarker>): SimpleTypeMarker {
|
||||||
|
require(this is ConeKotlinType)
|
||||||
|
return this.withArguments(newArguments.cast<List<ConeKotlinTypeProjection>>().toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun KotlinTypeMarker.hasExactAnnotation(): Boolean {
|
||||||
|
return false // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun KotlinTypeMarker.hasNoInferAnnotation(): Boolean {
|
||||||
|
return false // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun TypeVariableMarker.freshTypeConstructor(): TypeConstructorMarker {
|
||||||
|
require(this is ConeTypeVariable)
|
||||||
|
return this.typeConstructor
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun CapturedTypeMarker.typeConstructorProjection(): TypeArgumentMarker {
|
||||||
|
require(this is ConeCapturedType)
|
||||||
|
return this.constructor.projection
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun KotlinTypeMarker.isNullableType(): Boolean {
|
||||||
|
require(this is ConeKotlinType)
|
||||||
|
if (this.isMarkedNullable)
|
||||||
|
return true
|
||||||
|
|
||||||
|
if (this is ConeFlexibleType && this.upperBound.isNullableType())
|
||||||
|
return true
|
||||||
|
|
||||||
|
if (this is ConeTypeParameterType /* || is TypeVariable */)
|
||||||
|
return hasNullableSuperType(type)
|
||||||
|
|
||||||
|
// TODO: Intersection types
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker {
|
||||||
|
require(this is ConeDefinitelyNotNullType)
|
||||||
|
return this.original()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun typeSubstitutorByTypeConstructor(map: Map<TypeConstructorMarker, KotlinTypeMarker>): TypeSubstitutorMarker {
|
||||||
|
return object : AbstractConeSubstitutor(),
|
||||||
|
TypeSubstitutorMarker {
|
||||||
|
override fun substituteType(type: ConeKotlinType): ConeKotlinType? {
|
||||||
|
val new = map[type.typeConstructor()] ?: return null
|
||||||
|
return new as ConeKotlinType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun TypeSubstitutorMarker.safeSubstitute(type: KotlinTypeMarker): KotlinTypeMarker {
|
||||||
|
if (this === NoSubstitutor) return type
|
||||||
|
require(this is ConeSubstitutor)
|
||||||
|
require(type is ConeKotlinType)
|
||||||
|
return this.substituteOrSelf(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun TypeVariableMarker.defaultType(): SimpleTypeMarker {
|
||||||
|
require(this is ConeTypeVariable)
|
||||||
|
return this.defaultType
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun captureFromExpression(type: KotlinTypeMarker): KotlinTypeMarker? {
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun createErrorTypeWithCustomConstructor(debugName: String, constructor: TypeConstructorMarker): KotlinTypeMarker {
|
||||||
|
return ConeKotlinErrorType("$debugName c: $constructor")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun CapturedTypeMarker.captureStatus(): CaptureStatus {
|
||||||
|
require(this is ConeCapturedType)
|
||||||
|
return this.captureStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun TypeConstructorMarker.isCapturedTypeConstructor(): Boolean {
|
||||||
|
return this is ConeCapturedTypeConstructor
|
||||||
|
}
|
||||||
|
}
|
||||||
+133
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.resolve.calls
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
|
||||||
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.FirTypePlaceholderProjection
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||||
|
|
||||||
|
|
||||||
|
internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
|
||||||
|
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||||
|
val csBuilder = candidate.system.getBuilder()
|
||||||
|
val declaration = candidate.symbol.firUnsafe<FirCallableDeclaration>()
|
||||||
|
if (declaration !is FirCallableMemberDeclaration || declaration.typeParameters.isEmpty()) {
|
||||||
|
candidate.substitutor = ConeSubstitutor.Empty
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val (substitutor, freshVariables) = createToFreshVariableSubstitutorAndAddInitialConstraints(declaration, candidate, csBuilder)
|
||||||
|
candidate.substitutor = substitutor
|
||||||
|
|
||||||
|
|
||||||
|
// bad function -- error on declaration side
|
||||||
|
if (csBuilder.hasContradiction) {
|
||||||
|
sink.reportApplicability(CandidateApplicability.INAPPLICABLE) //TODO: auto report it
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// optimization
|
||||||
|
// if (resolvedCall.typeArgumentMappingByOriginal == NoExplicitArguments && knownTypeParametersResultingSubstitutor == null) {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
val typeParameters = declaration.typeParameters
|
||||||
|
for (index in typeParameters.indices) {
|
||||||
|
val typeParameter = typeParameters[index]
|
||||||
|
val freshVariable = freshVariables[index]
|
||||||
|
|
||||||
|
// val knownTypeArgument = knownTypeParametersResultingSubstitutor?.substitute(typeParameter.defaultType)
|
||||||
|
// if (knownTypeArgument != null) {
|
||||||
|
// csBuilder.addEqualityConstraint(
|
||||||
|
// freshVariable.defaultType,
|
||||||
|
// knownTypeArgument.unwrap(),
|
||||||
|
// KnownTypeParameterConstraintPosition(knownTypeArgument)
|
||||||
|
// )
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
val typeArgument =
|
||||||
|
callInfo.typeArguments.getOrElse(index) { FirTypePlaceholderProjection }//resolvedCall.typeArgumentMappingByOriginal.getTypeArgument(typeParameter)
|
||||||
|
//
|
||||||
|
if (typeArgument is FirTypeProjectionWithVariance) {
|
||||||
|
csBuilder.addEqualityConstraint(
|
||||||
|
freshVariable.defaultType,
|
||||||
|
typeArgument.typeRef.coneTypeUnsafe(),
|
||||||
|
SimpleConstraintSystemConstraintPosition // TODO
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
assert(typeArgument == FirTypePlaceholderProjection) // TODO
|
||||||
|
// assert(typeArgument == TypeArgumentPlaceholder) {
|
||||||
|
// "Unexpected typeArgument: $typeArgument, ${typeArgument.javaClass.canonicalName}"
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createToFreshVariableSubstitutorAndAddInitialConstraints(
|
||||||
|
declaration: FirCallableMemberDeclaration,
|
||||||
|
candidate: Candidate,
|
||||||
|
csBuilder: ConstraintSystemOperation
|
||||||
|
): Pair<ConeSubstitutor, List<ConeTypeVariable>> {
|
||||||
|
|
||||||
|
val typeParameters = declaration.typeParameters
|
||||||
|
|
||||||
|
val freshTypeVariables = typeParameters.map { TypeParameterBasedTypeVariable(it.symbol) }
|
||||||
|
|
||||||
|
val toFreshVariables = ConeSubstitutorByMap(freshTypeVariables.associate { it.typeParameterSymbol to it.defaultType })
|
||||||
|
|
||||||
|
for (freshVariable in freshTypeVariables) {
|
||||||
|
csBuilder.registerVariable(freshVariable)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun TypeParameterBasedTypeVariable.addSubtypeConstraint(
|
||||||
|
upperBound: ConeKotlinType//,
|
||||||
|
//position: DeclaredUpperBoundConstraintPosition
|
||||||
|
) {
|
||||||
|
csBuilder.addSubtypeConstraint(defaultType, toFreshVariables.substituteOrSelf(upperBound), SimpleConstraintSystemConstraintPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index in typeParameters.indices) {
|
||||||
|
val typeParameter = typeParameters[index]
|
||||||
|
val freshVariable = freshTypeVariables[index]
|
||||||
|
//val position = DeclaredUpperBoundConstraintPosition(typeParameter)
|
||||||
|
|
||||||
|
for (upperBound in typeParameter.bounds) {
|
||||||
|
freshVariable.addSubtypeConstraint(upperBound.coneTypeUnsafe()/*, position*/)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (candidateDescriptor is TypeAliasConstructorDescriptor) {
|
||||||
|
// val typeAliasDescriptor = candidateDescriptor.typeAliasDescriptor
|
||||||
|
// val originalTypes = typeAliasDescriptor.underlyingType.arguments.map { it.type }
|
||||||
|
// val originalTypeParameters = candidateDescriptor.underlyingConstructorDescriptor.typeParameters
|
||||||
|
// for (index in typeParameters.indices) {
|
||||||
|
// val typeParameter = typeParameters[index]
|
||||||
|
// val freshVariable = freshTypeVariables[index]
|
||||||
|
// val typeMapping = originalTypes.mapIndexedNotNull { i: Int, kotlinType: KotlinType ->
|
||||||
|
// if (kotlinType == typeParameter.defaultType) i else null
|
||||||
|
// }
|
||||||
|
// for (originalIndex in typeMapping) {
|
||||||
|
// // there can be null in case we already captured type parameter in outer class (in case of inner classes)
|
||||||
|
// // see test innerClassTypeAliasConstructor.kt
|
||||||
|
// val originalTypeParameter = originalTypeParameters.getOrNull(originalIndex) ?: continue
|
||||||
|
// val position = DeclaredUpperBoundConstraintPosition(originalTypeParameter)
|
||||||
|
// for (upperBound in originalTypeParameter.upperBounds) {
|
||||||
|
// freshVariable.addSubtypeConstraint(upperBound, position)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
return toFreshVariables to freshTypeVariables
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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 com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.fir.*
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
class FirNamedReferenceWithCandidate(session: FirSession, psi: PsiElement?, name: Name, val candidate: Candidate) :
|
||||||
|
FirResolvedCallableReferenceImpl(session, psi, name, candidate.symbol as ConeCallableSymbol)
|
||||||
+134
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.TypeVariableDirectionCalculator
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.VariableFixationFinder
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom
|
||||||
|
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||||
|
import org.jetbrains.kotlin.types.model.isIntegerLiteralTypeConstructor
|
||||||
|
import org.jetbrains.kotlin.types.model.typeConstructor
|
||||||
|
|
||||||
|
|
||||||
|
fun Candidate.computeCompletionMode(
|
||||||
|
components: InferenceComponents,
|
||||||
|
expectedType: FirTypeRef?,
|
||||||
|
currentReturnType: ConeKotlinType?
|
||||||
|
): KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode {
|
||||||
|
// Presence of expected type means that we trying to complete outermost call => completion mode should be full
|
||||||
|
if (expectedType != null) return KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL
|
||||||
|
|
||||||
|
// This is questionable as null return type can be only for error call
|
||||||
|
if (currentReturnType == null) return KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.PARTIAL
|
||||||
|
|
||||||
|
return when {
|
||||||
|
// Consider call foo(bar(x)), if return type of bar is a proper one, then we can complete resolve for bar => full completion mode
|
||||||
|
// Otherwise, we shouldn't complete bar until we process call foo
|
||||||
|
system.getBuilder().isProperType(currentReturnType) -> KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL
|
||||||
|
|
||||||
|
// Nested call is connected with the outer one through the UPPER constraint (returnType <: expectedOuterType)
|
||||||
|
// This means that there will be no new LOWER constraints =>
|
||||||
|
// it's possible to complete call now if there are proper LOWER constraints
|
||||||
|
system.getBuilder().isTypeVariable(currentReturnType) ->
|
||||||
|
if (hasProperNonTrivialLowerConstraints(components, currentReturnType))
|
||||||
|
KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL
|
||||||
|
else
|
||||||
|
KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.PARTIAL
|
||||||
|
|
||||||
|
else -> KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.PARTIAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val Candidate.csBuilder get() = system.getBuilder()
|
||||||
|
|
||||||
|
private fun Candidate.hasProperNonTrivialLowerConstraints(components: InferenceComponents, typeVariable: ConeKotlinType): Boolean {
|
||||||
|
assert(csBuilder.isTypeVariable(typeVariable)) { "$typeVariable is not a type variable" }
|
||||||
|
|
||||||
|
val context = components.ctx
|
||||||
|
val constructor = typeVariable.typeConstructor(context)
|
||||||
|
val variableWithConstraints = csBuilder.currentStorage().notFixedTypeVariables[constructor] ?: return false
|
||||||
|
val constraints = variableWithConstraints.constraints
|
||||||
|
return constraints.isNotEmpty() && constraints.all {
|
||||||
|
!it.type.typeConstructor(context).isIntegerLiteralTypeConstructor(context) &&
|
||||||
|
it.kind.isLower() && csBuilder.isProperType(it.type)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ConstraintSystemCompleter(val components: InferenceComponents) {
|
||||||
|
val variableFixationFinder = VariableFixationFinder(components.trivialConstraintTypeInferenceOracle)
|
||||||
|
fun complete(
|
||||||
|
c: KotlinConstraintSystemCompleter.Context,
|
||||||
|
completionMode: KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode,
|
||||||
|
candidateReturnType: ConeKotlinType
|
||||||
|
) {
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// if (analyzePostponeArgumentIfPossible(c, topLevelAtoms, analyze)) continue
|
||||||
|
|
||||||
|
|
||||||
|
// val allTypeVariables = getOrderedAllTypeVariables(c, collectVariablesFromContext, topLevelAtoms)
|
||||||
|
val allTypeVariables = c.notFixedTypeVariables.keys.toList()
|
||||||
|
// val postponedKtPrimitives = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)
|
||||||
|
val variableForFixation =
|
||||||
|
variableFixationFinder.findFirstVariableForFixation(
|
||||||
|
c, allTypeVariables, emptyList(), completionMode, candidateReturnType
|
||||||
|
) ?: break
|
||||||
|
|
||||||
|
// if (shouldForceCallableReferenceOrLambdaResolution(completionMode, variableForFixation)) {
|
||||||
|
// if (forcePostponedAtomResolution<ResolvedCallableReferenceAtom>(topLevelAtoms, analyze)) continue
|
||||||
|
// if (forcePostponedAtomResolution<LambdaWithTypeVariableAsExpectedTypeAtom>(topLevelAtoms, analyze)) continue
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (variableForFixation.hasProperConstraint || completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
|
||||||
|
val variableWithConstraints = c.notFixedTypeVariables.getValue(variableForFixation.variable)
|
||||||
|
|
||||||
|
fixVariable(c, candidateReturnType, variableWithConstraints, emptyList())
|
||||||
|
|
||||||
|
// if (!variableForFixation.hasProperConstraint) {
|
||||||
|
// c.addError(NotEnoughInformationForTypeParameter(variableWithConstraints.typeVariable))
|
||||||
|
// }
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
|
||||||
|
// force resolution for all not-analyzed argument's
|
||||||
|
// getOrderedNotAnalyzedPostponedArguments(topLevelAtoms).forEach(analyze)
|
||||||
|
//
|
||||||
|
// if (c.notFixedTypeVariables.isNotEmpty() && c.postponedTypeVariables.isEmpty()) {
|
||||||
|
// runCompletion(c, completionMode, topLevelAtoms, topLevelType, analyze)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fixVariable(
|
||||||
|
c: KotlinConstraintSystemCompleter.Context,
|
||||||
|
topLevelType: KotlinTypeMarker,
|
||||||
|
variableWithConstraints: VariableWithConstraints,
|
||||||
|
postponedResolveKtPrimitives: List<PostponedResolvedAtom>
|
||||||
|
) {
|
||||||
|
val direction = TypeVariableDirectionCalculator(c, postponedResolveKtPrimitives, topLevelType).getDirection(variableWithConstraints)
|
||||||
|
fixVariable(c, variableWithConstraints, direction)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fixVariable(
|
||||||
|
c: KotlinConstraintSystemCompleter.Context,
|
||||||
|
variableWithConstraints: VariableWithConstraints,
|
||||||
|
direction: TypeVariableDirectionCalculator.ResolveDirection
|
||||||
|
) {
|
||||||
|
val resultType = components.resultTypeResolver.findResultType(c, variableWithConstraints, direction)
|
||||||
|
c.fixVariable(variableWithConstraints.typeVariable, resultType)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.resolve.*
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.*
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
||||||
|
import org.jetbrains.kotlin.types.AbstractTypeApproximator
|
||||||
|
import org.jetbrains.kotlin.types.model.*
|
||||||
|
|
||||||
|
|
||||||
|
fun ConeInferenceContext.hasNullableSuperType(type: ConeKotlinType): Boolean {
|
||||||
|
if (type is ConeClassLikeType) return false
|
||||||
|
|
||||||
|
if (type !is ConeLookupTagBasedType) return false // TODO?
|
||||||
|
val symbol = type.lookupTag.toSymbol(session) ?: return false // TODO?!
|
||||||
|
for (superType in symbol.supertypes()) {
|
||||||
|
if (superType.isNullableType()) return true
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// for (KotlinType supertype : getImmediateSupertypes(type)) {
|
||||||
|
// if (isNullableType(supertype)) return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConeTypeVariableTypeConstructor(val debugName: String) : ConeSymbol, ConeClassifierLookupTag, TypeVariableTypeConstructorMarker {
|
||||||
|
override val name: Name get() = Name.identifier(debugName)
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeParameterBasedTypeVariable(val typeParameterSymbol: FirTypeParameterSymbol) :
|
||||||
|
ConeTypeVariable(typeParameterSymbol.name.identifier)
|
||||||
|
|
||||||
|
open class ConeTypeVariable(name: String) : TypeVariableMarker {
|
||||||
|
val typeConstructor = ConeTypeVariableTypeConstructor(name)
|
||||||
|
val defaultType = ConeTypeVariableType(ConeNullability.NOT_NULL, typeConstructor)
|
||||||
|
}
|
||||||
|
|
||||||
|
class InferenceComponents(val ctx: TypeSystemInferenceExtensionContextDelegate) {
|
||||||
|
private val approximator = object : AbstractTypeApproximator(ctx) {}
|
||||||
|
val trivialConstraintTypeInferenceOracle = TrivialConstraintTypeInferenceOracle(ctx)
|
||||||
|
private val incorporator = ConstraintIncorporator(approximator, trivialConstraintTypeInferenceOracle)
|
||||||
|
private val injector = ConstraintInjector(incorporator, approximator)
|
||||||
|
val resultTypeResolver = ResultTypeResolver(approximator, trivialConstraintTypeInferenceOracle)
|
||||||
|
|
||||||
|
fun createConstraintSystem(): NewConstraintSystemImpl {
|
||||||
|
return NewConstraintSystemImpl(injector, ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+215
@@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.resolve.calls
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirNamedFunction
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
|
||||||
|
import org.jetbrains.kotlin.resolve.OverloadabilitySpecificityCallbacks
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.FlatSignature
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.SimpleConstraintSystem
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.isSignatureNotLessSpecific
|
||||||
|
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||||
|
import org.jetbrains.kotlin.types.model.TypeParameterMarker
|
||||||
|
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
|
||||||
|
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
|
||||||
|
|
||||||
|
class ConeOverloadConflictResolver(
|
||||||
|
val specificityComparator: TypeSpecificityComparator,
|
||||||
|
val inferenceComponents: InferenceComponents
|
||||||
|
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun chooseMaximallySpecificCandidates(
|
||||||
|
candidates: Collection<Candidate>,
|
||||||
|
//checkArgumentsMode: CheckArgumentTypesMode,
|
||||||
|
discriminateGenerics: Boolean//,
|
||||||
|
//isDebuggerContext: Boolean
|
||||||
|
): Set<Candidate> {
|
||||||
|
|
||||||
|
val candidatesSet = candidates.toSet()
|
||||||
|
|
||||||
|
val maximallySpecific = findMaximallySpecificCall(candidatesSet, false/*, isDebuggerContext*/)
|
||||||
|
if (maximallySpecific != null) {
|
||||||
|
return setOf(maximallySpecific)
|
||||||
|
}
|
||||||
|
|
||||||
|
return candidatesSet
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createFlatSignature(call: Candidate): FlatSignature<Candidate> {
|
||||||
|
val declaration = call.symbol.firUnsafe<FirCallableDeclaration>()
|
||||||
|
return when (declaration) {
|
||||||
|
is FirNamedFunction -> createFlatSignature(call, declaration)
|
||||||
|
is FirConstructor -> createFlatSignature(call, declaration)
|
||||||
|
else -> error("Not supported: $declaration")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createFlatSignature(call: Candidate, constructor: FirConstructor): FlatSignature<Candidate> {
|
||||||
|
return FlatSignature(
|
||||||
|
call,
|
||||||
|
constructor.typeParameters.map { it.symbol },
|
||||||
|
constructor.valueParameters.map { it.returnTypeRef.coneTypeUnsafe() },
|
||||||
|
//constructor.receiverTypeRef != null,
|
||||||
|
false,
|
||||||
|
constructor.valueParameters.any { it.isVararg },
|
||||||
|
constructor.valueParameters.count { it.defaultValue != null },
|
||||||
|
constructor.isExpect,
|
||||||
|
false // TODO
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createFlatSignature(call: Candidate, function: FirNamedFunction): FlatSignature<Candidate> {
|
||||||
|
return FlatSignature(
|
||||||
|
call,
|
||||||
|
function.typeParameters.map { it.symbol },
|
||||||
|
function.valueParameters.map { it.returnTypeRef.coneTypeUnsafe() },
|
||||||
|
function.receiverTypeRef != null,
|
||||||
|
function.valueParameters.any { it.isVararg },
|
||||||
|
function.valueParameters.count { it.defaultValue != null },
|
||||||
|
function.isExpect,
|
||||||
|
false // TODO
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createEmptyConstraintSystem(): SimpleConstraintSystem {
|
||||||
|
return ConeSimpleConstraintSystemImpl(inferenceComponents.createConstraintSystem())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findMaximallySpecificCall(
|
||||||
|
candidates: Set<Candidate>,
|
||||||
|
discriminateGenerics: Boolean//,
|
||||||
|
//isDebuggerContext: Boolean
|
||||||
|
): Candidate? {
|
||||||
|
val filteredCandidates = candidates//uniquifyCandidatesSet(candidates)
|
||||||
|
|
||||||
|
if (filteredCandidates.size <= 1) return filteredCandidates.singleOrNull()
|
||||||
|
|
||||||
|
val conflictingCandidates = filteredCandidates.map { candidateCall ->
|
||||||
|
createFlatSignature(candidateCall)
|
||||||
|
}
|
||||||
|
|
||||||
|
val bestCandidatesByParameterTypes = conflictingCandidates.filter { candidate ->
|
||||||
|
isMostSpecific(candidate, conflictingCandidates) { call1, call2 ->
|
||||||
|
isNotLessSpecificCallWithArgumentMapping(call1, call2, discriminateGenerics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestCandidatesByParameterTypes.exactMaxWith { call1, call2 ->
|
||||||
|
isOfNotLessSpecificShape(call1, call2)// && isOfNotLessSpecificVisibilityForDebugger(call1, call2, isDebuggerContext)
|
||||||
|
}?.origin
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private inline fun <C : Any> Collection<C>.exactMaxWith(isNotWorse: (C, C) -> Boolean): C? {
|
||||||
|
var result: C? = null
|
||||||
|
for (candidate in this) {
|
||||||
|
if (result == null || isNotWorse(candidate, result)) {
|
||||||
|
result = candidate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result == null) return null
|
||||||
|
if (any { it != result && isNotWorse(it, result!!) }) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <C> isMostSpecific(candidate: C, candidates: Collection<C>, isNotLessSpecific: (C, C) -> Boolean): Boolean =
|
||||||
|
candidates.all { other ->
|
||||||
|
candidate === other ||
|
||||||
|
isNotLessSpecific(candidate, other)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `call1` is not less specific than `call2`
|
||||||
|
*/
|
||||||
|
private fun isNotLessSpecificCallWithArgumentMapping(
|
||||||
|
call1: FlatSignature<Candidate>,
|
||||||
|
call2: FlatSignature<Candidate>,
|
||||||
|
discriminateGenerics: Boolean
|
||||||
|
): Boolean {
|
||||||
|
return compareCallsByUsedArguments(
|
||||||
|
call1,
|
||||||
|
call2,
|
||||||
|
discriminateGenerics
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` if [call1] is definitely more or equally specific [call2],
|
||||||
|
* `false` otherwise.
|
||||||
|
*/
|
||||||
|
private fun compareCallsByUsedArguments(
|
||||||
|
call1: FlatSignature<Candidate>,
|
||||||
|
call2: FlatSignature<Candidate>,
|
||||||
|
discriminateGenerics: Boolean
|
||||||
|
): Boolean {
|
||||||
|
if (discriminateGenerics) {
|
||||||
|
val isGeneric1 = call1.isGeneric
|
||||||
|
val isGeneric2 = call2.isGeneric
|
||||||
|
// generic loses to non-generic
|
||||||
|
if (isGeneric1 && !isGeneric2) return false
|
||||||
|
if (!isGeneric1 && isGeneric2) return true
|
||||||
|
// two generics are non-comparable
|
||||||
|
if (isGeneric1 && isGeneric2) return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!call1.isExpect && call2.isExpect) return true
|
||||||
|
if (call1.isExpect && !call2.isExpect) return false
|
||||||
|
|
||||||
|
return createEmptyConstraintSystem().isSignatureNotLessSpecific(
|
||||||
|
call1,
|
||||||
|
call2,
|
||||||
|
OverloadabilitySpecificityCallbacks,
|
||||||
|
specificityComparator
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isOfNotLessSpecificShape(
|
||||||
|
call1: FlatSignature<Candidate>,
|
||||||
|
call2: FlatSignature<Candidate>
|
||||||
|
): Boolean {
|
||||||
|
val hasVarargs1 = call1.hasVarargs
|
||||||
|
val hasVarargs2 = call2.hasVarargs
|
||||||
|
if (hasVarargs1 && !hasVarargs2) return false
|
||||||
|
if (!hasVarargs1 && hasVarargs2) return true
|
||||||
|
|
||||||
|
if (call1.numDefaults > call2.numDefaults) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object NoSubstitutor : TypeSubstitutorMarker
|
||||||
|
|
||||||
|
class ConeSimpleConstraintSystemImpl(val system: NewConstraintSystemImpl) : SimpleConstraintSystem {
|
||||||
|
override fun registerTypeVariables(typeParameters: Collection<TypeParameterMarker>): TypeSubstitutorMarker {
|
||||||
|
return NoSubstitutor
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addSubtypeConstraint(subType: KotlinTypeMarker, superType: KotlinTypeMarker) {
|
||||||
|
system.addSubtypeConstraint(subType, superType, SimpleConstraintSystemConstraintPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasContradiction(): Boolean = system.hasContradiction
|
||||||
|
|
||||||
|
override val context: TypeSystemInferenceExtensionContext
|
||||||
|
get() = system
|
||||||
|
|
||||||
|
}
|
||||||
@@ -10,26 +10,42 @@ import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
|
|||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||||
|
|
||||||
|
|
||||||
sealed class ResolutionStage {
|
abstract class ResolutionStage {
|
||||||
abstract fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo)
|
abstract fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class CheckerStage : ResolutionStage()
|
abstract class CheckerStage : ResolutionStage()
|
||||||
|
|
||||||
internal object MapArguments : ResolutionStage() {
|
internal object MapArguments : ResolutionStage() {
|
||||||
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||||
val symbol = candidate.symbol as? FirFunctionSymbol ?: return sink.reportApplicability(CandidateApplicability.HIDDEN)
|
val symbol = candidate.symbol as? FirFunctionSymbol ?: return sink.reportApplicability(CandidateApplicability.HIDDEN)
|
||||||
if (symbol.firUnsafe<FirFunction>().valueParameters.size != callInfo.argumentCount) {
|
if (symbol.firUnsafe<FirFunction>().valueParameters.size != callInfo.arguments.size) {
|
||||||
return sink.reportApplicability(CandidateApplicability.PARAMETER_MAPPING_ERROR)
|
return sink.reportApplicability(CandidateApplicability.PARAMETER_MAPPING_ERROR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal object CheckArguments : CheckerStage() {
|
||||||
|
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||||
|
val symbol = candidate.symbol as? FirFunctionSymbol ?: error("Can't check arguments for non function")
|
||||||
|
val declaration = symbol.fir as FirFunction
|
||||||
|
for ((parameter, argument) in declaration.valueParameters.zip(callInfo.arguments)) {
|
||||||
|
|
||||||
|
candidate.resolveArgument(argument, parameter, isReceiver = false, typeProvider = callInfo.typeProvider, sink = sink)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidate.system.hasContradiction) {
|
||||||
|
sink.reportApplicability(CandidateApplicability.INAPPLICABLE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
internal fun functionCallResolutionSequence() =
|
internal fun functionCallResolutionSequence() =
|
||||||
listOf<ResolutionStage>(MapArguments)
|
listOf<ResolutionStage>(MapArguments, CreateFreshTypeVariableSubstitutorStage, CheckArguments)
|
||||||
|
|
||||||
|
|
||||||
internal fun qualifiedAccessResolutionSequence() =
|
internal fun qualifiedAccessResolutionSequence() =
|
||||||
listOf<ResolutionStage>()
|
listOf<ResolutionStage>(CreateFreshTypeVariableSubstitutorStage)
|
||||||
+130
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.substitution
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeAbbreviatedTypeImpl
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
||||||
|
|
||||||
|
|
||||||
|
interface ConeSubstitutor {
|
||||||
|
fun substituteOrSelf(type: ConeKotlinType): ConeKotlinType
|
||||||
|
fun substituteOrNull(type: ConeKotlinType): ConeKotlinType?
|
||||||
|
|
||||||
|
object Empty : ConeSubstitutor {
|
||||||
|
override fun substituteOrSelf(type: ConeKotlinType): ConeKotlinType {
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun substituteOrNull(type: ConeKotlinType): ConeKotlinType? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ConeSubstitutor.substituteOrNull(type: ConeKotlinType?): ConeKotlinType? {
|
||||||
|
return type?.let { substituteOrNull(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class AbstractConeSubstitutor : ConeSubstitutor {
|
||||||
|
private fun wrapProjection(old: ConeKotlinTypeProjection, newType: ConeKotlinType): ConeKotlinTypeProjection {
|
||||||
|
return when (old) {
|
||||||
|
is ConeStarProjection -> old
|
||||||
|
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(newType)
|
||||||
|
is ConeKotlinTypeProjectionOut -> ConeKotlinTypeProjectionOut(newType)
|
||||||
|
is ConeKotlinType -> newType
|
||||||
|
else -> old
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun substituteType(type: ConeKotlinType): ConeKotlinType?
|
||||||
|
|
||||||
|
override fun substituteOrSelf(type: ConeKotlinType): ConeKotlinType {
|
||||||
|
return substituteOrNull(type) ?: type
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun substituteOrNull(type: ConeKotlinType): ConeKotlinType? {
|
||||||
|
val newType = substituteType(type)
|
||||||
|
return (newType ?: type).substituteRecursive() ?: newType
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ConeKotlinType.substituteRecursive(): ConeKotlinType? {
|
||||||
|
return when (this) {
|
||||||
|
is ConeClassErrorType -> return null
|
||||||
|
is ConeClassType -> this.substituteArguments()
|
||||||
|
is ConeAbbreviatedType -> this.substituteArguments()
|
||||||
|
is ConeFunctionType -> TODO()
|
||||||
|
is ConeTypeParameterType -> return null
|
||||||
|
is ConeTypeVariableType -> return null
|
||||||
|
is ConeFlexibleType -> this.substituteBounds()
|
||||||
|
is ConeCapturedType -> TODO()
|
||||||
|
is ConeDefinitelyNotNullType -> this.substituteOriginal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ConeDefinitelyNotNullType.substituteOriginal(): ConeDefinitelyNotNullType? {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ConeFlexibleType.substituteBounds(): ConeFlexibleType? {
|
||||||
|
val newLowerBound = substituteOrNull(lowerBound) as ConeLookupTagBasedType?
|
||||||
|
val newUpperBound = substituteOrNull(upperBound) as ConeLookupTagBasedType?
|
||||||
|
if (newLowerBound != null || newUpperBound != null) {
|
||||||
|
return ConeFlexibleType(newLowerBound ?: lowerBound, newUpperBound ?: upperBound)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ConeKotlinType.substituteArguments(): ConeKotlinType? {
|
||||||
|
val newArguments by lazy { arrayOfNulls<ConeKotlinTypeProjection>(typeArguments.size) }
|
||||||
|
var initialized = false
|
||||||
|
for ((index, typeArgument) in this.typeArguments.withIndex()) {
|
||||||
|
val type = (typeArgument as? ConeTypedProjection)?.type ?: continue
|
||||||
|
val newType = substituteOrNull(type)
|
||||||
|
if (newType != null) {
|
||||||
|
initialized = true
|
||||||
|
newArguments[index] = wrapProjection(typeArgument, newType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initialized) {
|
||||||
|
for ((index, typeArgument) in this.typeArguments.withIndex()) {
|
||||||
|
if (newArguments[index] == null) {
|
||||||
|
newArguments[index] = typeArgument
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return when (this) {
|
||||||
|
is ConeClassTypeImpl -> ConeClassTypeImpl(
|
||||||
|
lookupTag,
|
||||||
|
newArguments as Array<ConeKotlinTypeProjection>,
|
||||||
|
nullability.isNullable
|
||||||
|
)
|
||||||
|
is ConeAbbreviatedTypeImpl -> ConeAbbreviatedTypeImpl(
|
||||||
|
abbreviationLookupTag,
|
||||||
|
newArguments as Array<ConeKotlinTypeProjection>,
|
||||||
|
nullability.isNullable
|
||||||
|
)
|
||||||
|
is ConeClassLikeType -> error("Unknown class-like type to substitute: $this, ${this::class}")
|
||||||
|
else -> error("Unknown type to substitute: $this, ${this::class}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ConeSubstitutorByMap(val substitution: Map<ConeTypeParameterSymbol, ConeKotlinType>) : AbstractConeSubstitutor() {
|
||||||
|
|
||||||
|
override fun substituteType(type: ConeKotlinType): ConeKotlinType? {
|
||||||
|
if (type !is ConeTypeParameterType) return null
|
||||||
|
return substitution[type.lookupTag]
|
||||||
|
}
|
||||||
|
}
|
||||||
+155
-54
@@ -10,13 +10,10 @@ import org.jetbrains.kotlin.fir.*
|
|||||||
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.FirErrorNamedReference
|
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
|
|
||||||
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
|
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.*
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.CallInfo
|
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.CallResolver
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.createFunctionConsumer
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.createVariableConsumer
|
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
|
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
|
||||||
@@ -24,16 +21,17 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirTopLevelDeclaredMemberScope
|
|||||||
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
|
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
|
||||||
import org.jetbrains.kotlin.fir.symbols.*
|
import org.jetbrains.kotlin.fir.symbols.*
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
import org.jetbrains.kotlin.fir.types.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.FirComputingImplicitTypeRef
|
|
||||||
import org.jetbrains.kotlin.fir.types.impl.FirErrorTypeRefImpl
|
|
||||||
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.FirTransformer
|
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||||
import org.jetbrains.kotlin.fir.visitors.compose
|
import org.jetbrains.kotlin.fir.visitors.compose
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
||||||
|
import org.jetbrains.kotlin.types.model.*
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
|
||||||
open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOnly: Boolean) : FirTransformer<Any?>() {
|
open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOnly: Boolean) : FirTransformer<Any?>() {
|
||||||
@@ -115,7 +113,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
|||||||
resolved.resultType =
|
resolved.resultType =
|
||||||
resolved.conversionTypeRef.withReplacedConeType(
|
resolved.conversionTypeRef.withReplacedConeType(
|
||||||
session,
|
session,
|
||||||
resolved.conversionTypeRef.coneTypeUnsafe<ConeKotlinType>().withNullability(ConeNullability.NULLABLE)
|
resolved.conversionTypeRef.coneTypeUnsafe().withNullability(ConeNullability.NULLABLE)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> error("Unknown type operator")
|
else -> error("Unknown type operator")
|
||||||
@@ -143,16 +141,36 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
|||||||
val jump = ReturnTypeCalculatorWithJump(session)
|
val jump = ReturnTypeCalculatorWithJump(session)
|
||||||
|
|
||||||
private fun <T> storeTypeFromCallee(access: T) where T : FirQualifiedAccess, T : FirExpression {
|
private fun <T> storeTypeFromCallee(access: T) where T : FirQualifiedAccess, T : FirExpression {
|
||||||
access.resultType =
|
access.resultType = typeFromCallee(access)
|
||||||
when (val newCallee = access.calleeReference) {
|
|
||||||
is FirErrorNamedReference ->
|
|
||||||
FirErrorTypeRefImpl(session, access.psi, newCallee.errorReason)
|
|
||||||
is FirResolvedCallableReference ->
|
|
||||||
jump.tryCalculateReturnType(newCallee.callableSymbol.firUnsafe())
|
|
||||||
else -> return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun <T> typeFromCallee(access: T): FirResolvedTypeRef where T : FirQualifiedAccess, T : FirExpression {
|
||||||
|
return when (val newCallee = access.calleeReference) {
|
||||||
|
is FirErrorNamedReference ->
|
||||||
|
FirErrorTypeRefImpl(session, access.psi, newCallee.errorReason)
|
||||||
|
is FirResolvedCallableReference ->
|
||||||
|
jump.tryCalculateReturnType(newCallee.callableSymbol.firUnsafe())
|
||||||
|
else -> error("Failed to extract type from: $newCallee")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val inferenceComponents = InferenceComponents(object : ConeInferenceContext, TypeSystemInferenceExtensionContextDelegate {
|
||||||
|
override fun findCommonIntegerLiteralTypesSuperType(explicitSupertypes: List<SimpleTypeMarker>): SimpleTypeMarker? {
|
||||||
|
TODO("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun TypeConstructorMarker.getApproximatedIntegerLiteralType(): KotlinTypeMarker {
|
||||||
|
TODO("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override val session: FirSession
|
||||||
|
get() = this@FirBodyResolveTransformer.session
|
||||||
|
|
||||||
|
override fun KotlinTypeMarker.removeExactAnnotation(): KotlinTypeMarker {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
override fun transformQualifiedAccessExpression(
|
override fun transformQualifiedAccessExpression(
|
||||||
qualifiedAccessExpression: FirQualifiedAccessExpression,
|
qualifiedAccessExpression: FirQualifiedAccessExpression,
|
||||||
data: Any?
|
data: Any?
|
||||||
@@ -180,13 +198,9 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
|||||||
}
|
}
|
||||||
val callee = qualifiedAccessExpression.calleeReference as? FirSimpleNamedReference ?: return qualifiedAccessExpression.compose()
|
val callee = qualifiedAccessExpression.calleeReference as? FirSimpleNamedReference ?: return qualifiedAccessExpression.compose()
|
||||||
|
|
||||||
qualifiedAccessExpression.explicitReceiver?.visitNoTransform(this, null)
|
val receiver = qualifiedAccessExpression.explicitReceiver?.transformSingle(this, null)
|
||||||
|
|
||||||
val receiver = qualifiedAccessExpression.explicitReceiver
|
val info = CallInfo(CallKind.VariableAccess, receiver, emptyList(), emptyList()) { it.resultType }
|
||||||
|
|
||||||
//val checkers = listOf(VariableApplicabilityChecker(callee.name))
|
|
||||||
|
|
||||||
val info = CallInfo(true, receiver, 0)
|
|
||||||
val resolver = CallResolver(jump, session)
|
val resolver = CallResolver(jump, session)
|
||||||
resolver.callInfo = info
|
resolver.callInfo = info
|
||||||
resolver.scopes = (scopes + localScopes).asReversed()
|
resolver.scopes = (scopes + localScopes).asReversed()
|
||||||
@@ -194,40 +208,44 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
|||||||
val consumer = createVariableConsumer(
|
val consumer = createVariableConsumer(
|
||||||
session,
|
session,
|
||||||
callee.name,
|
callee.name,
|
||||||
qualifiedAccessExpression.explicitReceiver,
|
info, inferenceComponents
|
||||||
qualifiedAccessExpression.explicitReceiver?.resultType
|
|
||||||
)
|
)
|
||||||
val result = resolver.runTowerResolver(consumer)
|
val result = resolver.runTowerResolver(consumer)
|
||||||
val successCandidates = result.successCandidates()
|
|
||||||
val resultExpression = qualifiedAccessExpression.transformCalleeReference(this, successCandidates)
|
val nameReference = createResolvedNamedReference(
|
||||||
|
callee,
|
||||||
|
result.bestCandidates(),
|
||||||
|
result.currentApplicability
|
||||||
|
)
|
||||||
|
|
||||||
|
val resultExpression =
|
||||||
|
qualifiedAccessExpression.transformCalleeReference(StoreNameReference, nameReference)
|
||||||
storeTypeFromCallee(resultExpression as FirQualifiedAccessExpression)
|
storeTypeFromCallee(resultExpression as FirQualifiedAccessExpression)
|
||||||
return resultExpression.compose()
|
return resultExpression.compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun transformFunctionCall(functionCall: FirFunctionCall, data: Any?): CompositeTransformResult<FirStatement> {
|
private fun resolveCallAndSelectCandidate(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?): FirFunctionCall {
|
||||||
|
|
||||||
val functionCall = functionCall.transformChildren(this, null) as FirFunctionCall
|
val functionCall = functionCall.transformChildren(this, null) as FirFunctionCall
|
||||||
|
|
||||||
if (functionCall.calleeReference !is FirSimpleNamedReference) return functionCall.compose()
|
|
||||||
|
|
||||||
val name = functionCall.calleeReference.name
|
val name = functionCall.calleeReference.name
|
||||||
|
|
||||||
val expectedTypeRef = data as FirTypeRef?
|
|
||||||
|
|
||||||
val receiver = functionCall.explicitReceiver
|
val receiver = functionCall.explicitReceiver
|
||||||
val arguments = functionCall.arguments
|
val arguments = functionCall.arguments
|
||||||
|
val typeArguments = functionCall.typeArguments
|
||||||
|
|
||||||
|
|
||||||
val info = CallInfo(false, receiver, arguments.size)
|
val info = CallInfo(CallKind.Function, receiver, arguments, typeArguments) { it.resultType }
|
||||||
val resolver = CallResolver(jump, session)
|
val resolver = CallResolver(jump, session)
|
||||||
resolver.callInfo = info
|
resolver.callInfo = info
|
||||||
resolver.scopes = (scopes + localScopes).asReversed()
|
resolver.scopes = (scopes + localScopes).asReversed()
|
||||||
|
|
||||||
|
val consumer = createFunctionConsumer(session, name, info, inferenceComponents)
|
||||||
|
|
||||||
val consumer = createFunctionConsumer(session, name, receiver, receiver?.resultType)
|
|
||||||
val result = resolver.runTowerResolver(consumer)
|
val result = resolver.runTowerResolver(consumer)
|
||||||
val successCandidates = result.successCandidates()
|
val bestCandidates = result.bestCandidates()
|
||||||
|
val reducedCandidates = ConeOverloadConflictResolver(TypeSpecificityComparator.NONE, inferenceComponents)
|
||||||
|
.chooseMaximallySpecificCandidates(bestCandidates, discriminateGenerics = false)
|
||||||
|
|
||||||
|
|
||||||
// fun isInvoke()
|
// fun isInvoke()
|
||||||
//
|
//
|
||||||
@@ -257,33 +275,103 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
|||||||
// }
|
// }
|
||||||
// else -> functionCall
|
// else -> functionCall
|
||||||
// }
|
// }
|
||||||
val resultExpression = functionCall.transformCalleeReference(this, successCandidates)
|
val nameReference = createResolvedNamedReference(
|
||||||
|
functionCall.calleeReference,
|
||||||
|
reducedCandidates,
|
||||||
|
result.currentApplicability
|
||||||
|
)
|
||||||
|
|
||||||
storeTypeFromCallee(resultExpression as FirFunctionCall)
|
val resultExpression = functionCall.transformCalleeReference(StoreNameReference, nameReference) as FirFunctionCall
|
||||||
return resultExpression.compose()
|
val typeRef = typeFromCallee(functionCall)
|
||||||
|
if (typeRef.type is ConeKotlinErrorType) {
|
||||||
|
functionCall.resultType = typeRef
|
||||||
|
}
|
||||||
|
return resultExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createResolvedNamedReference(namedReference: FirNamedReference, candidates: List<ConeCallableSymbol>): FirNamedReference {
|
private fun completeTypeInference(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?): FirFunctionCall {
|
||||||
|
val typeRef = typeFromCallee(functionCall)
|
||||||
|
if (typeRef.type is ConeKotlinErrorType) {
|
||||||
|
functionCall.resultType = typeRef
|
||||||
|
return functionCall
|
||||||
|
}
|
||||||
|
val candidate = functionCall.candidate() ?: return functionCall
|
||||||
|
val initialSubstitutor = candidate.substitutor
|
||||||
|
|
||||||
|
val initialType = initialSubstitutor.substituteOrSelf(typeRef.type)
|
||||||
|
|
||||||
|
val completionMode = candidate.computeCompletionMode(inferenceComponents, expectedTypeRef, initialType)
|
||||||
|
val completer = ConstraintSystemCompleter(inferenceComponents)
|
||||||
|
completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, initialType)
|
||||||
|
|
||||||
|
|
||||||
|
if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
|
||||||
|
val finalSubstitutor =
|
||||||
|
candidate.system.asReadOnlyStorage().buildAbstractResultingSubstitutor(inferenceComponents.ctx) as ConeSubstitutor
|
||||||
|
return functionCall.transformSingle(
|
||||||
|
FirCallCompleterTransformer(session, finalSubstitutor, jump),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return functionCall
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transformFunctionCall(functionCall: FirFunctionCall, data: Any?): CompositeTransformResult<FirStatement> {
|
||||||
|
if (functionCall.calleeReference !is FirSimpleNamedReference) return functionCall.compose()
|
||||||
|
val expectedTypeRef = data as FirTypeRef?
|
||||||
|
val completeInference =
|
||||||
|
try {
|
||||||
|
val resultExpression = resolveCallAndSelectCandidate(functionCall, expectedTypeRef)
|
||||||
|
completeTypeInference(resultExpression, expectedTypeRef)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
throw RuntimeException("While resolving call ${functionCall.render()}", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return completeInference.compose()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun describeSymbol(symbol: ConeSymbol): String {
|
||||||
|
return when (symbol) {
|
||||||
|
is ConeClassLikeSymbol -> symbol.classId.asString()
|
||||||
|
is ConeCallableSymbol -> symbol.callableId.toString()
|
||||||
|
else -> "$symbol"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createResolvedNamedReference(
|
||||||
|
namedReference: FirNamedReference,
|
||||||
|
candidates: Collection<Candidate>,
|
||||||
|
applicability: CandidateApplicability
|
||||||
|
): FirNamedReference {
|
||||||
val name = namedReference.name
|
val name = namedReference.name
|
||||||
return when (candidates.size) {
|
return when {
|
||||||
0 -> FirErrorNamedReference(
|
candidates.isEmpty() -> FirErrorNamedReference(
|
||||||
namedReference.session, namedReference.psi, "Unresolved name: $name"
|
namedReference.session, namedReference.psi, "Unresolved name: $name"
|
||||||
)
|
)
|
||||||
1 -> FirResolvedCallableReferenceImpl(
|
applicability < CandidateApplicability.RESOLVED -> {
|
||||||
|
FirErrorNamedReference(
|
||||||
|
namedReference.session,
|
||||||
|
namedReference.psi,
|
||||||
|
"Inapplicable($applicability): ${candidates.map { describeSymbol(it.symbol) }}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
candidates.size == 1 -> FirNamedReferenceWithCandidate(
|
||||||
namedReference.session, namedReference.psi,
|
namedReference.session, namedReference.psi,
|
||||||
name, candidates.single()
|
name, candidates.single()
|
||||||
)
|
)
|
||||||
else -> FirErrorNamedReference(
|
else -> FirErrorNamedReference(
|
||||||
namedReference.session, namedReference.psi, "Ambiguity: $name, ${candidates.map { it.callableId }}"
|
namedReference.session, namedReference.psi, "Ambiguity: $name, ${candidates.map { describeSymbol(it.symbol) }}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun transformNamedReference(namedReference: FirNamedReference, data: Any?): CompositeTransformResult<FirNamedReference> {
|
// override fun transformNamedReference(namedReference: FirNamedReference, data: Any?): CompositeTransformResult<FirNamedReference> {
|
||||||
if (namedReference is FirErrorNamedReference || namedReference is FirResolvedCallableReference) return namedReference.compose()
|
// if (namedReference is FirErrorNamedReference || namedReference is FirResolvedCallableReference) return namedReference.compose()
|
||||||
val referents = data as? List<ConeCallableSymbol> ?: return namedReference.compose()
|
// val referents = data as? List<ConeCallableSymbol> ?: return namedReference.compose()
|
||||||
return createResolvedNamedReference(namedReference, referents).compose()
|
// return createResolvedNamedReference(namedReference, referents).compose()
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
override fun transformBlock(block: FirBlock, data: Any?): CompositeTransformResult<FirStatement> {
|
override fun transformBlock(block: FirBlock, data: Any?): CompositeTransformResult<FirStatement> {
|
||||||
@@ -315,10 +403,10 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun <T> transformConstExpression(constExpression: FirConstExpression<T>, data: Any?): CompositeTransformResult<FirStatement> {
|
override fun <T> transformConstExpression(constExpression: FirConstExpression<T>, data: Any?): CompositeTransformResult<FirStatement> {
|
||||||
val expectedType = data as? FirTypeRef
|
val expectedType = data as FirTypeRef?
|
||||||
|
|
||||||
val kind = constExpression.kind
|
val kind = constExpression.kind
|
||||||
if (expectedType is FirImplicitTypeRef || expectedType == null ||
|
if (expectedType == null || expectedType is FirImplicitTypeRef || expectedType == null ||
|
||||||
kind == IrConstKind.Null || kind == IrConstKind.Boolean || kind == IrConstKind.Char
|
kind == IrConstKind.Null || kind == IrConstKind.Boolean || kind == IrConstKind.Char
|
||||||
) {
|
) {
|
||||||
val symbol = when (kind) {
|
val symbol = when (kind) {
|
||||||
@@ -424,7 +512,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
|||||||
|
|
||||||
override fun transformExpression(expression: FirExpression, data: Any?): CompositeTransformResult<FirStatement> {
|
override fun transformExpression(expression: FirExpression, data: Any?): CompositeTransformResult<FirStatement> {
|
||||||
if (expression.resultType is FirImplicitTypeRef) {
|
if (expression.resultType is FirImplicitTypeRef) {
|
||||||
val type = FirErrorTypeRefImpl(session, expression.psi, "Type calculating for ${expression.render()} is not supported")
|
val type = FirErrorTypeRefImpl(session, expression.psi, "Type calculating for ${expression::class} is not supported")
|
||||||
expression.resultType = type
|
expression.resultType = type
|
||||||
}
|
}
|
||||||
return super.transformExpression(expression, data)
|
return super.transformExpression(expression, data)
|
||||||
@@ -568,3 +656,16 @@ inline fun <reified T : FirElement> ConeSymbol.firSafeNullable(): T? {
|
|||||||
interface ReturnTypeCalculator {
|
interface ReturnTypeCalculator {
|
||||||
fun tryCalculateReturnType(declaration: FirTypedDeclaration): FirResolvedTypeRef
|
fun tryCalculateReturnType(declaration: FirTypedDeclaration): FirResolvedTypeRef
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private object StoreNameReference : FirTransformer<FirNamedReference>() {
|
||||||
|
override fun <E : FirElement> transformElement(element: E, data: FirNamedReference): CompositeTransformResult<E> {
|
||||||
|
return element.compose()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transformNamedReference(
|
||||||
|
namedReference: FirNamedReference,
|
||||||
|
data: FirNamedReference
|
||||||
|
): CompositeTransformResult<FirNamedReference> {
|
||||||
|
return data.compose()
|
||||||
|
}
|
||||||
|
}
|
||||||
+86
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.transformers
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.copy
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.substitution.substituteOrNull
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeProjectionWithVariance
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.FirTypeProjectionWithVarianceImpl
|
||||||
|
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
||||||
|
import org.jetbrains.kotlin.fir.visitors.compose
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
|
||||||
|
class FirCallCompleterTransformer(
|
||||||
|
val session: FirSession,
|
||||||
|
private val finalSubstitutor: ConeSubstitutor,
|
||||||
|
private val typeCalculator: ReturnTypeCalculator
|
||||||
|
) : FirAbstractTreeTransformer() {
|
||||||
|
|
||||||
|
|
||||||
|
override fun transformFunctionCall(functionCall: FirFunctionCall, data: Nothing?): CompositeTransformResult<FirStatement> {
|
||||||
|
val calleeReference = functionCall.calleeReference as? FirNamedReferenceWithCandidate ?: return functionCall.compose()
|
||||||
|
val functionCall = functionCall.transformChildren(this, data) as FirFunctionCall
|
||||||
|
|
||||||
|
val subCandidate = calleeReference.candidate
|
||||||
|
val declaration = subCandidate.symbol.firUnsafe<FirCallableMemberDeclaration>()
|
||||||
|
val newTypeParameters = declaration.typeParameters.map { ConeTypeParameterTypeImpl(it.symbol, false) }
|
||||||
|
.map { subCandidate.substitutor.substituteOrSelf(it) }
|
||||||
|
.map { finalSubstitutor.substituteOrSelf(it) }
|
||||||
|
.mapIndexed { index, type ->
|
||||||
|
when (val argument = functionCall.typeArguments.getOrNull(index)) {
|
||||||
|
is FirTypeProjectionWithVariance -> {
|
||||||
|
val typeRef = argument.typeRef as FirResolvedTypeRef
|
||||||
|
FirTypeProjectionWithVarianceImpl(
|
||||||
|
session,
|
||||||
|
argument.psi,
|
||||||
|
argument.variance,
|
||||||
|
typeRef.withReplacedConeType(session, type)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
FirTypeProjectionWithVarianceImpl(
|
||||||
|
session,
|
||||||
|
argument?.psi,
|
||||||
|
Variance.INVARIANT,
|
||||||
|
FirResolvedTypeRefImpl(session, null, type, false, emptyList())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val typeRef = typeCalculator.tryCalculateReturnType(declaration)
|
||||||
|
|
||||||
|
val initialType = subCandidate.substitutor.substituteOrNull(typeRef.type)
|
||||||
|
val finalType = finalSubstitutor.substituteOrNull(initialType)
|
||||||
|
|
||||||
|
val resultType = typeRef.withReplacedConeType(session, finalType)
|
||||||
|
|
||||||
|
return functionCall.copy(
|
||||||
|
resultType = resultType,
|
||||||
|
typeArguments = newTypeParameters,
|
||||||
|
calleeReference = FirResolvedCallableReferenceImpl(
|
||||||
|
calleeReference.session,
|
||||||
|
calleeReference.psi,
|
||||||
|
calleeReference.name,
|
||||||
|
calleeReference.callableSymbol
|
||||||
|
)
|
||||||
|
).compose()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+1
-1
@@ -52,7 +52,7 @@ abstract class FirAbstractSimpleImportingScope(session: FirSession) : FirAbstrac
|
|||||||
if (imports.isEmpty()) return ProcessorAction.NEXT
|
if (imports.isEmpty()) return ProcessorAction.NEXT
|
||||||
|
|
||||||
for (import in imports) {
|
for (import in imports) {
|
||||||
if (processCallables(import, name, token, processor).stop()) {
|
if (processCallables(import, import.importedName!!, token, processor).stop()) {
|
||||||
return ProcessorAction.STOP
|
return ProcessorAction.STOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-56
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.declarations.FirNamedFunction
|
|||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirMemberFunctionImpl
|
import org.jetbrains.kotlin.fir.declarations.impl.FirMemberFunctionImpl
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
|
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorWithJump
|
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorWithJump
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
|
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
@@ -20,72 +21,18 @@ import org.jetbrains.kotlin.fir.symbols.*
|
|||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeAbbreviatedTypeImpl
|
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
|
||||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
class FirClassSubstitutionScope(
|
class FirClassSubstitutionScope(
|
||||||
private val session: FirSession,
|
private val session: FirSession,
|
||||||
private val useSiteScope: FirScope,
|
private val useSiteScope: FirScope,
|
||||||
private val substitution: Map<ConeTypeParameterSymbol, ConeKotlinType>
|
substitution: Map<ConeTypeParameterSymbol, ConeKotlinType>
|
||||||
) : FirScope {
|
) : FirScope {
|
||||||
|
|
||||||
private val fakeOverrides = mutableMapOf<ConeCallableSymbol, ConeCallableSymbol>()
|
private val fakeOverrides = mutableMapOf<ConeCallableSymbol, ConeCallableSymbol>()
|
||||||
|
|
||||||
private fun wrapProjection(old: ConeKotlinTypeProjection, newType: ConeKotlinType): ConeKotlinTypeProjection {
|
private val substitutor = ConeSubstitutorByMap(substitution)
|
||||||
return when (old) {
|
|
||||||
is ConeStarProjection -> old
|
|
||||||
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(newType)
|
|
||||||
is ConeKotlinTypeProjectionOut -> ConeKotlinTypeProjectionOut(newType)
|
|
||||||
is ConeKotlinType -> newType
|
|
||||||
else -> old
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun ConeKotlinType.substitute(): ConeKotlinType? {
|
|
||||||
if (this is ConeTypeParameterType) return substitution[lookupTag]
|
|
||||||
|
|
||||||
val newArguments by lazy { arrayOfNulls<ConeKotlinTypeProjection>(typeArguments.size) }
|
|
||||||
var initialized = false
|
|
||||||
for ((index, typeArgument) in this.typeArguments.withIndex()) {
|
|
||||||
val type = (typeArgument as? ConeTypedProjection)?.type ?: continue
|
|
||||||
val newType = type.substitute()
|
|
||||||
if (newType != null) {
|
|
||||||
initialized = true
|
|
||||||
newArguments[index] = wrapProjection(typeArgument, newType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initialized) {
|
|
||||||
for ((index, typeArgument) in this.typeArguments.withIndex()) {
|
|
||||||
if (newArguments[index] == null) {
|
|
||||||
newArguments[index] = typeArgument
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
return when (this) {
|
|
||||||
is ConeKotlinErrorType -> error("Trying to substitute arguments for error type")
|
|
||||||
is ConeTypeParameterType -> error("Trying to substitute arguments for type parameter")
|
|
||||||
is ConeClassTypeImpl -> ConeClassTypeImpl(
|
|
||||||
lookupTag,
|
|
||||||
newArguments as Array<ConeKotlinTypeProjection>,
|
|
||||||
nullability.isNullable
|
|
||||||
)
|
|
||||||
is ConeAbbreviatedTypeImpl -> ConeAbbreviatedTypeImpl(
|
|
||||||
abbreviationLookupTag,
|
|
||||||
newArguments as Array<ConeKotlinTypeProjection>,
|
|
||||||
nullability.isNullable
|
|
||||||
)
|
|
||||||
is ConeFunctionType -> TODO("Substitute function type properly")
|
|
||||||
is ConeClassLikeType -> error("Unknown class-like type to substitute: $this, ${this::class}")
|
|
||||||
is ConeFlexibleType -> error("Trying to substitute arguments for flexible type")
|
|
||||||
is ConeCapturedType -> error("Not supported")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun processFunctionsByName(name: Name, processor: (ConeFunctionSymbol) -> ProcessorAction): ProcessorAction {
|
override fun processFunctionsByName(name: Name, processor: (ConeFunctionSymbol) -> ProcessorAction): ProcessorAction {
|
||||||
useSiteScope.processFunctionsByName(name) process@{ original ->
|
useSiteScope.processFunctionsByName(name) process@{ original ->
|
||||||
@@ -104,6 +51,10 @@ class FirClassSubstitutionScope(
|
|||||||
|
|
||||||
private val typeCalculator by lazy { ReturnTypeCalculatorWithJump(session) }
|
private val typeCalculator by lazy { ReturnTypeCalculatorWithJump(session) }
|
||||||
|
|
||||||
|
private fun ConeKotlinType.substitute(): ConeKotlinType? {
|
||||||
|
return substitutor.substituteOrNull(this)
|
||||||
|
}
|
||||||
|
|
||||||
private fun createFakeOverride(original: ConeFunctionSymbol): FirFunctionSymbol {
|
private fun createFakeOverride(original: ConeFunctionSymbol): FirFunctionSymbol {
|
||||||
|
|
||||||
val member = original.firUnsafe<FirFunction>()
|
val member = original.firUnsafe<FirFunction>()
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ import org.jetbrains.kotlin.descriptors.Modality
|
|||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.expandedConeType
|
import org.jetbrains.kotlin.fir.declarations.expandedConeType
|
||||||
import org.jetbrains.kotlin.fir.declarations.superConeTypes
|
import org.jetbrains.kotlin.fir.declarations.superConeTypes
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.ConeTypeVariableTypeConstructor
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.constructType
|
||||||
import org.jetbrains.kotlin.fir.resolve.directExpansionType
|
import org.jetbrains.kotlin.fir.resolve.directExpansionType
|
||||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
import org.jetbrains.kotlin.fir.resolve.withArguments
|
import org.jetbrains.kotlin.fir.resolve.withArguments
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
import org.jetbrains.kotlin.fir.service
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.*
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||||
@@ -47,9 +47,12 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
|
|||||||
assert(this is ConeKotlinType)
|
assert(this is ConeKotlinType)
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is ConeAbbreviatedType -> directExpansionType(session)
|
is ConeAbbreviatedType -> directExpansionType(session)
|
||||||
|
?: ConeClassErrorType("no expansion for type-alias: ${this.abbreviationLookupTag.classId}")
|
||||||
is ConeCapturedType -> this
|
is ConeCapturedType -> this
|
||||||
is ConeLookupTagBasedType -> this
|
is ConeLookupTagBasedType -> this
|
||||||
else -> null
|
is ConeDefinitelyNotNullType -> this
|
||||||
|
is ConeFlexibleType -> null
|
||||||
|
else -> error("Unknown simpleType: $this")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,6 +133,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
|
|||||||
override fun SimpleTypeMarker.typeConstructor(): TypeConstructorMarker {
|
override fun SimpleTypeMarker.typeConstructor(): TypeConstructorMarker {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is ConeCapturedType -> constructor
|
is ConeCapturedType -> constructor
|
||||||
|
is ConeTypeVariableType -> this.lookupTag as ConeTypeVariableTypeConstructor // TODO: WTF
|
||||||
is ConeLookupTagBasedType -> this.lookupTag.toSymbol(session) ?: ErrorTypeConstructor("Unresolved: ${this.lookupTag}")
|
is ConeLookupTagBasedType -> this.lookupTag.toSymbol(session) ?: ErrorTypeConstructor("Unresolved: ${this.lookupTag}")
|
||||||
else -> error("?: ${this}")
|
else -> error("?: ${this}")
|
||||||
}
|
}
|
||||||
@@ -145,7 +149,8 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
|
|||||||
override fun SimpleTypeMarker.getArgument(index: Int): TypeArgumentMarker {
|
override fun SimpleTypeMarker.getArgument(index: Int): TypeArgumentMarker {
|
||||||
require(this is ConeKotlinType)
|
require(this is ConeKotlinType)
|
||||||
|
|
||||||
return this.typeArguments[index]
|
return this.typeArguments.getOrNull(index)
|
||||||
|
?: StandardClassIds.Any(session.service()).constructType(emptyArray(), false) // TODO wtf
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun KotlinTypeMarker.asTypeArgument(): TypeArgumentMarker {
|
override fun KotlinTypeMarker.asTypeArgument(): TypeArgumentMarker {
|
||||||
@@ -184,7 +189,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
|
|||||||
override fun TypeConstructorMarker.parametersCount(): Int {
|
override fun TypeConstructorMarker.parametersCount(): Int {
|
||||||
//require(this is ConeSymbol)
|
//require(this is ConeSymbol)
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is ConeTypeParameterSymbol, is ConeCapturedTypeConstructor, is ErrorTypeConstructor -> 0
|
is ConeTypeParameterSymbol, is ConeCapturedTypeConstructor, is ErrorTypeConstructor, is ConeTypeVariableTypeConstructor -> 0
|
||||||
is FirClassSymbol -> fir.typeParameters.size
|
is FirClassSymbol -> fir.typeParameters.size
|
||||||
is FirTypeAliasSymbol -> fir.typeParameters.size
|
is FirTypeAliasSymbol -> fir.typeParameters.size
|
||||||
else -> error("?!:10")
|
else -> error("?!:10")
|
||||||
@@ -205,7 +210,8 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
|
|||||||
if (this is ErrorTypeConstructor) return emptyList()
|
if (this is ErrorTypeConstructor) return emptyList()
|
||||||
//require(this is ConeSymbol)
|
//require(this is ConeSymbol)
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is ConeTypeParameterSymbol -> emptyList()
|
is ConeTypeVariableTypeConstructor -> emptyList()
|
||||||
|
is FirTypeParameterSymbol -> fir.bounds.map { it.coneTypeUnsafe() }
|
||||||
is FirClassSymbol -> fir.superConeTypes
|
is FirClassSymbol -> fir.superConeTypes
|
||||||
is FirTypeAliasSymbol -> listOfNotNull(fir.expandedConeType)
|
is FirTypeAliasSymbol -> listOfNotNull(fir.expandedConeType)
|
||||||
is ConeCapturedTypeConstructor -> supertypes!!
|
is ConeCapturedTypeConstructor -> supertypes!!
|
||||||
@@ -263,7 +269,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun captureFromArguments(type: SimpleTypeMarker, status: CaptureStatus): SimpleTypeMarker? {
|
override fun captureFromArguments(type: SimpleTypeMarker, status: CaptureStatus): SimpleTypeMarker? {
|
||||||
require(type is ConeLookupTagBasedType) { ":( $type" }
|
require(type is ConeKotlinType)
|
||||||
val typeConstructor = type.typeConstructor()
|
val typeConstructor = type.typeConstructor()
|
||||||
if (type.argumentsCount() != typeConstructor.parametersCount()) return null
|
if (type.argumentsCount() != typeConstructor.parametersCount()) return null
|
||||||
if (type.asArgumentList().all(this) { !it.isStarProjection() && it.getVariance() == TypeVariance.INV }) return null
|
if (type.asArgumentList().all(this) { !it.isStarProjection() && it.getVariance() == TypeVariance.INV }) return null
|
||||||
@@ -314,7 +320,6 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun TypeConstructorMarker.isAnyConstructor(): Boolean {
|
override fun TypeConstructorMarker.isAnyConstructor(): Boolean {
|
||||||
assert(this is ConeSymbol)
|
|
||||||
return this is ConeClassLikeSymbol && classId.asString() == "kotlin/Any"
|
return this is ConeClassLikeSymbol && classId.asString() == "kotlin/Any"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,36 +337,39 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
|
|||||||
override fun SimpleTypeMarker.isSingleClassifierType(): Boolean {
|
override fun SimpleTypeMarker.isSingleClassifierType(): Boolean {
|
||||||
if (isError()) return false
|
if (isError()) return false
|
||||||
if (this is ConeCapturedType) return true
|
if (this is ConeCapturedType) return true
|
||||||
|
if (this is ConeTypeVariableType) return false
|
||||||
require(this is ConeLookupTagBasedType)
|
require(this is ConeLookupTagBasedType)
|
||||||
val symbol = this.lookupTag.toSymbol(session)
|
val symbol = this.lookupTag.toSymbol(session)
|
||||||
return symbol is FirClassSymbol ||
|
return symbol is FirClassSymbol ||
|
||||||
symbol is FirTypeParameterSymbol
|
symbol is FirTypeParameterSymbol
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker {
|
|
||||||
TODO("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun intersectTypes(types: List<SimpleTypeMarker>): SimpleTypeMarker {
|
|
||||||
TODO("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
|
|
||||||
TODO("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun SimpleTypeMarker.isStubType(): Boolean {
|
|
||||||
TODO("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun captureFromExpression(type: KotlinTypeMarker): KotlinTypeMarker? {
|
override fun captureFromExpression(type: KotlinTypeMarker): KotlinTypeMarker? {
|
||||||
TODO("not implemented")
|
TODO("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun SimpleTypeMarker.isPrimitiveType(): Boolean {
|
override fun SimpleTypeMarker.isPrimitiveType(): Boolean {
|
||||||
TODO("not implemented")
|
return false //TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun SimpleTypeMarker.isStubType(): Boolean {
|
||||||
|
return false // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun intersectTypes(types: List<SimpleTypeMarker>): SimpleTypeMarker {
|
||||||
|
return types.first() // TODO: proper implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker {
|
||||||
|
return types.first() // TODO: proper implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
|
||||||
|
return when (type) {
|
||||||
|
is ConeAbbreviatedType -> prepareType(type.directExpansionType(session) ?: ConeClassErrorType("unresolved"))
|
||||||
|
else -> type
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConeTypeCheckerContext(override val isErrorTypeEqualsToAnything: Boolean, override val session: FirSession) :
|
class ConeTypeCheckerContext(override val isErrorTypeEqualsToAnything: Boolean, override val session: FirSession) :
|
||||||
@@ -379,16 +387,11 @@ class ConeTypeCheckerContext(override val isErrorTypeEqualsToAnything: Boolean,
|
|||||||
return a == b
|
return a == b
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker {
|
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
|
||||||
return types.first() // TODO: proper implementation
|
return super<ConeTypeContext>.prepareType(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean
|
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean
|
||||||
get() = false
|
get() = false
|
||||||
|
|
||||||
|
|
||||||
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
|
|
||||||
return super<ConeTypeContext>.prepareType(type)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ FILE: access.kt
|
|||||||
^plus String()
|
^plus String()
|
||||||
}
|
}
|
||||||
|
|
||||||
public final fun R|Foo|.check(): <ERROR TYPE REF: Ambiguity: plus, [kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus]> {
|
public final fun R|Foo|.check(): R|kotlin/String| {
|
||||||
^check R|/Foo.abc|().<Ambiguity: plus, [kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus]>#(R|/Bar.bar|())
|
^check R|/Foo.abc|().R|/Bar.plus|(R|/Bar.bar|())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
class A
|
||||||
|
open class B
|
||||||
|
class C : B
|
||||||
|
|
||||||
|
|
||||||
|
fun bar(a: A) = a
|
||||||
|
fun bar(b: B) = b
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val a = A()
|
||||||
|
val b = B()
|
||||||
|
val c = C()
|
||||||
|
val ra = bar(a)
|
||||||
|
val rb = bar(b)
|
||||||
|
val rc = bar(c)
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
FILE: checkArguments.kt
|
||||||
|
public final class A : R|kotlin/Any| {
|
||||||
|
public constructor(): super<R|kotlin/Any|>()
|
||||||
|
|
||||||
|
}
|
||||||
|
public open class B : R|kotlin/Any| {
|
||||||
|
public constructor(): super<R|kotlin/Any|>()
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class C : R|B|, R|kotlin/Any| {
|
||||||
|
public constructor(): super<R|kotlin/Any|>()
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun bar(a: R|A|): R|A| {
|
||||||
|
^bar R|<local>/a|
|
||||||
|
}
|
||||||
|
public final fun bar(b: R|B|): R|B| {
|
||||||
|
^bar R|<local>/b|
|
||||||
|
}
|
||||||
|
public final fun foo(): R|kotlin/Unit| {
|
||||||
|
lval a: R|A| = R|/A.A|()
|
||||||
|
lval b: R|B| = R|/B.B|()
|
||||||
|
lval c: R|C| = R|/C.C|()
|
||||||
|
lval ra: R|A| = R|/bar|(R|<local>/a|)
|
||||||
|
lval rb: R|B| = R|/bar|(R|<local>/b|)
|
||||||
|
lval rc: R|B| = R|/bar|(R|<local>/c|)
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fun <T> id(t: T) = t
|
||||||
|
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val a = id("string")
|
||||||
|
val b = id(null)
|
||||||
|
val c = id(id(a))
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
FILE: id.kt
|
||||||
|
public final fun <T> id(t: R|T|): R|T| {
|
||||||
|
^id R|<local>/t|
|
||||||
|
}
|
||||||
|
public final fun main(): R|kotlin/Unit| {
|
||||||
|
lval a: R|kotlin/String| = R|/id|<R|kotlin/String|>(String(string))
|
||||||
|
lval b: R|kotlin/Nothing|? = R|/id|<R|kotlin/Nothing|?>(Null(null))
|
||||||
|
lval c: R|kotlin/String| = R|/id|<R|kotlin/String|>(R|/id|<R|kotlin/String|>(R|<local>/a|))
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
interface Foo
|
||||||
|
class FooImpl : Foo
|
||||||
|
class Bar
|
||||||
|
|
||||||
|
fun <T : Foo> foo(t: T) = t
|
||||||
|
|
||||||
|
|
||||||
|
fun main(fooImpl: FooImpl, bar: Bar) {
|
||||||
|
val a = foo(fooImpl)
|
||||||
|
val b = foo(bar)
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
FILE: typeParameters.kt
|
||||||
|
public abstract interface Foo : R|kotlin/Any| {
|
||||||
|
}
|
||||||
|
public final class FooImpl : R|Foo| {
|
||||||
|
public constructor(): R|FooImpl| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class Bar : R|kotlin/Any| {
|
||||||
|
public constructor(): R|Bar| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun <T : R|Foo|> foo(t: R|T|): R|T| {
|
||||||
|
^foo R|<local>/t|
|
||||||
|
}
|
||||||
|
public final fun main(fooImpl: R|FooImpl|, bar: R|Bar|): R|kotlin/Unit| {
|
||||||
|
lval a: R|FooImpl| = R|/foo|<R|FooImpl|>(R|<local>/fooImpl|)
|
||||||
|
lval b: <ERROR TYPE REF: Inapplicable(INAPPLICABLE): [/foo]> = <Inapplicable(INAPPLICABLE): [/foo]>#(R|<local>/bar|)
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
interface Foo
|
||||||
|
class FooImpl : Foo
|
||||||
|
class FooBarImpl : Foo
|
||||||
|
|
||||||
|
fun <T : Foo> foo(t: T) = t
|
||||||
|
|
||||||
|
|
||||||
|
fun main(fooImpl: FooImpl, fooBarImpl: FooBarImpl) {
|
||||||
|
val a = foo<FooImpl>(fooBarImpl)
|
||||||
|
val b = foo<Foo>(fooImpl)
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
FILE: typeParameters2.kt
|
||||||
|
public abstract interface Foo : R|kotlin/Any| {
|
||||||
|
}
|
||||||
|
public final class FooImpl : R|Foo| {
|
||||||
|
public constructor(): R|FooImpl| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class FooBarImpl : R|Foo| {
|
||||||
|
public constructor(): R|FooBarImpl| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun <T : R|Foo|> foo(t: R|T|): R|T| {
|
||||||
|
^foo R|<local>/t|
|
||||||
|
}
|
||||||
|
public final fun main(fooImpl: R|FooImpl|, fooBarImpl: R|FooBarImpl|): R|kotlin/Unit| {
|
||||||
|
lval a: <ERROR TYPE REF: Inapplicable(INAPPLICABLE): [/foo]> = <Inapplicable(INAPPLICABLE): [/foo]>#<R|FooImpl|>(R|<local>/fooBarImpl|)
|
||||||
|
lval b: R|Foo| = R|/foo|<R|Foo|>(R|<local>/fooImpl|)
|
||||||
|
}
|
||||||
@@ -70,7 +70,7 @@ FILE: enums.kt
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final val g: R|kotlin/Double| = <Unresolved name: G>#.<Unresolved name: times>#(R|/Planet.m|).<Unresolved name: div>#(R|/Planet.r|.<Ambiguity: times, [kotlin/Double.times, kotlin/Double.times, kotlin/Double.times, kotlin/Double.times, kotlin/Double.times, kotlin/Double.times]>#(R|/Planet.r|))
|
public final val g: R|kotlin/Double| = <Unresolved name: G>#.<Unresolved name: times>#(R|/Planet.m|).<Unresolved name: div>#(R|/Planet.r|.R|kotlin/Double.times|(R|/Planet.r|))
|
||||||
public get(): R|kotlin/Double|
|
public get(): R|kotlin/Double|
|
||||||
|
|
||||||
public abstract fun sayHello(): R|kotlin/Unit|
|
public abstract fun sayHello(): R|kotlin/Unit|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun main() {
|
||||||
|
println("Hello, world!")
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
FILE: helloWorld.kt
|
||||||
|
public final fun main(): R|kotlin/Unit| {
|
||||||
|
R|kotlin/io/println|(String(Hello, world!))
|
||||||
|
}
|
||||||
+35
@@ -159,6 +159,11 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/resolve/expresssions"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/resolve/expresssions"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("checkArguments.kt")
|
||||||
|
public void testCheckArguments() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/checkArguments.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("constructor.kt")
|
@TestMetadata("constructor.kt")
|
||||||
public void testConstructor() throws Exception {
|
public void testConstructor() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/constructor.kt");
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/constructor.kt");
|
||||||
@@ -189,6 +194,36 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
|
|||||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/when.kt");
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/when.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/fir/resolve/testData/resolve/expresssions/inference")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Inference extends AbstractFirResolveTestCase {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInInference() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(),
|
||||||
|
new File("compiler/fir/resolve/testData/resolve/expresssions/inference"),
|
||||||
|
Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("id.kt")
|
||||||
|
public void testId() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/inference/id.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeParameters.kt")
|
||||||
|
public void testTypeParameters() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/inference/typeParameters.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeParameters2.kt")
|
||||||
|
public void testTypeParameters2() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/inference/typeParameters2.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/fir/resolve/testData/resolve/expresssions/invoke")
|
@TestMetadata("compiler/fir/resolve/testData/resolve/expresssions/invoke")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Generated
+5
@@ -39,6 +39,11 @@ public class FirResolveTestCaseWithStdlibGenerated extends AbstractFirResolveTes
|
|||||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/functionX.kt");
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/functionX.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("helloWorld.kt")
|
||||||
|
public void testHelloWorld() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/helloWorld.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("reflectionClass.kt")
|
@TestMetadata("reflectionClass.kt")
|
||||||
public void testReflectionClass() throws Exception {
|
public void testReflectionClass() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/reflectionClass.kt");
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/reflectionClass.kt");
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ fun FirElement.render(): String = buildString { this@render.accept(FirRenderer(t
|
|||||||
|
|
||||||
fun ConeKotlinType.render(): String {
|
fun ConeKotlinType.render(): String {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
|
is ConeTypeVariableType -> "TypeVariable(${this.lookupTag.name})"
|
||||||
|
is ConeDefinitelyNotNullType -> "${original.render()}!"
|
||||||
is ConeKotlinErrorType -> "error: $reason"
|
is ConeKotlinErrorType -> "error: $reason"
|
||||||
is ConeClassErrorType -> "class error: $reason"
|
is ConeClassErrorType -> "class error: $reason"
|
||||||
is ConeCapturedType -> "captured type: lowerType = ${lowerType?.render()}"
|
is ConeCapturedType -> "captured type: lowerType = ${lowerType?.render()}"
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.fir.FirSession
|
|||||||
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
class FirResolvedCallableReferenceImpl(
|
open class FirResolvedCallableReferenceImpl(
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
psi: PsiElement?,
|
psi: PsiElement?,
|
||||||
override val name: Name,
|
override val name: Name,
|
||||||
|
|||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.types.impl
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||||
|
|
||||||
|
object FirTypePlaceholderProjection : FirTypeProjection {
|
||||||
|
override val psi: PsiElement?
|
||||||
|
get() = null // TODO
|
||||||
|
override val session: FirSession
|
||||||
|
get() = error("ahahahhahah")
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user