diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/classifierAccessFromCompanion.fir.txt b/compiler/fir/analysis-tests/testData/resolve/expresssions/classifierAccessFromCompanion.fir.txt index 96ce52c79eb..44a42109dee 100644 --- a/compiler/fir/analysis-tests/testData/resolve/expresssions/classifierAccessFromCompanion.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/classifierAccessFromCompanion.fir.txt @@ -23,7 +23,7 @@ FILE: classifierAccessFromCompanion.kt super() } - public final val f: R|kotlin/Unit| = Q|Factory.Function| + public final val f: R|kotlin/Unit| = R|kotlin/Unit| public get(): R|kotlin/Unit| public final val x: R|Factory.Function.Default| = Q|Factory.Function.Default| diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/innerQualifier.fir.txt b/compiler/fir/analysis-tests/testData/resolve/expresssions/innerQualifier.fir.txt index b01a138d56c..2cb5e764514 100644 --- a/compiler/fir/analysis-tests/testData/resolve/expresssions/innerQualifier.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/innerQualifier.fir.txt @@ -12,7 +12,7 @@ FILE: innerQualifier.kt } } - public final val x: R|kotlin/Unit| = Q|Outer.Inner| + public final val x: R|kotlin/Unit| = R|kotlin/Unit| public get(): R|kotlin/Unit| public final val klass: R|kotlin/reflect/KClass| = (Q|Outer.Inner|) public get(): R|kotlin/reflect/KClass| diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/qualifierPriority.fir.txt b/compiler/fir/analysis-tests/testData/resolve/expresssions/qualifierPriority.fir.txt index bd437213061..106c6dd6f96 100644 --- a/compiler/fir/analysis-tests/testData/resolve/expresssions/qualifierPriority.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/qualifierPriority.fir.txt @@ -59,8 +59,8 @@ FILE: qualifierPriority.kt } public final val def: R|D.E.F| = Q|D.E.F| public get(): R|D.E.F| - public final val de: R|kotlin/Unit| = Q|D.E| - public get(): R|kotlin/Unit| + public final val de: R|kotlin/String| = Q|D|.R|/E| + public get(): R|kotlin/String| public final enum class G : R|kotlin/Enum| { private constructor(): R|G| { super|>() diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/qualifierPriority.kt b/compiler/fir/analysis-tests/testData/resolve/expresssions/qualifierPriority.kt index be82ea3493a..26e7e40dcb9 100644 --- a/compiler/fir/analysis-tests/testData/resolve/expresssions/qualifierPriority.kt +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/qualifierPriority.kt @@ -24,7 +24,7 @@ val D.E get() = "" val def = D.E.F // object // See KT-46409 -val de = D.E // Should be: extension & no error, in fact: qualifier +val de = D.E enum class G { H; diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index fb4f4e73a81..68165f08700 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -24117,6 +24117,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/resolve/resolveAnnotatedLambdaArgument.kt"); } + @Test + @TestMetadata("resolveToStarImportMemberInsteadOfBuiltin.kt") + public void testResolveToStarImportMemberInsteadOfBuiltin() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/resolveToStarImportMemberInsteadOfBuiltin.kt"); + } + @Test @TestMetadata("resolveTypeArgsForUnresolvedCall.kt") public void testResolveTypeArgsForUnresolvedCall() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index 53ad6cc29d5..32f4b807d9c 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -24117,6 +24117,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/resolve/resolveAnnotatedLambdaArgument.kt"); } + @Test + @TestMetadata("resolveToStarImportMemberInsteadOfBuiltin.kt") + public void testResolveToStarImportMemberInsteadOfBuiltin() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/resolveToStarImportMemberInsteadOfBuiltin.kt"); + } + @Test @TestMetadata("resolveTypeArgsForUnresolvedCall.kt") public void testResolveTypeArgsForUnresolvedCall() throws Exception { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index 71098f3a305..6edb353ae2d 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -44,6 +44,7 @@ private fun ConeDiagnostic.toFirDiagnostic( is ConeFunctionExpectedError -> FirErrors.FUNCTION_EXPECTED.createOn(source, this.expression, this.type) is ConeResolutionToClassifierError -> FirErrors.RESOLUTION_TO_CLASSIFIER.createOn(source, this.classSymbol) is ConeHiddenCandidateError -> FirErrors.INVISIBLE_REFERENCE.createOn(source, this.candidateSymbol) + is ConeNoCompanionObject -> FirErrors.NO_COMPANION_OBJECT.createOn(source, this.symbol) is ConeAmbiguityError -> when { applicability.isSuccess -> FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY.createOn(source, this.candidates.map { it.symbol }) applicability == CandidateApplicability.UNSAFE_CALL -> { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index 876d42617d3..85ff066cd6d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -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? = null - if (result.candidates.isEmpty()) { - val newResult = collectCandidates(functionCall, name, CallKind.VariableAccess) - if (newResult.candidates.isNotEmpty()) { - forceCandidates = newResult.candidates + var forceCandidates: Collection? = 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 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() - qualifiedResolver.replacedQualifier(qualifiedAccess)?.let { resolvedQualifierPart -> - return resolvedQualifierPart - } + @Suppress("NAME_SHADOWING") + val qualifiedAccess = qualifiedAccess.transformExplicitReceiver() + 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( diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt index 1031985d759..a5d72c992c7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt @@ -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 } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt index 3a0bbe3437a..a2360c2b676 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt @@ -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) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevelHandler.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevelHandler.kt index 67fbe722a04..ff27ae8b25b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevelHandler.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevelHandler.kt @@ -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 ) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt index 8808f2600c8..ad1827f173c 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt @@ -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 diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt index 6b7c31523da..af5230a7034 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt @@ -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() { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt index 3b962833ef7..6c2438d43b6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt @@ -75,7 +75,7 @@ class BodyResolveContext( get() = towerDataContextsForClassParts.towerDataContextForCallableReferences @set:PrivateForInline - var containers: MutableList = mutableListOf() + var containers: ArrayDeque = 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 withIncrementedQualifierPartIndex(l: () -> R): R { + qualifierPartIndexFromEnd++ + return try { + l() + } finally { + qualifierPartIndexFromEnd-- + } + } + @PrivateForInline fun replaceTowerDataContext(newContext: FirTowerDataContext) { towerDataContextsForClassParts.currentContext = newContext diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index acc450d3226..706be6249c3 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -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 -> { diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt index 653d478e27d..4ae77c63086 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt @@ -13,6 +13,7 @@ enum class CandidateApplicability { INAPPLICABLE_ARGUMENTS_MAPPING_ERROR, // arguments not mapped to parameters (i.e. different size of arguments and parameters) INAPPLICABLE, // arguments have wrong types INAPPLICABLE_MODIFIER, // no expected modifier (eg infix call on non-infix function) + NO_COMPANION_OBJECT, // Classifier does not have a companion object IMPOSSIBLE_TO_GENERATE, // access to outer class from nested RUNTIME_ERROR, // problems with visibility UNSAFE_CALL, // receiver or argument nullability doesn't match diff --git a/compiler/testData/codegen/box/package/privateMembersInImportList.kt b/compiler/testData/codegen/box/package/privateMembersInImportList.kt index 260602bfe57..e7009753efa 100644 --- a/compiler/testData/codegen/box/package/privateMembersInImportList.kt +++ b/compiler/testData/codegen/box/package/privateMembersInImportList.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR package test import test.C.E1 @@ -17,7 +16,6 @@ class A { } fun test() { - // Note: FIR resolve this to test/C instead of test/A.B.C C D() } diff --git a/compiler/testData/diagnostics/tests/resolve/resolveToStarImportMemberInsteadOfBuiltin.kt b/compiler/testData/diagnostics/tests/resolve/resolveToStarImportMemberInsteadOfBuiltin.kt new file mode 100644 index 00000000000..677afde4e2e --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/resolveToStarImportMemberInsteadOfBuiltin.kt @@ -0,0 +1,24 @@ +// FIR_IDENTICAL +// https://youtrack.jetbrains.com/issue/KT-48157 + +import TestEnum.* + +enum class TestEnum { + Annotation, + Collection, + Set, + List, + Map, + Function, + Enum +} + +fun test() { + val x1 = Annotation + val x2 = Collection + val x3 = Set + val x4 = List + val x5 = Map + val x6 = Function + val x7 = Enum +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/resolve/resolveToStarImportMemberInsteadOfBuiltin.txt b/compiler/testData/diagnostics/tests/resolve/resolveToStarImportMemberInsteadOfBuiltin.txt new file mode 100644 index 00000000000..5faa60d37dc --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/resolveToStarImportMemberInsteadOfBuiltin.txt @@ -0,0 +1,34 @@ +package + +public fun test(): kotlin.Unit + +public final enum class TestEnum : kotlin.Enum { + enum entry Annotation + + enum entry Collection + + enum entry Set + + enum entry List + + enum entry Map + + enum entry Function + + enum entry Enum + + private constructor TestEnum() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: TestEnum): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): TestEnum + public final /*synthesized*/ fun values(): kotlin.Array +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 440bb5f3673..153f381d79e 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -24129,6 +24129,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/resolve/resolveAnnotatedLambdaArgument.kt"); } + @Test + @TestMetadata("resolveToStarImportMemberInsteadOfBuiltin.kt") + public void testResolveToStarImportMemberInsteadOfBuiltin() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/resolveToStarImportMemberInsteadOfBuiltin.kt"); + } + @Test @TestMetadata("resolveTypeArgsForUnresolvedCall.kt") public void testResolveTypeArgsForUnresolvedCall() throws Exception { diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 7bc16eb9726..f43c9ee6504 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -24117,6 +24117,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/resolve/resolveAnnotatedLambdaArgument.kt"); } + @Test + @TestMetadata("resolveToStarImportMemberInsteadOfBuiltin.kt") + public void testResolveToStarImportMemberInsteadOfBuiltin() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/resolveToStarImportMemberInsteadOfBuiltin.kt"); + } + @Test @TestMetadata("resolveTypeArgsForUnresolvedCall.kt") public void testResolveTypeArgsForUnresolvedCall() throws Exception { diff --git a/idea/idea-frontend-fir/testData/referenceResolve/TopLevelCompanionObjectVsLocalClassConstructor.txt b/idea/idea-frontend-fir/testData/referenceResolve/TopLevelCompanionObjectVsLocalClassConstructor.txt index 0c4af2db10d..8ee0b5e8878 100644 --- a/idea/idea-frontend-fir/testData/referenceResolve/TopLevelCompanionObjectVsLocalClassConstructor.txt +++ b/idea/idea-frontend-fir/testData/referenceResolve/TopLevelCompanionObjectVsLocalClassConstructor.txt @@ -1,2 +1,2 @@ Resolved to: -0: (in : test) class Conflict \ No newline at end of file +0: (in test.Conflict) companion object \ No newline at end of file diff --git a/idea/idea-frontend-fir/testData/referenceResolve/TopLevelObjectVsLocalClassQualifier.txt b/idea/idea-frontend-fir/testData/referenceResolve/TopLevelObjectVsLocalClassQualifier.txt index 0c4af2db10d..f768393ae5d 100644 --- a/idea/idea-frontend-fir/testData/referenceResolve/TopLevelObjectVsLocalClassQualifier.txt +++ b/idea/idea-frontend-fir/testData/referenceResolve/TopLevelObjectVsLocalClassQualifier.txt @@ -1,2 +1,2 @@ Resolved to: -0: (in : test) class Conflict \ No newline at end of file +0: (in test) object Conflict \ No newline at end of file