From a86b4d767e3d4abcfa5853d029d38bb54fb8ab67 Mon Sep 17 00:00:00 2001 From: "Anastasia.Shadrina" Date: Thu, 20 Jan 2022 18:03:51 +0700 Subject: [PATCH] [FE] KT-50878 Prohibit using contextual declarations without `-Xcontext-receivers` --- .../jetbrains/kotlin/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 1 + .../DiagnosticReporterByTrackingStrategy.kt | 4 +++ .../calls/components/ResolutionParts.kt | 9 ++++--- .../resolve/calls/tower/ImplicitScopeTower.kt | 6 +++++ .../contextReceivers/unsupported.fir.kt | 26 ++++++++++++++++++- .../contextReceivers/unsupported.kt | 24 +++++++++++++++++ .../contextReceivers/unsupported.txt | 4 +++ 8 files changed, 70 insertions(+), 5 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 22d161ebbd4..72b80bc2ff9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -1299,6 +1299,7 @@ public interface Errors { DiagnosticFactory1 NO_CONTEXT_RECEIVER = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL = DiagnosticFactory0.create(ERROR); // Error sets ImmutableSet> UNRESOLVED_REFERENCE_DIAGNOSTICS = ImmutableSet.of( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 3b44554bea4..b6377be141e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -1109,6 +1109,7 @@ public class DefaultErrorMessages { MAP.put(NO_CONTEXT_RECEIVER, "No required context receiver found: {0}", TO_STRING); MAP.put(MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER, "Multiple arguments applicable for context receiver: {0}", TO_STRING); MAP.put(AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER, "With implicit context receiver, call is ambiguous. Specify the receiver explicitly"); + MAP.put(UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL, "To use contextual declarations, specify the `-Xcontext-receivers` compiler option"); MAP.setImmutable(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt index b6cfeeb863b..6a487ed9083 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt @@ -132,6 +132,10 @@ class DiagnosticReporterByTrackingStrategy( val callElement = psiKotlinCall.psiCall.callElement trace.report(AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER.on(callElement)) } + UnsupportedContextualDeclarationCall::class.java -> { + val callElement = psiKotlinCall.psiCall.callElement + trace.report(UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL.on(callElement)) + } } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index 1cabfa42dcc..3d00a19baa3 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -19,10 +19,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.* import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCast import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.* -import org.jetbrains.kotlin.resolve.calls.tower.ContextReceiverAmbiguity -import org.jetbrains.kotlin.resolve.calls.tower.InfixCallNoInfixModifier -import org.jetbrains.kotlin.resolve.calls.tower.InvokeConventionCallNoOperatorModifier -import org.jetbrains.kotlin.resolve.calls.tower.VisibilityError +import org.jetbrains.kotlin.resolve.calls.tower.* import org.jetbrains.kotlin.resolve.descriptorUtil.isInsideInterface import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo @@ -857,6 +854,10 @@ internal object ErrorDescriptorResolutionPart : ResolutionPart() { internal object CheckContextReceiversResolutionPart : ResolutionPart() { override fun ResolutionCandidate.process(workIndex: Int) { if (candidateDescriptor.contextReceiverParameters.isEmpty()) return + if (!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.ContextReceivers)) { + addDiagnostic(UnsupportedContextualDeclarationCall()) + return + } val parentLexicalScopes = scopeTower.lexicalScope.parentsWithSelf.filterIsInstance() val implicitReceiversGroups = mutableListOf>() for (scope in parentLexicalScopes) { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt index 67f0a02a25e..a7cc029bff1 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt @@ -120,6 +120,12 @@ class ContextReceiverAmbiguity : ResolutionDiagnostic(RESOLVED_WITH_ERROR) { } } +class UnsupportedContextualDeclarationCall : ResolutionDiagnostic(RESOLVED_WITH_ERROR) { + override fun report(reporter: DiagnosticReporter) { + reporter.onCall(this) + } +} + // todo error for this access from nested class class VisibilityError(val invisibleMember: DeclarationDescriptorWithVisibility) : ResolutionDiagnostic(RUNTIME_ERROR) { override fun report(reporter: DiagnosticReporter) { diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/unsupported.fir.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/unsupported.fir.kt index 20373298fb5..bb560acc564 100644 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/unsupported.fir.kt +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/unsupported.fir.kt @@ -5,6 +5,17 @@ fun f(g: context(Any) () -> Unit, value: Any): context(A) () -> Unit { return value as (context(A) () -> Unit) } +fun f(g: () -> Unit, value: Any) : () -> Unit { + return g +} + +context(Any) +fun sameAsFWithoutNonContextualCounterpart(g: () -> Unit, value: Any) : () -> Unit { + return g +} + +context(Any) val p get() = 42 + context(String, Int) class A { context(Any) @@ -12,4 +23,17 @@ class A { context(String, Int) fun m() {} -} \ No newline at end of file +} + +fun useWithContextReceivers() { + with(42) { + with("") { + f({}, 42) + sameAsFWithoutNonContextualCounterpart({}, 42) + p + val a = A() + a.p + a.m() + } + } +} diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/unsupported.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/unsupported.kt index 67917bf3580..e36675c48ac 100644 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/unsupported.kt +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/unsupported.kt @@ -5,6 +5,17 @@ fun f(g: context(Any) () -> Unit, value: Any): context(A) () -> Unit) } +fun f(g: () -> Unit, value: Any) : () -> Unit { + return g +} + +context(Any) +fun sameAsFWithoutNonContextualCounterpart(g: () -> Unit, value: Any) : () -> Unit { + return g +} + +context(Any) val p get() = 42 + context(String, Int) class A { context(Any) @@ -12,4 +23,17 @@ class A { context(String, Int) fun m() {} +} + +fun useWithContextReceivers() { + with(42) { + with("") { + f({}, 42) + sameAsFWithoutNonContextualCounterpart({}, 42) + p + val a = A() + a.p + a.m() + } + } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/unsupported.txt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/unsupported.txt index bf9e7af6539..b3df1924925 100644 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/unsupported.txt +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/unsupported.txt @@ -1,6 +1,10 @@ package +context(kotlin.Any) public val p: kotlin.Int +public fun f(/*0*/ g: () -> kotlin.Unit, /*1*/ value: kotlin.Any): () -> kotlin.Unit context(kotlin.Any) public fun f(/*0*/ g: context(kotlin.Any) () -> kotlin.Unit, /*1*/ value: kotlin.Any): context(A) () -> kotlin.Unit +context(kotlin.Any) public fun sameAsFWithoutNonContextualCounterpart(/*0*/ g: () -> kotlin.Unit, /*1*/ value: kotlin.Any): () -> kotlin.Unit +public fun useWithContextReceivers(): kotlin.Unit context(kotlin.String, kotlin.Int) public final class A { public constructor A()