[FIR] Fix resolving to star import member instead of builtin (^KT-48157 Fixed)
This commit is contained in:
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import java.lang.annotation.ElementType
|
||||
|
||||
class FirCallResolver(
|
||||
private val components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents,
|
||||
@@ -73,7 +74,7 @@ class FirCallResolver(
|
||||
qualifiedResolver.reset()
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val functionCall = if (needTransformArguments) {
|
||||
functionCall.transformExplicitReceiver()
|
||||
components.context.withIncrementedQualifierPartIndex { functionCall.transformExplicitReceiver() }
|
||||
.also {
|
||||
components.dataFlowAnalyzer.enterQualifiedAccessExpression()
|
||||
functionCall.argumentList.transformArguments(transformer, ResolutionMode.ContextDependent)
|
||||
@@ -82,51 +83,53 @@ class FirCallResolver(
|
||||
functionCall
|
||||
}
|
||||
|
||||
val name = functionCall.calleeReference.name
|
||||
val result = collectCandidates(functionCall, name)
|
||||
return components.context.withIncrementedQualifierPartIndex {
|
||||
val name = functionCall.calleeReference.name
|
||||
val result = collectCandidates(functionCall, name)
|
||||
|
||||
var forceCandidates: Collection<Candidate>? = null
|
||||
if (result.candidates.isEmpty()) {
|
||||
val newResult = collectCandidates(functionCall, name, CallKind.VariableAccess)
|
||||
if (newResult.candidates.isNotEmpty()) {
|
||||
forceCandidates = newResult.candidates
|
||||
var forceCandidates: Collection<Candidate>? = null
|
||||
if (result.candidates.isEmpty()) {
|
||||
val newResult = collectCandidates(functionCall, name, CallKind.VariableAccess)
|
||||
if (newResult.candidates.isNotEmpty()) {
|
||||
forceCandidates = newResult.candidates
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val nameReference = createResolvedNamedReference(
|
||||
functionCall.calleeReference,
|
||||
name,
|
||||
result.info,
|
||||
result.candidates,
|
||||
result.applicability,
|
||||
functionCall.explicitReceiver,
|
||||
expectedCallKind = if (forceCandidates != null) CallKind.VariableAccess else null,
|
||||
expectedCandidates = forceCandidates
|
||||
)
|
||||
|
||||
val resultExpression = functionCall.transformCalleeReference(StoreNameReference, nameReference)
|
||||
val candidate = (nameReference as? FirNamedReferenceWithCandidate)?.candidate
|
||||
val resolvedReceiver = functionCall.explicitReceiver
|
||||
if (candidate != null && resolvedReceiver is FirResolvedQualifier) {
|
||||
resolvedReceiver.replaceResolvedToCompanionObject(candidate.isFromCompanionObjectTypeScope)
|
||||
}
|
||||
|
||||
// We need desugaring
|
||||
val resultFunctionCall = if (candidate != null && candidate.callInfo != result.info) {
|
||||
functionCall.copy(
|
||||
explicitReceiver = candidate.callInfo.explicitReceiver,
|
||||
dispatchReceiver = candidate.dispatchReceiverExpression(),
|
||||
extensionReceiver = candidate.extensionReceiverExpression(),
|
||||
argumentList = candidate.callInfo.argumentList,
|
||||
val nameReference = createResolvedNamedReference(
|
||||
functionCall.calleeReference,
|
||||
name,
|
||||
result.info,
|
||||
result.candidates,
|
||||
result.applicability,
|
||||
functionCall.explicitReceiver,
|
||||
expectedCallKind = if (forceCandidates != null) CallKind.VariableAccess else null,
|
||||
expectedCandidates = forceCandidates
|
||||
)
|
||||
} else {
|
||||
resultExpression
|
||||
|
||||
val resultExpression = functionCall.transformCalleeReference(StoreNameReference, nameReference)
|
||||
val candidate = (nameReference as? FirNamedReferenceWithCandidate)?.candidate
|
||||
val resolvedReceiver = functionCall.explicitReceiver
|
||||
if (candidate != null && resolvedReceiver is FirResolvedQualifier) {
|
||||
resolvedReceiver.replaceResolvedToCompanionObject(candidate.isFromCompanionObjectTypeScope)
|
||||
}
|
||||
|
||||
// We need desugaring
|
||||
val resultFunctionCall = if (candidate != null && candidate.callInfo != result.info) {
|
||||
functionCall.copy(
|
||||
explicitReceiver = candidate.callInfo.explicitReceiver,
|
||||
dispatchReceiver = candidate.dispatchReceiverExpression(),
|
||||
extensionReceiver = candidate.extensionReceiverExpression(),
|
||||
argumentList = candidate.callInfo.argumentList,
|
||||
)
|
||||
} else {
|
||||
resultExpression
|
||||
}
|
||||
val typeRef = components.typeFromCallee(resultFunctionCall)
|
||||
if (typeRef.type is ConeKotlinErrorType) {
|
||||
resultFunctionCall.resultType = typeRef
|
||||
}
|
||||
return@withIncrementedQualifierPartIndex resultFunctionCall
|
||||
}
|
||||
val typeRef = components.typeFromCallee(resultFunctionCall)
|
||||
if (typeRef.type is ConeKotlinErrorType) {
|
||||
resultFunctionCall.resultType = typeRef
|
||||
}
|
||||
return resultFunctionCall
|
||||
}
|
||||
|
||||
private inline fun <reified Q : FirQualifiedAccess> Q.transformExplicitReceiver(): Q {
|
||||
@@ -216,97 +219,99 @@ class FirCallResolver(
|
||||
): FirStatement {
|
||||
val callee = qualifiedAccess.calleeReference as? FirSimpleNamedReference ?: return qualifiedAccess
|
||||
|
||||
qualifiedResolver.initProcessingQualifiedAccess(callee, qualifiedAccess.typeArguments)
|
||||
return components.context.withIncrementedQualifierPartIndex {
|
||||
qualifiedResolver.initProcessingQualifiedAccess(callee, qualifiedAccess.typeArguments)
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val qualifiedAccess = qualifiedAccess.transformExplicitReceiver<FirQualifiedAccess>()
|
||||
qualifiedResolver.replacedQualifier(qualifiedAccess)?.let { resolvedQualifierPart ->
|
||||
return resolvedQualifierPart
|
||||
}
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val qualifiedAccess = qualifiedAccess.transformExplicitReceiver<FirQualifiedAccess>()
|
||||
qualifiedResolver.replacedQualifier(qualifiedAccess)?.let { resolvedQualifierPart ->
|
||||
return@withIncrementedQualifierPartIndex resolvedQualifierPart
|
||||
}
|
||||
|
||||
var result = collectCandidates(qualifiedAccess, callee.name)
|
||||
var result = collectCandidates(qualifiedAccess, callee.name)
|
||||
|
||||
if (qualifiedAccess.explicitReceiver == null) {
|
||||
if (!result.applicability.isSuccess) {
|
||||
// We should run QualifierResolver if no successful candidates are available
|
||||
// Otherwise expression (even ambiguous) beat qualifier
|
||||
qualifiedResolver.tryResolveAsQualifier(qualifiedAccess.source)?.let { resolvedQualifier ->
|
||||
return resolvedQualifier
|
||||
if (qualifiedAccess.explicitReceiver == null) {
|
||||
if (!result.applicability.isSuccess) {
|
||||
// We should run QualifierResolver if no successful candidates are available
|
||||
// Otherwise expression (even ambiguous) beat qualifier
|
||||
qualifiedResolver.tryResolveAsQualifier(qualifiedAccess.source)?.let { resolvedQualifier ->
|
||||
return@withIncrementedQualifierPartIndex resolvedQualifier
|
||||
}
|
||||
}
|
||||
qualifiedResolver.reset()
|
||||
}
|
||||
|
||||
var functionCallExpected = false
|
||||
if (result.candidates.isEmpty() && qualifiedAccess !is FirFunctionCall) {
|
||||
val newResult = collectCandidates(qualifiedAccess, callee.name, CallKind.Function)
|
||||
if (newResult.candidates.isNotEmpty()) {
|
||||
result = newResult
|
||||
functionCallExpected = true
|
||||
}
|
||||
}
|
||||
qualifiedResolver.reset()
|
||||
}
|
||||
|
||||
var functionCallExpected = false
|
||||
if (result.candidates.isEmpty() && qualifiedAccess !is FirFunctionCall) {
|
||||
val newResult = collectCandidates(qualifiedAccess, callee.name, CallKind.Function)
|
||||
if (newResult.candidates.isNotEmpty()) {
|
||||
result = newResult
|
||||
functionCallExpected = true
|
||||
val reducedCandidates = result.candidates
|
||||
if (!acceptCandidates(reducedCandidates)) return@withIncrementedQualifierPartIndex qualifiedAccess
|
||||
|
||||
val nameReference = createResolvedNamedReference(
|
||||
callee,
|
||||
callee.name,
|
||||
result.info,
|
||||
reducedCandidates,
|
||||
result.applicability,
|
||||
qualifiedAccess.explicitReceiver,
|
||||
expectedCallKind = if (functionCallExpected) CallKind.Function else null
|
||||
)
|
||||
|
||||
val referencedSymbol = when (nameReference) {
|
||||
is FirResolvedNamedReference -> nameReference.resolvedSymbol
|
||||
is FirNamedReferenceWithCandidate -> nameReference.candidateSymbol
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
val reducedCandidates = result.candidates
|
||||
if (!acceptCandidates(reducedCandidates)) return qualifiedAccess
|
||||
val diagnostic = when (nameReference) {
|
||||
is FirErrorReferenceWithCandidate -> nameReference.diagnostic
|
||||
is FirErrorNamedReference -> nameReference.diagnostic
|
||||
else -> null
|
||||
}
|
||||
|
||||
val nameReference = createResolvedNamedReference(
|
||||
callee,
|
||||
callee.name,
|
||||
result.info,
|
||||
reducedCandidates,
|
||||
result.applicability,
|
||||
qualifiedAccess.explicitReceiver,
|
||||
expectedCallKind = if (functionCallExpected) CallKind.Function else null
|
||||
)
|
||||
(qualifiedAccess.explicitReceiver as? FirResolvedQualifier)?.replaceResolvedToCompanionObject(
|
||||
reducedCandidates.isNotEmpty() && reducedCandidates.all { it.isFromCompanionObjectTypeScope }
|
||||
)
|
||||
|
||||
val referencedSymbol = when (nameReference) {
|
||||
is FirResolvedNamedReference -> nameReference.resolvedSymbol
|
||||
is FirNamedReferenceWithCandidate -> nameReference.candidateSymbol
|
||||
else -> null
|
||||
}
|
||||
|
||||
val diagnostic = when (nameReference) {
|
||||
is FirErrorReferenceWithCandidate -> nameReference.diagnostic
|
||||
is FirErrorNamedReference -> nameReference.diagnostic
|
||||
else -> null
|
||||
}
|
||||
|
||||
(qualifiedAccess.explicitReceiver as? FirResolvedQualifier)?.replaceResolvedToCompanionObject(
|
||||
reducedCandidates.isNotEmpty() && reducedCandidates.all { it.isFromCompanionObjectTypeScope }
|
||||
)
|
||||
|
||||
when {
|
||||
referencedSymbol is FirClassLikeSymbol<*> -> {
|
||||
return components.buildResolvedQualifierForClass(
|
||||
referencedSymbol,
|
||||
nameReference.source,
|
||||
qualifiedAccess.typeArguments,
|
||||
diagnostic,
|
||||
nonFatalDiagnostics = extractNonFatalDiagnostics(
|
||||
nameReference.source,
|
||||
qualifiedAccess.explicitReceiver,
|
||||
when {
|
||||
referencedSymbol is FirClassLikeSymbol<*> -> {
|
||||
return@withIncrementedQualifierPartIndex components.buildResolvedQualifierForClass(
|
||||
referencedSymbol,
|
||||
(qualifiedAccess as? FirPropertyAccessExpression)?.nonFatalDiagnostics
|
||||
nameReference.source,
|
||||
qualifiedAccess.typeArguments,
|
||||
diagnostic,
|
||||
nonFatalDiagnostics = extractNonFatalDiagnostics(
|
||||
nameReference.source,
|
||||
qualifiedAccess.explicitReceiver,
|
||||
referencedSymbol,
|
||||
(qualifiedAccess as? FirPropertyAccessExpression)?.nonFatalDiagnostics
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
referencedSymbol is FirTypeParameterSymbol && referencedSymbol.fir.isReified -> {
|
||||
return buildResolvedReifiedParameterReference {
|
||||
source = nameReference.source
|
||||
symbol = referencedSymbol
|
||||
typeRef = typeForReifiedParameterReference(this)
|
||||
}
|
||||
referencedSymbol is FirTypeParameterSymbol && referencedSymbol.fir.isReified -> {
|
||||
return@withIncrementedQualifierPartIndex buildResolvedReifiedParameterReference {
|
||||
source = nameReference.source
|
||||
symbol = referencedSymbol
|
||||
typeRef = typeForReifiedParameterReference(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var resultExpression = qualifiedAccess.transformCalleeReference(StoreNameReference, nameReference)
|
||||
if (reducedCandidates.size == 1) {
|
||||
val candidate = reducedCandidates.single()
|
||||
resultExpression = resultExpression.transformDispatchReceiver(StoreReceiver, candidate.dispatchReceiverExpression())
|
||||
resultExpression = resultExpression.transformExtensionReceiver(StoreReceiver, candidate.extensionReceiverExpression())
|
||||
var resultExpression = qualifiedAccess.transformCalleeReference(StoreNameReference, nameReference)
|
||||
if (reducedCandidates.size == 1) {
|
||||
val candidate = reducedCandidates.single()
|
||||
resultExpression = resultExpression.transformDispatchReceiver(StoreReceiver, candidate.dispatchReceiverExpression())
|
||||
resultExpression = resultExpression.transformExtensionReceiver(StoreReceiver, candidate.extensionReceiverExpression())
|
||||
}
|
||||
if (resultExpression is FirExpression) transformer.storeTypeFromCallee(resultExpression)
|
||||
return@withIncrementedQualifierPartIndex resultExpression
|
||||
}
|
||||
if (resultExpression is FirExpression) transformer.storeTypeFromCallee(resultExpression)
|
||||
return resultExpression
|
||||
}
|
||||
|
||||
private fun extractNonFatalDiagnostics(
|
||||
@@ -700,6 +705,7 @@ class FirCallResolver(
|
||||
val candidate = candidates.single()
|
||||
val diagnostic = when (applicability) {
|
||||
CandidateApplicability.HIDDEN -> ConeHiddenCandidateError(candidate.symbol)
|
||||
CandidateApplicability.NO_COMPANION_OBJECT -> ConeNoCompanionObject(candidate.symbol as FirRegularClassSymbol)
|
||||
else -> ConeInapplicableCandidateError(applicability, candidate)
|
||||
}
|
||||
createErrorReferenceWithExistingCandidate(
|
||||
|
||||
+10
-1
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
@@ -48,7 +49,8 @@ class CandidateFactory private constructor(
|
||||
scope: FirScope?,
|
||||
dispatchReceiverValue: ReceiverValue? = null,
|
||||
extensionReceiverValue: ReceiverValue? = null,
|
||||
builtInExtensionFunctionReceiverValue: ReceiverValue? = null
|
||||
builtInExtensionFunctionReceiverValue: ReceiverValue? = null,
|
||||
objectsByName: Boolean = false
|
||||
): Candidate {
|
||||
val result = Candidate(
|
||||
symbol, dispatchReceiverValue, extensionReceiverValue,
|
||||
@@ -72,6 +74,13 @@ class CandidateFactory private constructor(
|
||||
if (symbol is FirValueParameterSymbol || symbol is FirPropertySymbol && symbol.isLocal || symbol is FirBackingFieldSymbol) {
|
||||
result.addDiagnostic(Unsupported("References to variables aren't supported yet", callSite.calleeReference.source))
|
||||
}
|
||||
} else if (objectsByName &&
|
||||
context.bodyResolveContext.qualifierPartIndexFromEnd == 0 &&
|
||||
symbol is FirRegularClassSymbol &&
|
||||
symbol.classKind != ClassKind.OBJECT &&
|
||||
symbol.companionObjectSymbol == null
|
||||
) {
|
||||
result.addDiagnostic(NoCompanionObject)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
+2
@@ -70,6 +70,8 @@ class InapplicableWrongReceiver(
|
||||
val actualType: ConeKotlinType? = null,
|
||||
) : ResolutionDiagnostic(INAPPLICABLE_WRONG_RECEIVER)
|
||||
|
||||
object NoCompanionObject : ResolutionDiagnostic(NO_COMPANION_OBJECT)
|
||||
|
||||
class UnsafeCall(val actualType: ConeKotlinType) : ResolutionDiagnostic(UNSAFE_CALL)
|
||||
|
||||
object LowerPriorityToPreserveCompatibilityDiagnostic : ResolutionDiagnostic(RESOLVED_NEED_PRESERVE_COMPATIBILITY)
|
||||
|
||||
+4
-2
@@ -76,7 +76,8 @@ private class TowerScopeLevelProcessor(
|
||||
dispatchReceiverValue: ReceiverValue?,
|
||||
extensionReceiverValue: ReceiverValue?,
|
||||
scope: FirScope,
|
||||
builtInExtensionFunctionReceiverValue: ReceiverValue?
|
||||
builtInExtensionFunctionReceiverValue: ReceiverValue?,
|
||||
objectsByName: Boolean
|
||||
) {
|
||||
resultCollector.consumeCandidate(
|
||||
group, candidateFactory.createCandidate(
|
||||
@@ -86,7 +87,8 @@ private class TowerScopeLevelProcessor(
|
||||
scope,
|
||||
dispatchReceiverValue,
|
||||
extensionReceiverValue,
|
||||
builtInExtensionFunctionReceiverValue
|
||||
builtInExtensionFunctionReceiverValue,
|
||||
objectsByName
|
||||
), candidateFactory.context
|
||||
)
|
||||
}
|
||||
|
||||
+4
-2
@@ -52,7 +52,8 @@ abstract class TowerScopeLevel {
|
||||
dispatchReceiverValue: ReceiverValue?,
|
||||
extensionReceiverValue: ReceiverValue?,
|
||||
scope: FirScope,
|
||||
builtInExtensionFunctionReceiverValue: ReceiverValue? = null
|
||||
builtInExtensionFunctionReceiverValue: ReceiverValue? = null,
|
||||
objectsByName: Boolean = false
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -335,7 +336,8 @@ class ScopeTowerLevel(
|
||||
processor.consumeCandidate(
|
||||
it, dispatchReceiverValue = null,
|
||||
extensionReceiverValue = null,
|
||||
scope = scope
|
||||
scope = scope,
|
||||
objectsByName = true
|
||||
)
|
||||
}
|
||||
return if (empty) ProcessResult.SCOPE_EMPTY else ProcessResult.FOUND
|
||||
|
||||
+6
@@ -70,6 +70,12 @@ class ConeInapplicableCandidateError(
|
||||
override val reason: String get() = "Inapplicable($applicability): ${describeSymbol(candidate.symbol)}"
|
||||
}
|
||||
|
||||
class ConeNoCompanionObject(
|
||||
val symbol: FirRegularClassSymbol
|
||||
) : ConeDiagnostic() {
|
||||
override val reason: String get() = "Classifier ''$symbol'' does not have a companion object, and thus must be initialized here"
|
||||
}
|
||||
|
||||
class ConeConstraintSystemHasContradiction(
|
||||
val candidate: Candidate,
|
||||
) : ConeDiagnostic() {
|
||||
|
||||
+14
-3
@@ -75,7 +75,7 @@ class BodyResolveContext(
|
||||
get() = towerDataContextsForClassParts.towerDataContextForCallableReferences
|
||||
|
||||
@set:PrivateForInline
|
||||
var containers: MutableList<FirDeclaration> = mutableListOf()
|
||||
var containers: ArrayDeque<FirDeclaration> = ArrayDeque()
|
||||
|
||||
@set:PrivateForInline
|
||||
var containingClass: FirRegularClass? = null
|
||||
@@ -118,7 +118,7 @@ class BodyResolveContext(
|
||||
return try {
|
||||
f()
|
||||
} finally {
|
||||
containers.removeAt(containers.size - 1)
|
||||
containers.removeLast()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ class BodyResolveContext(
|
||||
return try {
|
||||
f()
|
||||
} finally {
|
||||
containers.removeAt(containers.size - 1)
|
||||
containers.removeLast()
|
||||
containingClass = oldContainingClass
|
||||
}
|
||||
}
|
||||
@@ -172,6 +172,17 @@ class BodyResolveContext(
|
||||
}
|
||||
}
|
||||
|
||||
var qualifierPartIndexFromEnd: Int = -1
|
||||
|
||||
inline fun <R> withIncrementedQualifierPartIndex(l: () -> R): R {
|
||||
qualifierPartIndexFromEnd++
|
||||
return try {
|
||||
l()
|
||||
} finally {
|
||||
qualifierPartIndexFromEnd--
|
||||
}
|
||||
}
|
||||
|
||||
@PrivateForInline
|
||||
fun replaceTowerDataContext(newContext: FirTowerDataContext) {
|
||||
towerDataContextsForClassParts.currentContext = newContext
|
||||
|
||||
+9
-4
@@ -837,9 +837,11 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
||||
|
||||
callableReferenceAccess.transformAnnotations(transformer, data)
|
||||
val explicitReceiver = callableReferenceAccess.explicitReceiver
|
||||
val transformedLHS = explicitReceiver?.transformSingle(this, ResolutionMode.ContextIndependent)?.apply {
|
||||
if (this is FirResolvedQualifier && callableReferenceAccess.hasQuestionMarkAtLHS) {
|
||||
replaceIsNullableLHSForCallableReference(true)
|
||||
val transformedLHS = context.withIncrementedQualifierPartIndex {
|
||||
explicitReceiver?.transformSingle(this, ResolutionMode.ContextIndependent)?.apply {
|
||||
if (this is FirResolvedQualifier && callableReferenceAccess.hasQuestionMarkAtLHS) {
|
||||
replaceIsNullableLHSForCallableReference(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -867,7 +869,10 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
||||
} else {
|
||||
data
|
||||
}
|
||||
val transformedGetClassCall = transformExpression(getClassCall, dataWithExpectedType) as FirGetClassCall
|
||||
|
||||
val transformedGetClassCall = context.withIncrementedQualifierPartIndex {
|
||||
transformExpression(getClassCall, dataWithExpectedType) as FirGetClassCall
|
||||
}
|
||||
|
||||
val typeOfExpression = when (val lhs = transformedGetClassCall.argument) {
|
||||
is FirResolvedQualifier -> {
|
||||
|
||||
Reference in New Issue
Block a user