FIR: Support inferring PRIVATE_TO_THIS visibility see KT-49875
This commit is contained in:
+6
@@ -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 {
|
||||
|
||||
+2
-2
@@ -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 () {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+66
-7
@@ -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
|
||||
}
|
||||
Generated
+6
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user