Prohibit inline lambda parameters of suspend function type

#KT-16068 Fixed
This commit is contained in:
Denis Zharkov
2017-01-31 11:11:14 +03:00
parent 67835b642d
commit 39fc1789e0
6 changed files with 62 additions and 2 deletions
@@ -193,6 +193,7 @@ public interface Errors {
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> WRONG_MODIFIER_CONTAINING_DECLARATION = DiagnosticFactory2.create(ERROR);
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> DEPRECATED_MODIFIER_CONTAINING_DECLARATION = DiagnosticFactory2.create(WARNING);
DiagnosticFactory1<PsiElement, KtModifierKeywordToken> ILLEGAL_INLINE_PARAMETER_MODIFIER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<KtParameter> INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<KtAnnotationEntry, String> WRONG_ANNOTATION_TARGET = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<KtAnnotationEntry, String, String> WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET = DiagnosticFactory2.create(ERROR);
DiagnosticFactory0<KtAnnotationEntry> REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR);
@@ -159,6 +159,7 @@ public class DefaultErrorMessages {
MAP.put(WRONG_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is not applicable inside ''{1}''", TO_STRING, TO_STRING);
MAP.put(DEPRECATED_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is deprecated inside ''{1}''", TO_STRING, TO_STRING);
MAP.put(ILLEGAL_INLINE_PARAMETER_MODIFIER, "Modifier ''{0}'' is allowed only for function parameters of an inline function", TO_STRING);
MAP.put(INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED, "Inline lambda parameters of suspend function type are not fully supported. Add 'noinline' modifier.");
MAP.put(WRONG_ANNOTATION_TARGET, "This annotation is not applicable to target ''{0}''", TO_STRING);
MAP.put(WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET, "This annotation is not applicable to target ''{0}'' and use site target ''@{1}''", TO_STRING, TO_STRING);
MAP.put(REPEATED_ANNOTATION, "This annotation is not repeatable");
@@ -16,7 +16,9 @@
package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
@@ -35,10 +37,15 @@ object InlineParameterChecker : SimpleDeclarationChecker {
val inline = declaration.hasModifier(KtTokens.INLINE_KEYWORD)
for (parameter in declaration.valueParameters) {
val parameterDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER, parameter)
if (!inline || (parameterDescriptor != null && !parameterDescriptor.type.isFunctionType)) {
if (!inline || (parameterDescriptor != null && !parameterDescriptor.type.isBuiltinFunctionalType)) {
parameter.reportIncorrectInline(KtTokens.NOINLINE_KEYWORD, diagnosticHolder)
parameter.reportIncorrectInline(KtTokens.CROSSINLINE_KEYWORD, diagnosticHolder)
}
if (inline && !parameter.hasModifier(KtTokens.NOINLINE_KEYWORD) &&
parameterDescriptor?.type?.isSuspendFunctionType == true) {
diagnosticHolder.report(Errors.INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED.on(parameter))
}
}
}
}
@@ -12,7 +12,7 @@ class MyTest {
}
}
inline suspend fun <T> testAsync(routine: suspend MyTest.() -> T): T = routine(MyTest())
inline suspend fun <T> testAsync(noinline routine: suspend MyTest.() -> T): T = routine(MyTest())
inline suspend fun Iterable<String>.test() = testAsync {
var sum = ""
@@ -0,0 +1,45 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// SKIP_TXT
<!NOTHING_TO_INLINE!>inline<!> fun foo1(<!INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED!>x: suspend () -> Unit<!>) {}
<!NOTHING_TO_INLINE!>inline<!> fun foo2(<!INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED!>crossinline x: suspend () -> Unit<!>) {}
<!NOTHING_TO_INLINE!>inline<!> fun foo3(noinline x: suspend () -> Unit) {}
<!NOTHING_TO_INLINE!>inline<!> fun foo4(<!INCOMPATIBLE_MODIFIERS!>noinline<!> <!INCOMPATIBLE_MODIFIERS!>crossinline<!> x: suspend () -> Unit) {}
suspend <!NOTHING_TO_INLINE!>inline<!> fun bar1(<!INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED!>x: suspend () -> Unit<!>) {}
suspend <!NOTHING_TO_INLINE!>inline<!> fun bar2(<!INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED!>crossinline x: suspend () -> Unit<!>) {}
suspend <!NOTHING_TO_INLINE!>inline<!> fun bar3(noinline x: suspend () -> Unit) {}
suspend <!NOTHING_TO_INLINE!>inline<!> fun bar4(<!INCOMPATIBLE_MODIFIERS!>noinline<!> <!INCOMPATIBLE_MODIFIERS!>crossinline<!> x: suspend () -> Unit) {}
suspend fun baz() {
foo1 {
<!RETURN_NOT_ALLOWED!>return@baz<!>
}
foo2 {
<!RETURN_NOT_ALLOWED!>return@baz<!>
}
foo3 {
<!RETURN_NOT_ALLOWED!>return@baz<!>
}
foo4 {
<!RETURN_NOT_ALLOWED!>return@baz<!>
}
bar1 {
<!RETURN_NOT_ALLOWED!>return@baz<!>
}
bar2 {
<!RETURN_NOT_ALLOWED!>return@baz<!>
}
bar3 {
<!RETURN_NOT_ALLOWED!>return@baz<!>
}
bar4 {
<!RETURN_NOT_ALLOWED!>return@baz<!>
}
}
@@ -979,6 +979,12 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
doTest(fileName);
}
@TestMetadata("inline.kt")
public void testInline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/inline.kt");
doTest(fileName);
}
@TestMetadata("invoke.kt")
public void testInvoke() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/invoke.kt");