[FIR] Do not dereference delegate in lazy mode

Tenth step for ^KT-52615
This commit is contained in:
Egor Kulikov
2023-02-24 14:13:05 +01:00
committed by teamcity
parent 7ce2f64c18
commit 163017fcaf
9 changed files with 42 additions and 26 deletions
@@ -150,14 +150,7 @@ internal object FirLazyBodiesCalculator {
val newDelegate = newProperty.delegate as? FirWrappedDelegateExpression val newDelegate = newProperty.delegate as? FirWrappedDelegateExpression
check(newDelegate != null) { "Invalid replacement delegate" } check(newDelegate != null) { "Invalid replacement delegate" }
delegate.replaceExpression(newDelegate.expression) delegate.replaceExpression(newDelegate.expression)
delegate.replaceDelegateProvider(newDelegate.delegateProvider)
val delegateProviderCall = delegate.delegateProvider as? FirFunctionCall
val delegateProviderExplicitReceiver = delegateProviderCall?.explicitReceiver
if (delegateProviderExplicitReceiver is FirLazyExpression) {
val newDelegateProviderExplicitReceiver = (newDelegate.delegateProvider as? FirFunctionCall)?.explicitReceiver
check(newDelegateProviderExplicitReceiver != null) { "Invalid replacement expression" }
delegateProviderCall.replaceExplicitReceiver(newDelegateProviderExplicitReceiver)
}
} }
} }
@@ -31,16 +31,16 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
val delegate = declaration.delegate ?: return val delegate = declaration.delegate ?: return
val delegateType = delegate.typeRef.coneType val delegateType = delegate.typeRef.coneType
val source = delegate.source;
// TODO: Also suppress delegate issue if type inference failed. For example, in // TODO: Also suppress delegate issue if type inference failed. For example, in
// compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.fir.kt, no delegate issues are // compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.fir.kt, no delegate issues are
// reported due to the inference issue. // reported due to the inference issue.
if (delegateType is ConeErrorType) { if (delegateType is ConeErrorType) {
val delegateSource = delegate.source
// Implicit recursion type is not reported since the type ref does not have a real source. // Implicit recursion type is not reported since the type ref does not have a real source.
if (delegateSource != null && (delegateType.diagnostic as? ConeSimpleDiagnostic)?.kind == DiagnosticKind.RecursionInImplicitTypes) { if (source != null && (delegateType.diagnostic as? ConeSimpleDiagnostic)?.kind == DiagnosticKind.RecursionInImplicitTypes) {
// skip reporting other issues in this case // skip reporting other issues in this case
reporter.reportOn(delegateSource, FirErrors.RECURSION_IN_IMPLICIT_TYPES, context) reporter.reportOn(source, FirErrors.RECURSION_IN_IMPLICIT_TYPES, context)
} }
return return
} }
@@ -74,7 +74,7 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
fun reportInapplicableDiagnostics(candidates: Collection<FirBasedSymbol<*>>) { fun reportInapplicableDiagnostics(candidates: Collection<FirBasedSymbol<*>>) {
reporter.reportOn( reporter.reportOn(
reference.source, source,
FirErrors.DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, FirErrors.DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE,
expectedFunctionSignature, expectedFunctionSignature,
candidates, candidates,
@@ -85,7 +85,7 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
var errorReported = true var errorReported = true
when (diagnostic) { when (diagnostic) {
is ConeUnresolvedNameError -> reporter.reportOn( is ConeUnresolvedNameError -> reporter.reportOn(
reference.source, source,
FirErrors.DELEGATE_SPECIAL_FUNCTION_MISSING, FirErrors.DELEGATE_SPECIAL_FUNCTION_MISSING,
expectedFunctionSignature, expectedFunctionSignature,
delegateType, delegateType,
@@ -97,7 +97,7 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
if (diagnostic.applicability.isSuccess) { if (diagnostic.applicability.isSuccess) {
// Match is successful but there are too many matches! So we report DELEGATE_SPECIAL_FUNCTION_AMBIGUITY. // Match is successful but there are too many matches! So we report DELEGATE_SPECIAL_FUNCTION_AMBIGUITY.
reporter.reportOn( reporter.reportOn(
reference.source, source,
FirErrors.DELEGATE_SPECIAL_FUNCTION_AMBIGUITY, FirErrors.DELEGATE_SPECIAL_FUNCTION_AMBIGUITY,
expectedFunctionSignature, expectedFunctionSignature,
diagnostic.candidates.map { it.symbol }, diagnostic.candidates.map { it.symbol },
@@ -109,7 +109,7 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
} }
is ConeInapplicableWrongReceiver -> reporter.reportOn( is ConeInapplicableWrongReceiver -> reporter.reportOn(
reference.source, source,
FirErrors.DELEGATE_SPECIAL_FUNCTION_MISSING, FirErrors.DELEGATE_SPECIAL_FUNCTION_MISSING,
expectedFunctionSignature, expectedFunctionSignature,
delegateType, delegateType,
@@ -131,7 +131,7 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
val propertyType = declaration.returnTypeRef.coneType val propertyType = declaration.returnTypeRef.coneType
if (!AbstractTypeChecker.isSubtypeOf(context.session.typeContext, returnType, propertyType)) { if (!AbstractTypeChecker.isSubtypeOf(context.session.typeContext, returnType, propertyType)) {
reporter.reportOn( reporter.reportOn(
delegate.source, source,
FirErrors.DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH, FirErrors.DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH,
"getValue", "getValue",
propertyType, propertyType,
@@ -7,8 +7,10 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fakeElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.isLhsOfAssignment import org.jetbrains.kotlin.fir.analysis.checkers.isLhsOfAssignment
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.references.toResolvedBaseSymbol import org.jetbrains.kotlin.fir.references.toResolvedBaseSymbol
@@ -37,7 +39,13 @@ object FirOptInUsageAccessChecker : FirBasicExpressionChecker() {
val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType) + val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType) +
loadExperimentalitiesFromTypeArguments(context, expression.typeArguments) loadExperimentalitiesFromTypeArguments(context, expression.typeArguments)
reportNotAcceptedExperimentalities(experimentalities, expression, context, reporter) val source = if (expression.source?.kind == KtFakeSourceElementKind.DelegatedPropertyAccessor) {
val property = context.containingDeclarations.lastOrNull { it is FirProperty } as? FirProperty ?: return
property.delegate?.source?.fakeElement(KtFakeSourceElementKind.DelegatedPropertyAccessor) ?: return
} else {
expression.source
}
reportNotAcceptedExperimentalities(experimentalities, expression, context, reporter, source)
} }
} }
} }
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.config.AnalysisFlags import org.jetbrains.kotlin.config.AnalysisFlags
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.diagnostics.reportOn
@@ -262,7 +263,8 @@ object FirOptInUsageBaseChecker {
experimentalities: Collection<Experimentality>, experimentalities: Collection<Experimentality>,
element: FirElement, element: FirElement,
context: CheckerContext, context: CheckerContext,
reporter: DiagnosticReporter reporter: DiagnosticReporter,
source: KtSourceElement? = element.source,
) { ) {
for ((annotationClassId, severity, message, _, fromSupertype) in experimentalities) { for ((annotationClassId, severity, message, _, fromSupertype) in experimentalities) {
if (!isExperimentalityAcceptableInContext(annotationClassId, context, fromSupertype)) { if (!isExperimentalityAcceptableInContext(annotationClassId, context, fromSupertype)) {
@@ -273,7 +275,7 @@ object FirOptInUsageBaseChecker {
val fqName = annotationClassId.asSingleFqName() val fqName = annotationClassId.asSingleFqName()
val reportedMessage = message?.takeIf { it.isNotBlank() } val reportedMessage = message?.takeIf { it.isNotBlank() }
?: OptInNames.buildDefaultDiagnosticMessage(OptInNames.buildMessagePrefix(verb), fqName.asString()) ?: OptInNames.buildDefaultDiagnosticMessage(OptInNames.buildMessagePrefix(verb), fqName.asString())
reporter.reportOn(element.source, diagnostic, fqName, reportedMessage, context) reporter.reportOn(source, diagnostic, fqName, reportedMessage, context)
} }
} }
} }
@@ -11,9 +11,11 @@ import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fakeElement
import org.jetbrains.kotlin.fir.analysis.diagnostics.toFirDiagnostics import org.jetbrains.kotlin.fir.analysis.diagnostics.toFirDiagnostics
import org.jetbrains.kotlin.fir.declarations.FirErrorFunction import org.jetbrains.kotlin.fir.declarations.FirErrorFunction
import org.jetbrains.kotlin.fir.declarations.FirErrorImport import org.jetbrains.kotlin.fir.declarations.FirErrorImport
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.diagnostics.ConeAmbiguousSuper import org.jetbrains.kotlin.fir.diagnostics.ConeAmbiguousSuper
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
@@ -59,7 +61,7 @@ class ErrorNodeDiagnosticCollectorComponent(
} }
private fun processErrorReference(reference: FirNamedReference, diagnostic: ConeDiagnostic, context: CheckerContext) { private fun processErrorReference(reference: FirNamedReference, diagnostic: ConeDiagnostic, context: CheckerContext) {
val source = reference.source ?: return var source = reference.source ?: return
val qualifiedAccessOrAnnotationCall = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.lastOrNull()?.takeIf { val qualifiedAccessOrAnnotationCall = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.lastOrNull()?.takeIf {
// Use the source of the enclosing FirQualifiedAccess if it is exactly the call to the erroneous callee. // Use the source of the enclosing FirQualifiedAccess if it is exactly the call to the erroneous callee.
it.calleeReference == reference it.calleeReference == reference
@@ -79,6 +81,11 @@ class ErrorNodeDiagnosticCollectorComponent(
) return ) return
} }
if (source.kind == KtFakeSourceElementKind.DelegatedPropertyAccessor) {
val property = context.containingDeclarations.lastOrNull { it is FirProperty } as? FirProperty ?: return
source = property.delegate?.source?.fakeElement(KtFakeSourceElementKind.DelegatedPropertyAccessor) ?: return
}
reportFirDiagnostic(diagnostic, source, context, qualifiedAccessOrAnnotationCall?.source) reportFirDiagnostic(diagnostic, source, context, qualifiedAccessOrAnnotationCall?.source)
} }
@@ -1803,18 +1803,18 @@ open class RawFirBuilder(
} }
if (hasDelegate()) { if (hasDelegate()) {
fun extractDelegateExpression() = this@toFirProperty.delegate?.expression?.let { expression -> fun extractDelegateExpression() = buildOrLazyExpression(this@toFirProperty.toFirSourceElement(KtFakeSourceElementKind.WrappedDelegate)) {
buildOrLazyExpression(expression.toFirSourceElement()) { this@toFirProperty.delegate?.expression?.let { expression ->
expression.toFirExpression("Should have delegate") expression.toFirExpression("Should have delegate")
} ?: buildErrorExpression {
diagnostic = ConeSimpleDiagnostic("Should have delegate", DiagnosticKind.ExpressionExpected)
} }
} ?: buildErrorExpression {
diagnostic = ConeSimpleDiagnostic("Should have delegate", DiagnosticKind.ExpressionExpected)
} }
val delegateBuilder = FirWrappedDelegateExpressionBuilder().apply { val delegateBuilder = FirWrappedDelegateExpressionBuilder().apply {
val delegateExpression = extractDelegateExpression() val delegateExpression = extractDelegateExpression()
source = delegateExpression.source?.fakeElement(KtFakeSourceElementKind.WrappedDelegate) source = delegateExpression.source?.fakeElement(KtFakeSourceElementKind.WrappedDelegate)
expression = extractDelegateExpression() expression = delegateExpression
} }
generateAccessorsByDelegate( generateAccessorsByDelegate(
@@ -34,5 +34,7 @@ abstract class FirWrappedDelegateExpression : FirWrappedExpression() {
abstract override fun replaceExpression(newExpression: FirExpression) abstract override fun replaceExpression(newExpression: FirExpression)
abstract fun replaceDelegateProvider(newDelegateProvider: FirExpression)
abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirWrappedDelegateExpression abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirWrappedDelegateExpression
} }
@@ -56,4 +56,8 @@ internal class FirWrappedDelegateExpressionImpl(
override fun replaceExpression(newExpression: FirExpression) { override fun replaceExpression(newExpression: FirExpression) {
expression = newExpression expression = newExpression
} }
override fun replaceDelegateProvider(newDelegateProvider: FirExpression) {
delegateProvider = newDelegateProvider
}
} }
@@ -628,7 +628,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
} }
wrappedDelegateExpression.configure { wrappedDelegateExpression.configure {
+field("delegateProvider", expression) +field("delegateProvider", expression).withReplace()
} }
namedReference.configure { namedReference.configure {