[FIR] Fix resolving to star import member instead of builtin (^KT-48157 Fixed)

This commit is contained in:
Ivan Kochurkin
2021-08-19 22:43:57 +03:00
committed by Space
parent bb27ae2b42
commit 34cc7e5199
23 changed files with 262 additions and 137 deletions
@@ -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(
@@ -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
}
@@ -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)
@@ -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
)
}
@@ -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
@@ -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() {
@@ -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
@@ -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 -> {