Expand ConeTypeContext, implement FIR type inference & related checkers

This commit is contained in:
Simon Ogorodnik
2019-03-19 16:49:37 +03:00
committed by Mikhail Glukhikh
parent f1eb66819b
commit 1dae135840
37 changed files with 1784 additions and 188 deletions
@@ -123,8 +123,9 @@ class ConeFlexibleType(val lowerBound: ConeLookupTagBasedType, val upperBound: C
get() = lowerBound.nullability.takeIf { it == upperBound.nullability } ?: ConeNullability.UNKNOWN get() = lowerBound.nullability.takeIf { it == upperBound.nullability } ?: ConeNullability.UNKNOWN
} }
class ConeCapturedTypeConstructor(val projection: ConeKotlinTypeProjection) : TypeConstructorMarker { class ConeCapturedTypeConstructor(val projection: ConeKotlinTypeProjection, var supertypes: List<ConeKotlinType>? = null) :
var supertypes: List<ConeKotlinType>? = null TypeConstructorMarker {
} }
class ConeCapturedType( class ConeCapturedType(
@@ -144,3 +145,17 @@ class ConeCapturedType(
override val typeArguments: Array<out ConeKotlinTypeProjection> override val typeArguments: Array<out ConeKotlinTypeProjection>
get() = emptyArray() get() = emptyArray()
} }
class ConeTypeVariableType(
override val nullability: ConeNullability,
override val lookupTag: ConeClassifierLookupTag
) : ConeLookupTagBasedType() {
override val typeArguments: Array<out ConeKotlinTypeProjection> get() = emptyArray()
}
class ConeDefinitelyNotNullType(val original: ConeKotlinType): ConeKotlinType(), DefinitelyNotNullTypeMarker {
override val typeArguments: Array<out ConeKotlinTypeProjection>
get() = original.typeArguments
override val nullability: ConeNullability
get() = ConeNullability.NOT_NULL
}
@@ -55,6 +55,7 @@ fun ConeKotlinType.toIrType(session: FirSession, declarationStorage: Fir2IrDecla
upperBound.toIrType(session, declarationStorage) upperBound.toIrType(session, declarationStorage)
} }
is ConeCapturedType -> TODO() is ConeCapturedType -> TODO()
is ConeDefinitelyNotNullType -> TODO()
} }
} }
@@ -102,7 +103,7 @@ fun FirReference.toSymbol(declarationStorage: Fir2IrDeclarationStorage): IrSymbo
fun FirNamedReference.toSymbol(declarationStorage: Fir2IrDeclarationStorage): IrSymbol? { fun FirNamedReference.toSymbol(declarationStorage: Fir2IrDeclarationStorage): IrSymbol? {
if (this is FirResolvedCallableReference) { if (this is FirResolvedCallableReference) {
when (val callableSymbol = this.callableSymbol) { when (val callableSymbol = this.coneSymbol) {
is FirFunctionSymbol -> return callableSymbol.toFunctionSymbol(declarationStorage) is FirFunctionSymbol -> return callableSymbol.toFunctionSymbol(declarationStorage)
is FirPropertySymbol -> return callableSymbol.toPropertySymbol(declarationStorage) is FirPropertySymbol -> return callableSymbol.toPropertySymbol(declarationStorage)
is FirVariableSymbol -> return callableSymbol.toValueSymbol(declarationStorage) is FirVariableSymbol -> return callableSymbol.toValueSymbol(declarationStorage)
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl
import org.jetbrains.kotlin.fir.types.FirTypeProjection
import org.jetbrains.kotlin.fir.types.FirTypeRef
fun FirFunctionCall.copy(
annotations: List<FirAnnotationCall> = this.annotations,
arguments: List<FirExpression> = this.arguments,
calleeReference: FirNamedReference = this.calleeReference,
explicitReceiver: FirExpression? = this.explicitReceiver,
psi: PsiElement? = this.psi,
safe: Boolean = this.safe,
session: FirSession = this.session,
typeArguments: List<FirTypeProjection> = this.typeArguments,
resultType: FirTypeRef = this.typeRef
): FirFunctionCall {
return FirFunctionCallImpl(
session, psi, safe
).apply {
this.annotations.addAll(annotations)
this.arguments.addAll(arguments)
this.calleeReference = calleeReference
this.explicitReceiver = explicitReceiver
this.typeArguments.addAll(typeArguments)
this.typeRef = resultType
}
}
@@ -42,7 +42,7 @@ fun ConeClassifierLookupTag.toSymbol(useSiteSession: FirSession): ConeClassifier
when (this) { when (this) {
is ConeClassLikeLookupTag -> toSymbol(useSiteSession) is ConeClassLikeLookupTag -> toSymbol(useSiteSession)
is ConeTypeParameterSymbol -> this is ConeTypeParameterSymbol -> this
else -> error("sealed") else -> error("sealed ${this::class}")
} }
fun ConeClassLikeLookupTag.constructClassType(typeArguments: Array<ConeKotlinTypeProjection>, isNullable: Boolean): ConeLookupTagBasedType { fun ConeClassLikeLookupTag.constructClassType(typeArguments: Array<ConeKotlinTypeProjection>, isNullable: Boolean): ConeLookupTagBasedType {
@@ -116,7 +116,8 @@ fun <T : ConeKotlinType> T.withNullability(nullability: ConeNullability): T {
is ConeFunctionTypeImpl -> ConeFunctionTypeImpl(receiverType, parameterTypes, returnType, lookupTag, nullability.isNullable) as T is ConeFunctionTypeImpl -> ConeFunctionTypeImpl(receiverType, parameterTypes, returnType, lookupTag, nullability.isNullable) as T
is ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable) as T is ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable) as T
is ConeFlexibleType -> ConeFlexibleType(lowerBound.withNullability(nullability), upperBound.withNullability(nullability)) as T is ConeFlexibleType -> ConeFlexibleType(lowerBound.withNullability(nullability), upperBound.withNullability(nullability)) as T
else -> TODO("FIX KOTLIN COMPILER") is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag) as T
else -> error("sealed: ${this::class}")
} }
} }
@@ -0,0 +1,95 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.resolve.withNullability
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
fun resolveArgumentExpression(
/*
csBuilder: ConstraintSystemBuilder,
argument: KotlinCallArgument,
expectedType: UnwrappedType?,
diagnosticsHolder: KotlinDiagnosticsHolder,
isReceiver: Boolean
*/
csBuilder: ConstraintSystemBuilder,
argument: FirExpression,
expectedType: ConeKotlinType,
sink: CheckerSink,
isReceiver: Boolean,
typeProvider: (FirExpression) -> FirTypeRef?
) {
return when (argument) {
is FirQualifiedAccessExpression, is FirFunctionCall -> checkPlainExpressionArgument(csBuilder, argument, expectedType, sink, isReceiver, typeProvider)
// TODO:!
is FirAnonymousFunction -> Unit
// TODO:!
is FirCallableReferenceAccess -> Unit
// TODO:!
//TODO: Collection literal
else -> checkPlainExpressionArgument(csBuilder, argument, expectedType, sink, isReceiver, typeProvider)
}
}
fun checkPlainExpressionArgument(
csBuilder: ConstraintSystemBuilder,
argument: FirExpression,
expectedType: ConeKotlinType?,
sink: CheckerSink,
isReceiver: Boolean,
typeProvider: (FirExpression) -> FirTypeRef?
) {
if (expectedType == null) return
val argumentType = typeProvider(argument)?.coneTypeSafe<ConeKotlinType>() ?: return
val position = SimpleConstraintSystemConstraintPosition //TODO
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) {
if (!isReceiver) {
csBuilder.addSubtypeConstraint(argumentType, expectedType, position)
}
val nullableExpectedType = expectedType.withNullability(ConeNullability.NULLABLE)
if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, nullableExpectedType, position)) {
sink.reportApplicability(CandidateApplicability.WRONG_RECEIVER) // TODO
}
}
}
internal fun Candidate.resolveArgument(
argument: FirExpression,
parameter: FirValueParameter,
isReceiver: Boolean,
typeProvider: (FirExpression) -> FirTypeRef?,
sink: CheckerSink
) {
val expectedType = prepareExpectedType(argument, parameter)
resolveArgumentExpression(this.system.getBuilder(), argument, expectedType, sink, isReceiver, typeProvider)
}
private fun Candidate.prepareExpectedType(argument: FirExpression, parameter: FirValueParameter): ConeKotlinType {
val expectedType = argument.getExpectedType(parameter/*, LanguageVersionSettings*/)
return this.substitutor.substituteOrSelf(expectedType)
}
internal fun FirExpression.getExpectedType(parameter: FirValueParameter/*, languageVersionSettings: LanguageVersionSettings*/) =
// if (this.isSpread || this.isArrayAssignedAsNamedArgumentInAnnotation(parameter, languageVersionSettings)) {
// parameter.type.unwrap()
// } else {
parameter.returnTypeRef.coneTypeUnsafe()//?.varargElementType?.unwrap() ?: parameter.type.unwrap()
// }
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.renderWithType
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.defaultType import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.scope import org.jetbrains.kotlin.fir.resolve.scope
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
import org.jetbrains.kotlin.fir.scopes.FirPosition import org.jetbrains.kotlin.fir.scopes.FirPosition
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
@@ -22,14 +23,22 @@ import org.jetbrains.kotlin.fir.symbols.*
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.cast
class CallInfo( class CallInfo(
val variableAccess: Boolean, val callKind: CallKind,
val explicitReceiver: FirExpression?, val explicitReceiver: FirExpression?,
val argumentCount: Int
val arguments: List<FirExpression>,
val typeArguments: List<FirTypeProjection>,
val typeProvider: (FirExpression) -> FirTypeRef?
) { ) {
} }
@@ -50,11 +59,20 @@ class CheckerSinkImpl : CheckerSink {
class Candidate( class Candidate(
val symbol: ConeSymbol, val symbol: ConeSymbol,
val receiverKind: ExplicitReceiverKind, val receiverKind: ExplicitReceiverKind,
val callKind: CallKind private val inferenceComponents: InferenceComponents,
) private val baseSystem: ConstraintStorage
) {
val system by lazy {
val system = inferenceComponents.createConstraintSystem()
system.addOtherSystem(baseSystem)
system
}
lateinit var substitutor: ConeSubstitutor
}
sealed class CallKind { sealed class CallKind {
abstract fun sequence(): List<ResolutionStage> abstract fun sequence(): List<ResolutionStage>
object Function : CallKind() { object Function : CallKind() {
override fun sequence(): List<ResolutionStage> { override fun sequence(): List<ResolutionStage> {
return functionCallResolutionSequence() return functionCallResolutionSequence()
@@ -177,19 +195,31 @@ abstract class TowerDataConsumer {
fun createVariableConsumer( fun createVariableConsumer(
session: FirSession, session: FirSession,
name: Name, name: Name,
explicitReceiver: FirExpression?, callInfo: CallInfo,
explicitReceiverType: FirTypeRef? inferenceComponents: InferenceComponents
): TowerDataConsumer { ): TowerDataConsumer {
return createSimpleConsumer(session, name, TowerScopeLevel.Token.Properties, explicitReceiver, explicitReceiverType, CallKind.VariableAccess) return createSimpleConsumer(
session,
name,
TowerScopeLevel.Token.Properties,
callInfo,
inferenceComponents
)
} }
fun createFunctionConsumer( fun createFunctionConsumer(
session: FirSession, session: FirSession,
name: Name, name: Name,
explicitReceiver: FirExpression?, callInfo: CallInfo,
explicitReceiverType: FirTypeRef? inferenceComponents: InferenceComponents
): TowerDataConsumer { ): TowerDataConsumer {
return createSimpleConsumer(session, name, TowerScopeLevel.Token.Functions, explicitReceiver, explicitReceiverType, CallKind.Function) return createSimpleConsumer(
session,
name,
TowerScopeLevel.Token.Functions,
callInfo,
inferenceComponents
)
} }
@@ -197,18 +227,24 @@ fun createSimpleConsumer(
session: FirSession, session: FirSession,
name: Name, name: Name,
token: TowerScopeLevel.Token<*>, token: TowerScopeLevel.Token<*>,
explicitReceiver: FirExpression?, callInfo: CallInfo,
explicitReceiverType: FirTypeRef?, inferenceComponents: InferenceComponents
callKind: CallKind
): TowerDataConsumer { ): TowerDataConsumer {
return if (explicitReceiver != null) { val factory = CandidateFactory(inferenceComponents, callInfo)
ExplicitReceiverTowerDataConsumer(session, name, token, object : ReceiverValueWithPossibleTypes { return if (callInfo.explicitReceiver != null) {
override val type: ConeKotlinType ExplicitReceiverTowerDataConsumer(
get() = explicitReceiverType?.coneTypeSafe() session,
?: ConeKotlinErrorType("No type calculated for: ${explicitReceiver.renderWithType()}") // TODO: assert here name,
}, callKind) token,
object : ReceiverValueWithPossibleTypes {
override val type: ConeKotlinType
get() = callInfo.typeProvider(callInfo.explicitReceiver)?.coneTypeSafe()
?: ConeKotlinErrorType("No type calculated for: ${callInfo.explicitReceiver.renderWithType()}") // TODO: assert here
},
factory
)
} else { } else {
NoExplicitReceiverTowerDataConsumer(session, name, token, callKind) NoExplicitReceiverTowerDataConsumer(session, name, token, factory)
} }
} }
@@ -217,7 +253,7 @@ class ExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
val name: Name, val name: Name,
val token: TowerScopeLevel.Token<T>, val token: TowerScopeLevel.Token<T>,
val explicitReceiver: ReceiverValueWithPossibleTypes, val explicitReceiver: ReceiverValueWithPossibleTypes,
val callKind: CallKind val candidateFactory: CandidateFactory
) : TowerDataConsumer() { ) : TowerDataConsumer() {
var groupId = 0 var groupId = 0
@@ -237,7 +273,14 @@ class ExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
null, null,
object : TowerScopeLevel.TowerScopeLevelProcessor<T> { object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction { override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction {
resultCollector.consumeCandidate(groupId, Candidate(symbol, ExplicitReceiverKind.DISPATCH_RECEIVER, callKind)) resultCollector.consumeCandidate(
groupId,
candidateFactory.createCandidate(
symbol,
boundDispatchReceiver,
ExplicitReceiverKind.DISPATCH_RECEIVER
)
)
return ProcessorAction.NEXT return ProcessorAction.NEXT
} }
} }
@@ -249,7 +292,14 @@ class ExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
explicitReceiver, explicitReceiver,
object : TowerScopeLevel.TowerScopeLevelProcessor<T> { object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction { override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction {
resultCollector.consumeCandidate(groupId, Candidate(symbol, ExplicitReceiverKind.EXTENSION_RECEIVER, callKind)) resultCollector.consumeCandidate(
groupId,
candidateFactory.createCandidate(
symbol,
boundDispatchReceiver,
ExplicitReceiverKind.EXTENSION_RECEIVER
)
)
return ProcessorAction.NEXT return ProcessorAction.NEXT
} }
} }
@@ -263,7 +313,7 @@ class NoExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
val session: FirSession, val session: FirSession,
val name: Name, val name: Name,
val token: TowerScopeLevel.Token<T>, val token: TowerScopeLevel.Token<T>,
val callKind: CallKind val candidateFactory: CandidateFactory
) : TowerDataConsumer() { ) : TowerDataConsumer() {
var groupId = 0 var groupId = 0
@@ -284,7 +334,10 @@ class NoExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
null, null,
object : TowerScopeLevel.TowerScopeLevelProcessor<T> { object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction { override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction {
resultCollector.consumeCandidate(groupId, Candidate(symbol, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, callKind)) resultCollector.consumeCandidate(
groupId,
candidateFactory.createCandidate(symbol, boundDispatchReceiver, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER)
)
return ProcessorAction.NEXT return ProcessorAction.NEXT
} }
} }
@@ -350,7 +403,7 @@ class CandidateCollector(val callInfo: CallInfo) {
val sink = CheckerSinkImpl() val sink = CheckerSinkImpl()
candidate.callKind.sequence().forEach { callInfo.callKind.sequence().forEach {
it.check(candidate, sink, callInfo) it.check(candidate, sink, callInfo)
} }
@@ -374,9 +427,9 @@ class CandidateCollector(val callInfo: CallInfo) {
} }
fun successCandidates(): List<ConeSymbol> { fun bestCandidates(): List<Candidate> {
if (groupNumbers.isEmpty()) return emptyList() if (groupNumbers.isEmpty()) return emptyList()
val result = mutableListOf<ConeSymbol>() val result = mutableListOf<Candidate>()
var bestGroup = groupNumbers.first() var bestGroup = groupNumbers.first()
for ((index, candidate) in candidates.withIndex()) { for ((index, candidate) in candidates.withIndex()) {
val group = groupNumbers[index] val group = groupNumbers[index]
@@ -385,7 +438,7 @@ class CandidateCollector(val callInfo: CallInfo) {
result.clear() result.clear()
} }
if (bestGroup == group) { if (bestGroup == group) {
result.add(candidate.symbol) result.add(candidate)
} }
} }
return result return result
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
class CandidateFactory(
val inferenceComponents: InferenceComponents,
callInfo: CallInfo
) {
val baseSystem: ConstraintStorage
init {
val system = inferenceComponents.createConstraintSystem()
callInfo.arguments.forEach {
system.addSubsystemFromExpression(it)
}
baseSystem = system.asReadOnlyStorage()
}
fun createCandidate(
symbol: ConeSymbol,
boundDispatchReceiver: ReceiverValueWithPossibleTypes?,
explicitReceiverKind: ExplicitReceiverKind
): Candidate {
return Candidate(symbol, explicitReceiverKind, inferenceComponents, baseSystem)
}
}
private fun PostponedArgumentsAnalyzer.Context.addSubsystemFromExpression(expression: FirExpression) {
when (expression) {
is FirFunctionCall -> expression.candidate()?.let { addOtherSystem(it.system.asReadOnlyStorage()) }
}
}
internal fun FirFunctionCall.candidate(): Candidate? {
val callee = this.calleeReference
return when (callee) {
is FirNamedReferenceWithCandidate -> return callee.candidate
else -> null
}
}
@@ -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
}
}
@@ -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
}
@@ -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)
@@ -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)
}
}
@@ -0,0 +1,215 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirNamedFunction
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
import org.jetbrains.kotlin.resolve.OverloadabilitySpecificityCallbacks
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
import org.jetbrains.kotlin.resolve.calls.results.FlatSignature
import org.jetbrains.kotlin.resolve.calls.results.SimpleConstraintSystem
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
import org.jetbrains.kotlin.resolve.calls.results.isSignatureNotLessSpecific
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeParameterMarker
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
class ConeOverloadConflictResolver(
val specificityComparator: TypeSpecificityComparator,
val inferenceComponents: InferenceComponents
) {
fun chooseMaximallySpecificCandidates(
candidates: Collection<Candidate>,
//checkArgumentsMode: CheckArgumentTypesMode,
discriminateGenerics: Boolean//,
//isDebuggerContext: Boolean
): Set<Candidate> {
val candidatesSet = candidates.toSet()
val maximallySpecific = findMaximallySpecificCall(candidatesSet, false/*, isDebuggerContext*/)
if (maximallySpecific != null) {
return setOf(maximallySpecific)
}
return candidatesSet
}
private fun createFlatSignature(call: Candidate): FlatSignature<Candidate> {
val declaration = call.symbol.firUnsafe<FirCallableDeclaration>()
return when (declaration) {
is FirNamedFunction -> createFlatSignature(call, declaration)
is FirConstructor -> createFlatSignature(call, declaration)
else -> error("Not supported: $declaration")
}
}
private fun createFlatSignature(call: Candidate, constructor: FirConstructor): FlatSignature<Candidate> {
return FlatSignature(
call,
constructor.typeParameters.map { it.symbol },
constructor.valueParameters.map { it.returnTypeRef.coneTypeUnsafe() },
//constructor.receiverTypeRef != null,
false,
constructor.valueParameters.any { it.isVararg },
constructor.valueParameters.count { it.defaultValue != null },
constructor.isExpect,
false // TODO
)
}
private fun createFlatSignature(call: Candidate, function: FirNamedFunction): FlatSignature<Candidate> {
return FlatSignature(
call,
function.typeParameters.map { it.symbol },
function.valueParameters.map { it.returnTypeRef.coneTypeUnsafe() },
function.receiverTypeRef != null,
function.valueParameters.any { it.isVararg },
function.valueParameters.count { it.defaultValue != null },
function.isExpect,
false // TODO
)
}
private fun createEmptyConstraintSystem(): SimpleConstraintSystem {
return ConeSimpleConstraintSystemImpl(inferenceComponents.createConstraintSystem())
}
private fun findMaximallySpecificCall(
candidates: Set<Candidate>,
discriminateGenerics: Boolean//,
//isDebuggerContext: Boolean
): Candidate? {
val filteredCandidates = candidates//uniquifyCandidatesSet(candidates)
if (filteredCandidates.size <= 1) return filteredCandidates.singleOrNull()
val conflictingCandidates = filteredCandidates.map { candidateCall ->
createFlatSignature(candidateCall)
}
val bestCandidatesByParameterTypes = conflictingCandidates.filter { candidate ->
isMostSpecific(candidate, conflictingCandidates) { call1, call2 ->
isNotLessSpecificCallWithArgumentMapping(call1, call2, discriminateGenerics)
}
}
return bestCandidatesByParameterTypes.exactMaxWith { call1, call2 ->
isOfNotLessSpecificShape(call1, call2)// && isOfNotLessSpecificVisibilityForDebugger(call1, call2, isDebuggerContext)
}?.origin
}
private inline fun <C : Any> Collection<C>.exactMaxWith(isNotWorse: (C, C) -> Boolean): C? {
var result: C? = null
for (candidate in this) {
if (result == null || isNotWorse(candidate, result)) {
result = candidate
}
}
if (result == null) return null
if (any { it != result && isNotWorse(it, result!!) }) {
return null
}
return result
}
private inline fun <C> isMostSpecific(candidate: C, candidates: Collection<C>, isNotLessSpecific: (C, C) -> Boolean): Boolean =
candidates.all { other ->
candidate === other ||
isNotLessSpecific(candidate, other)
}
/**
* `call1` is not less specific than `call2`
*/
private fun isNotLessSpecificCallWithArgumentMapping(
call1: FlatSignature<Candidate>,
call2: FlatSignature<Candidate>,
discriminateGenerics: Boolean
): Boolean {
return compareCallsByUsedArguments(
call1,
call2,
discriminateGenerics
)
}
/**
* Returns `true` if [call1] is definitely more or equally specific [call2],
* `false` otherwise.
*/
private fun compareCallsByUsedArguments(
call1: FlatSignature<Candidate>,
call2: FlatSignature<Candidate>,
discriminateGenerics: Boolean
): Boolean {
if (discriminateGenerics) {
val isGeneric1 = call1.isGeneric
val isGeneric2 = call2.isGeneric
// generic loses to non-generic
if (isGeneric1 && !isGeneric2) return false
if (!isGeneric1 && isGeneric2) return true
// two generics are non-comparable
if (isGeneric1 && isGeneric2) return false
}
if (!call1.isExpect && call2.isExpect) return true
if (call1.isExpect && !call2.isExpect) return false
return createEmptyConstraintSystem().isSignatureNotLessSpecific(
call1,
call2,
OverloadabilitySpecificityCallbacks,
specificityComparator
)
}
private fun isOfNotLessSpecificShape(
call1: FlatSignature<Candidate>,
call2: FlatSignature<Candidate>
): Boolean {
val hasVarargs1 = call1.hasVarargs
val hasVarargs2 = call2.hasVarargs
if (hasVarargs1 && !hasVarargs2) return false
if (!hasVarargs1 && hasVarargs2) return true
if (call1.numDefaults > call2.numDefaults) {
return false
}
return true
}
}
object NoSubstitutor : TypeSubstitutorMarker
class ConeSimpleConstraintSystemImpl(val system: NewConstraintSystemImpl) : SimpleConstraintSystem {
override fun registerTypeVariables(typeParameters: Collection<TypeParameterMarker>): TypeSubstitutorMarker {
return NoSubstitutor
}
override fun addSubtypeConstraint(subType: KotlinTypeMarker, superType: KotlinTypeMarker) {
system.addSubtypeConstraint(subType, superType, SimpleConstraintSystemConstraintPosition)
}
override fun hasContradiction(): Boolean = system.hasContradiction
override val context: TypeSystemInferenceExtensionContext
get() = system
}
@@ -10,26 +10,42 @@ import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
sealed class ResolutionStage { abstract class ResolutionStage {
abstract fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) abstract fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo)
} }
sealed class CheckerStage : ResolutionStage() abstract class CheckerStage : ResolutionStage()
internal object MapArguments : ResolutionStage() { internal object MapArguments : ResolutionStage() {
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
val symbol = candidate.symbol as? FirFunctionSymbol ?: return sink.reportApplicability(CandidateApplicability.HIDDEN) val symbol = candidate.symbol as? FirFunctionSymbol ?: return sink.reportApplicability(CandidateApplicability.HIDDEN)
if (symbol.firUnsafe<FirFunction>().valueParameters.size != callInfo.argumentCount) { if (symbol.firUnsafe<FirFunction>().valueParameters.size != callInfo.arguments.size) {
return sink.reportApplicability(CandidateApplicability.PARAMETER_MAPPING_ERROR) return sink.reportApplicability(CandidateApplicability.PARAMETER_MAPPING_ERROR)
} }
} }
} }
internal object CheckArguments : CheckerStage() {
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
val symbol = candidate.symbol as? FirFunctionSymbol ?: error("Can't check arguments for non function")
val declaration = symbol.fir as FirFunction
for ((parameter, argument) in declaration.valueParameters.zip(callInfo.arguments)) {
candidate.resolveArgument(argument, parameter, isReceiver = false, typeProvider = callInfo.typeProvider, sink = sink)
}
if (candidate.system.hasContradiction) {
sink.reportApplicability(CandidateApplicability.INAPPLICABLE)
}
}
}
internal fun functionCallResolutionSequence() = internal fun functionCallResolutionSequence() =
listOf<ResolutionStage>(MapArguments) listOf<ResolutionStage>(MapArguments, CreateFreshTypeVariableSubstitutorStage, CheckArguments)
internal fun qualifiedAccessResolutionSequence() = internal fun qualifiedAccessResolutionSequence() =
listOf<ResolutionStage>() listOf<ResolutionStage>(CreateFreshTypeVariableSubstitutorStage)
@@ -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]
}
}
@@ -10,13 +10,10 @@ import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.CallInfo import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.calls.CallResolver import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.calls.createFunctionConsumer
import org.jetbrains.kotlin.fir.resolve.calls.createVariableConsumer
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.addImportingScopes import org.jetbrains.kotlin.fir.scopes.addImportingScopes
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
@@ -24,16 +21,17 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirTopLevelDeclaredMemberScope
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
import org.jetbrains.kotlin.fir.symbols.* import org.jetbrains.kotlin.fir.symbols.*
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl import org.jetbrains.kotlin.fir.types.impl.*
import org.jetbrains.kotlin.fir.types.impl.FirComputingImplicitTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirErrorTypeRefImpl
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.compose import org.jetbrains.kotlin.fir.visitors.compose
import org.jetbrains.kotlin.ir.expressions.IrConstKind import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOnly: Boolean) : FirTransformer<Any?>() { open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOnly: Boolean) : FirTransformer<Any?>() {
@@ -115,7 +113,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
resolved.resultType = resolved.resultType =
resolved.conversionTypeRef.withReplacedConeType( resolved.conversionTypeRef.withReplacedConeType(
session, session,
resolved.conversionTypeRef.coneTypeUnsafe<ConeKotlinType>().withNullability(ConeNullability.NULLABLE) resolved.conversionTypeRef.coneTypeUnsafe().withNullability(ConeNullability.NULLABLE)
) )
} }
else -> error("Unknown type operator") else -> error("Unknown type operator")
@@ -143,16 +141,36 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
val jump = ReturnTypeCalculatorWithJump(session) val jump = ReturnTypeCalculatorWithJump(session)
private fun <T> storeTypeFromCallee(access: T) where T : FirQualifiedAccess, T : FirExpression { private fun <T> storeTypeFromCallee(access: T) where T : FirQualifiedAccess, T : FirExpression {
access.resultType = access.resultType = typeFromCallee(access)
when (val newCallee = access.calleeReference) {
is FirErrorNamedReference ->
FirErrorTypeRefImpl(session, access.psi, newCallee.errorReason)
is FirResolvedCallableReference ->
jump.tryCalculateReturnType(newCallee.callableSymbol.firUnsafe())
else -> return
}
} }
private fun <T> typeFromCallee(access: T): FirResolvedTypeRef where T : FirQualifiedAccess, T : FirExpression {
return when (val newCallee = access.calleeReference) {
is FirErrorNamedReference ->
FirErrorTypeRefImpl(session, access.psi, newCallee.errorReason)
is FirResolvedCallableReference ->
jump.tryCalculateReturnType(newCallee.callableSymbol.firUnsafe())
else -> error("Failed to extract type from: $newCallee")
}
}
val inferenceComponents = InferenceComponents(object : ConeInferenceContext, TypeSystemInferenceExtensionContextDelegate {
override fun findCommonIntegerLiteralTypesSuperType(explicitSupertypes: List<SimpleTypeMarker>): SimpleTypeMarker? {
TODO("not implemented")
}
override fun TypeConstructorMarker.getApproximatedIntegerLiteralType(): KotlinTypeMarker {
TODO("not implemented")
}
override val session: FirSession
get() = this@FirBodyResolveTransformer.session
override fun KotlinTypeMarker.removeExactAnnotation(): KotlinTypeMarker {
return this
}
})
override fun transformQualifiedAccessExpression( override fun transformQualifiedAccessExpression(
qualifiedAccessExpression: FirQualifiedAccessExpression, qualifiedAccessExpression: FirQualifiedAccessExpression,
data: Any? data: Any?
@@ -180,13 +198,9 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
} }
val callee = qualifiedAccessExpression.calleeReference as? FirSimpleNamedReference ?: return qualifiedAccessExpression.compose() val callee = qualifiedAccessExpression.calleeReference as? FirSimpleNamedReference ?: return qualifiedAccessExpression.compose()
qualifiedAccessExpression.explicitReceiver?.visitNoTransform(this, null) val receiver = qualifiedAccessExpression.explicitReceiver?.transformSingle(this, null)
val receiver = qualifiedAccessExpression.explicitReceiver val info = CallInfo(CallKind.VariableAccess, receiver, emptyList(), emptyList()) { it.resultType }
//val checkers = listOf(VariableApplicabilityChecker(callee.name))
val info = CallInfo(true, receiver, 0)
val resolver = CallResolver(jump, session) val resolver = CallResolver(jump, session)
resolver.callInfo = info resolver.callInfo = info
resolver.scopes = (scopes + localScopes).asReversed() resolver.scopes = (scopes + localScopes).asReversed()
@@ -194,40 +208,44 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
val consumer = createVariableConsumer( val consumer = createVariableConsumer(
session, session,
callee.name, callee.name,
qualifiedAccessExpression.explicitReceiver, info, inferenceComponents
qualifiedAccessExpression.explicitReceiver?.resultType
) )
val result = resolver.runTowerResolver(consumer) val result = resolver.runTowerResolver(consumer)
val successCandidates = result.successCandidates()
val resultExpression = qualifiedAccessExpression.transformCalleeReference(this, successCandidates) val nameReference = createResolvedNamedReference(
callee,
result.bestCandidates(),
result.currentApplicability
)
val resultExpression =
qualifiedAccessExpression.transformCalleeReference(StoreNameReference, nameReference)
storeTypeFromCallee(resultExpression as FirQualifiedAccessExpression) storeTypeFromCallee(resultExpression as FirQualifiedAccessExpression)
return resultExpression.compose() return resultExpression.compose()
} }
override fun transformFunctionCall(functionCall: FirFunctionCall, data: Any?): CompositeTransformResult<FirStatement> { private fun resolveCallAndSelectCandidate(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?): FirFunctionCall {
val functionCall = functionCall.transformChildren(this, null) as FirFunctionCall val functionCall = functionCall.transformChildren(this, null) as FirFunctionCall
if (functionCall.calleeReference !is FirSimpleNamedReference) return functionCall.compose()
val name = functionCall.calleeReference.name val name = functionCall.calleeReference.name
val expectedTypeRef = data as FirTypeRef?
val receiver = functionCall.explicitReceiver val receiver = functionCall.explicitReceiver
val arguments = functionCall.arguments val arguments = functionCall.arguments
val typeArguments = functionCall.typeArguments
val info = CallInfo(false, receiver, arguments.size) val info = CallInfo(CallKind.Function, receiver, arguments, typeArguments) { it.resultType }
val resolver = CallResolver(jump, session) val resolver = CallResolver(jump, session)
resolver.callInfo = info resolver.callInfo = info
resolver.scopes = (scopes + localScopes).asReversed() resolver.scopes = (scopes + localScopes).asReversed()
val consumer = createFunctionConsumer(session, name, info, inferenceComponents)
val consumer = createFunctionConsumer(session, name, receiver, receiver?.resultType)
val result = resolver.runTowerResolver(consumer) val result = resolver.runTowerResolver(consumer)
val successCandidates = result.successCandidates() val bestCandidates = result.bestCandidates()
val reducedCandidates = ConeOverloadConflictResolver(TypeSpecificityComparator.NONE, inferenceComponents)
.chooseMaximallySpecificCandidates(bestCandidates, discriminateGenerics = false)
// fun isInvoke() // fun isInvoke()
// //
@@ -257,33 +275,103 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
// } // }
// else -> functionCall // else -> functionCall
// } // }
val resultExpression = functionCall.transformCalleeReference(this, successCandidates) val nameReference = createResolvedNamedReference(
functionCall.calleeReference,
reducedCandidates,
result.currentApplicability
)
storeTypeFromCallee(resultExpression as FirFunctionCall) val resultExpression = functionCall.transformCalleeReference(StoreNameReference, nameReference) as FirFunctionCall
return resultExpression.compose() val typeRef = typeFromCallee(functionCall)
if (typeRef.type is ConeKotlinErrorType) {
functionCall.resultType = typeRef
}
return resultExpression
} }
private fun createResolvedNamedReference(namedReference: FirNamedReference, candidates: List<ConeCallableSymbol>): FirNamedReference { private fun completeTypeInference(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?): FirFunctionCall {
val typeRef = typeFromCallee(functionCall)
if (typeRef.type is ConeKotlinErrorType) {
functionCall.resultType = typeRef
return functionCall
}
val candidate = functionCall.candidate() ?: return functionCall
val initialSubstitutor = candidate.substitutor
val initialType = initialSubstitutor.substituteOrSelf(typeRef.type)
val completionMode = candidate.computeCompletionMode(inferenceComponents, expectedTypeRef, initialType)
val completer = ConstraintSystemCompleter(inferenceComponents)
completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, initialType)
if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
val finalSubstitutor =
candidate.system.asReadOnlyStorage().buildAbstractResultingSubstitutor(inferenceComponents.ctx) as ConeSubstitutor
return functionCall.transformSingle(
FirCallCompleterTransformer(session, finalSubstitutor, jump),
null
)
}
return functionCall
}
override fun transformFunctionCall(functionCall: FirFunctionCall, data: Any?): CompositeTransformResult<FirStatement> {
if (functionCall.calleeReference !is FirSimpleNamedReference) return functionCall.compose()
val expectedTypeRef = data as FirTypeRef?
val completeInference =
try {
val resultExpression = resolveCallAndSelectCandidate(functionCall, expectedTypeRef)
completeTypeInference(resultExpression, expectedTypeRef)
} catch (e: Throwable) {
throw RuntimeException("While resolving call ${functionCall.render()}", e)
}
return completeInference.compose()
}
private fun describeSymbol(symbol: ConeSymbol): String {
return when (symbol) {
is ConeClassLikeSymbol -> symbol.classId.asString()
is ConeCallableSymbol -> symbol.callableId.toString()
else -> "$symbol"
}
}
private fun createResolvedNamedReference(
namedReference: FirNamedReference,
candidates: Collection<Candidate>,
applicability: CandidateApplicability
): FirNamedReference {
val name = namedReference.name val name = namedReference.name
return when (candidates.size) { return when {
0 -> FirErrorNamedReference( candidates.isEmpty() -> FirErrorNamedReference(
namedReference.session, namedReference.psi, "Unresolved name: $name" namedReference.session, namedReference.psi, "Unresolved name: $name"
) )
1 -> FirResolvedCallableReferenceImpl( applicability < CandidateApplicability.RESOLVED -> {
FirErrorNamedReference(
namedReference.session,
namedReference.psi,
"Inapplicable($applicability): ${candidates.map { describeSymbol(it.symbol) }}"
)
}
candidates.size == 1 -> FirNamedReferenceWithCandidate(
namedReference.session, namedReference.psi, namedReference.session, namedReference.psi,
name, candidates.single() name, candidates.single()
) )
else -> FirErrorNamedReference( else -> FirErrorNamedReference(
namedReference.session, namedReference.psi, "Ambiguity: $name, ${candidates.map { it.callableId }}" namedReference.session, namedReference.psi, "Ambiguity: $name, ${candidates.map { describeSymbol(it.symbol) }}"
) )
} }
} }
override fun transformNamedReference(namedReference: FirNamedReference, data: Any?): CompositeTransformResult<FirNamedReference> { // override fun transformNamedReference(namedReference: FirNamedReference, data: Any?): CompositeTransformResult<FirNamedReference> {
if (namedReference is FirErrorNamedReference || namedReference is FirResolvedCallableReference) return namedReference.compose() // if (namedReference is FirErrorNamedReference || namedReference is FirResolvedCallableReference) return namedReference.compose()
val referents = data as? List<ConeCallableSymbol> ?: return namedReference.compose() // val referents = data as? List<ConeCallableSymbol> ?: return namedReference.compose()
return createResolvedNamedReference(namedReference, referents).compose() // return createResolvedNamedReference(namedReference, referents).compose()
} // }
override fun transformBlock(block: FirBlock, data: Any?): CompositeTransformResult<FirStatement> { override fun transformBlock(block: FirBlock, data: Any?): CompositeTransformResult<FirStatement> {
@@ -315,10 +403,10 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
} }
override fun <T> transformConstExpression(constExpression: FirConstExpression<T>, data: Any?): CompositeTransformResult<FirStatement> { override fun <T> transformConstExpression(constExpression: FirConstExpression<T>, data: Any?): CompositeTransformResult<FirStatement> {
val expectedType = data as? FirTypeRef val expectedType = data as FirTypeRef?
val kind = constExpression.kind val kind = constExpression.kind
if (expectedType is FirImplicitTypeRef || expectedType == null || if (expectedType == null || expectedType is FirImplicitTypeRef || expectedType == null ||
kind == IrConstKind.Null || kind == IrConstKind.Boolean || kind == IrConstKind.Char kind == IrConstKind.Null || kind == IrConstKind.Boolean || kind == IrConstKind.Char
) { ) {
val symbol = when (kind) { val symbol = when (kind) {
@@ -424,7 +512,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
override fun transformExpression(expression: FirExpression, data: Any?): CompositeTransformResult<FirStatement> { override fun transformExpression(expression: FirExpression, data: Any?): CompositeTransformResult<FirStatement> {
if (expression.resultType is FirImplicitTypeRef) { if (expression.resultType is FirImplicitTypeRef) {
val type = FirErrorTypeRefImpl(session, expression.psi, "Type calculating for ${expression.render()} is not supported") val type = FirErrorTypeRefImpl(session, expression.psi, "Type calculating for ${expression::class} is not supported")
expression.resultType = type expression.resultType = type
} }
return super.transformExpression(expression, data) return super.transformExpression(expression, data)
@@ -568,3 +656,16 @@ inline fun <reified T : FirElement> ConeSymbol.firSafeNullable(): T? {
interface ReturnTypeCalculator { interface ReturnTypeCalculator {
fun tryCalculateReturnType(declaration: FirTypedDeclaration): FirResolvedTypeRef fun tryCalculateReturnType(declaration: FirTypedDeclaration): FirResolvedTypeRef
} }
private object StoreNameReference : FirTransformer<FirNamedReference>() {
override fun <E : FirElement> transformElement(element: E, data: FirNamedReference): CompositeTransformResult<E> {
return element.compose()
}
override fun transformNamedReference(
namedReference: FirNamedReference,
data: FirNamedReference
): CompositeTransformResult<FirNamedReference> {
return data.compose()
}
}
@@ -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()
}
}
@@ -52,7 +52,7 @@ abstract class FirAbstractSimpleImportingScope(session: FirSession) : FirAbstrac
if (imports.isEmpty()) return ProcessorAction.NEXT if (imports.isEmpty()) return ProcessorAction.NEXT
for (import in imports) { for (import in imports) {
if (processCallables(import, name, token, processor).stop()) { if (processCallables(import, import.importedName!!, token, processor).stop()) {
return ProcessorAction.STOP return ProcessorAction.STOP
} }
} }
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.declarations.FirNamedFunction
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirMemberFunctionImpl import org.jetbrains.kotlin.fir.declarations.impl.FirMemberFunctionImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorWithJump import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorWithJump
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
@@ -20,72 +21,18 @@ import org.jetbrains.kotlin.fir.symbols.*
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeAbbreviatedTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
class FirClassSubstitutionScope( class FirClassSubstitutionScope(
private val session: FirSession, private val session: FirSession,
private val useSiteScope: FirScope, private val useSiteScope: FirScope,
private val substitution: Map<ConeTypeParameterSymbol, ConeKotlinType> substitution: Map<ConeTypeParameterSymbol, ConeKotlinType>
) : FirScope { ) : FirScope {
private val fakeOverrides = mutableMapOf<ConeCallableSymbol, ConeCallableSymbol>() private val fakeOverrides = mutableMapOf<ConeCallableSymbol, ConeCallableSymbol>()
private fun wrapProjection(old: ConeKotlinTypeProjection, newType: ConeKotlinType): ConeKotlinTypeProjection { private val substitutor = ConeSubstitutorByMap(substitution)
return when (old) {
is ConeStarProjection -> old
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(newType)
is ConeKotlinTypeProjectionOut -> ConeKotlinTypeProjectionOut(newType)
is ConeKotlinType -> newType
else -> old
}
}
private fun ConeKotlinType.substitute(): ConeKotlinType? {
if (this is ConeTypeParameterType) return substitution[lookupTag]
val newArguments by lazy { arrayOfNulls<ConeKotlinTypeProjection>(typeArguments.size) }
var initialized = false
for ((index, typeArgument) in this.typeArguments.withIndex()) {
val type = (typeArgument as? ConeTypedProjection)?.type ?: continue
val newType = type.substitute()
if (newType != null) {
initialized = true
newArguments[index] = wrapProjection(typeArgument, newType)
}
}
if (initialized) {
for ((index, typeArgument) in this.typeArguments.withIndex()) {
if (newArguments[index] == null) {
newArguments[index] = typeArgument
}
}
@Suppress("UNCHECKED_CAST")
return when (this) {
is ConeKotlinErrorType -> error("Trying to substitute arguments for error type")
is ConeTypeParameterType -> error("Trying to substitute arguments for type parameter")
is ConeClassTypeImpl -> ConeClassTypeImpl(
lookupTag,
newArguments as Array<ConeKotlinTypeProjection>,
nullability.isNullable
)
is ConeAbbreviatedTypeImpl -> ConeAbbreviatedTypeImpl(
abbreviationLookupTag,
newArguments as Array<ConeKotlinTypeProjection>,
nullability.isNullable
)
is ConeFunctionType -> TODO("Substitute function type properly")
is ConeClassLikeType -> error("Unknown class-like type to substitute: $this, ${this::class}")
is ConeFlexibleType -> error("Trying to substitute arguments for flexible type")
is ConeCapturedType -> error("Not supported")
}
}
return null
}
override fun processFunctionsByName(name: Name, processor: (ConeFunctionSymbol) -> ProcessorAction): ProcessorAction { override fun processFunctionsByName(name: Name, processor: (ConeFunctionSymbol) -> ProcessorAction): ProcessorAction {
useSiteScope.processFunctionsByName(name) process@{ original -> useSiteScope.processFunctionsByName(name) process@{ original ->
@@ -104,6 +51,10 @@ class FirClassSubstitutionScope(
private val typeCalculator by lazy { ReturnTypeCalculatorWithJump(session) } private val typeCalculator by lazy { ReturnTypeCalculatorWithJump(session) }
private fun ConeKotlinType.substitute(): ConeKotlinType? {
return substitutor.substituteOrNull(this)
}
private fun createFakeOverride(original: ConeFunctionSymbol): FirFunctionSymbol { private fun createFakeOverride(original: ConeFunctionSymbol): FirFunctionSymbol {
val member = original.firUnsafe<FirFunction>() val member = original.firUnsafe<FirFunction>()
@@ -10,13 +10,13 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.expandedConeType import org.jetbrains.kotlin.fir.declarations.expandedConeType
import org.jetbrains.kotlin.fir.declarations.superConeTypes import org.jetbrains.kotlin.fir.declarations.superConeTypes
import org.jetbrains.kotlin.fir.resolve.calls.ConeTypeVariableTypeConstructor
import org.jetbrains.kotlin.fir.resolve.constructType
import org.jetbrains.kotlin.fir.resolve.directExpansionType import org.jetbrains.kotlin.fir.resolve.directExpansionType
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.withArguments import org.jetbrains.kotlin.fir.resolve.withArguments
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.ConeClassSymbol import org.jetbrains.kotlin.fir.symbols.*
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
@@ -47,9 +47,12 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
assert(this is ConeKotlinType) assert(this is ConeKotlinType)
return when (this) { return when (this) {
is ConeAbbreviatedType -> directExpansionType(session) is ConeAbbreviatedType -> directExpansionType(session)
?: ConeClassErrorType("no expansion for type-alias: ${this.abbreviationLookupTag.classId}")
is ConeCapturedType -> this is ConeCapturedType -> this
is ConeLookupTagBasedType -> this is ConeLookupTagBasedType -> this
else -> null is ConeDefinitelyNotNullType -> this
is ConeFlexibleType -> null
else -> error("Unknown simpleType: $this")
} }
} }
@@ -130,6 +133,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
override fun SimpleTypeMarker.typeConstructor(): TypeConstructorMarker { override fun SimpleTypeMarker.typeConstructor(): TypeConstructorMarker {
return when (this) { return when (this) {
is ConeCapturedType -> constructor is ConeCapturedType -> constructor
is ConeTypeVariableType -> this.lookupTag as ConeTypeVariableTypeConstructor // TODO: WTF
is ConeLookupTagBasedType -> this.lookupTag.toSymbol(session) ?: ErrorTypeConstructor("Unresolved: ${this.lookupTag}") is ConeLookupTagBasedType -> this.lookupTag.toSymbol(session) ?: ErrorTypeConstructor("Unresolved: ${this.lookupTag}")
else -> error("?: ${this}") else -> error("?: ${this}")
} }
@@ -145,7 +149,8 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
override fun SimpleTypeMarker.getArgument(index: Int): TypeArgumentMarker { override fun SimpleTypeMarker.getArgument(index: Int): TypeArgumentMarker {
require(this is ConeKotlinType) require(this is ConeKotlinType)
return this.typeArguments[index] return this.typeArguments.getOrNull(index)
?: StandardClassIds.Any(session.service()).constructType(emptyArray(), false) // TODO wtf
} }
override fun KotlinTypeMarker.asTypeArgument(): TypeArgumentMarker { override fun KotlinTypeMarker.asTypeArgument(): TypeArgumentMarker {
@@ -184,7 +189,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
override fun TypeConstructorMarker.parametersCount(): Int { override fun TypeConstructorMarker.parametersCount(): Int {
//require(this is ConeSymbol) //require(this is ConeSymbol)
return when (this) { return when (this) {
is ConeTypeParameterSymbol, is ConeCapturedTypeConstructor, is ErrorTypeConstructor -> 0 is ConeTypeParameterSymbol, is ConeCapturedTypeConstructor, is ErrorTypeConstructor, is ConeTypeVariableTypeConstructor -> 0
is FirClassSymbol -> fir.typeParameters.size is FirClassSymbol -> fir.typeParameters.size
is FirTypeAliasSymbol -> fir.typeParameters.size is FirTypeAliasSymbol -> fir.typeParameters.size
else -> error("?!:10") else -> error("?!:10")
@@ -205,7 +210,8 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
if (this is ErrorTypeConstructor) return emptyList() if (this is ErrorTypeConstructor) return emptyList()
//require(this is ConeSymbol) //require(this is ConeSymbol)
return when (this) { return when (this) {
is ConeTypeParameterSymbol -> emptyList() is ConeTypeVariableTypeConstructor -> emptyList()
is FirTypeParameterSymbol -> fir.bounds.map { it.coneTypeUnsafe() }
is FirClassSymbol -> fir.superConeTypes is FirClassSymbol -> fir.superConeTypes
is FirTypeAliasSymbol -> listOfNotNull(fir.expandedConeType) is FirTypeAliasSymbol -> listOfNotNull(fir.expandedConeType)
is ConeCapturedTypeConstructor -> supertypes!! is ConeCapturedTypeConstructor -> supertypes!!
@@ -263,7 +269,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
} }
override fun captureFromArguments(type: SimpleTypeMarker, status: CaptureStatus): SimpleTypeMarker? { override fun captureFromArguments(type: SimpleTypeMarker, status: CaptureStatus): SimpleTypeMarker? {
require(type is ConeLookupTagBasedType) { ":( $type" } require(type is ConeKotlinType)
val typeConstructor = type.typeConstructor() val typeConstructor = type.typeConstructor()
if (type.argumentsCount() != typeConstructor.parametersCount()) return null if (type.argumentsCount() != typeConstructor.parametersCount()) return null
if (type.asArgumentList().all(this) { !it.isStarProjection() && it.getVariance() == TypeVariance.INV }) return null if (type.asArgumentList().all(this) { !it.isStarProjection() && it.getVariance() == TypeVariance.INV }) return null
@@ -314,7 +320,6 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
} }
override fun TypeConstructorMarker.isAnyConstructor(): Boolean { override fun TypeConstructorMarker.isAnyConstructor(): Boolean {
assert(this is ConeSymbol)
return this is ConeClassLikeSymbol && classId.asString() == "kotlin/Any" return this is ConeClassLikeSymbol && classId.asString() == "kotlin/Any"
} }
@@ -332,36 +337,39 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
override fun SimpleTypeMarker.isSingleClassifierType(): Boolean { override fun SimpleTypeMarker.isSingleClassifierType(): Boolean {
if (isError()) return false if (isError()) return false
if (this is ConeCapturedType) return true if (this is ConeCapturedType) return true
if (this is ConeTypeVariableType) return false
require(this is ConeLookupTagBasedType) require(this is ConeLookupTagBasedType)
val symbol = this.lookupTag.toSymbol(session) val symbol = this.lookupTag.toSymbol(session)
return symbol is FirClassSymbol || return symbol is FirClassSymbol ||
symbol is FirTypeParameterSymbol symbol is FirTypeParameterSymbol
} }
override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker {
TODO("not implemented")
}
override fun intersectTypes(types: List<SimpleTypeMarker>): SimpleTypeMarker {
TODO("not implemented")
}
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
TODO("not implemented")
}
override fun SimpleTypeMarker.isStubType(): Boolean {
TODO("not implemented")
}
override fun captureFromExpression(type: KotlinTypeMarker): KotlinTypeMarker? { override fun captureFromExpression(type: KotlinTypeMarker): KotlinTypeMarker? {
TODO("not implemented") TODO("not implemented")
} }
override fun SimpleTypeMarker.isPrimitiveType(): Boolean { override fun SimpleTypeMarker.isPrimitiveType(): Boolean {
TODO("not implemented") return false //TODO
} }
override fun SimpleTypeMarker.isStubType(): Boolean {
return false // TODO
}
override fun intersectTypes(types: List<SimpleTypeMarker>): SimpleTypeMarker {
return types.first() // TODO: proper implementation
}
override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker {
return types.first() // TODO: proper implementation
}
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
return when (type) {
is ConeAbbreviatedType -> prepareType(type.directExpansionType(session) ?: ConeClassErrorType("unresolved"))
else -> type
}
}
} }
class ConeTypeCheckerContext(override val isErrorTypeEqualsToAnything: Boolean, override val session: FirSession) : class ConeTypeCheckerContext(override val isErrorTypeEqualsToAnything: Boolean, override val session: FirSession) :
@@ -379,16 +387,11 @@ class ConeTypeCheckerContext(override val isErrorTypeEqualsToAnything: Boolean,
return a == b return a == b
} }
override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker { override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
return types.first() // TODO: proper implementation return super<ConeTypeContext>.prepareType(type)
} }
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean override val KotlinTypeMarker.isAllowedTypeVariable: Boolean
get() = false get() = false
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
return super<ConeTypeContext>.prepareType(type)
}
} }
@@ -36,8 +36,8 @@ FILE: access.kt
^plus String() ^plus String()
} }
public final fun R|Foo|.check(): <ERROR TYPE REF: Ambiguity: plus, [kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus]> { public final fun R|Foo|.check(): R|kotlin/String| {
^check R|/Foo.abc|().<Ambiguity: plus, [kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus]>#(R|/Bar.bar|()) ^check R|/Foo.abc|().R|/Bar.plus|(R|/Bar.bar|())
} }
} }
@@ -0,0 +1,16 @@
class A
open class B
class C : B
fun bar(a: A) = a
fun bar(b: B) = b
fun foo() {
val a = A()
val b = B()
val c = C()
val ra = bar(a)
val rb = bar(b)
val rc = bar(c)
}
@@ -0,0 +1,27 @@
FILE: checkArguments.kt
public final class A : R|kotlin/Any| {
public constructor(): super<R|kotlin/Any|>()
}
public open class B : R|kotlin/Any| {
public constructor(): super<R|kotlin/Any|>()
}
public final class C : R|B|, R|kotlin/Any| {
public constructor(): super<R|kotlin/Any|>()
}
public final fun bar(a: R|A|): R|A| {
^bar R|<local>/a|
}
public final fun bar(b: R|B|): R|B| {
^bar R|<local>/b|
}
public final fun foo(): R|kotlin/Unit| {
lval a: R|A| = R|/A.A|()
lval b: R|B| = R|/B.B|()
lval c: R|C| = R|/C.C|()
lval ra: R|A| = R|/bar|(R|<local>/a|)
lval rb: R|B| = R|/bar|(R|<local>/b|)
lval rc: R|B| = R|/bar|(R|<local>/c|)
}
@@ -0,0 +1,8 @@
fun <T> id(t: T) = t
fun main() {
val a = id("string")
val b = id(null)
val c = id(id(a))
}
@@ -0,0 +1,9 @@
FILE: id.kt
public final fun <T> id(t: R|T|): R|T| {
^id R|<local>/t|
}
public final fun main(): R|kotlin/Unit| {
lval a: R|kotlin/String| = R|/id|<R|kotlin/String|>(String(string))
lval b: R|kotlin/Nothing|? = R|/id|<R|kotlin/Nothing|?>(Null(null))
lval c: R|kotlin/String| = R|/id|<R|kotlin/String|>(R|/id|<R|kotlin/String|>(R|<local>/a|))
}
@@ -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)
}
@@ -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|)
}
@@ -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)
}
@@ -0,0 +1,22 @@
FILE: typeParameters2.kt
public abstract interface Foo : R|kotlin/Any| {
}
public final class FooImpl : R|Foo| {
public constructor(): R|FooImpl| {
super<R|kotlin/Any|>()
}
}
public final class FooBarImpl : R|Foo| {
public constructor(): R|FooBarImpl| {
super<R|kotlin/Any|>()
}
}
public final fun <T : R|Foo|> foo(t: R|T|): R|T| {
^foo R|<local>/t|
}
public final fun main(fooImpl: R|FooImpl|, fooBarImpl: R|FooBarImpl|): R|kotlin/Unit| {
lval a: <ERROR TYPE REF: Inapplicable(INAPPLICABLE): [/foo]> = <Inapplicable(INAPPLICABLE): [/foo]>#<R|FooImpl|>(R|<local>/fooBarImpl|)
lval b: R|Foo| = R|/foo|<R|Foo|>(R|<local>/fooImpl|)
}
@@ -70,7 +70,7 @@ FILE: enums.kt
} }
public final val g: R|kotlin/Double| = <Unresolved name: G>#.<Unresolved name: times>#(R|/Planet.m|).<Unresolved name: div>#(R|/Planet.r|.<Ambiguity: times, [kotlin/Double.times, kotlin/Double.times, kotlin/Double.times, kotlin/Double.times, kotlin/Double.times, kotlin/Double.times]>#(R|/Planet.r|)) public final val g: R|kotlin/Double| = <Unresolved name: G>#.<Unresolved name: times>#(R|/Planet.m|).<Unresolved name: div>#(R|/Planet.r|.R|kotlin/Double.times|(R|/Planet.r|))
public get(): R|kotlin/Double| public get(): R|kotlin/Double|
public abstract fun sayHello(): R|kotlin/Unit| public abstract fun sayHello(): R|kotlin/Unit|
@@ -0,0 +1,3 @@
fun main() {
println("Hello, world!")
}
@@ -0,0 +1,4 @@
FILE: helloWorld.kt
public final fun main(): R|kotlin/Unit| {
R|kotlin/io/println|(String(Hello, world!))
}
@@ -159,6 +159,11 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/resolve/expresssions"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/resolve/expresssions"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true);
} }
@TestMetadata("checkArguments.kt")
public void testCheckArguments() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/expresssions/checkArguments.kt");
}
@TestMetadata("constructor.kt") @TestMetadata("constructor.kt")
public void testConstructor() throws Exception { public void testConstructor() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/expresssions/constructor.kt"); runTest("compiler/fir/resolve/testData/resolve/expresssions/constructor.kt");
@@ -189,6 +194,36 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
runTest("compiler/fir/resolve/testData/resolve/expresssions/when.kt"); runTest("compiler/fir/resolve/testData/resolve/expresssions/when.kt");
} }
@TestMetadata("compiler/fir/resolve/testData/resolve/expresssions/inference")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Inference extends AbstractFirResolveTestCase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInInference() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(),
new File("compiler/fir/resolve/testData/resolve/expresssions/inference"),
Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("id.kt")
public void testId() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/expresssions/inference/id.kt");
}
@TestMetadata("typeParameters.kt")
public void testTypeParameters() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/expresssions/inference/typeParameters.kt");
}
@TestMetadata("typeParameters2.kt")
public void testTypeParameters2() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/expresssions/inference/typeParameters2.kt");
}
}
@TestMetadata("compiler/fir/resolve/testData/resolve/expresssions/invoke") @TestMetadata("compiler/fir/resolve/testData/resolve/expresssions/invoke")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -39,6 +39,11 @@ public class FirResolveTestCaseWithStdlibGenerated extends AbstractFirResolveTes
runTest("compiler/fir/resolve/testData/resolve/stdlib/functionX.kt"); runTest("compiler/fir/resolve/testData/resolve/stdlib/functionX.kt");
} }
@TestMetadata("helloWorld.kt")
public void testHelloWorld() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/stdlib/helloWorld.kt");
}
@TestMetadata("reflectionClass.kt") @TestMetadata("reflectionClass.kt")
public void testReflectionClass() throws Exception { public void testReflectionClass() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/stdlib/reflectionClass.kt"); runTest("compiler/fir/resolve/testData/resolve/stdlib/reflectionClass.kt");
@@ -34,6 +34,8 @@ fun FirElement.render(): String = buildString { this@render.accept(FirRenderer(t
fun ConeKotlinType.render(): String { fun ConeKotlinType.render(): String {
return when (this) { return when (this) {
is ConeTypeVariableType -> "TypeVariable(${this.lookupTag.name})"
is ConeDefinitelyNotNullType -> "${original.render()}!"
is ConeKotlinErrorType -> "error: $reason" is ConeKotlinErrorType -> "error: $reason"
is ConeClassErrorType -> "class error: $reason" is ConeClassErrorType -> "class error: $reason"
is ConeCapturedType -> "captured type: lowerType = ${lowerType?.render()}" is ConeCapturedType -> "captured type: lowerType = ${lowerType?.render()}"
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
class FirResolvedCallableReferenceImpl( open class FirResolvedCallableReferenceImpl(
session: FirSession, session: FirSession,
psi: PsiElement?, psi: PsiElement?,
override val name: Name, override val name: Name,
@@ -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")
}