diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 1cf9760be81..a6798f079cd 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -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 { diff --git a/compiler/fir/analysis-tests/testData/resolve/problems/compilerPhase.fir.txt b/compiler/fir/analysis-tests/testData/resolve/problems/compilerPhase.fir.txt index c44e2a17b6f..de9c7b69002 100644 --- a/compiler/fir/analysis-tests/testData/resolve/problems/compilerPhase.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/problems/compilerPhase.fir.txt @@ -27,8 +27,8 @@ FILE: compilerPhase.kt super() } - private final val lower: R|CompilerPhase| = R|/lower| - private get(): R|CompilerPhase| + private/*private to this*/ final val lower: R|CompilerPhase| = R|/lower| + private/*private to this*/ get(): R|CompilerPhase| public final override fun invoke(phaseConfig: R|PhaseConfig|, phaserState: R|PhaserState|, context: R|Context|, input: R|Data|): R|Data| { lval output: R|Data| = when () { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 3506f45a0bb..8e24a4afccb 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -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 { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index 7705c96b00e..6633d432b95 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -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 { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolver.kt index d7b1f52b829..f7afd8aa98d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolver.kt @@ -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() ?: 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?, diff --git a/compiler/testData/diagnostics/tests/visibility/privateToThis.fir.kt b/compiler/testData/diagnostics/tests/visibility/privateToThis.fir.kt new file mode 100644 index 00000000000..52c6a704545 --- /dev/null +++ b/compiler/testData/diagnostics/tests/visibility/privateToThis.fir.kt @@ -0,0 +1,14 @@ +// FIR_DUMP + +class A(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) { + val x: String = a.t // Invisible! + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/visibility/privateToThis.fir.txt b/compiler/testData/diagnostics/tests/visibility/privateToThis.fir.txt new file mode 100644 index 00000000000..acf2117f5e5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/visibility/privateToThis.fir.txt @@ -0,0 +1,19 @@ +FILE: privateToThis.fir.kt + public final class A : R|kotlin/Any| { + public constructor(t: R|T|): R|A| { + super() + } + + private/*private to this*/ final val t: R|T| = R|/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|): R|kotlin/Unit| { + lval x: R|kotlin/String| = R|/a|.R|SubstitutionOverride| + } + + } diff --git a/compiler/testData/diagnostics/tests/visibility/privateToThis.kt b/compiler/testData/diagnostics/tests/visibility/privateToThis.kt new file mode 100644 index 00000000000..46e7452bd48 --- /dev/null +++ b/compiler/testData/diagnostics/tests/visibility/privateToThis.kt @@ -0,0 +1,14 @@ +// FIR_DUMP + +class A(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) { + val x: String = a.t // Invisible! + } +} diff --git a/compiler/testData/diagnostics/tests/visibility/privateToThis.txt b/compiler/testData/diagnostics/tests/visibility/privateToThis.txt new file mode 100644 index 00000000000..13be1569a4c --- /dev/null +++ b/compiler/testData/diagnostics/tests/visibility/privateToThis.txt @@ -0,0 +1,11 @@ +package + +public final class A { + public constructor A(/*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.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 +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index fa61b73be5e..91965bb591a 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -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 {