FIR: Support inferring PRIVATE_TO_THIS visibility see KT-49875

This commit is contained in:
Mikhail Glukhikh
2022-07-11 18:05:06 +02:00
committed by Space
parent 3b613b3745
commit 83200f8774
10 changed files with 150 additions and 9 deletions
@@ -33728,6 +33728,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/visibility/privateFromInAnonymousObject.kt");
}
@Test
@TestMetadata("privateToThis.kt")
public void testPrivateToThis() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/privateToThis.kt");
}
@Test
@TestMetadata("protectedInternal.kt")
public void testProtectedInternal() throws Exception {
@@ -27,8 +27,8 @@ FILE: compilerPhase.kt
super<R|kotlin/Any|>()
}
private final val lower: R|CompilerPhase<Context, Data, Data>| = R|<local>/lower|
private get(): R|CompilerPhase<Context, Data, Data>|
private/*private to this*/ final val lower: R|CompilerPhase<Context, Data, Data>| = R|<local>/lower|
private/*private to this*/ get(): R|CompilerPhase<Context, Data, Data>|
public final override fun invoke(phaseConfig: R|PhaseConfig|, phaserState: R|PhaserState<Data>|, context: R|Context|, input: R|Data|): R|Data| {
lval output: R|Data| = when () {
@@ -33728,6 +33728,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/visibility/privateFromInAnonymousObject.kt");
}
@Test
@TestMetadata("privateToThis.kt")
public void testPrivateToThis() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/privateToThis.kt");
}
@Test
@TestMetadata("protectedInternal.kt")
public void testProtectedInternal() throws Exception {
@@ -33728,6 +33728,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/visibility/privateFromInAnonymousObject.kt");
}
@Test
@TestMetadata("privateToThis.kt")
public void testPrivateToThis() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/privateToThis.kt");
}
@Test
@TestMetadata("protectedInternal.kt")
public void testProtectedInternal() throws Exception {
@@ -21,10 +21,9 @@ import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
import org.jetbrains.kotlin.fir.symbols.ensureResolved
import org.jetbrains.kotlin.fir.toEffectiveVisibility
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.fir.types.typeContext
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.runIf
class FirStatusResolver(
@@ -80,7 +79,6 @@ class FirStatusResolver(
}
}
@OptIn(ExperimentalStdlibApi::class)
fun getOverriddenProperties(
property: FirProperty,
containingClass: FirClass?,
@@ -100,7 +98,6 @@ class FirStatusResolver(
}
}
@OptIn(ExperimentalStdlibApi::class)
fun resolveStatus(
property: FirProperty,
containingClass: FirClass?,
@@ -138,7 +135,6 @@ class FirStatusResolver(
}
}
@OptIn(ExperimentalStdlibApi::class)
fun resolveStatus(function: FirSimpleFunction, containingClass: FirClass?, isLocal: Boolean): FirResolvedDeclarationStatus {
val status = function.applyExtensionTransformers { transformStatus(it, function, containingClass, isLocal) }
val overriddenStatuses = getOverriddenStatuses(function, containingClass)
@@ -185,7 +181,7 @@ class FirStatusResolver(
return resolveStatus(field, field.status, containingClass, null, isLocal, emptyList())
}
fun resolveStatus(
private fun resolveStatus(
backingField: FirBackingField,
containingClass: FirClass?,
isLocal: Boolean
@@ -217,6 +213,15 @@ class FirStatusResolver(
isLocal -> Visibilities.Local
else -> resolveVisibility(declaration, containingClass, containingProperty, overriddenStatuses)
}
Visibilities.Private -> when {
declaration is FirPropertyAccessor -> if (containingProperty?.visibility == Visibilities.PrivateToThis) {
Visibilities.PrivateToThis
} else {
Visibilities.Private
}
isPrivateToThis(declaration, containingClass) -> Visibilities.PrivateToThis
else -> Visibilities.Private
}
else -> status.visibility
}
@@ -277,6 +282,60 @@ class FirStatusResolver(
return status.resolved(visibility, modality, effectiveVisibility)
}
private fun isPrivateToThis(
declaration: FirDeclaration,
containingClass: FirClass?,
): Boolean {
if (containingClass == null) return false
if (declaration !is FirCallableDeclaration) return false
if (declaration is FirConstructor) return false
if (containingClass.typeParameters.all { it.symbol.variance == Variance.INVARIANT }) return false
if (declaration.receiverTypeRef?.contradictsWith(Variance.IN_VARIANCE) == true) {
return true
}
if (declaration.returnTypeRef.contradictsWith(
if (declaration is FirProperty && declaration.isVar) Variance.INVARIANT
else Variance.OUT_VARIANCE
)
) {
return true
}
if (declaration is FirFunction) {
for (parameter in declaration.valueParameters) {
if (parameter.returnTypeRef.contradictsWith(Variance.IN_VARIANCE)) {
return true
}
}
}
return false
}
private fun FirTypeRef.contradictsWith(requiredVariance: Variance): Boolean {
val type = coneTypeSafe<ConeKotlinType>() ?: return false
return contradictsWith(type, requiredVariance)
}
private fun contradictsWith(type: ConeKotlinType, requiredVariance: Variance): Boolean {
if (type is ConeTypeParameterType) {
return !type.lookupTag.typeParameterSymbol.fir.variance.allowsPosition(requiredVariance)
}
if (type is ConeClassLikeType) {
for (argument in type.typeArguments) {
val (argType, requiredVarianceForArgument) = when (argument) {
is ConeKotlinTypeProjectionOut -> argument.type to requiredVariance
is ConeKotlinTypeProjectionIn -> argument.type to requiredVariance.opposite()
is ConeKotlinTypeProjection -> argument.type to Variance.INVARIANT
is ConeStarProjection -> continue
}
if (contradictsWith(argType, requiredVarianceForArgument)) {
return true
}
}
}
return false
}
private fun resolveVisibility(
declaration: FirDeclaration,
containingClass: FirClass?,
@@ -0,0 +1,14 @@
// FIR_DUMP
class A<in T>(t: T) {
private val t: T = t // PRIVATE_TO_THIS
fun test() {
val x: T = t // Ok
val y: T = this.t // Ok
}
fun foo(a: A<String>) {
val x: String = a.t // Invisible!
}
}
@@ -0,0 +1,19 @@
FILE: privateToThis.fir.kt
public final class A<in T> : R|kotlin/Any| {
public constructor<in T>(t: R|T|): R|A<T>| {
super<R|kotlin/Any|>()
}
private/*private to this*/ final val t: R|T| = R|<local>/t|
private/*private to this*/ get(): R|T|
public final fun test(): R|kotlin/Unit| {
lval x: R|T| = this@R|/A|.R|/A.t|
lval y: R|T| = this@R|/A|.R|/A.t|
}
public final fun foo(a: R|A<kotlin/String>|): R|kotlin/Unit| {
lval x: R|kotlin/String| = R|<local>/a|.R|SubstitutionOverride</A.t: R|kotlin/String|>|
}
}
@@ -0,0 +1,14 @@
// FIR_DUMP
class A<in T>(t: T) {
private val t: T = t // PRIVATE_TO_THIS
fun test() {
val x: T = t // Ok
val y: T = this.t // Ok
}
fun foo(a: A<String>) {
val x: String = a.<!INVISIBLE_MEMBER!>t<!> // Invisible!
}
}
@@ -0,0 +1,11 @@
package
public final class A</*0*/ in T> {
public constructor A</*0*/ in T>(/*0*/ t: T)
private/*private to this*/ final val t: T
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(/*0*/ a: A<kotlin.String>): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun test(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -33818,6 +33818,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/visibility/privateFromInAnonymousObject.kt");
}
@Test
@TestMetadata("privateToThis.kt")
public void testPrivateToThis() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/privateToThis.kt");
}
@Test
@TestMetadata("protectedInternal.kt")
public void testProtectedInternal() throws Exception {