From 67604551c5fd0e34303caea1d9118b0bbb712179 Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Tue, 17 Nov 2020 07:11:13 -0800 Subject: [PATCH] FIR: reuse visibility checker when determining immutable property reference --- .../converter/DeclarationsConverter.kt | 19 ++++- .../kotlin/fir/builder/RawFirBuilder.kt | 6 ++ .../calls/CallableReferenceResolution.kt | 75 +++---------------- .../resolve/providers/impl/FirProviderImpl.kt | 7 +- .../fir/declarations/FirDeclarationUtil.kt | 4 - 5 files changed, 39 insertions(+), 72 deletions(-) diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt index 8f3ea61e77f..1d8c066ead6 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt @@ -999,11 +999,23 @@ class DeclarationsConverter( val convertedAccessors = accessors.map { convertGetterOrSetter(it, returnType, propertyVisibility, modifiers) } this.getter = convertedAccessors.find { it.isGetter } - ?: FirDefaultPropertyGetter(null, session, FirDeclarationOrigin.Source, returnType, propertyVisibility) + ?: FirDefaultPropertyGetter( + null, session, FirDeclarationOrigin.Source, returnType, propertyVisibility + ).also { + currentDispatchReceiverType()?.lookupTag?.let { lookupTag -> + it.containingClassAttr = lookupTag + } + } this.setter = if (isVar) { convertedAccessors.find { it.isSetter } - ?: FirDefaultPropertySetter(null, session, FirDeclarationOrigin.Source, returnType, propertyVisibility) + ?: FirDefaultPropertySetter( + null, session, FirDeclarationOrigin.Source, returnType, propertyVisibility + ).also { + currentDispatchReceiverType()?.lookupTag?.let { lookupTag -> + it.containingClassAttr = lookupTag + } + } } else null // Upward propagation of `inline` and `external` modifiers (from accessors to property) @@ -1173,6 +1185,9 @@ class DeclarationsConverter( context.firFunctionTargets.removeLast() }.also { target.bind(it) + currentDispatchReceiverType()?.lookupTag?.let { lookupTag -> + it.containingClassAttr = lookupTag + } } } diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index 7c9ffe9e39b..9901f5a2481 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -350,6 +350,9 @@ class RawFirBuilder( it.extractAnnotationsFrom(this) } it.status = status + currentDispatchReceiverType()?.lookupTag?.let { lookupTag -> + it.containingClassAttr = lookupTag + } } } val source = this.toFirSourceElement() @@ -386,6 +389,9 @@ class RawFirBuilder( this.contractDescription = it } }.also { + currentDispatchReceiverType()?.lookupTag?.let { lookupTag -> + it.containingClassAttr = lookupTag + } accessorTarget.bind(it) this@RawFirBuilder.context.firFunctionTargets.removeLast() } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallableReferenceResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallableReferenceResolution.kt index 217611780bd..697b5c25814 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallableReferenceResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallableReferenceResolution.kt @@ -5,10 +5,7 @@ package org.jetbrains.kotlin.fir.resolve.calls -import org.jetbrains.kotlin.descriptors.Visibilities -import org.jetbrains.kotlin.fir.FirElement -import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.FirSourceElement +import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall import org.jetbrains.kotlin.fir.expressions.FirExpression @@ -22,19 +19,14 @@ import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnsupportedCallableRefer import org.jetbrains.kotlin.fir.resolve.inference.extractInputOutputTypesFromCallableReferenceExpectedType import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType import org.jetbrains.kotlin.fir.symbols.StandardClassIds -import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol -import org.jetbrains.kotlin.fir.typeCheckerContext import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.FirVisitor -import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.resolve.calls.components.SuspendConversionStrategy import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition import org.jetbrains.kotlin.resolve.calls.tower.isSuccess -import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.expressions.CoercionStrategy @@ -51,7 +43,7 @@ internal object CheckCallableReferenceExpectedType : CheckerStage() { val fir: FirCallableDeclaration<*> = candidate.symbol.fir - val (rawResultingType, callableReferenceAdaptation) = buildReflectionType(fir, resultingReceiverType, callInfo, context) + val (rawResultingType, callableReferenceAdaptation) = buildReflectionType(fir, resultingReceiverType, candidate, context) val resultingType = candidate.substitutor.substituteOrSelf(rawResultingType) if (callableReferenceAdaptation.needCompatibilityResolveForCallableReference()) { @@ -98,7 +90,7 @@ internal object CheckCallableReferenceExpectedType : CheckerStage() { private fun buildReflectionType( fir: FirCallableDeclaration<*>, receiverType: ConeKotlinType?, - callInfo: CallInfo, + candidate: Candidate, context: ResolutionContext ): Pair { val returnTypeRef = context.bodyResolveComponents.returnTypeCalculator.tryCalculateReturnType(fir) @@ -107,7 +99,7 @@ private fun buildReflectionType( val unboundReferenceTarget = if (receiverType != null) 1 else 0 val callableReferenceAdaptation = context.bodyResolveComponents - .getCallableReferenceAdaptation(context.session, fir, callInfo.expectedType, unboundReferenceTarget) + .getCallableReferenceAdaptation(context.session, fir, candidate.callInfo.expectedType, unboundReferenceTarget) val parameters = mutableListOf() @@ -132,7 +124,7 @@ private fun buildReflectionType( isSuspend = isSuspend ) to callableReferenceAdaptation } - is FirVariable -> createKPropertyType(fir, receiverType, returnTypeRef, callInfo) to null + is FirVariable -> createKPropertyType(fir, receiverType, returnTypeRef, candidate) to null else -> ConeClassErrorType(ConeUnsupportedCallableReferenceTarget(fir)) to null } } @@ -396,66 +388,19 @@ private fun createKPropertyType( propertyOrField: FirVariable<*>, receiverType: ConeKotlinType?, returnTypeRef: FirResolvedTypeRef, - callInfo: CallInfo, + candidate: Candidate, ): ConeKotlinType { val propertyType = returnTypeRef.type return org.jetbrains.kotlin.fir.resolve.createKPropertyType( receiverType, propertyType, - isMutable = propertyOrField.canBeMutableReference(callInfo) + isMutable = propertyOrField.canBeMutableReference(candidate) ) } -private fun FirVariable<*>.canBeMutableReference(callInfo: CallInfo): Boolean { +private fun FirVariable<*>.canBeMutableReference(candidate: Candidate): Boolean { if (!isVar) return false if (this is FirField) return true - if (this is FirProperty && this.hasJvmFieldAnnotation) return true - return setter == null || setter!!.isVisible(this, callInfo) -} - -private fun FirPropertyAccessor.isVisible(variable: FirVariable<*>, callInfo: CallInfo): Boolean { - if (visibility == Visibilities.Public) { - return true - } - val variableOwnerClassId = variable.ownerClassId - var containingDeclarationOwnerClassId = callInfo.containingDeclarations.last().ownerClassId - // For a (nested) local class, find a declaration, which contains that local class - while (containingDeclarationOwnerClassId?.isLocal == true) { - var last: FirDeclaration? = null - var localContainer: FirDeclaration? = null - for (containingDeclaration in callInfo.containingDeclarations.asReversed()) { - if (last != null && last is FirClass<*> && last.classId == containingDeclarationOwnerClassId) { - localContainer = containingDeclaration - break - } - last = containingDeclaration - } - if (localContainer == null || last == callInfo.containingDeclarations.first()) { - break - } - containingDeclarationOwnerClassId = localContainer.ownerClassId - } - return when (visibility) { - is Visibilities.Protected -> { - // Check if containing declaration's owner class is a subtype of this accessor's owner class - fun ClassId.toClassLikeType() = ConeClassLikeTypeImpl(ConeClassLikeLookupTagImpl(this), emptyArray(), isNullable = false) - val variableOwner = variableOwnerClassId?.toClassLikeType() ?: return false - val containingDeclarationOwner = containingDeclarationOwnerClassId?.toClassLikeType() ?: return false - AbstractTypeChecker.isSubtypeOf( - session.typeCheckerContext, containingDeclarationOwner, variableOwner, isFromNullabilityConstraint = false - ) - } - is Visibilities.Internal -> { - // TODO: Check if containing declaration's owner class is in the same module of this accessor's owner class - true - } - is Visibilities.Private, is Visibilities.PrivateToThis -> { - // Check if containing declaration's owner class is... - // 1) ...same as the owner class of this variable - // 2) ...inner class of the owner class of this variable - variableOwnerClassId == containingDeclarationOwnerClassId || - variableOwnerClassId == containingDeclarationOwnerClassId?.outerClassId - } - else -> false - } + return source?.kind == FirFakeSourceElementKind.PropertyFromParameter || + (setter is FirMemberDeclaration && candidate.callInfo.session.visibilityChecker.isVisible(setter!!, candidate)) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirProviderImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirProviderImpl.kt index fbc09a08e8b..e2956676d6d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirProviderImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirProviderImpl.kt @@ -121,7 +121,10 @@ class FirProviderImpl(val session: FirSession, val kotlinScopeProvider: KotlinSc state.classifierContainerFileMap[classId] = file } - override fun > visitCallableDeclaration(callableDeclaration: FirCallableDeclaration, data: Pair) { + override fun > visitCallableDeclaration( + callableDeclaration: FirCallableDeclaration, + data: Pair + ) { val symbol = callableDeclaration.symbol val callableId = symbol.callableId val (state, file) = data @@ -139,6 +142,8 @@ class FirProviderImpl(val session: FirSession, val kotlinScopeProvider: KotlinSc override fun visitProperty(property: FirProperty, data: Pair) { visitCallableDeclaration(property, data) + property.getter?.let { visitCallableDeclaration(it, data) } + property.setter?.let { visitCallableDeclaration(it, data) } } override fun visitEnumEntry(enumEntry: FirEnumEntry, data: Pair) { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt index 9ace088f2e5..8b70b7bb7e3 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt @@ -20,7 +20,6 @@ import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.ConeFlexibleType import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.coneTypeSafe -import org.jetbrains.kotlin.name.ClassId fun FirTypeParameterBuilder.addDefaultBoundIfNecessary(isFlexible: Boolean = false) { if (bounds.isEmpty()) { @@ -86,9 +85,6 @@ val FirTypeAlias.expandedConeType: ConeClassLikeType? get() = expandedTypeRef.co val FirClass<*>.classId get() = symbol.classId -inline val FirDeclaration.ownerClassId: ClassId? - get() = (this as? FirCallableMemberDeclaration<*>)?.symbol?.callableId?.classId - val FirClassSymbol<*>.superConeTypes get() = when (this) { is FirRegularClassSymbol -> fir.superConeTypes