diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java
index 74ce75971cb..ee7f3d34909 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java
@@ -206,7 +206,7 @@ public class ModifiersChecker {
for (KtDestructuringDeclarationEntry multiEntry: multiDeclaration.getEntries()) {
annotationChecker.check(multiEntry, trace, null);
ModifierCheckerCore.INSTANCE.check(multiEntry, trace, null, languageVersionSettings);
- UnderscoreChecker.INSTANCE.checkNamed(multiEntry, trace, /* allowSingleUnderscore = */ true);
+ UnderscoreChecker.INSTANCE.checkNamed(multiEntry, trace, languageVersionSettings, /* allowSingleUnderscore = */ true);
}
}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/UnderscoreChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/UnderscoreChecker.kt
index 5e946b16e40..0fa7fb7416b 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/UnderscoreChecker.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/UnderscoreChecker.kt
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.resolve.checkers
import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.config.LanguageFeature
+import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.FunctionExpressionDescriptor
@@ -25,39 +27,57 @@ import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
-object UnderscoreChecker : SimpleDeclarationChecker {
+object UnderscoreChecker : DeclarationChecker {
@JvmOverloads
- fun checkIdentifier(identifier: PsiElement?, diagnosticHolder: DiagnosticSink, allowSingleUnderscore: Boolean = false) {
+ fun checkIdentifier(
+ identifier: PsiElement?,
+ diagnosticHolder: DiagnosticSink,
+ languageVersionSettings: LanguageVersionSettings,
+ allowSingleUnderscore: Boolean = false
+ ) {
if (identifier == null || identifier.text.isEmpty()) return
- if (identifier.text.all { it == '_' } && (!allowSingleUnderscore || identifier.text.length != 1)) {
+ val isValidSingleUnderscore = allowSingleUnderscore && identifier.text == "_"
+ if (!isValidSingleUnderscore && identifier.text.all { it == '_' }) {
diagnosticHolder.report(Errors.UNDERSCORE_IS_RESERVED.on(identifier))
}
+ else if (isValidSingleUnderscore && !languageVersionSettings.supportsFeature(LanguageFeature.SingleUnderscoreForParameterName)) {
+ diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(identifier, LanguageFeature.SingleUnderscoreForParameterName))
+ }
}
@JvmOverloads
- fun checkNamed(declaration: KtNamedDeclaration, diagnosticHolder: DiagnosticSink, allowSingleUnderscore: Boolean = false) {
- checkIdentifier(declaration.nameIdentifier, diagnosticHolder, allowSingleUnderscore)
+ fun checkNamed(
+ declaration: KtNamedDeclaration,
+ diagnosticHolder: DiagnosticSink,
+ languageVersionSettings: LanguageVersionSettings,
+ allowSingleUnderscore: Boolean = false
+ ) {
+ checkIdentifier(declaration.nameIdentifier, diagnosticHolder, languageVersionSettings, allowSingleUnderscore)
}
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
- bindingContext: BindingContext
+ bindingContext: BindingContext,
+ languageVersionSettings: LanguageVersionSettings
) {
if (declaration is KtProperty && descriptor !is VariableDescriptor) return
if (declaration is KtCallableDeclaration) {
for (parameter in declaration.valueParameters) {
- checkNamed(parameter, diagnosticHolder, allowSingleUnderscore = descriptor is FunctionExpressionDescriptor)
+ checkNamed(
+ parameter, diagnosticHolder, languageVersionSettings,
+ allowSingleUnderscore = descriptor is FunctionExpressionDescriptor
+ )
}
}
if (declaration is KtTypeParameterListOwner) {
for (typeParameter in declaration.typeParameters) {
- checkNamed(typeParameter, diagnosticHolder)
+ checkNamed(typeParameter, diagnosticHolder, languageVersionSettings)
}
}
if (declaration !is KtNamedDeclaration) return
- checkNamed(declaration, diagnosticHolder)
+ checkNamed(declaration, diagnosticHolder, languageVersionSettings)
}
}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java
index 723cc63e39c..37429a2d3e2 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java
@@ -870,7 +870,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
KtSimpleNameExpression labelExpression = expression.getTargetLabel();
if (labelExpression != null) {
PsiElement labelIdentifier = labelExpression.getIdentifier();
- UnderscoreChecker.INSTANCE.checkIdentifier(labelIdentifier, context.trace);
+ UnderscoreChecker.INSTANCE.checkIdentifier(labelIdentifier, context.trace, components.languageVersionSettings);
}
KtExpression baseExpression = expression.getBaseExpression();
if (baseExpression == null) return TypeInfoFactoryKt.noTypeInfo(context);
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt
index 3b2ed6cab79..2e6921e2636 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt
@@ -146,7 +146,7 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
val functionDescriptor = createFunctionLiteralDescriptor(expression, context)
expression.valueParameters.forEach {
components.identifierChecker.checkDeclaration(it, context.trace)
- UnderscoreChecker.checkNamed(it, context.trace, allowSingleUnderscore = true)
+ UnderscoreChecker.checkNamed(it, context.trace, components.languageVersionSettings, allowSingleUnderscore = true)
}
val safeReturnType = computeReturnType(expression, context, functionDescriptor, functionTypeExpected)
functionDescriptor.setReturnType(safeReturnType)
diff --git a/compiler/testData/diagnostics/tests/SingleUnderscoreUnsupported.kt b/compiler/testData/diagnostics/tests/SingleUnderscoreUnsupported.kt
new file mode 100644
index 00000000000..cb316cf88b2
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/SingleUnderscoreUnsupported.kt
@@ -0,0 +1,27 @@
+// !LANGUAGE: -SingleUnderscoreForParameterName
+
+data class A(val x: Int, val y: Int)
+
+fun foo(a: Array) {
+ val (_, y) = A(1, 2)
+ y.hashCode()
+
+ val q1: (Int, String) -> Unit = {
+ _, s -> s.hashCode()
+ }
+ q1(1, "")
+
+ val q2: (Int, String) -> Unit = fun(_: Int, s: String) {
+ s.hashCode()
+ }
+ q2(1, "")
+
+ val q3: (A) -> Unit = {
+ (_, y) -> y.hashCode()
+ }
+ q3(A(2, 3))
+
+ for ((_, z) in a) {
+ z.hashCode()
+ }
+}
diff --git a/compiler/testData/diagnostics/tests/SingleUnderscoreUnsupported.txt b/compiler/testData/diagnostics/tests/SingleUnderscoreUnsupported.txt
new file mode 100644
index 00000000000..98548b36ce7
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/SingleUnderscoreUnsupported.txt
@@ -0,0 +1,15 @@
+package
+
+public fun foo(/*0*/ a: kotlin.Array): kotlin.Unit
+
+public final data class A {
+ public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int)
+ public final val x: kotlin.Int
+ public final val y: kotlin.Int
+ public final operator /*synthesized*/ fun component1(): kotlin.Int
+ public final operator /*synthesized*/ fun component2(): kotlin.Int
+ public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ..., /*1*/ y: kotlin.Int = ...): A
+ public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+ public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
+ public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
+}
diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java
index 39bb3516f93..b917daf5f81 100644
--- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java
@@ -655,6 +655,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
+ @TestMetadata("SingleUnderscoreUnsupported.kt")
+ public void testSingleUnderscoreUnsupported() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/SingleUnderscoreUnsupported.kt");
+ doTest(fileName);
+ }
+
@TestMetadata("StarsInFunctionCalls.kt")
public void testStarsInFunctionCalls() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/StarsInFunctionCalls.kt");
diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt
index 2c25fcccefd..c561cf6acf6 100644
--- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt
+++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt
@@ -29,6 +29,7 @@ enum class LanguageFeature(val sinceVersion: LanguageVersion) {
DataClassInheritance(KOTLIN_1_1),
InlineProperties(KOTLIN_1_1),
DestructuringLambdaParameters(KOTLIN_1_1),
+ SingleUnderscoreForParameterName(KOTLIN_1_1)
;
val presentableText: String