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
|
||||
}
|
||||
|
||||
class ConeCapturedTypeConstructor(val projection: ConeKotlinTypeProjection) : TypeConstructorMarker {
|
||||
var supertypes: List<ConeKotlinType>? = null
|
||||
class ConeCapturedTypeConstructor(val projection: ConeKotlinTypeProjection, var supertypes: List<ConeKotlinType>? = null) :
|
||||
TypeConstructorMarker {
|
||||
|
||||
}
|
||||
|
||||
class ConeCapturedType(
|
||||
@@ -143,4 +144,18 @@ class ConeCapturedType(
|
||||
|
||||
override val typeArguments: Array<out ConeKotlinTypeProjection>
|
||||
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)
|
||||
}
|
||||
is ConeCapturedType -> TODO()
|
||||
is ConeDefinitelyNotNullType -> TODO()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +103,7 @@ fun FirReference.toSymbol(declarationStorage: Fir2IrDeclarationStorage): IrSymbo
|
||||
|
||||
fun FirNamedReference.toSymbol(declarationStorage: Fir2IrDeclarationStorage): IrSymbol? {
|
||||
if (this is FirResolvedCallableReference) {
|
||||
when (val callableSymbol = this.callableSymbol) {
|
||||
when (val callableSymbol = this.coneSymbol) {
|
||||
is FirFunctionSymbol -> return callableSymbol.toFunctionSymbol(declarationStorage)
|
||||
is FirPropertySymbol -> return callableSymbol.toPropertySymbol(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) {
|
||||
is ConeClassLikeLookupTag -> toSymbol(useSiteSession)
|
||||
is ConeTypeParameterSymbol -> this
|
||||
else -> error("sealed")
|
||||
else -> error("sealed ${this::class}")
|
||||
}
|
||||
|
||||
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 ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable) 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.defaultType
|
||||
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.scopes.FirPosition
|
||||
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.types.*
|
||||
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.utils.addToStdlib.cast
|
||||
|
||||
|
||||
|
||||
|
||||
class CallInfo(
|
||||
val variableAccess: Boolean,
|
||||
val callKind: CallKind,
|
||||
|
||||
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(
|
||||
val symbol: ConeSymbol,
|
||||
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 {
|
||||
abstract fun sequence(): List<ResolutionStage>
|
||||
|
||||
object Function : CallKind() {
|
||||
override fun sequence(): List<ResolutionStage> {
|
||||
return functionCallResolutionSequence()
|
||||
@@ -177,19 +195,31 @@ abstract class TowerDataConsumer {
|
||||
fun createVariableConsumer(
|
||||
session: FirSession,
|
||||
name: Name,
|
||||
explicitReceiver: FirExpression?,
|
||||
explicitReceiverType: FirTypeRef?
|
||||
callInfo: CallInfo,
|
||||
inferenceComponents: InferenceComponents
|
||||
): TowerDataConsumer {
|
||||
return createSimpleConsumer(session, name, TowerScopeLevel.Token.Properties, explicitReceiver, explicitReceiverType, CallKind.VariableAccess)
|
||||
return createSimpleConsumer(
|
||||
session,
|
||||
name,
|
||||
TowerScopeLevel.Token.Properties,
|
||||
callInfo,
|
||||
inferenceComponents
|
||||
)
|
||||
}
|
||||
|
||||
fun createFunctionConsumer(
|
||||
session: FirSession,
|
||||
name: Name,
|
||||
explicitReceiver: FirExpression?,
|
||||
explicitReceiverType: FirTypeRef?
|
||||
callInfo: CallInfo,
|
||||
inferenceComponents: InferenceComponents
|
||||
): 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,
|
||||
name: Name,
|
||||
token: TowerScopeLevel.Token<*>,
|
||||
explicitReceiver: FirExpression?,
|
||||
explicitReceiverType: FirTypeRef?,
|
||||
callKind: CallKind
|
||||
callInfo: CallInfo,
|
||||
inferenceComponents: InferenceComponents
|
||||
): TowerDataConsumer {
|
||||
return if (explicitReceiver != null) {
|
||||
ExplicitReceiverTowerDataConsumer(session, name, token, object : ReceiverValueWithPossibleTypes {
|
||||
override val type: ConeKotlinType
|
||||
get() = explicitReceiverType?.coneTypeSafe()
|
||||
?: ConeKotlinErrorType("No type calculated for: ${explicitReceiver.renderWithType()}") // TODO: assert here
|
||||
}, callKind)
|
||||
val factory = CandidateFactory(inferenceComponents, callInfo)
|
||||
return if (callInfo.explicitReceiver != null) {
|
||||
ExplicitReceiverTowerDataConsumer(
|
||||
session,
|
||||
name,
|
||||
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 {
|
||||
NoExplicitReceiverTowerDataConsumer(session, name, token, callKind)
|
||||
NoExplicitReceiverTowerDataConsumer(session, name, token, factory)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +253,7 @@ class ExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
||||
val name: Name,
|
||||
val token: TowerScopeLevel.Token<T>,
|
||||
val explicitReceiver: ReceiverValueWithPossibleTypes,
|
||||
val callKind: CallKind
|
||||
val candidateFactory: CandidateFactory
|
||||
) : TowerDataConsumer() {
|
||||
|
||||
var groupId = 0
|
||||
@@ -237,7 +273,14 @@ class ExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
||||
null,
|
||||
object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -249,7 +292,14 @@ class ExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
||||
explicitReceiver,
|
||||
object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -263,7 +313,7 @@ class NoExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
||||
val session: FirSession,
|
||||
val name: Name,
|
||||
val token: TowerScopeLevel.Token<T>,
|
||||
val callKind: CallKind
|
||||
val candidateFactory: CandidateFactory
|
||||
) : TowerDataConsumer() {
|
||||
var groupId = 0
|
||||
|
||||
@@ -284,7 +334,10 @@ class NoExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
||||
null,
|
||||
object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -350,7 +403,7 @@ class CandidateCollector(val callInfo: CallInfo) {
|
||||
val sink = CheckerSinkImpl()
|
||||
|
||||
|
||||
candidate.callKind.sequence().forEach {
|
||||
callInfo.callKind.sequence().forEach {
|
||||
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()
|
||||
val result = mutableListOf<ConeSymbol>()
|
||||
val result = mutableListOf<Candidate>()
|
||||
var bestGroup = groupNumbers.first()
|
||||
for ((index, candidate) in candidates.withIndex()) {
|
||||
val group = groupNumbers[index]
|
||||
@@ -385,7 +438,7 @@ class CandidateCollector(val callInfo: CallInfo) {
|
||||
result.clear()
|
||||
}
|
||||
if (bestGroup == group) {
|
||||
result.add(candidate.symbol)
|
||||
result.add(candidate)
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
|
||||
sealed class ResolutionStage {
|
||||
abstract class ResolutionStage {
|
||||
abstract fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo)
|
||||
}
|
||||
|
||||
sealed class CheckerStage : ResolutionStage()
|
||||
abstract class CheckerStage : ResolutionStage()
|
||||
|
||||
internal object MapArguments : ResolutionStage() {
|
||||
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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() =
|
||||
listOf<ResolutionStage>(MapArguments)
|
||||
listOf<ResolutionStage>(MapArguments, CreateFreshTypeVariableSubstitutorStage, CheckArguments)
|
||||
|
||||
|
||||
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.expressions.*
|
||||
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.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.CallInfo
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.CallResolver
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.createFunctionConsumer
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.createVariableConsumer
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
||||
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.symbols.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
||||
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.types.impl.*
|
||||
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.compose
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
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
|
||||
|
||||
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.conversionTypeRef.withReplacedConeType(
|
||||
session,
|
||||
resolved.conversionTypeRef.coneTypeUnsafe<ConeKotlinType>().withNullability(ConeNullability.NULLABLE)
|
||||
resolved.conversionTypeRef.coneTypeUnsafe().withNullability(ConeNullability.NULLABLE)
|
||||
)
|
||||
}
|
||||
else -> error("Unknown type operator")
|
||||
@@ -143,16 +141,36 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
val jump = ReturnTypeCalculatorWithJump(session)
|
||||
|
||||
private fun <T> storeTypeFromCallee(access: T) where T : FirQualifiedAccess, T : FirExpression {
|
||||
access.resultType =
|
||||
when (val newCallee = access.calleeReference) {
|
||||
is FirErrorNamedReference ->
|
||||
FirErrorTypeRefImpl(session, access.psi, newCallee.errorReason)
|
||||
is FirResolvedCallableReference ->
|
||||
jump.tryCalculateReturnType(newCallee.callableSymbol.firUnsafe())
|
||||
else -> return
|
||||
}
|
||||
access.resultType = typeFromCallee(access)
|
||||
}
|
||||
|
||||
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(
|
||||
qualifiedAccessExpression: FirQualifiedAccessExpression,
|
||||
data: Any?
|
||||
@@ -180,13 +198,9 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
}
|
||||
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 checkers = listOf(VariableApplicabilityChecker(callee.name))
|
||||
|
||||
val info = CallInfo(true, receiver, 0)
|
||||
val info = CallInfo(CallKind.VariableAccess, receiver, emptyList(), emptyList()) { it.resultType }
|
||||
val resolver = CallResolver(jump, session)
|
||||
resolver.callInfo = info
|
||||
resolver.scopes = (scopes + localScopes).asReversed()
|
||||
@@ -194,40 +208,44 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
val consumer = createVariableConsumer(
|
||||
session,
|
||||
callee.name,
|
||||
qualifiedAccessExpression.explicitReceiver,
|
||||
qualifiedAccessExpression.explicitReceiver?.resultType
|
||||
info, inferenceComponents
|
||||
)
|
||||
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)
|
||||
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
|
||||
|
||||
if (functionCall.calleeReference !is FirSimpleNamedReference) return functionCall.compose()
|
||||
|
||||
val name = functionCall.calleeReference.name
|
||||
|
||||
val expectedTypeRef = data as FirTypeRef?
|
||||
|
||||
val receiver = functionCall.explicitReceiver
|
||||
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)
|
||||
resolver.callInfo = info
|
||||
resolver.scopes = (scopes + localScopes).asReversed()
|
||||
|
||||
|
||||
|
||||
val consumer = createFunctionConsumer(session, name, receiver, receiver?.resultType)
|
||||
val consumer = createFunctionConsumer(session, name, info, inferenceComponents)
|
||||
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()
|
||||
//
|
||||
@@ -257,33 +275,103 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
// }
|
||||
// else -> functionCall
|
||||
// }
|
||||
val resultExpression = functionCall.transformCalleeReference(this, successCandidates)
|
||||
val nameReference = createResolvedNamedReference(
|
||||
functionCall.calleeReference,
|
||||
reducedCandidates,
|
||||
result.currentApplicability
|
||||
)
|
||||
|
||||
storeTypeFromCallee(resultExpression as FirFunctionCall)
|
||||
return resultExpression.compose()
|
||||
val resultExpression = functionCall.transformCalleeReference(StoreNameReference, nameReference) as FirFunctionCall
|
||||
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
|
||||
return when (candidates.size) {
|
||||
0 -> FirErrorNamedReference(
|
||||
return when {
|
||||
candidates.isEmpty() -> FirErrorNamedReference(
|
||||
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,
|
||||
name, candidates.single()
|
||||
)
|
||||
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> {
|
||||
if (namedReference is FirErrorNamedReference || namedReference is FirResolvedCallableReference) return namedReference.compose()
|
||||
val referents = data as? List<ConeCallableSymbol> ?: return namedReference.compose()
|
||||
return createResolvedNamedReference(namedReference, referents).compose()
|
||||
}
|
||||
// override fun transformNamedReference(namedReference: FirNamedReference, data: Any?): CompositeTransformResult<FirNamedReference> {
|
||||
// if (namedReference is FirErrorNamedReference || namedReference is FirResolvedCallableReference) return namedReference.compose()
|
||||
// val referents = data as? List<ConeCallableSymbol> ?: return namedReference.compose()
|
||||
// return createResolvedNamedReference(namedReference, referents).compose()
|
||||
// }
|
||||
|
||||
|
||||
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> {
|
||||
val expectedType = data as? FirTypeRef
|
||||
val expectedType = data as FirTypeRef?
|
||||
|
||||
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
|
||||
) {
|
||||
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> {
|
||||
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
|
||||
}
|
||||
return super.transformExpression(expression, data)
|
||||
@@ -568,3 +656,16 @@ inline fun <reified T : FirElement> ConeSymbol.firSafeNullable(): T? {
|
||||
interface ReturnTypeCalculator {
|
||||
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
|
||||
|
||||
for (import in imports) {
|
||||
if (processCallables(import, name, token, processor).stop()) {
|
||||
if (processCallables(import, import.importedName!!, token, processor).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.FirMemberFunctionImpl
|
||||
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.firUnsafe
|
||||
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.FirVariableSymbol
|
||||
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.name.Name
|
||||
|
||||
class FirClassSubstitutionScope(
|
||||
private val session: FirSession,
|
||||
private val useSiteScope: FirScope,
|
||||
private val substitution: Map<ConeTypeParameterSymbol, ConeKotlinType>
|
||||
substitution: Map<ConeTypeParameterSymbol, ConeKotlinType>
|
||||
) : FirScope {
|
||||
|
||||
private val fakeOverrides = mutableMapOf<ConeCallableSymbol, ConeCallableSymbol>()
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
private val substitutor = ConeSubstitutorByMap(substitution)
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (ConeFunctionSymbol) -> ProcessorAction): ProcessorAction {
|
||||
useSiteScope.processFunctionsByName(name) process@{ original ->
|
||||
@@ -104,6 +51,10 @@ class FirClassSubstitutionScope(
|
||||
|
||||
private val typeCalculator by lazy { ReturnTypeCalculatorWithJump(session) }
|
||||
|
||||
private fun ConeKotlinType.substitute(): ConeKotlinType? {
|
||||
return substitutor.substituteOrNull(this)
|
||||
}
|
||||
|
||||
private fun createFakeOverride(original: ConeFunctionSymbol): FirFunctionSymbol {
|
||||
|
||||
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.declarations.expandedConeType
|
||||
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.toSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.withArguments
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.symbols.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
@@ -47,9 +47,12 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
|
||||
assert(this is ConeKotlinType)
|
||||
return when (this) {
|
||||
is ConeAbbreviatedType -> directExpansionType(session)
|
||||
?: ConeClassErrorType("no expansion for type-alias: ${this.abbreviationLookupTag.classId}")
|
||||
is ConeCapturedType -> 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 {
|
||||
return when (this) {
|
||||
is ConeCapturedType -> constructor
|
||||
is ConeTypeVariableType -> this.lookupTag as ConeTypeVariableTypeConstructor // TODO: WTF
|
||||
is ConeLookupTagBasedType -> this.lookupTag.toSymbol(session) ?: ErrorTypeConstructor("Unresolved: ${this.lookupTag}")
|
||||
else -> error("?: ${this}")
|
||||
}
|
||||
@@ -145,7 +149,8 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
|
||||
override fun SimpleTypeMarker.getArgument(index: Int): TypeArgumentMarker {
|
||||
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 {
|
||||
@@ -184,7 +189,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
|
||||
override fun TypeConstructorMarker.parametersCount(): Int {
|
||||
//require(this is ConeSymbol)
|
||||
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 FirTypeAliasSymbol -> fir.typeParameters.size
|
||||
else -> error("?!:10")
|
||||
@@ -205,7 +210,8 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
|
||||
if (this is ErrorTypeConstructor) return emptyList()
|
||||
//require(this is ConeSymbol)
|
||||
return when (this) {
|
||||
is ConeTypeParameterSymbol -> emptyList()
|
||||
is ConeTypeVariableTypeConstructor -> emptyList()
|
||||
is FirTypeParameterSymbol -> fir.bounds.map { it.coneTypeUnsafe() }
|
||||
is FirClassSymbol -> fir.superConeTypes
|
||||
is FirTypeAliasSymbol -> listOfNotNull(fir.expandedConeType)
|
||||
is ConeCapturedTypeConstructor -> supertypes!!
|
||||
@@ -263,7 +269,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
|
||||
}
|
||||
|
||||
override fun captureFromArguments(type: SimpleTypeMarker, status: CaptureStatus): SimpleTypeMarker? {
|
||||
require(type is ConeLookupTagBasedType) { ":( $type" }
|
||||
require(type is ConeKotlinType)
|
||||
val typeConstructor = type.typeConstructor()
|
||||
if (type.argumentsCount() != typeConstructor.parametersCount()) 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 {
|
||||
assert(this is ConeSymbol)
|
||||
return this is ConeClassLikeSymbol && classId.asString() == "kotlin/Any"
|
||||
}
|
||||
|
||||
@@ -332,36 +337,39 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
|
||||
override fun SimpleTypeMarker.isSingleClassifierType(): Boolean {
|
||||
if (isError()) return false
|
||||
if (this is ConeCapturedType) return true
|
||||
if (this is ConeTypeVariableType) return false
|
||||
require(this is ConeLookupTagBasedType)
|
||||
val symbol = this.lookupTag.toSymbol(session)
|
||||
return symbol is FirClassSymbol ||
|
||||
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? {
|
||||
TODO("not implemented")
|
||||
}
|
||||
|
||||
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) :
|
||||
@@ -379,16 +387,11 @@ class ConeTypeCheckerContext(override val isErrorTypeEqualsToAnything: Boolean,
|
||||
return a == b
|
||||
}
|
||||
|
||||
override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker {
|
||||
return types.first() // TODO: proper implementation
|
||||
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
|
||||
return super<ConeTypeContext>.prepareType(type)
|
||||
}
|
||||
|
||||
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean
|
||||
get() = false
|
||||
|
||||
|
||||
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
|
||||
return super<ConeTypeContext>.prepareType(type)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ FILE: access.kt
|
||||
^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]> {
|
||||
^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|())
|
||||
public final fun R|Foo|.check(): R|kotlin/String| {
|
||||
^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 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);
|
||||
}
|
||||
|
||||
@TestMetadata("checkArguments.kt")
|
||||
public void testCheckArguments() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/checkArguments.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("constructor.kt")
|
||||
public void testConstructor() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@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")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Generated
+5
@@ -39,6 +39,11 @@ public class FirResolveTestCaseWithStdlibGenerated extends AbstractFirResolveTes
|
||||
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")
|
||||
public void testReflectionClass() throws Exception {
|
||||
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 {
|
||||
return when (this) {
|
||||
is ConeTypeVariableType -> "TypeVariable(${this.lookupTag.name})"
|
||||
is ConeDefinitelyNotNullType -> "${original.render()}!"
|
||||
is ConeKotlinErrorType -> "error: $reason"
|
||||
is ConeClassErrorType -> "class error: $reason"
|
||||
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.name.Name
|
||||
|
||||
class FirResolvedCallableReferenceImpl(
|
||||
open class FirResolvedCallableReferenceImpl(
|
||||
session: FirSession,
|
||||
psi: PsiElement?,
|
||||
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