From a226e40e346e4720e1644dc047ebbde618b026b3 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 24 Jul 2019 16:08:46 +0300 Subject: [PATCH] [FIR] Refactor FirResolveBodyTransformer Extract from it components responsible for call completion, call resolution and resolution of FQN --- .../jetbrains/kotlin/fir/FirCallResolver.kt | 250 +++++++ .../kotlin/fir/FirQualifiedNameResolver.kt | 72 ++ .../kotlin/fir/resolve/ResolveUtils.kt | 109 ++- .../kotlin/fir/resolve/SessionHolder.kt | 24 + .../fir/resolve/inference/FirCallCompleter.kt | 123 ++++ .../transformers/FirBodyResolveTransformer.kt | 678 +++--------------- ...CallCompletionResultsWriterTransformer.kt} | 2 +- .../transformers/ReturnTypeCalculator.kt | 96 +++ 8 files changed, 771 insertions(+), 583 deletions(-) create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirQualifiedNameResolver.kt create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SessionHolder.kt create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt rename compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/{FirCallCompleterTransformer.kt => FirCallCompletionResultsWriterTransformer.kt} (99%) create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ReturnTypeCalculator.kt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt new file mode 100644 index 00000000000..34e2ac89920 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -0,0 +1,250 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir + +import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration +import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.FirFunctionCall +import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess +import org.jetbrains.kotlin.fir.expressions.FirStatement +import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedQualifierImpl +import org.jetbrains.kotlin.fir.references.FirBackingFieldReferenceImpl +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.BodyResolveComponents +import org.jetbrains.kotlin.fir.resolve.calls.* +import org.jetbrains.kotlin.fir.resolve.transformers.FirBodyResolveTransformer +import org.jetbrains.kotlin.fir.resolve.transformers.StoreNameReference +import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe +import org.jetbrains.kotlin.fir.resolve.transformers.resultType +import org.jetbrains.kotlin.fir.resolve.typeForQualifier +import org.jetbrains.kotlin.fir.resolve.typeFromCallee +import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol +import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol +import org.jetbrains.kotlin.fir.symbols.ConeSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol +import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator + +class FirCallResolver( + private val transformer: FirBodyResolveTransformer, + private val inferenceComponents: InferenceComponents, + private val scopes: List, + private val localScopes: List, + private val implicitReceiverStack: List, + private val qualifiedResolver: FirQualifiedNameResolver +) : BodyResolveComponents by transformer { + + fun resolveCallAndSelectCandidate(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?, file: FirFile): FirFunctionCall { + qualifiedResolver.reset() + @Suppress("NAME_SHADOWING") + val functionCall = (functionCall.transformExplicitReceiver(transformer, noExpectedType) as FirFunctionCall) + .transformArguments(transformer, null) as FirFunctionCall + + val name = functionCall.calleeReference.name + + val explicitReceiver = functionCall.explicitReceiver + val arguments = functionCall.arguments + val typeArguments = functionCall.typeArguments + + val info = CallInfo( + CallKind.Function, + explicitReceiver, + arguments, + functionCall.safe, + typeArguments, + session, + file, + transformer.container + ) { it.resultType } + val resolver = CallResolver(returnTypeCalculator, inferenceComponents) + resolver.callInfo = info + resolver.scopes = (scopes + localScopes).asReversed() + + val consumer = createFunctionConsumer(session, name, info, inferenceComponents, resolver.collector, resolver) + val result = resolver.runTowerResolver(consumer, implicitReceiverStack.asReversed()) + val bestCandidates = result.bestCandidates() + val reducedCandidates = if (result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED) { + bestCandidates.toSet() + } else { + ConeOverloadConflictResolver(TypeSpecificityComparator.NONE, inferenceComponents) + .chooseMaximallySpecificCandidates(bestCandidates, discriminateGenerics = false) + } + + +/* + fun isInvoke() + + val resultExpression = + + when { + successCandidates.singleOrNull() as? ConeCallableSymbol -> { + FirFunctionCallImpl(functionCall.session, functionCall.psi, safe = functionCall.safe).apply { + calleeReference = + functionCall.calleeReference.transformSingle(this@FirBodyResolveTransformer, result.successCandidates()) + explicitReceiver = + FirQualifiedAccessExpressionImpl( + functionCall.session, + functionCall.calleeReference.psi, + functionCall.safe + ).apply { + calleeReference = createResolvedNamedReference( + functionCall.calleeReference, + result.variableChecker.successCandidates() as List + ) + explicitReceiver = functionCall.explicitReceiver + } + } + } + is ApplicabilityChecker -> { + functionCall.transformCalleeReference(this, result.successCandidates()) + } + else -> functionCall + } +*/ + val nameReference = createResolvedNamedReference( + functionCall.calleeReference, + reducedCandidates, + result.currentApplicability + ) + + val resultExpression = functionCall.transformCalleeReference(StoreNameReference, nameReference) as FirFunctionCall + val candidate = resultExpression.candidate() + + // We need desugaring + val resultFunctionCall = if (candidate != null && candidate.callInfo != info) { + functionCall.copy( + explicitReceiver = candidate.callInfo.explicitReceiver, + arguments = candidate.callInfo.arguments, + safe = candidate.callInfo.isSafeCall + ) + } else { + resultExpression + } + val typeRef = typeFromCallee(resultFunctionCall) + if (typeRef.type is ConeKotlinErrorType) { + resultFunctionCall.resultType = typeRef + } + return resultFunctionCall + } + + fun resolveVariableAccessAndSelectCandidate(qualifiedAccess: T, file: FirFile): FirStatement { + val callee = qualifiedAccess.calleeReference as? FirSimpleNamedReference ?: return qualifiedAccess + + qualifiedResolver.initProcessingQualifiedAccess(qualifiedAccess, callee) + + @Suppress("NAME_SHADOWING") + val qualifiedAccess = qualifiedAccess.transformExplicitReceiver(transformer, noExpectedType) + qualifiedResolver.replacedQualifier(qualifiedAccess)?.let { return it } + + val info = CallInfo( + CallKind.VariableAccess, + qualifiedAccess.explicitReceiver, + emptyList(), + qualifiedAccess.safe, + emptyList(), + session, + file, + transformer.container + ) { it.resultType } + val resolver = CallResolver(returnTypeCalculator, inferenceComponents) + resolver.callInfo = info + resolver.scopes = (scopes + localScopes).asReversed() + + val consumer = createVariableAndObjectConsumer( + session, + callee.name, + info, inferenceComponents, + resolver.collector + ) + val result = resolver.runTowerResolver(consumer, implicitReceiverStack.asReversed()) + + val candidates = result.bestCandidates() + val nameReference = createResolvedNamedReference( + callee, + candidates, + result.currentApplicability + ) + + if (qualifiedAccess.explicitReceiver == null && + (candidates.size <= 1 && result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED) + ) { + qualifiedResolver.tryResolveAsQualifier()?.let { return it } + } + + val referencedSymbol = when (nameReference) { + is FirResolvedCallableReference -> nameReference.coneSymbol + is FirNamedReferenceWithCandidate -> nameReference.candidateSymbol + else -> null + } + if (referencedSymbol is ConeClassLikeSymbol) { + return FirResolvedQualifierImpl(session, nameReference.psi, referencedSymbol.classId).apply { + resultType = typeForQualifier(this) + } + } + + if (qualifiedAccess.explicitReceiver == null) { + qualifiedResolver.reset() + } + + @Suppress("UNCHECKED_CAST") + val resultExpression = qualifiedAccess.transformCalleeReference(StoreNameReference, nameReference) as T + if (resultExpression is FirExpression) transformer.storeTypeFromCallee(resultExpression) + return resultExpression + } + + private fun createResolvedNamedReference( + namedReference: FirNamedReference, + candidates: Collection, + applicability: CandidateApplicability + ): FirNamedReference { + val name = namedReference.name + val firSession = namedReference.session + val psi = namedReference.psi + return when { + candidates.isEmpty() -> FirErrorNamedReference( + firSession, psi, "Unresolved name: $name" + ) + applicability < CandidateApplicability.SYNTHETIC_RESOLVED -> { + FirErrorNamedReference( + firSession, psi, + "Inapplicable($applicability): ${candidates.map { describeSymbol(it.symbol) }}", + namedReference.name + ) + } + candidates.size == 1 -> { + val candidate = candidates.single() + val coneSymbol = candidate.symbol + when { + coneSymbol is FirBackingFieldSymbol -> FirBackingFieldReferenceImpl(firSession, psi, coneSymbol) + coneSymbol is FirVariableSymbol && + (coneSymbol !is FirPropertySymbol || coneSymbol.firUnsafe().typeParameters.isEmpty()) -> + FirResolvedCallableReferenceImpl(firSession, psi, name, coneSymbol) + else -> FirNamedReferenceWithCandidate(firSession, psi, name, candidate) + } + } + else -> FirErrorNamedReference( + firSession, psi, "Ambiguity: $name, ${candidates.map { describeSymbol(it.symbol) }}", + namedReference.name + ) + } + } + + + private fun describeSymbol(symbol: ConeSymbol): String { + return when (symbol) { + is ConeClassLikeSymbol -> symbol.classId.asString() + is ConeCallableSymbol -> symbol.callableId.toString() + else -> "$symbol" + } + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirQualifiedNameResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirQualifiedNameResolver.kt new file mode 100644 index 00000000000..63d51f1d5e2 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirQualifiedNameResolver.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir + +import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess +import org.jetbrains.kotlin.fir.expressions.FirStatement +import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedQualifierImpl +import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference +import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents +import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider +import org.jetbrains.kotlin.fir.resolve.transformers.PackageOrClass +import org.jetbrains.kotlin.fir.resolve.transformers.resolveToPackageOrClass +import org.jetbrains.kotlin.fir.resolve.transformers.resultType +import org.jetbrains.kotlin.fir.resolve.typeForQualifier +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name + +class FirQualifiedNameResolver(components: BodyResolveComponents) : BodyResolveComponents by components { + private var qualifierStack = mutableListOf() + private var qualifierPartsToDrop = 0 + + fun reset() { + qualifierStack.clear() + } + + fun initProcessingQualifiedAccess(qualifiedAccess: FirQualifiedAccess, callee: FirSimpleNamedReference) { + if (qualifiedAccess.safe || callee.name.isSpecial) { + qualifierStack.clear() + } else { + qualifierStack.add(callee.name) + } + } + + fun replacedQualifier(qualifiedAccess: FirQualifiedAccess): FirStatement? = + if (qualifierPartsToDrop > 0) { + qualifierPartsToDrop-- + qualifiedAccess.explicitReceiver ?: qualifiedAccess + } else { + null + } + + fun tryResolveAsQualifier(): FirStatement? { + val symbolProvider = session.service() + var qualifierParts = qualifierStack.asReversed().map { it.asString() } + var resolved: PackageOrClass? + do { + resolved = resolveToPackageOrClass( + symbolProvider, + FqName.fromSegments(qualifierParts) + ) + if (resolved == null) + qualifierParts = qualifierParts.dropLast(1) + } while (resolved == null && qualifierParts.isNotEmpty()) + + if (resolved != null) { + qualifierPartsToDrop = qualifierParts.size - 1 + return FirResolvedQualifierImpl( + session, + null /* TODO */, + resolved.packageFqName, + resolved.relativeClassFqName + ) + .apply { resultType = typeForQualifier(this) } + } + + return null + } + +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index 5dd1f9ececb..fbbc4670b27 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -5,18 +5,22 @@ package org.jetbrains.kotlin.fir.resolve -import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.render -import org.jetbrains.kotlin.fir.service +import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess +import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier +import org.jetbrains.kotlin.fir.references.FirErrorNamedReference +import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate +import org.jetbrains.kotlin.fir.resolve.transformers.resultType +import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType import org.jetbrains.kotlin.fir.symbols.* +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol 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.ConeTypeParameterTypeImpl -import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl +import org.jetbrains.kotlin.fir.types.impl.* +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -167,3 +171,94 @@ fun FirFunction.constructFunctionalTypeRef(session: FirSession): FirResolvedType return FirResolvedTypeRefImpl(session, psi, functionalType) } + +fun BodyResolveComponents.typeForQualifier(resolvedQualifier: FirResolvedQualifier): FirTypeRef { + val classId = resolvedQualifier.classId + val resultType = resolvedQualifier.resultType + if (classId != null) { + val classSymbol = symbolProvider.getClassLikeSymbolByFqName(classId)!! + val declaration = classSymbol.fir + if (declaration is FirClass) { + if (declaration.classKind == ClassKind.OBJECT) { + return resultType.resolvedTypeFromPrototype( + classSymbol.constructType(emptyArray(), false) + ) + } else if (declaration.classKind == ClassKind.ENUM_ENTRY) { + val enumClassSymbol = symbolProvider.getClassLikeSymbolByFqName(classSymbol.classId.outerClassId!!)!! + return resultType.resolvedTypeFromPrototype( + enumClassSymbol.constructType(emptyArray(), false) + ) + } else { + if (declaration is FirRegularClass) { + val companionObject = declaration.companionObject + if (companionObject != null) { + return resultType.resolvedTypeFromPrototype( + companionObject.symbol.constructType(emptyArray(), false) + ) + } + } + } + } + } + // TODO: Handle no value type here + return resultType.resolvedTypeFromPrototype( + StandardClassIds.Unit(symbolProvider).constructType(emptyArray(), isNullable = false) + ) +} + + +fun BodyResolveComponents.typeFromCallee(access: T): FirResolvedTypeRef { + val makeNullable: Boolean by lazy { + access.safe && access.explicitReceiver!!.resultType.coneTypeUnsafe().isNullable + } + + return when (val newCallee = access.calleeReference) { + is FirErrorNamedReference -> + FirErrorTypeRefImpl(session, access.psi, newCallee.errorReason) + is FirNamedReferenceWithCandidate -> { + typeFromSymbol(newCallee.candidateSymbol, makeNullable) + } + is FirResolvedCallableReference -> { + typeFromSymbol(newCallee.coneSymbol, makeNullable) + } + is FirThisReference -> { + val labelName = newCallee.labelName + val types = if (labelName == null) labels.values() else labels[Name.identifier(labelName)] + val type = types.lastOrNull() ?: ConeKotlinErrorType("Unresolved this@$labelName") + FirResolvedTypeRefImpl(session, null, type, emptyList()) + } + else -> error("Failed to extract type from: $newCallee") + } +} + +private fun BodyResolveComponents.typeFromSymbol(symbol: ConeSymbol, makeNullable: Boolean): FirResolvedTypeRef { + return when (symbol) { + is FirCallableSymbol<*> -> { + val returnType = returnTypeCalculator.tryCalculateReturnType(symbol.fir) + if (makeNullable) { + returnType.withReplacedConeType( + session, + returnType.coneTypeUnsafe().withNullability(ConeNullability.NULLABLE) + ) + } else { + returnType + } + } + is ConeClassifierSymbol -> { + val fir = (symbol as? FirBasedSymbol<*>)?.fir + // TODO: unhack + if (fir is FirEnumEntry) { + (fir.superTypeRefs.firstOrNull() as? FirResolvedTypeRef) ?: FirErrorTypeRefImpl( + session, + null, + "no enum item supertype" + ) + } else + FirResolvedTypeRefImpl( + session, null, symbol.constructType(emptyArray(), isNullable = false), + annotations = emptyList() + ) + } + else -> error("WTF ! $symbol") + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SessionHolder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SessionHolder.kt new file mode 100644 index 00000000000..f4e58031627 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SessionHolder.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.resolve + +import com.google.common.collect.SetMultimap +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.name.Name + +interface SessionHolder { + val session: FirSession +} + +interface BodyResolveComponents : SessionHolder { + val returnTypeCalculator: ReturnTypeCalculator + val labels: SetMultimap + val noExpectedType: FirTypeRef + val symbolProvider: FirSymbolProvider +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt new file mode 100644 index 00000000000..bdadf4bcfa9 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt @@ -0,0 +1,123 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.resolve.inference + +import org.jetbrains.kotlin.fir.copy +import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction +import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl +import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess +import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents +import org.jetbrains.kotlin.fir.resolve.calls.* +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor +import org.jetbrains.kotlin.fir.resolve.transformers.* +import org.jetbrains.kotlin.fir.resolve.transformers.MapArguments +import org.jetbrains.kotlin.fir.resolve.typeFromCallee +import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype +import org.jetbrains.kotlin.fir.transformSingle +import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.calls.components.InferenceSession +import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor +import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter +import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition +import org.jetbrains.kotlin.types.model.StubTypeMarker +import org.jetbrains.kotlin.types.model.TypeVariableMarker + +class FirCallCompleter( + private val transformer: FirBodyResolveTransformer, + private val inferenceComponents: InferenceComponents +) : BodyResolveComponents by transformer { + fun completeCall(call: T, expectedTypeRef: FirTypeRef?): T { + val typeRef = typeFromCallee(call) + if (typeRef.type is ConeKotlinErrorType) { + if (call is FirExpression) { + call.resultType = typeRef + } + return call + } + val candidate = call.candidate() ?: return call + val initialSubstitutor = candidate.substitutor + + val initialType = initialSubstitutor.substituteOrSelf(typeRef.type) + + if (expectedTypeRef is FirResolvedTypeRef) { + candidate.system.addSubtypeConstraint(initialType, expectedTypeRef.type, SimpleConstraintSystemConstraintPosition) + } + + val completionMode = candidate.computeCompletionMode(inferenceComponents, expectedTypeRef, initialType) + val completer = ConstraintSystemCompleter(inferenceComponents) + val replacements = mutableMapOf() + + val analyzer = PostponedArgumentsAnalyzer(LambdaAnalyzerImpl(replacements), { it.resultType }, inferenceComponents) + + completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, listOf(call), initialType) { + analyzer.analyze(candidate.system.asPostponedArgumentsAnalyzerContext(), it) + } + + call.transformChildren(MapArguments, replacements.toMap()) + + if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) { + val finalSubstitutor = + candidate.system.asReadOnlyStorage().buildAbstractResultingSubstitutor(inferenceComponents.ctx) as ConeSubstitutor + return call.transformSingle( + FirCallCompletionResultsWriterTransformer(session, finalSubstitutor, returnTypeCalculator), + null + ) + } + return call + } + + private inner class LambdaAnalyzerImpl( + val replacements: MutableMap + ) : LambdaAnalyzer { + override fun analyzeAndGetLambdaReturnArguments( + lambdaArgument: FirAnonymousFunction, + isSuspend: Boolean, + receiverType: ConeKotlinType?, + parameters: List, + expectedReturnType: ConeKotlinType?, + rawReturnType: ConeKotlinType, + stubsForPostponedVariables: Map + ): Pair, InferenceSession> { + + val itParam = when { + lambdaArgument.valueParameters.isEmpty() && parameters.size == 1 -> + FirValueParameterImpl( + session, + null, + Name.identifier("it"), + FirResolvedTypeRefImpl(session, null, parameters.single(), emptyList()), + defaultValue = null, + isCrossinline = false, + isNoinline = false, + isVararg = false + ) + else -> null + } + + val expectedReturnTypeRef = expectedReturnType?.let { lambdaArgument.returnTypeRef.resolvedTypeFromPrototype(it) } + + val newLambdaExpression = lambdaArgument.copy( + receiverTypeRef = receiverType?.let { lambdaArgument.receiverTypeRef!!.resolvedTypeFromPrototype(it) }, + valueParameters = lambdaArgument.valueParameters.mapIndexed { index, parameter -> + parameter.transformReturnTypeRef(StoreType, parameter.returnTypeRef.resolvedTypeFromPrototype(parameters[index])) + parameter + } + listOfNotNull(itParam), + returnTypeRef = expectedReturnTypeRef ?: noExpectedType + ) + + replacements[lambdaArgument] = + newLambdaExpression.transformSingle(transformer, FirBodyResolveTransformer.LambdaResolution(expectedReturnTypeRef)) + + return listOfNotNull(newLambdaExpression.body?.statements?.lastOrNull() as? FirExpression) to InferenceSession.default + } + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt index 45ac29ca75a..60da548916d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt @@ -6,27 +6,25 @@ package org.jetbrains.kotlin.fir.resolve.transformers import com.google.common.collect.LinkedHashMultimap -import org.jetbrains.kotlin.descriptors.ClassKind +import com.google.common.collect.SetMultimap import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl import org.jetbrains.kotlin.fir.expressions.* -import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedQualifierImpl -import org.jetbrains.kotlin.fir.references.FirBackingFieldReferenceImpl -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.* -import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor +import org.jetbrains.kotlin.fir.resolve.inference.FirCallCompleter import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.addImportingScopes import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope 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.symbols.impl.* +import org.jetbrains.kotlin.fir.symbols.ConeSymbol +import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol +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.* import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult @@ -37,29 +35,43 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator -import org.jetbrains.kotlin.resolve.calls.components.InferenceSession -import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor -import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter -import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition -import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator -import org.jetbrains.kotlin.types.model.* +import org.jetbrains.kotlin.types.model.KotlinTypeMarker +import org.jetbrains.kotlin.types.model.SimpleTypeMarker +import org.jetbrains.kotlin.types.model.TypeConstructorMarker +import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContextDelegate import org.jetbrains.kotlin.utils.addIfNotNull open class FirBodyResolveTransformer( - val session: FirSession, val implicitTypeOnly: Boolean, + final override val session: FirSession, + val implicitTypeOnly: Boolean, val scopeSession: ScopeSession = ScopeSession() -) : FirTransformer() { +) : FirTransformer(), BodyResolveComponents { + final override val returnTypeCalculator: ReturnTypeCalculator = ReturnTypeCalculatorWithJump(session, scopeSession) + override val labels: SetMultimap = LinkedHashMultimap.create() + override val noExpectedType = FirImplicitTypeRefImpl(session, null) - val symbolProvider = session.service() - - override fun transformElement(element: E, data: Any?): CompositeTransformResult { - @Suppress("UNCHECKED_CAST") - return (element.transformChildren(this, data) as E).compose() - } + override val symbolProvider = session.service() + val scopes = mutableListOf() private var packageFqName = FqName.ROOT private lateinit var file: FirFile - private var container: FirDeclaration? = null + + private var _container: FirDeclaration? = null + internal var container: FirDeclaration + get() = _container!! + set(value) { + _container = value + } + + private val localScopes = mutableListOf() + private val implicitReceiverStack = mutableListOf() + private val inferenceComponents = inferenceComponents(session, returnTypeCalculator, scopeSession) + + private var primaryConstructorParametersScope: FirLocalScope? = null + + private val callCompleter: FirCallCompleter = FirCallCompleter(this, inferenceComponents) + private val qualifiedResolver: FirQualifiedNameResolver = FirQualifiedNameResolver(this) + private val callResolver: FirCallResolver = FirCallResolver(this, inferenceComponents, scopes, localScopes, implicitReceiverStack, qualifiedResolver) override fun transformFile(file: FirFile, data: Any?): CompositeTransformResult { packageFqName = file.packageFqName @@ -71,7 +83,10 @@ open class FirBodyResolveTransformer( } } - private var primaryConstructorParametersScope: FirLocalScope? = null + override fun transformElement(element: E, data: Any?): CompositeTransformResult { + @Suppress("UNCHECKED_CAST") + return (element.transformChildren(this, data) as E).compose() + } override fun transformConstructor(constructor: FirConstructor, data: Any?): CompositeTransformResult { if (implicitTypeOnly) return constructor.compose() @@ -102,19 +117,6 @@ open class FirBodyResolveTransformer( return super.transformValueParameter(valueParameter, valueParameter.returnTypeRef) } - private inline fun withLabelAndReceiverType(labelName: Name, owner: FirElement, type: ConeKotlinType, block: () -> T): T { - labels.put(labelName, type) - when (owner) { - is FirRegularClass -> implicitReceiverStack += ImplicitDispatchReceiverValue(owner.symbol, type) - is FirFunction -> implicitReceiverStack += ImplicitExtensionReceiverValue(type) - else -> throw IllegalArgumentException("Incorrect label & receiver owner: ${owner.javaClass}") - } - val result = block() - implicitReceiverStack.removeAt(implicitReceiverStack.size - 1) - labels.remove(labelName, type) - return result - } - override fun transformRegularClass(regularClass: FirRegularClass, data: Any?): CompositeTransformResult { return withScopeCleanup(scopes) { val oldConstructorScope = primaryConstructorParametersScope @@ -177,217 +179,6 @@ open class FirBodyResolveTransformer( return resolved.compose() } - protected inline fun withScopeCleanup(scopes: MutableList<*>, crossinline l: () -> T): T { - val sizeBefore = scopes.size - val result = l() - val size = scopes.size - assert(size >= sizeBefore) - repeat(size - sizeBefore) { - scopes.let { it.removeAt(it.size - 1) } - } - return result - } - - val scopes = mutableListOf() - private val localScopes = mutableListOf() - - private val labels = LinkedHashMultimap.create() - - private val implicitReceiverStack = mutableListOf() - - private val jump = ReturnTypeCalculatorWithJump(session, scopeSession) - - private fun storeTypeFromCallee(access: T) where T : FirQualifiedAccess, T : FirExpression { - access.resultType = typeFromCallee(access) - } - - private fun typeFromSymbol(symbol: ConeSymbol, makeNullable: Boolean): FirResolvedTypeRef { - return when (symbol) { - is FirCallableSymbol<*> -> { - val returnType = jump.tryCalculateReturnType(symbol.fir) - if (makeNullable) { - returnType.withReplacedConeType( - session, - returnType.coneTypeUnsafe().withNullability(ConeNullability.NULLABLE) - ) - } else { - returnType - } - } - is ConeClassifierSymbol -> { - val fir = (symbol as? FirBasedSymbol<*>)?.fir - // TODO: unhack - if (fir is FirEnumEntry) { - (fir.superTypeRefs.firstOrNull() as? FirResolvedTypeRef) ?: FirErrorTypeRefImpl( - session, - null, - "no enum item supertype" - ) - } else - FirResolvedTypeRefImpl( - session, null, symbol.constructType(emptyArray(), isNullable = false), - annotations = emptyList() - ) - } - else -> error("WTF ! $symbol") - } - } - - private fun typeFromCallee(access: T): FirResolvedTypeRef where T : FirQualifiedAccess { - val makeNullable: Boolean by lazy { - access.safe && access.explicitReceiver!!.resultType.coneTypeUnsafe().isNullable - } - - return when (val newCallee = access.calleeReference) { - is FirErrorNamedReference -> - FirErrorTypeRefImpl(session, access.psi, newCallee.errorReason) - is FirNamedReferenceWithCandidate -> { - typeFromSymbol(newCallee.candidateSymbol, makeNullable) - } - is FirResolvedCallableReference -> { - typeFromSymbol(newCallee.coneSymbol, makeNullable) - } - is FirThisReference -> { - val labelName = newCallee.labelName - val types = if (labelName == null) labels.values() else labels[Name.identifier(labelName)] - val type = types.lastOrNull() ?: ConeKotlinErrorType("Unresolved this@$labelName") - FirResolvedTypeRefImpl(session, null, type, emptyList()) - } - else -> error("Failed to extract type from: $newCallee") - } - } - - - private var qualifierStack = mutableListOf() - private var qualifierPartsToDrop = 0 - - private fun tryResolveAsQualifier(): FirStatement? { - - val symbolProvider = session.service() - var qualifierParts = qualifierStack.asReversed().map { it.asString() } - var resolved: PackageOrClass? - do { - resolved = resolveToPackageOrClass( - symbolProvider, - FqName.fromSegments(qualifierParts) - ) - if (resolved == null) - qualifierParts = qualifierParts.dropLast(1) - } while (resolved == null && qualifierParts.isNotEmpty()) - - if (resolved != null) { - qualifierPartsToDrop = qualifierParts.size - 1 - return FirResolvedQualifierImpl(session, null /* TODO */, resolved.packageFqName, resolved.relativeClassFqName) - .apply { resultType = typeForQualifier(this) } - } - - return null - } - - private fun typeForQualifier(resolvedQualifier: FirResolvedQualifier): FirTypeRef { - val classId = resolvedQualifier.classId - val resultType = resolvedQualifier.resultType - if (classId != null) { - val classSymbol = symbolProvider.getClassLikeSymbolByFqName(classId)!! - val declaration = classSymbol.fir - if (declaration is FirClass) { - if (declaration.classKind == ClassKind.OBJECT) { - return resultType.resolvedTypeFromPrototype( - classSymbol.constructType(emptyArray(), false) - ) - } else if (declaration.classKind == ClassKind.ENUM_ENTRY) { - val enumClassSymbol = symbolProvider.getClassLikeSymbolByFqName(classSymbol.classId.outerClassId!!)!! - return resultType.resolvedTypeFromPrototype( - enumClassSymbol.constructType(emptyArray(), false) - ) - } else { - if (declaration is FirRegularClass) { - val companionObject = declaration.companionObject - if (companionObject != null) { - return resultType.resolvedTypeFromPrototype( - companionObject.symbol.constructType(emptyArray(), false) - ) - } - } - } - } - } - // TODO: Handle no value type here - return resultType.resolvedTypeFromPrototype( - StandardClassIds.Unit(symbolProvider).constructType(emptyArray(), isNullable = false) - ) - } - - private fun transformCallee(qualifiedAccess: T): FirStatement { - val callee = qualifiedAccess.calleeReference as? FirSimpleNamedReference ?: return qualifiedAccess - if (qualifiedAccess.safe || callee.name.isSpecial) { - qualifierStack.clear() - } else { - qualifierStack.add(callee.name) - } - - val qualifiedAccess = qualifiedAccess.transformExplicitReceiver(this, noExpectedType) - if (qualifierPartsToDrop > 0) { - qualifierPartsToDrop-- - return qualifiedAccess.explicitReceiver ?: qualifiedAccess - } - - val info = CallInfo( - CallKind.VariableAccess, - qualifiedAccess.explicitReceiver, - emptyList(), - qualifiedAccess.safe, - emptyList(), - session, - file, - container!! - ) { it.resultType } - val resolver = CallResolver(jump, inferenceComponents) - resolver.callInfo = info - resolver.scopes = (scopes + localScopes).asReversed() - - val consumer = createVariableAndObjectConsumer( - session, - callee.name, - info, inferenceComponents, - resolver.collector - ) - val result = resolver.runTowerResolver(consumer, implicitReceiverStack.asReversed()) - - val candidates = result.bestCandidates() - val nameReference = createResolvedNamedReference( - callee, - candidates, - result.currentApplicability - ) - - if (qualifiedAccess.explicitReceiver == null && - (candidates.size <= 1 && result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED) - ) { - tryResolveAsQualifier()?.let { return it } - } - - val referencedSymbol = when (nameReference) { - is FirResolvedCallableReference -> nameReference.coneSymbol - is FirNamedReferenceWithCandidate -> nameReference.candidateSymbol - else -> null - } - if (referencedSymbol is ConeClassLikeSymbol) { - return FirResolvedQualifierImpl(session, nameReference.psi, referencedSymbol.classId).apply { - resultType = typeForQualifier(this) - } - } - - if (qualifiedAccess.explicitReceiver == null) { - qualifierStack.clear() - } - - val resultExpression = - qualifiedAccess.transformCalleeReference(StoreNameReference, nameReference) as T - if (resultExpression is FirExpression) storeTypeFromCallee(resultExpression) - return resultExpression - } - override fun transformQualifiedAccessExpression( qualifiedAccessExpression: FirQualifiedAccessExpression, data: Any? @@ -395,7 +186,6 @@ open class FirBodyResolveTransformer( when (val callee = qualifiedAccessExpression.calleeReference) { is FirThisReference -> { - val labelName = callee.labelName val types = if (labelName == null) labels.values() else labels[Name.identifier(labelName)] val type = types.lastOrNull() ?: ConeKotlinErrorType("Unresolved this@$labelName") @@ -426,11 +216,12 @@ open class FirBodyResolveTransformer( return qualifiedAccessExpression.compose() } } - val transformedCallee = transformCallee(qualifiedAccessExpression) + + val transformedCallee = callResolver.resolveVariableAccessAndSelectCandidate(qualifiedAccessExpression, file) // NB: here we can get raw expression because of dropped qualifiers (see transform callee), // so candidate existence must be checked before calling completion return if (transformedCallee is FirQualifiedAccessExpression && transformedCallee.candidate() != null) { - completeTypeInference(transformedCallee, data as? FirTypeRef).compose() + callCompleter.completeCall(transformedCallee, data as? FirTypeRef).compose() } else { transformedCallee.compose() } @@ -440,9 +231,10 @@ open class FirBodyResolveTransformer( variableAssignment: FirVariableAssignment, data: Any? ): CompositeTransformResult { - val resolvedAssignment = transformCallee(variableAssignment) + // val resolvedAssignment = transformCallee(variableAssignment) + val resolvedAssignment = callResolver.resolveVariableAccessAndSelectCandidate(variableAssignment, file) return if (resolvedAssignment is FirVariableAssignment) { - val completeAssignment = completeTypeInference(resolvedAssignment, noExpectedType) + val completeAssignment = callCompleter.completeCall(resolvedAssignment, noExpectedType) val expectedType = typeFromCallee(completeAssignment) completeAssignment.transformRValue(this, expectedType).compose() } else { @@ -551,198 +343,13 @@ open class FirBodyResolveTransformer( } } - private val noExpectedType = FirImplicitTypeRefImpl(session, null) - private val inferenceComponents = inferenceComponents(session, jump, scopeSession) - - private fun resolveCallAndSelectCandidate(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?): FirFunctionCall { - - qualifierStack.clear() - - val functionCall = - (functionCall.transformExplicitReceiver(this, noExpectedType) as FirFunctionCall) - .transformArguments(this, null) as FirFunctionCall - - val name = functionCall.calleeReference.name - - val explicitReceiver = functionCall.explicitReceiver - val arguments = functionCall.arguments - val typeArguments = functionCall.typeArguments - - val info = CallInfo( - CallKind.Function, - explicitReceiver, - arguments, - functionCall.safe, - typeArguments, - session, - file, - container!! - ) { it.resultType } - val resolver = CallResolver(jump, inferenceComponents) - resolver.callInfo = info - resolver.scopes = (scopes + localScopes).asReversed() - - val consumer = createFunctionConsumer(session, name, info, inferenceComponents, resolver.collector, resolver) - val result = resolver.runTowerResolver(consumer, implicitReceiverStack.asReversed()) - val bestCandidates = result.bestCandidates() - val reducedCandidates = if (result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED) { - bestCandidates.toSet() - } else { - ConeOverloadConflictResolver(TypeSpecificityComparator.NONE, inferenceComponents) - .chooseMaximallySpecificCandidates(bestCandidates, discriminateGenerics = false) - } - - -// fun isInvoke() -// -// val resultExpression = -// -// when { -// successCandidates.singleOrNull() as? ConeCallableSymbol -> { -// FirFunctionCallImpl(functionCall.session, functionCall.psi, safe = functionCall.safe).apply { -// calleeReference = -// functionCall.calleeReference.transformSingle(this@FirBodyResolveTransformer, result.successCandidates()) -// explicitReceiver = -// FirQualifiedAccessExpressionImpl( -// functionCall.session, -// functionCall.calleeReference.psi, -// functionCall.safe -// ).apply { -// calleeReference = createResolvedNamedReference( -// functionCall.calleeReference, -// result.variableChecker.successCandidates() as List -// ) -// explicitReceiver = functionCall.explicitReceiver -// } -// } -// } -// is ApplicabilityChecker -> { -// functionCall.transformCalleeReference(this, result.successCandidates()) -// } -// else -> functionCall -// } - val nameReference = createResolvedNamedReference( - functionCall.calleeReference, - reducedCandidates, - result.currentApplicability - ) - - val resultExpression = functionCall.transformCalleeReference(StoreNameReference, nameReference) as FirFunctionCall - val candidate = resultExpression.candidate() - - // We need desugaring - val resultFunctionCall = if (candidate != null && candidate.callInfo != info) { - functionCall.copy( - explicitReceiver = candidate.callInfo.explicitReceiver, - arguments = candidate.callInfo.arguments, - safe = candidate.callInfo.isSafeCall - ) - } else { - resultExpression - } - val typeRef = typeFromCallee(resultFunctionCall) - if (typeRef.type is ConeKotlinErrorType) { - resultFunctionCall.resultType = typeRef - } - return resultFunctionCall - } - data class LambdaResolution(val expectedReturnTypeRef: FirResolvedTypeRef?) - private fun completeTypeInference(qualifiedAccess: T, expectedTypeRef: FirTypeRef?): T { - val typeRef = typeFromCallee(qualifiedAccess) - if (typeRef.type is ConeKotlinErrorType) { - if (qualifiedAccess is FirExpression) { - qualifiedAccess.resultType = typeRef - } - return qualifiedAccess - } - val candidate = qualifiedAccess.candidate() ?: return qualifiedAccess - val initialSubstitutor = candidate.substitutor - - val initialType = initialSubstitutor.substituteOrSelf(typeRef.type) - - if (expectedTypeRef is FirResolvedTypeRef) { - candidate.system.addSubtypeConstraint(initialType, expectedTypeRef.type, SimpleConstraintSystemConstraintPosition) - } - - val completionMode = candidate.computeCompletionMode(inferenceComponents, expectedTypeRef, initialType) - val completer = ConstraintSystemCompleter(inferenceComponents) - val replacements = mutableMapOf() - - val analyzer = PostponedArgumentsAnalyzer(object : LambdaAnalyzer { - override fun analyzeAndGetLambdaReturnArguments( - lambdaArgument: FirAnonymousFunction, - isSuspend: Boolean, - receiverType: ConeKotlinType?, - parameters: List, - expectedReturnType: ConeKotlinType?, - rawReturnType: ConeKotlinType, - stubsForPostponedVariables: Map - ): Pair, InferenceSession> { - - val itParam = when { - lambdaArgument.valueParameters.isEmpty() && parameters.size == 1 -> - FirValueParameterImpl( - session, - null, - Name.identifier("it"), - FirResolvedTypeRefImpl(session, null, parameters.single(), emptyList()), - defaultValue = null, - isCrossinline = false, - isNoinline = false, - isVararg = false - ) - else -> null - } - - - val expectedReturnTypeRef = expectedReturnType?.let { lambdaArgument.returnTypeRef.resolvedTypeFromPrototype(it) } - - val newLambdaExpression = lambdaArgument.copy( - receiverTypeRef = receiverType?.let { lambdaArgument.receiverTypeRef!!.resolvedTypeFromPrototype(it) }, - valueParameters = lambdaArgument.valueParameters.mapIndexed { index, parameter -> - parameter.transformReturnTypeRef(StoreType, parameter.returnTypeRef.resolvedTypeFromPrototype(parameters[index])) - parameter - } + listOfNotNull(itParam), - returnTypeRef = expectedReturnTypeRef ?: noExpectedType - ) - - replacements[lambdaArgument] = - newLambdaExpression.transformSingle(this@FirBodyResolveTransformer, LambdaResolution(expectedReturnTypeRef)) - - - return listOfNotNull(newLambdaExpression.body?.statements?.lastOrNull() as? FirExpression) to InferenceSession.default - } - - }, { it.resultType }, inferenceComponents) - - completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, listOf(qualifiedAccess), initialType) { - analyzer.analyze( - candidate.system.asPostponedArgumentsAnalyzerContext(), - it -// diagnosticsHolder - ) - } - - qualifiedAccess.transformChildren(MapArguments, replacements.toMap()) - - - if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) { - val finalSubstitutor = - candidate.system.asReadOnlyStorage().buildAbstractResultingSubstitutor(inferenceComponents.ctx) as ConeSubstitutor - return qualifiedAccess.transformSingle( - FirCallCompleterTransformer(session, finalSubstitutor, jump), - null - ) - } - return qualifiedAccess - } - override fun transformTryExpression(tryExpression: FirTryExpression, data: Any?): CompositeTransformResult { + @Suppress("NAME_SHADOWING") val tryExpression = tryExpression.transformChildren(this, data) as FirTryExpression if (tryExpression.resultType !is FirResolvedTypeRef) { - val type = commonSuperType((listOf(tryExpression.tryBlock) + tryExpression.catches.map { it.block }).mapNotNull { + val type = commonSuperType((listOf(tryExpression.tryBlock) + tryExpression.catches.map { it.block }).map { val expression = it.statements.lastOrNull() as? FirExpression if (expression != null) { (expression.resultType as? FirResolvedTypeRef) ?: FirErrorTypeRefImpl(session, null, "No type for when branch result") @@ -764,13 +371,13 @@ open class FirBodyResolveTransformer( val completeInference = try { val initialExplicitReceiver = functionCall.explicitReceiver - val resultExpression = resolveCallAndSelectCandidate(functionCall, expectedTypeRef) + val resultExpression = callResolver.resolveCallAndSelectCandidate(functionCall, expectedTypeRef, file) val resultExplicitReceiver = resultExpression.explicitReceiver if (initialExplicitReceiver !== resultExplicitReceiver && resultExplicitReceiver is FirQualifiedAccess) { // name.invoke() case - completeTypeInference(resultExplicitReceiver, null) + callCompleter.completeCall(resultExplicitReceiver, null) } - completeTypeInference(resultExpression, expectedTypeRef) + callCompleter.completeCall(resultExpression, expectedTypeRef) } catch (e: Throwable) { throw RuntimeException("While resolving call ${functionCall.render()}", e) } @@ -780,51 +387,6 @@ open class FirBodyResolveTransformer( } - 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, - applicability: CandidateApplicability - ): FirNamedReference { - val name = namedReference.name - val firSession = namedReference.session - val psi = namedReference.psi - return when { - candidates.isEmpty() -> FirErrorNamedReference( - firSession, psi, "Unresolved name: $name" - ) - applicability < CandidateApplicability.SYNTHETIC_RESOLVED -> { - FirErrorNamedReference( - firSession, psi, - "Inapplicable($applicability): ${candidates.map { describeSymbol(it.symbol) }}", - namedReference.name - ) - } - candidates.size == 1 -> { - val candidate = candidates.single() - val coneSymbol = candidate.symbol - when { - coneSymbol is FirBackingFieldSymbol -> FirBackingFieldReferenceImpl(firSession, psi, coneSymbol) - coneSymbol is FirVariableSymbol && - (coneSymbol !is FirPropertySymbol || coneSymbol.firUnsafe().typeParameters.isEmpty()) -> - FirResolvedCallableReferenceImpl(firSession, psi, name, coneSymbol) - else -> FirNamedReferenceWithCandidate(firSession, psi, name, candidate) - } - } - else -> FirErrorNamedReference( - firSession, psi, "Ambiguity: $name, ${candidates.map { describeSymbol(it.symbol) }}", - namedReference.name - ) - } - } - // override fun transformNamedReference(namedReference: FirNamedReference, data: Any?): CompositeTransformResult { // if (namedReference is FirErrorNamedReference || namedReference is FirResolvedCallableReference) return namedReference.compose() // val referents = data as? List ?: return namedReference.compose() @@ -833,6 +395,7 @@ open class FirBodyResolveTransformer( override fun transformBlock(block: FirBlock, data: Any?): CompositeTransformResult { + @Suppress("NAME_SHADOWING") val block = block.transformChildren(this, data) as FirBlock val statement = block.statements.lastOrNull() @@ -850,6 +413,7 @@ open class FirBodyResolveTransformer( return block.compose() } + @Deprecated("should be removed after try/when completion") private fun commonSuperType(types: List): FirTypeRef? { val commonSuperType = with(NewCommonSuperTypeCalculator) { with(inferenceComponents.ctx) { @@ -862,7 +426,7 @@ open class FirBodyResolveTransformer( override fun transformWhenExpression(whenExpression: FirWhenExpression, data: Any?): CompositeTransformResult { whenExpression.transformChildren(this, data) if (whenExpression.resultType !is FirResolvedTypeRef) { - val type = commonSuperType(whenExpression.branches.mapNotNull { + val type = commonSuperType(whenExpression.branches.map { val expression = it.result.statements.lastOrNull() as? FirExpression if (expression != null) { (expression.resultType as? FirResolvedTypeRef) ?: FirErrorTypeRefImpl(session, null, "No type for when branch result") @@ -918,20 +482,6 @@ open class FirBodyResolveTransformer( return super.transformConstExpression(constExpression, data) } - private inline var FirExpression.resultType: FirTypeRef - get() = typeRef - set(type) { - replaceTypeRef(type) - } - - private fun withContainer(declaration: FirDeclaration, f: () -> T): T { - val prevContainer = container - container = declaration - val result = f() - container = prevContainer - return result - } - override fun transformDeclaration(declaration: FirDeclaration, data: Any?): CompositeTransformResult { return withContainer(declaration) { super.transformDeclaration(declaration, data) @@ -1121,12 +671,6 @@ open class FirBodyResolveTransformer( return (expression.transformChildren(this, data) as FirStatement).compose() } - fun FirElement.visitNoTransform(transformer: FirTransformer, data: D) { - val result = this.transform(transformer, data) - require(result.single === this) { "become ${result.single}: `${result.single.render()}`, was ${this}: `${this.render()}`" } - } - - override fun transformGetClassCall(getClassCall: FirGetClassCall, data: Any?): CompositeTransformResult { val transformedGetClassCall = super.transformGetClassCall(getClassCall, data).single as FirGetClassCall val kClassSymbol = ClassId.fromString("kotlin/reflect/KClass")(session.service()) @@ -1159,9 +703,52 @@ open class FirBodyResolveTransformer( ) return transformedGetClassCall.compose() } + + // ----------------------- Util functions ----------------------- + + private inline fun withLabelAndReceiverType(labelName: Name, owner: FirElement, type: ConeKotlinType, block: () -> T): T { + labels.put(labelName, type) + when (owner) { + is FirRegularClass -> implicitReceiverStack += ImplicitDispatchReceiverValue(owner.symbol, type) + is FirFunction -> implicitReceiverStack += ImplicitExtensionReceiverValue(type) + else -> throw IllegalArgumentException("Incorrect label & receiver owner: ${owner.javaClass}") + } + val result = block() + implicitReceiverStack.removeAt(implicitReceiverStack.size - 1) + labels.remove(labelName, type) + return result + } + + protected inline fun withScopeCleanup(scopes: MutableList<*>, crossinline l: () -> T): T { + val sizeBefore = scopes.size + val result = l() + val size = scopes.size + assert(size >= sizeBefore) + repeat(size - sizeBefore) { + scopes.let { it.removeAt(it.size - 1) } + } + return result + } + + internal fun storeTypeFromCallee(access: T) where T : FirQualifiedAccess, T : FirExpression { + access.resultType = callCompleter.typeFromCallee(access) + } + + private fun withContainer(declaration: FirDeclaration, f: () -> T): T { + val prevContainer = _container + _container = declaration + val result = f() + _container = prevContainer + return result + } + + fun FirElement.visitNoTransform(transformer: FirTransformer, data: D) { + val result = this.transform(transformer, data) + require(result.single === this) { "become ${result.single}: `${result.single.render()}`, was ${this}: `${this.render()}`" } + } } -private fun inferenceComponents(session: FirSession, jump: ReturnTypeCalculatorWithJump, scopeSession: ScopeSession) = +private fun inferenceComponents(session: FirSession, returnTypeCalculator: ReturnTypeCalculator, scopeSession: ScopeSession) = InferenceComponents(object : ConeInferenceContext, TypeSystemInferenceExtensionContextDelegate { override fun findCommonIntegerLiteralTypesSuperType(explicitSupertypes: List): SimpleTypeMarker? { //TODO wtf @@ -1178,65 +765,7 @@ private fun inferenceComponents(session: FirSession, jump: ReturnTypeCalculatorW override fun KotlinTypeMarker.removeExactAnnotation(): KotlinTypeMarker { return this } - }, session, jump, scopeSession) - - -class ReturnTypeCalculatorWithJump(val session: FirSession, val scopeSession: ScopeSession) : ReturnTypeCalculator { - - private fun cycleErrorType(declaration: FirTypedDeclaration): FirResolvedTypeRef? { - if (declaration.returnTypeRef is FirComputingImplicitTypeRef) { - declaration.transformReturnTypeRef(TransformImplicitType, FirErrorTypeRefImpl(session, null, "cycle")) - return declaration.returnTypeRef as FirResolvedTypeRef - } - return null - } - - override fun tryCalculateReturnType(declaration: FirTypedDeclaration): FirResolvedTypeRef { - - if (declaration is FirValueParameter && declaration.returnTypeRef is FirImplicitTypeRef) { - // TODO? - declaration.transformReturnTypeRef(TransformImplicitType, FirErrorTypeRefImpl(session, null, "Unsupported: implicit VP type")) - } - val returnTypeRef = declaration.returnTypeRef - if (returnTypeRef is FirResolvedTypeRef) return returnTypeRef - cycleErrorType(declaration)?.let { return it } - require(declaration is FirCallableMemberDeclaration<*>) { "${declaration::class}: ${declaration.render()}" } - - - val symbol = declaration.symbol as ConeCallableSymbol - val id = symbol.callableId - - val provider = session.service() - - val file = provider.getFirCallableContainerFile(symbol) - - val outerClasses = generateSequence(id.classId) { classId -> - classId.outerClassId - }.mapTo(mutableListOf()) { provider.getFirClassifierByFqName(it) } - - if (file == null || outerClasses.any { it == null }) return FirErrorTypeRefImpl( - session, - null, - "I don't know what todo" - ) - - declaration.transformReturnTypeRef(TransformImplicitType, FirComputingImplicitTypeRef) - - val transformer = FirDesignatedBodyResolveTransformer( - (listOf(file) + outerClasses.filterNotNull().asReversed() + listOf(declaration)).iterator(), - file.fileSession, - scopeSession - ) - - file.transform(transformer, null) - - - val newReturnTypeRef = declaration.returnTypeRef - cycleErrorType(declaration)?.let { return it } - require(newReturnTypeRef is FirResolvedTypeRef) { declaration.render() } - return newReturnTypeRef - } -} + }, session, returnTypeCalculator, scopeSession) class FirDesignatedBodyResolveTransformer(val designation: Iterator, session: FirSession, scopeSession: ScopeSession) : @@ -1294,9 +823,8 @@ inline fun ConeSymbol.firSafeNullable(): T? { return fir as? T } - -interface ReturnTypeCalculator { - fun tryCalculateReturnType(declaration: FirTypedDeclaration): FirResolvedTypeRef -} - - +internal inline var FirExpression.resultType: FirTypeRef + get() = typeRef + set(type) { + replaceTypeRef(type) + } \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompleterTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt similarity index 99% rename from compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompleterTransformer.kt rename to compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt index 9eaf9ea3237..e6e460f025f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompleterTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt @@ -28,7 +28,7 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.compose import org.jetbrains.kotlin.types.Variance -class FirCallCompleterTransformer( +class FirCallCompletionResultsWriterTransformer( val session: FirSession, private val finalSubstitutor: ConeSubstitutor, private val typeCalculator: ReturnTypeCalculator diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ReturnTypeCalculator.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ReturnTypeCalculator.kt new file mode 100644 index 00000000000..c72157b6b6e --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ReturnTypeCalculator.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.resolve.transformers + +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration +import org.jetbrains.kotlin.fir.declarations.FirTypedDeclaration +import org.jetbrains.kotlin.fir.declarations.FirValueParameter +import org.jetbrains.kotlin.fir.render +import org.jetbrains.kotlin.fir.resolve.FirProvider +import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.service +import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol +import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef +import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef +import org.jetbrains.kotlin.fir.types.impl.FirComputingImplicitTypeRef +import org.jetbrains.kotlin.fir.types.impl.FirErrorTypeRefImpl + +interface ReturnTypeCalculator { + fun tryCalculateReturnType(declaration: FirTypedDeclaration): FirResolvedTypeRef +} + +class ReturnTypeCalculatorWithJump(val session: FirSession, val scopeSession: ScopeSession) : + ReturnTypeCalculator { + + private fun cycleErrorType(declaration: FirTypedDeclaration): FirResolvedTypeRef? { + if (declaration.returnTypeRef is FirComputingImplicitTypeRef) { + declaration.transformReturnTypeRef( + TransformImplicitType, + FirErrorTypeRefImpl(session, null, "cycle") + ) + return declaration.returnTypeRef as FirResolvedTypeRef + } + return null + } + + override fun tryCalculateReturnType(declaration: FirTypedDeclaration): FirResolvedTypeRef { + + if (declaration is FirValueParameter && declaration.returnTypeRef is FirImplicitTypeRef) { + // TODO? + declaration.transformReturnTypeRef( + TransformImplicitType, + FirErrorTypeRefImpl( + session, + null, + "Unsupported: implicit VP type" + ) + ) + } + val returnTypeRef = declaration.returnTypeRef + if (returnTypeRef is FirResolvedTypeRef) return returnTypeRef + cycleErrorType(declaration)?.let { return it } + require(declaration is FirCallableMemberDeclaration<*>) { "${declaration::class}: ${declaration.render()}" } + + + val symbol = declaration.symbol as ConeCallableSymbol + val id = symbol.callableId + + val provider = session.service() + + val file = provider.getFirCallableContainerFile(symbol) + + val outerClasses = generateSequence(id.classId) { classId -> + classId.outerClassId + }.mapTo(mutableListOf()) { provider.getFirClassifierByFqName(it) } + + if (file == null || outerClasses.any { it == null }) return FirErrorTypeRefImpl( + session, + null, + "I don't know what todo" + ) + + declaration.transformReturnTypeRef( + TransformImplicitType, + FirComputingImplicitTypeRef + ) + + val transformer = FirDesignatedBodyResolveTransformer( + (listOf(file) + outerClasses.filterNotNull().asReversed() + listOf(declaration)).iterator(), + file.fileSession, + scopeSession + ) + + file.transform(transformer, null) + + + val newReturnTypeRef = declaration.returnTypeRef + cycleErrorType(declaration)?.let { return it } + require(newReturnTypeRef is FirResolvedTypeRef) { declaration.render() } + return newReturnTypeRef + } +} \ No newline at end of file