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");
|
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
|
@Test
|
||||||
@TestMetadata("protectedInternal.kt")
|
@TestMetadata("protectedInternal.kt")
|
||||||
public void testProtectedInternal() throws Exception {
|
public void testProtectedInternal() throws Exception {
|
||||||
|
|||||||
+2
-2
@@ -27,8 +27,8 @@ FILE: compilerPhase.kt
|
|||||||
super<R|kotlin/Any|>()
|
super<R|kotlin/Any|>()
|
||||||
}
|
}
|
||||||
|
|
||||||
private final val lower: R|CompilerPhase<Context, Data, Data>| = R|<local>/lower|
|
private/*private to this*/ final val lower: R|CompilerPhase<Context, Data, Data>| = R|<local>/lower|
|
||||||
private get(): R|CompilerPhase<Context, Data, Data>|
|
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| {
|
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 () {
|
lval output: R|Data| = when () {
|
||||||
|
|||||||
+6
@@ -33728,6 +33728,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
runTest("compiler/testData/diagnostics/tests/visibility/privateFromInAnonymousObject.kt");
|
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
|
@Test
|
||||||
@TestMetadata("protectedInternal.kt")
|
@TestMetadata("protectedInternal.kt")
|
||||||
public void testProtectedInternal() throws Exception {
|
public void testProtectedInternal() throws Exception {
|
||||||
|
|||||||
+6
@@ -33728,6 +33728,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
|||||||
runTest("compiler/testData/diagnostics/tests/visibility/privateFromInAnonymousObject.kt");
|
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
|
@Test
|
||||||
@TestMetadata("protectedInternal.kt")
|
@TestMetadata("protectedInternal.kt")
|
||||||
public void testProtectedInternal() throws Exception {
|
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.scopes.unsubstitutedScope
|
||||||
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
||||||
import org.jetbrains.kotlin.fir.toEffectiveVisibility
|
import org.jetbrains.kotlin.fir.toEffectiveVisibility
|
||||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
|
||||||
import org.jetbrains.kotlin.fir.types.typeContext
|
|
||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||||
|
|
||||||
class FirStatusResolver(
|
class FirStatusResolver(
|
||||||
@@ -80,7 +79,6 @@ class FirStatusResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
|
||||||
fun getOverriddenProperties(
|
fun getOverriddenProperties(
|
||||||
property: FirProperty,
|
property: FirProperty,
|
||||||
containingClass: FirClass?,
|
containingClass: FirClass?,
|
||||||
@@ -100,7 +98,6 @@ class FirStatusResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
|
||||||
fun resolveStatus(
|
fun resolveStatus(
|
||||||
property: FirProperty,
|
property: FirProperty,
|
||||||
containingClass: FirClass?,
|
containingClass: FirClass?,
|
||||||
@@ -138,7 +135,6 @@ class FirStatusResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
|
||||||
fun resolveStatus(function: FirSimpleFunction, containingClass: FirClass?, isLocal: Boolean): FirResolvedDeclarationStatus {
|
fun resolveStatus(function: FirSimpleFunction, containingClass: FirClass?, isLocal: Boolean): FirResolvedDeclarationStatus {
|
||||||
val status = function.applyExtensionTransformers { transformStatus(it, function, containingClass, isLocal) }
|
val status = function.applyExtensionTransformers { transformStatus(it, function, containingClass, isLocal) }
|
||||||
val overriddenStatuses = getOverriddenStatuses(function, containingClass)
|
val overriddenStatuses = getOverriddenStatuses(function, containingClass)
|
||||||
@@ -185,7 +181,7 @@ class FirStatusResolver(
|
|||||||
return resolveStatus(field, field.status, containingClass, null, isLocal, emptyList())
|
return resolveStatus(field, field.status, containingClass, null, isLocal, emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resolveStatus(
|
private fun resolveStatus(
|
||||||
backingField: FirBackingField,
|
backingField: FirBackingField,
|
||||||
containingClass: FirClass?,
|
containingClass: FirClass?,
|
||||||
isLocal: Boolean
|
isLocal: Boolean
|
||||||
@@ -217,6 +213,15 @@ class FirStatusResolver(
|
|||||||
isLocal -> Visibilities.Local
|
isLocal -> Visibilities.Local
|
||||||
else -> resolveVisibility(declaration, containingClass, containingProperty, overriddenStatuses)
|
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
|
else -> status.visibility
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,6 +282,60 @@ class FirStatusResolver(
|
|||||||
return status.resolved(visibility, modality, effectiveVisibility)
|
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(
|
private fun resolveVisibility(
|
||||||
declaration: FirDeclaration,
|
declaration: FirDeclaration,
|
||||||
containingClass: FirClass?,
|
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");
|
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
|
@Test
|
||||||
@TestMetadata("protectedInternal.kt")
|
@TestMetadata("protectedInternal.kt")
|
||||||
public void testProtectedInternal() throws Exception {
|
public void testProtectedInternal() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user