From 5bca1d3c8fea5e5f7b888bfc33f0d467b8f4a490 Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Wed, 20 May 2015 15:04:59 +0300 Subject: [PATCH] Added dianostic error for non-local return on disabled inlines, Render bytecode diagnostics in BytecodeToolWindow #KT-5584 Fixed --- .../kotlin/codegen/ExpressionCodegen.java | 6 ++++- .../kotlin/diagnostics/DiagnosticSink.java | 18 +++++++++++++++ .../rendering/DefaultErrorMessages.java | 1 + .../testData/cli/jvm/nonLocalDisabled.args | 4 ++++ compiler/testData/cli/jvm/nonLocalDisabled.kt | 13 +++++++++++ .../testData/cli/jvm/nonLocalDisabled.out | 3 +++ .../cli/KotlincExecutableTestGenerated.java | 6 +++++ .../internal/KotlinBytecodeToolWindow.java | 22 ++++++++++++++++++- 8 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/cli/jvm/nonLocalDisabled.args create mode 100644 compiler/testData/cli/jvm/nonLocalDisabled.kt create mode 100644 compiler/testData/cli/jvm/nonLocalDisabled.out diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 428c3ee2e3a..788342333c6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -46,6 +46,7 @@ import org.jetbrains.kotlin.codegen.when.SwitchCodegen; import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.diagnostics.DiagnosticUtils; +import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor; @@ -1828,7 +1829,10 @@ public class ExpressionCodegen extends JetVisitor implem NonLocalReturnInfo nonLocalReturn = getNonLocalReturnInfo(descriptor, expression); boolean isNonLocalReturn = nonLocalReturn != null; if (isNonLocalReturn && !state.isInlineEnabled()) { - throw new CompilationException("Non local returns requires enabled inlining", null, expression); + state.getDiagnostics().report(Errors.NON_LOCAL_RETURN_IN_DISABLED_INLINE.on(expression)); + genThrow(v, "java/lang/UnsupportedOperationException", + "Non-local returns are not allowed with inlining disabled"); + return StackValue.none(); } Type returnType = isNonLocalReturn ? nonLocalReturn.returnType : this.returnType; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java index 494a63f5ac1..9dc7486d572 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java @@ -21,6 +21,8 @@ import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; public interface DiagnosticSink { @@ -29,6 +31,22 @@ public interface DiagnosticSink { public void report(@NotNull Diagnostic diagnostic) { } }; + + class CollectAll implements DiagnosticSink { + + List diagnostics = new ArrayList(); + + @Override + public void report(@NotNull Diagnostic diagnostic) { + diagnostics.add(diagnostic); + } + + @NotNull + public List getDiagnostics() { + return Collections.unmodifiableList(diagnostics); + } + }; + DiagnosticSink THROW_EXCEPTION = new DiagnosticSink() { @Override public void report(@NotNull Diagnostic diagnostic) { 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 afbfb6e4efb..f8ea8a6d2a5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -613,6 +613,7 @@ public class DefaultErrorMessages { //Inline non Locals MAP.put(NON_LOCAL_RETURN_NOT_ALLOWED, "Can''t inline ''{0}'' here: it may contain non-local returns. Annotate parameter declaration ''{0}'' with ''inlineOptions(ONLY_LOCAL_RETURN)''", ELEMENT_TEXT, SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES); MAP.put(INLINE_CALL_CYCLE, "The ''{0}'' invocation is a part of inline cycle", NAME); + MAP.put(NON_LOCAL_RETURN_IN_DISABLED_INLINE, "Non-local returns are not allowed with inlining disabled"); MAP.setImmutable(); diff --git a/compiler/testData/cli/jvm/nonLocalDisabled.args b/compiler/testData/cli/jvm/nonLocalDisabled.args new file mode 100644 index 00000000000..9977cf533b1 --- /dev/null +++ b/compiler/testData/cli/jvm/nonLocalDisabled.args @@ -0,0 +1,4 @@ +$TESTDATA_DIR$/nonLocalDisabled.kt +-Xno-inline +-d +$TEMP_DIR$ diff --git a/compiler/testData/cli/jvm/nonLocalDisabled.kt b/compiler/testData/cli/jvm/nonLocalDisabled.kt new file mode 100644 index 00000000000..c19ab60f57c --- /dev/null +++ b/compiler/testData/cli/jvm/nonLocalDisabled.kt @@ -0,0 +1,13 @@ +fun a() { + c { + return + } + + c { + return@a + } +} + +inline fun c(p: () -> Unit) { + p() +} \ No newline at end of file diff --git a/compiler/testData/cli/jvm/nonLocalDisabled.out b/compiler/testData/cli/jvm/nonLocalDisabled.out new file mode 100644 index 00000000000..6af6051a9bd --- /dev/null +++ b/compiler/testData/cli/jvm/nonLocalDisabled.out @@ -0,0 +1,3 @@ +ERROR: compiler/testData/cli/jvm/nonLocalDisabled.kt: (3, 9) Non-local returns are not allowed with inlining disabled +ERROR: compiler/testData/cli/jvm/nonLocalDisabled.kt: (7, 9) Non-local returns are not allowed with inlining disabled +COMPILATION_ERROR \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/cli/KotlincExecutableTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/cli/KotlincExecutableTestGenerated.java index fcc5d812712..4f6a3226dd0 100644 --- a/compiler/tests/org/jetbrains/kotlin/cli/KotlincExecutableTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/cli/KotlincExecutableTestGenerated.java @@ -109,6 +109,12 @@ public class KotlincExecutableTestGenerated extends AbstractKotlincExecutableTes doJvmTest(fileName); } + @TestMetadata("nonLocalDisabled.args") + public void testNonLocalDisabled() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/cli/jvm/nonLocalDisabled.args"); + doJvmTest(fileName); + } + @TestMetadata("pluginSimple.args") public void testPluginSimple() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/cli/jvm/pluginSimple.args"); diff --git a/idea/src/org/jetbrains/kotlin/idea/internal/KotlinBytecodeToolWindow.java b/idea/src/org/jetbrains/kotlin/idea/internal/KotlinBytecodeToolWindow.java index 92e034a2dfe..e6db8f4e59a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/internal/KotlinBytecodeToolWindow.java +++ b/idea/src/org/jetbrains/kotlin/idea/internal/KotlinBytecodeToolWindow.java @@ -43,7 +43,9 @@ import org.jetbrains.kotlin.codegen.KotlinCodegenFacade; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.Progress; import org.jetbrains.kotlin.descriptors.ModuleDescriptor; +import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.DiagnosticSink; +import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages; import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade; import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage; import org.jetbrains.kotlin.idea.util.DebuggerUtils; @@ -54,6 +56,7 @@ import org.jetbrains.kotlin.psi.JetClassOrObject; import org.jetbrains.kotlin.psi.JetFile; import org.jetbrains.kotlin.psi.JetScript; import org.jetbrains.kotlin.resolve.BindingContext; +import org.jetbrains.kotlin.utils.UtilsPackage; import javax.swing.*; import java.awt.*; @@ -197,6 +200,7 @@ public class KotlinBytecodeToolWindow extends JPanel implements Disposable { boolean enableOptimization ) { GenerationState state; + DiagnosticSink.CollectAll sink = new DiagnosticSink.CollectAll(); try { ResolutionFacade resolutionFacade = ResolvePackage.getResolutionFacade(jetFile); @@ -233,12 +237,13 @@ public class KotlinBytecodeToolWindow extends JPanel implements Disposable { }; ModuleDescriptor moduleDescriptor = resolutionFacade.findModuleDescriptor(jetFile); + state = new GenerationState(jetFile.getProject(), ClassBuilderFactories.TEST, Progress.DEAF, moduleDescriptor, bindingContext, toProcess, !enableAssertions, !enableAssertions, generateClassFilter, !enableInline, !enableOptimization, null, null, - DiagnosticSink.DO_NOTHING, null); + sink, null); KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION); } catch (ProcessCanceledException e) { @@ -250,6 +255,21 @@ public class KotlinBytecodeToolWindow extends JPanel implements Disposable { StringBuilder answer = new StringBuilder(); + List diagnostics = sink.getDiagnostics(); + if (!diagnostics.isEmpty()) { + answer.append("// Backend Errors: \n"); + answer.append("// ================\n"); + for (Diagnostic diagnostic : diagnostics) { + answer.append("// Error at ") + .append(diagnostic.getPsiFile().getName()) + .append(UtilsPackage.join(diagnostic.getTextRanges(), ",")) + .append(": ") + .append(DefaultErrorMessages.render(diagnostic)) + .append("\n"); + } + answer.append("// ================\n\n"); + } + OutputFileCollection outputFiles = state.getFactory(); for (OutputFile outputFile : outputFiles.asList()) { answer.append("// ================");