diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index d93fc8e8466..ea6aa27bf86 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -346,6 +346,9 @@ public interface Errors { DiagnosticFactory0 USELESS_VARARG_ON_PARAMETER = DiagnosticFactory0.create(WARNING); + DiagnosticFactory0 DEPRECATED_LAMBDA_SYNTAX = + DiagnosticFactory0.create(WARNING, FUNCTION_LITERAL_EXPRESSION_DECLARATION); + // Named parameters DiagnosticFactory0 DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE = DiagnosticFactory0.create(ERROR, PARAMETER_DEFAULT_VALUE); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt index 551bdd054d4..7d659246c63 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt @@ -34,7 +34,7 @@ public object PositioningStrategies { if (element is JetNamedDeclaration && element !is JetObjectDeclaration && element !is JetSecondaryConstructor && - element !is JetNamedFunction + element !is JetFunction ) { if (element.getNameIdentifier() == null) { return false @@ -115,14 +115,20 @@ public object PositioningStrategies { public val DECLARATION_SIGNATURE: PositioningStrategy = object : DeclarationHeader() { override fun mark(element: JetDeclaration): List { when (element) { - is JetNamedFunction -> { + is JetFunction -> { val endOfSignatureElement = element.getTypeReference() ?: element.getValueParameterList() ?: element.getNameIdentifier() ?: element - - return markRange(element, endOfSignatureElement) + val startElement + = if (element is JetFunctionLiteral) { + element.getReceiverTypeReference() + ?: element.getValueParameterList() + ?: element + } + else element + return markRange(startElement, endOfSignatureElement) } is JetProperty -> { val endOfSignatureElement = element.getTypeReference() ?: element.getNameIdentifier() ?: element @@ -168,6 +174,12 @@ public object PositioningStrategies { } } + public val FUNCTION_LITERAL_EXPRESSION_DECLARATION: PositioningStrategy + = object : PositioningStrategy() { + override fun mark(element: JetFunctionLiteralExpression) = DECLARATION_SIGNATURE_OR_DEFAULT.mark(element.getFunctionLiteral()) + override fun isValid(element: JetFunctionLiteralExpression) = DECLARATION_SIGNATURE_OR_DEFAULT.isValid(element.getFunctionLiteral()) + } + public val TYPE_PARAMETERS_OR_DECLARATION_SIGNATURE: PositioningStrategy = object : PositioningStrategy() { override fun mark(element: JetDeclaration): List { if (element is JetTypeParameterListOwner) { 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 9cf9b1cc4b9..d3c0504d197 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -230,6 +230,8 @@ public class DefaultErrorMessages { MAP.put(FUNCTION_EXPRESSION_PARAMETER_WITH_DEFAULT_VALUE, "A function expression is not allowed to specify default values for its parameters"); MAP.put(USELESS_VARARG_ON_PARAMETER, "Vararg on this parameter is useless"); + MAP.put(DEPRECATED_LAMBDA_SYNTAX, + "This syntax for lambda is deprecated. Use short lambda notation {a[: Int], b[: String] -> ...} or function expression instead."); MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties"); MAP.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetParameterList.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetParameterList.java index 078dd7e78f8..8a94cb60619 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetParameterList.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetParameterList.java @@ -17,7 +17,9 @@ package org.jetbrains.kotlin.psi; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub; import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes; @@ -41,4 +43,14 @@ public class JetParameterList extends JetElementImplStub getParameters() { return getStubOrPsiChildrenAsList(JetStubElementTypes.VALUE_PARAMETER); } + + // this method needed only for migrate lambda syntax + @Deprecated + public boolean isParenthesized() { + PsiElement firstChild = getFirstChild(); + if (firstChild != null && firstChild.getNode() != null) { + return firstChild.getNode().getElementType() == JetTokens.LPAR; + } + return false; + } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java index 231b7979758..df2da20d52c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java @@ -911,4 +911,14 @@ public class JetPsiUtil { } return null; } + + public static boolean isDeprecatedLambdaSyntax(@NotNull JetFunctionLiteralExpression functionLiteralExpression) { + JetFunctionLiteral functionLiteral = functionLiteralExpression.getFunctionLiteral(); + if (functionLiteral.hasDeclaredReturnType() || functionLiteral.getReceiverTypeReference() != null) return true; + + JetParameterList valueParameterList = functionLiteral.getValueParameterList(); + if (valueParameterList != null && valueParameterList.isParenthesized()) return true; + + return false; + } } 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 a182279564d..219fbaf4214 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt @@ -124,6 +124,10 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express override fun visitFunctionLiteralExpression(expression: JetFunctionLiteralExpression, context: ExpressionTypingContext): JetTypeInfo? { if (!expression.getFunctionLiteral().hasBody()) return null + if (JetPsiUtil.isDeprecatedLambdaSyntax(expression)) { + context.trace.report(DEPRECATED_LAMBDA_SYNTAX.on(expression)) + } + val expectedType = context.expectedType val functionTypeExpected = !noExpectedType(expectedType) && KotlinBuiltIns.isFunctionOrExtensionFunctionType(expectedType) diff --git a/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.kt b/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.kt new file mode 100644 index 00000000000..32296c421f0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.kt @@ -0,0 +1,24 @@ +val receiver = { Int.() -> } +val receiverWithParameter = { Int.(a) -> } + +val receiverAndReturnType = { Int.(): Int -> 5 } +val receiverAndReturnTypeWithParameter = { Int.(a: Int): Int -> 5 } + +val returnType = { (): Int -> 5 } +val returnTypeWithParameter = { (b: Int): Int -> 5 } + +val receiverWithFunctionType = { ((Int) -> Int).() -> } + +val parenthesizedParameters = { (a: Int) -> } +val parenthesizedParameters2 = { (b) -> } + +val none = { -> } + + +val parameterWithFunctionType = { a: ((Int) -> Int) -> } // todo fix parser + +val newSyntax = { a: Int -> } +val newSyntax1 = { a, b -> } +val newSyntax2 = { a: Int, b: Int -> } +val newSyntax3 = { a, b: Int -> } +val newSyntax4 = { a: Int, b -> } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.txt b/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.txt new file mode 100644 index 00000000000..21186bb1cbf --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.txt @@ -0,0 +1,18 @@ +package + +internal val newSyntax: (kotlin.Int) -> kotlin.Unit +internal val newSyntax1: (???, ???) -> kotlin.Unit +internal val newSyntax2: (kotlin.Int, kotlin.Int) -> kotlin.Unit +internal val newSyntax3: (???, kotlin.Int) -> kotlin.Unit +internal val newSyntax4: (kotlin.Int, ???) -> kotlin.Unit +internal val none: () -> kotlin.Unit +internal val parameterWithFunctionType: () -> ((kotlin.Int) -> kotlin.Int) -> [ERROR : No type element] +internal val parenthesizedParameters: (kotlin.Int) -> kotlin.Unit +internal val parenthesizedParameters2: (???) -> kotlin.Unit +internal val receiver: kotlin.Int.() -> kotlin.Unit +internal val receiverAndReturnType: kotlin.Int.() -> kotlin.Int +internal val receiverAndReturnTypeWithParameter: kotlin.Int.(kotlin.Int) -> kotlin.Int +internal val receiverWithFunctionType: (kotlin.Int) -> kotlin.Int.() -> kotlin.Unit +internal val receiverWithParameter: kotlin.Int.(???) -> kotlin.Unit +internal val returnType: () -> kotlin.Int +internal val returnTypeWithParameter: (kotlin.Int) -> kotlin.Int diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index c119fc45578..c8798054dfa 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -4754,6 +4754,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("DeprecatedSyntax.kt") + public void testDeprecatedSyntax() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.kt"); + doTest(fileName); + } + @TestMetadata("ExpectedParameterTypeMismatchVariance.kt") public void testExpectedParameterTypeMismatchVariance() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/ExpectedParameterTypeMismatchVariance.kt");