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