Add overload of `context` with zero value arguments This often reduces the noise in error messages and while writing code with context parameters
diff --git a/compiler/fir/analysis-tests/testData/resolve/contextParameters/declarationAndUsages/onClassifierDeclaration.fir.txt b/compiler/fir/analysis-tests/testData/resolve/contextParameters/declarationAndUsages/onClassifierDeclaration.fir.txt index 9cede32f..9ff3b2a 100644 --- a/compiler/fir/analysis-tests/testData/resolve/contextParameters/declarationAndUsages/onClassifierDeclaration.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/contextParameters/declarationAndUsages/onClassifierDeclaration.fir.txt
@@ -139,8 +139,8 @@ } } - public final val test12: <ERROR TYPE REF: Ambiguity: context, [kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context]> = <Ambiguity: context, [kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context]>#(<Unresolved name: c>#) - public get(): <ERROR TYPE REF: Ambiguity: context, [kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context]> + public final val test12: <ERROR TYPE REF: Cannot infer argument for type parameter R> = R|kotlin/context<CS errors: kotlin/context>#|<<ERROR TYPE REF: Cannot infer argument for type parameter R>>(<Unresolved name: c>#) + public get(): <ERROR TYPE REF: Cannot infer argument for type parameter R> public final object <no name provided> : R|kotlin/Any| { private constructor(): R|<no name provided>| { super<R|kotlin/Any|>()
diff --git a/compiler/fir/analysis-tests/testData/resolve/contextParameters/declarationAndUsages/onClassifierDeclaration.kt b/compiler/fir/analysis-tests/testData/resolve/contextParameters/declarationAndUsages/onClassifierDeclaration.kt index e34e515..bf78b15 100644 --- a/compiler/fir/analysis-tests/testData/resolve/contextParameters/declarationAndUsages/onClassifierDeclaration.kt +++ b/compiler/fir/analysis-tests/testData/resolve/contextParameters/declarationAndUsages/onClassifierDeclaration.kt
@@ -54,7 +54,7 @@ companion object { } } -val test12 = context(<!UNRESOLVED_REFERENCE!>c<!><!SYNTAX!>: A<!>)<!SYNTAX!><!> object<!SYNTAX!><!> { } +val test12 = <!CANNOT_INFER_PARAMETER_TYPE, DEPRECATION_ERROR!>context<!>(<!UNRESOLVED_REFERENCE!>c<!><!SYNTAX!>: A<!>)<!SYNTAX!><!> object<!SYNTAX!><!> { } <!UNSUPPORTED!>context(c: A)<!> typealias Test13 = String
diff --git a/compiler/fir/analysis-tests/testData/resolve/contextParameters/diagnostics/unsupportedContextParameters.fir.txt b/compiler/fir/analysis-tests/testData/resolve/contextParameters/diagnostics/unsupportedContextParameters.fir.txt index 130775d..4f8a4e3 100644 --- a/compiler/fir/analysis-tests/testData/resolve/contextParameters/diagnostics/unsupportedContextParameters.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/contextParameters/diagnostics/unsupportedContextParameters.fir.txt
@@ -54,8 +54,8 @@ } public final typealias TA = R|kotlin/Any| - public final val objectExpression: <ERROR TYPE REF: Ambiguity: context, [kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context]> = <Ambiguity: context, [kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context]>#(<Unresolved name: _>#) - public get(): <ERROR TYPE REF: Ambiguity: context, [kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context, kotlin/context]> + public final val objectExpression: <ERROR TYPE REF: Cannot infer argument for type parameter R> = R|kotlin/context<CS errors: kotlin/context>#|<<ERROR TYPE REF: Cannot infer argument for type parameter R>>(<Unresolved name: _>#) + public get(): <ERROR TYPE REF: Cannot infer argument for type parameter R> public final object <no name provided> : R|kotlin/Any| { private constructor(): R|<no name provided>| { super<R|kotlin/Any|>()
diff --git a/compiler/fir/analysis-tests/testData/resolve/contextParameters/diagnostics/unsupportedContextParameters.kt b/compiler/fir/analysis-tests/testData/resolve/contextParameters/diagnostics/unsupportedContextParameters.kt index 0d28805..710b888 100644 --- a/compiler/fir/analysis-tests/testData/resolve/contextParameters/diagnostics/unsupportedContextParameters.kt +++ b/compiler/fir/analysis-tests/testData/resolve/contextParameters/diagnostics/unsupportedContextParameters.kt
@@ -32,7 +32,7 @@ <!UNSUPPORTED!>context(_: String)<!> typealias TA = Any -val objectExpression = context(<!UNRESOLVED_REFERENCE!>_<!><!SYNTAX!>: String<!>)<!SYNTAX!><!> object<!SYNTAX!><!> {} +val objectExpression = <!CANNOT_INFER_PARAMETER_TYPE, DEPRECATION_ERROR!>context<!>(<!UNRESOLVED_REFERENCE!>_<!><!SYNTAX!>: String<!>)<!SYNTAX!><!> object<!SYNTAX!><!> {} <!UNSUPPORTED!>context(_: String)<!> operator fun Any.getValue(thiz: Any?, metadata: Any?): Any = this
diff --git a/generators/builtins/contextParameters.kt b/generators/builtins/contextParameters.kt index efc4fc5..dde3789 100644 --- a/generators/builtins/contextParameters.kt +++ b/generators/builtins/contextParameters.kt
@@ -13,6 +13,7 @@ override fun getMultifileClassName(): String = "ContextParametersKt" override fun generateBody() { + generateZeroFunction() generateSingleFunction(listOf("with"), listOf("T"), "R") for (i in 2..MAX_PARAM_COUNT) { val parameterNames = ('a' .. 'z').take(i) @@ -24,24 +25,26 @@ } } + fun generateZeroFunction() { + out.println( + """ +${generateComment(0)} +@kotlin.internal.InlineOnly +@SinceKotlin("2.2") +@Deprecated(level = DeprecationLevel.ERROR, message = "'context' requires at least one value") +public fun <R> context(block: () -> R): R = throw NotImplementedError() +""" + ) + } + fun generateSingleFunction(parameterNames: List<String>, parameterTypes: List<String>, resultType: String) { val arguments = parameterNames.joinToString() val parameters = parameterNames.zip(parameterTypes) { name, type -> "$name: $type" }.joinToString() val types = parameterTypes.joinToString() - val values = if (parameterTypes.size == 1) "value" else "values" - val receivers = if (parameterTypes.size == 1) "receiver" else "receivers" - out.println( """ -/** - * Runs the specified [block] with the given $values in context scope. - * - * As opposed to [with], [context] only makes the $values available for - * context parameter resolution, but not as implicit $receivers. - * - * @sample samples.misc.ContextParameters.useContext - */ +${generateComment(parameterTypes.size)} @kotlin.internal.InlineOnly @SinceKotlin("2.2") public inline fun <$types, $resultType> context($parameters, block: context($types) () -> $resultType): $resultType { @@ -54,4 +57,20 @@ ) } + fun generateComment(size: Int): String { + val values = if (size == 1) "value" else "values" + val receivers = if (size == 1) "receiver" else "receivers" + + return """ +/** + * Runs the specified [block] with the given $values in context scope. + * + * As opposed to [with], [context] only makes the $values available for + * context parameter resolution, but not as implicit $receivers. + * + * @sample samples.misc.ContextParameters.useContext + */ +""".trim() + } + }
diff --git a/libraries/stdlib/src/kotlin/contextParameters/Context.kt b/libraries/stdlib/src/kotlin/contextParameters/Context.kt index 801cd36..5b54fb3 100644 --- a/libraries/stdlib/src/kotlin/contextParameters/Context.kt +++ b/libraries/stdlib/src/kotlin/contextParameters/Context.kt
@@ -12,6 +12,20 @@ /** + * Runs the specified [block] with the given values in context scope. + * + * As opposed to [with], [context] only makes the values available for + * context parameter resolution, but not as implicit receivers. + * + * @sample samples.misc.ContextParameters.useContext + */ +@kotlin.internal.InlineOnly +@SinceKotlin("2.2") +@Deprecated(level = DeprecationLevel.ERROR, message = "'context' requires at least one value") +public fun <R> context(block: () -> R): R = throw NotImplementedError() + + +/** * Runs the specified [block] with the given value in context scope. * * As opposed to [with], [context] only makes the value available for
diff --git a/libraries/tools/binary-compatibility-validator/klib-public-api/kotlin-stdlib.api b/libraries/tools/binary-compatibility-validator/klib-public-api/kotlin-stdlib.api index e605a9f..67469fd 100644 --- a/libraries/tools/binary-compatibility-validator/klib-public-api/kotlin-stdlib.api +++ b/libraries/tools/binary-compatibility-validator/klib-public-api/kotlin-stdlib.api
@@ -6576,6 +6576,7 @@ final fun <#A: kotlin/Any?> kotlin.sequences/sequence(kotlin.coroutines/SuspendFunction1<kotlin.sequences/SequenceScope<#A>, kotlin/Unit>): kotlin.sequences/Sequence<#A> // kotlin.sequences/sequence|sequence(kotlin.coroutines.SuspendFunction1<kotlin.sequences.SequenceScope<0:0>,kotlin.Unit>){0§<kotlin.Any?>}[0] final fun <#A: kotlin/Any?> kotlin.sequences/sequenceOf(#A): kotlin.sequences/Sequence<#A> // kotlin.sequences/sequenceOf|sequenceOf(0:0){0§<kotlin.Any?>}[0] final fun <#A: kotlin/Any?> kotlin.sequences/sequenceOf(kotlin/Array<out #A>...): kotlin.sequences/Sequence<#A> // kotlin.sequences/sequenceOf|sequenceOf(kotlin.Array<out|0:0>...){0§<kotlin.Any?>}[0] +final fun <#A: kotlin/Any?> kotlin/context(kotlin/Function0<#A>): #A // kotlin/context|context(kotlin.Function0<0:0>){0§<kotlin.Any?>}[0] final fun <#A: kotlin/Any?> kotlin/lazy(kotlin/Any?, kotlin/Function0<#A>): kotlin/Lazy<#A> // kotlin/lazy|lazy(kotlin.Any?;kotlin.Function0<0:0>){0§<kotlin.Any?>}[0] final fun <#A: kotlin/Any?> kotlin/lazy(kotlin/Function0<#A>): kotlin/Lazy<#A> // kotlin/lazy|lazy(kotlin.Function0<0:0>){0§<kotlin.Any?>}[0] final fun <#A: kotlin/Any?> kotlin/lazy(kotlin/LazyThreadSafetyMode, kotlin/Function0<#A>): kotlin/Lazy<#A> // kotlin/lazy|lazy(kotlin.LazyThreadSafetyMode;kotlin.Function0<0:0>){0§<kotlin.Any?>}[0]
diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt index 7ec17b9..c6122cb 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt
@@ -8,6 +8,10 @@ public abstract fun count ()I } +public final class kotlin/ContextParametersKt { + public static final fun context (Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; +} + public final class kotlin/DeepRecursiveFunction { public fun <init> (Lkotlin/jvm/functions/Function3;)V }