From 11e957a87d62304556b2e2afbbd119751934c3e0 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 28 Nov 2011 21:44:10 +0300 Subject: [PATCH 1/6] "Resolve window" for debugging purposes --- .../lang/resolve/calls/AutoCastReceiver.java | 5 + .../resolve/calls/DefaultValueArgument.java | 5 + .../calls/ExpressionValueArgument.java | 5 + .../resolve/calls/VarargValueArgument.java | 14 + .../calls/autocasts/AutoCastService.java | 9 +- .../calls/autocasts/AutoCastServiceImpl.java | 4 +- .../scopes/receivers/ClassReceiver.java | 5 + .../scopes/receivers/ExpressionReceiver.java | 5 + .../scopes/receivers/ExtensionReceiver.java | 5 + .../scopes/receivers/TransientReceiver.java | 5 + idea/src/META-INF/plugin.xml | 3 + .../codewindow/BytecodeToolwindow.java | 18 +- .../resolvewindow/ResolveToolwindow.java | 251 ++++++++++++++++++ 13 files changed, 330 insertions(+), 4 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastReceiver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastReceiver.java index 00c7fde93b7..e2b7bf3571c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastReceiver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastReceiver.java @@ -32,4 +32,9 @@ public class AutoCastReceiver extends AbstractReceiverDescriptor { public R accept(@NotNull ReceiverDescriptorVisitor visitor, D data) { return original.accept(visitor, data); } + + @Override + public String toString() { + return "(" + original + " as " + getType() + ")"; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java index 2303269f5be..ed2dccb7512 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java @@ -19,4 +19,9 @@ public class DefaultValueArgument implements ResolvedValueArgument { public List getArgumentExpressions() { return Collections.emptyList(); //throw new UnsupportedOperationException("Look into the default value of the parameter"); } + + @Override + public String toString() { + return "|DEFAULT|"; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java index 02abdc635eb..6131c9c1a2c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java @@ -29,4 +29,9 @@ public class ExpressionValueArgument implements ResolvedValueArgument { if (expression == null) return Collections.emptyList(); return Collections.singletonList(expression); } + + @Override + public String toString() { + return expression.getText(); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java index 3430aa4f8e5..1b1eb7d56ba 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java @@ -4,6 +4,7 @@ import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.psi.JetExpression; +import java.util.Iterator; import java.util.List; /** @@ -17,4 +18,17 @@ public class VarargValueArgument implements ResolvedValueArgument { public List getArgumentExpressions() { return values; } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("vararg:{"); + for (Iterator iterator = values.iterator(); iterator.hasNext(); ) { + JetExpression expression = iterator.next(); + builder.append(expression.getText()); + if (iterator.hasNext()) { + builder.append(", "); + } + } + return builder.append("}").toString(); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/AutoCastService.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/AutoCastService.java index 4c0de1c1ca5..c3318690a20 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/AutoCastService.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/AutoCastService.java @@ -11,6 +11,7 @@ import java.util.List; */ public interface AutoCastService { AutoCastService NO_AUTO_CASTS = new AutoCastService() { + @NotNull @Override public DataFlowInfo getDataFlowInfo() { return DataFlowInfo.EMPTY; @@ -21,13 +22,17 @@ public interface AutoCastService { return !receiver.getType().isNullable(); } + @NotNull @Override - public List getVariantsForReceiver(ReceiverDescriptor receiverDescriptor) { + public List getVariantsForReceiver(@NotNull ReceiverDescriptor receiverDescriptor) { return Collections.singletonList(receiverDescriptor); } }; - List getVariantsForReceiver(ReceiverDescriptor receiverDescriptor); + @NotNull + List getVariantsForReceiver(@NotNull ReceiverDescriptor receiverDescriptor); + + @NotNull DataFlowInfo getDataFlowInfo(); boolean isNotNull(@NotNull ReceiverDescriptor receiver); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/AutoCastServiceImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/AutoCastServiceImpl.java index c5cf125e80a..5789419b22e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/AutoCastServiceImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/AutoCastServiceImpl.java @@ -18,11 +18,13 @@ public class AutoCastServiceImpl implements AutoCastService { this.bindingContext = bindingContext; } + @NotNull @Override - public List getVariantsForReceiver(ReceiverDescriptor receiverDescriptor) { + public List getVariantsForReceiver(@NotNull ReceiverDescriptor receiverDescriptor) { return AutoCastUtils.getAutoCastVariants(bindingContext, dataFlowInfo, receiverDescriptor); } + @NotNull @Override public DataFlowInfo getDataFlowInfo() { return dataFlowInfo; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ClassReceiver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ClassReceiver.java index 2f5f916a626..429a21b184f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ClassReceiver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ClassReceiver.java @@ -37,4 +37,9 @@ public class ClassReceiver implements ThisReceiverDescriptor { public R accept(@NotNull ReceiverDescriptorVisitor visitor, D data) { return visitor.visitClassReceiver(this, data); } + + @Override + public String toString() { + return "Class{" + getType() + "}"; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ExpressionReceiver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ExpressionReceiver.java index d7a50974481..3ab7933e68a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ExpressionReceiver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ExpressionReceiver.java @@ -25,4 +25,9 @@ public class ExpressionReceiver extends AbstractReceiverDescriptor implements Re public R accept(@NotNull ReceiverDescriptorVisitor visitor, D data) { return visitor.visitExpressionReceiver(this, data); } + + @Override + public String toString() { + return getType() + " {" + expression + ": " + expression.getText() + "}"; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ExtensionReceiver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ExtensionReceiver.java index ed7e876e29c..b9d801ebc9a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ExtensionReceiver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ExtensionReceiver.java @@ -27,4 +27,9 @@ public class ExtensionReceiver extends AbstractReceiverDescriptor implements Thi public R accept(@NotNull ReceiverDescriptorVisitor visitor, D data) { return visitor.visitExtensionReceiver(this, data); } + + @Override + public String toString() { + return getType() + "Ext{" + descriptor + "}"; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/TransientReceiver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/TransientReceiver.java index ca79ac48409..687b45ea0b8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/TransientReceiver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/TransientReceiver.java @@ -18,4 +18,9 @@ public class TransientReceiver extends AbstractReceiverDescriptor { public R accept(@NotNull ReceiverDescriptorVisitor visitor, D data) { return visitor.visitTransientReceiver(this, data); } + + @Override + public String toString() { + return "{Transient} : " + getType(); + } } diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index fe7b457af02..3c218cee23f 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -61,5 +61,8 @@ + diff --git a/idea/src/org/jetbrains/jet/plugin/internal/codewindow/BytecodeToolwindow.java b/idea/src/org/jetbrains/jet/plugin/internal/codewindow/BytecodeToolwindow.java index ad1f700d7fd..31992d30e86 100644 --- a/idea/src/org/jetbrains/jet/plugin/internal/codewindow/BytecodeToolwindow.java +++ b/idea/src/org/jetbrains/jet/plugin/internal/codewindow/BytecodeToolwindow.java @@ -208,7 +208,7 @@ public class BytecodeToolwindow extends JPanel { } } - private static class Location { + public static class Location { final Editor editor; final long modificationStamp; final int startOffset; @@ -225,6 +225,22 @@ public class BytecodeToolwindow extends JPanel { return new Location(editor); } + public Editor getEditor() { + return editor; + } + + public long getModificationStamp() { + return modificationStamp; + } + + public int getStartOffset() { + return startOffset; + } + + public int getEndOffset() { + return endOffset; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java b/idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java new file mode 100644 index 00000000000..d5dbe042557 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java @@ -0,0 +1,251 @@ +/* + * @author max + */ +package org.jetbrains.jet.plugin.internal.resolvewindow; + +import com.intellij.openapi.application.Result; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowFactory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtilCore; +import com.intellij.ui.content.ContentFactory; +import com.intellij.util.Alarm; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.JetElement; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.JetReferenceExpression; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; +import org.jetbrains.jet.lang.resolve.calls.ResolvedValueArgument; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.plugin.JetFileType; +import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; +import org.jetbrains.jet.plugin.internal.codewindow.BytecodeToolwindow; + +import javax.swing.*; +import java.awt.*; +import java.util.Map; + +import static org.jetbrains.jet.lang.resolve.BindingContext.EXPRESSION_TYPE; +import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; +import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL; + +public class ResolveToolwindow extends JPanel { + public static class Factory implements ToolWindowFactory { + @Override + public void createToolWindowContent(Project project, ToolWindow toolWindow) { + toolWindow.getContentManager().addContent(ContentFactory.SERVICE.getInstance().createContent(new ResolveToolwindow(project), "", false)); + } + } + + private static final int UPDATE_DELAY = 500; + private final Editor myEditor; + private final Alarm myUpdateAlarm; + private BytecodeToolwindow.Location myCurrentLocation; + private final Project myProject; + + + public ResolveToolwindow(Project project) { + super(new BorderLayout()); + myProject = project; + myEditor = EditorFactory.getInstance().createEditor(EditorFactory.getInstance().createDocument(""), project, JetFileType.INSTANCE, true); + add(myEditor.getComponent()); + myUpdateAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); + myUpdateAlarm.addRequest(new Runnable() { + @Override + public void run() { + myUpdateAlarm.addRequest(this, UPDATE_DELAY); + BytecodeToolwindow.Location location = BytecodeToolwindow.Location.fromEditor(FileEditorManager.getInstance(myProject).getSelectedTextEditor()); + if (!Comparing.equal(location, myCurrentLocation)) { + render(location, myCurrentLocation); + myCurrentLocation = location; + } + } + }, UPDATE_DELAY); + } + + private void render(BytecodeToolwindow.Location location, BytecodeToolwindow.Location oldLocation) { + Editor editor = location.getEditor(); + if (editor == null) { + setText("No editor"); + } + else { + VirtualFile vFile = ((EditorEx) editor).getVirtualFile(); + if (vFile == null) { + setText(""); + return; + } + + PsiFile psiFile = PsiManager.getInstance(myProject).findFile(vFile); + if (!(psiFile instanceof JetFile)) { + setText(""); + return; + } + + + int startOffset = location.getStartOffset(); + int endOffset = location.getEndOffset(); + if (oldLocation == null || !Comparing.equal(oldLocation.getEditor(), location.getEditor()) + || oldLocation.getStartOffset() != startOffset + || oldLocation.getEndOffset() != endOffset) { + + BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) psiFile); + + + PsiElement elementAtOffset; + if (startOffset == endOffset) { + elementAtOffset = PsiUtilCore.getElementAtOffset(psiFile, startOffset); + } + else { + PsiElement start = PsiUtilCore.getElementAtOffset(psiFile, startOffset); + System.out.println("start = " + start.getText()); + PsiElement end = PsiUtilCore.getElementAtOffset(psiFile, endOffset - 1); + System.out.println("end = " + end.getText()); + elementAtOffset = PsiTreeUtil.findCommonParent(start, end); + System.out.println("elementAtOffset = " + elementAtOffset.getText()); + } + + PsiElement currentElement = elementAtOffset; + + boolean callFound = false; + while (currentElement != null && !(currentElement instanceof PsiFile)) { + if (currentElement instanceof JetElement) { + JetElement atOffset = (JetElement) currentElement; + ResolvedCall resolvedCall = bindingContext.get(RESOLVED_CALL, (JetElement) atOffset); + if (resolvedCall != null) { + setText(renderCall(resolvedCall) + "\n===\n" + currentElement + ": " + currentElement.getText()); + callFound = true; + break; + } + + } + currentElement = currentElement.getParent(); + } + if (!callFound) { + + JetExpression parentExpression = (elementAtOffset instanceof JetExpression) ? (JetExpression) elementAtOffset + : PsiTreeUtil.getParentOfType(elementAtOffset, JetExpression.class); + if (parentExpression != null) { + JetType type = bindingContext.get(EXPRESSION_TYPE, parentExpression); + String text = parentExpression + "|" + parentExpression.getText() + "| : " + type; + if (parentExpression instanceof JetReferenceExpression) { + JetReferenceExpression referenceExpression = (JetReferenceExpression) parentExpression; + DeclarationDescriptor target = bindingContext.get(REFERENCE_TARGET, referenceExpression); + text += "\nReference target: \n" + target; + } + setText(text); + } + } + } + } + } + + private String renderCall(ResolvedCall resolvedCall) { + StringBuilder builder = new StringBuilder(); + + CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor(); + ReceiverDescriptor receiverArgument = resolvedCall.getReceiverArgument(); + ReceiverDescriptor thisObject = resolvedCall.getThisObject(); + Map typeArguments = resolvedCall.getTypeArguments(); + Map valueArguments = resolvedCall.getValueArguments(); + + renderReceiver(receiverArgument, thisObject, builder); + builder.append(resultingDescriptor.getName()); + renderTypeArguments(typeArguments, builder); + + if (resultingDescriptor instanceof FunctionDescriptor) { + renderValueArguments(valueArguments, builder); + } + + builder.append(" : ").append(resultingDescriptor.getReturnType()); + + builder.append("\n"); + builder.append("\n"); + + CallableDescriptor candidateDescriptor = resolvedCall.getCandidateDescriptor(); + builder.append("Candidate: \n").append(candidateDescriptor).append("\n"); + if (resultingDescriptor != candidateDescriptor) { + builder.append("Result: \n").append(resultingDescriptor).append("\n"); + } + + builder.append("Receiver: \n").append(receiverArgument).append("\n"); + builder.append("This object: \n").append(thisObject).append("\n"); + builder.append("Type args: \n").append(typeArguments).append("\n"); + builder.append("Value args: \n").append(valueArguments).append("\n"); + + return builder.toString(); + } + + private void renderValueArguments(Map valueArguments, StringBuilder builder) { + ResolvedValueArgument[] args = new ResolvedValueArgument[valueArguments.size()]; + for (Map.Entry entry : valueArguments.entrySet()) { + ValueParameterDescriptor key = entry.getKey(); + ResolvedValueArgument value = entry.getValue(); + + args[key.getIndex()] = value; + } + builder.append("("); + for (int i = 0, argsLength = args.length; i < argsLength; i++) { + ResolvedValueArgument arg = args[i]; + builder.append(arg); + if (i != argsLength - 1) { + builder.append(", "); + } + } + builder.append(")"); + } + + private void renderTypeArguments(Map typeArguments, StringBuilder builder) { + JetType[] args = new JetType[typeArguments.size()]; + for (Map.Entry entry : typeArguments.entrySet()) { + TypeParameterDescriptor key = entry.getKey(); + JetType value = entry.getValue(); + args[key.getIndex()] = value; + } + builder.append("<"); + for (int i = 0, argsLength = args.length; i < argsLength; i++) { + JetType type = args[i]; + builder.append(type); + if (i != argsLength - 1) { + builder.append(", "); + } + } + builder.append(">"); + } + + private void renderReceiver(ReceiverDescriptor receiverArgument, ReceiverDescriptor thisObject, StringBuilder builder) { + if (receiverArgument.exists()) { + builder.append("/").append(receiverArgument); + } + + if (thisObject.exists()) { + builder.append("/this=").append(thisObject); + } + + if (thisObject.exists() || receiverArgument.exists()) { + builder.append("/."); + } + } + + private void setText(final String text) { + new WriteCommandAction(myProject) { + @Override + protected void run(Result result) throws Throwable { + myEditor.getDocument().setText(text); + } + }.execute(); + } +} From 8498280b0eb67684a43e65b226895914b5a489ff Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 28 Nov 2011 21:52:04 +0300 Subject: [PATCH 2/6] Debug output removed --- .../plugin/internal/resolvewindow/ResolveToolwindow.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java b/idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java index d5dbe042557..4e35628ae2b 100644 --- a/idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java +++ b/idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java @@ -43,6 +43,9 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.EXPRESSION_TYPE; import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL; +/* + * @author abreslav + */ public class ResolveToolwindow extends JPanel { public static class Factory implements ToolWindowFactory { @Override @@ -111,11 +114,8 @@ public class ResolveToolwindow extends JPanel { } else { PsiElement start = PsiUtilCore.getElementAtOffset(psiFile, startOffset); - System.out.println("start = " + start.getText()); PsiElement end = PsiUtilCore.getElementAtOffset(psiFile, endOffset - 1); - System.out.println("end = " + end.getText()); elementAtOffset = PsiTreeUtil.findCommonParent(start, end); - System.out.println("elementAtOffset = " + elementAtOffset.getText()); } PsiElement currentElement = elementAtOffset; From 4fc41f4ad986f53dbe0f6598abbeb33ca0e40dc4 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 29 Nov 2011 01:55:39 +0400 Subject: [PATCH 3/6] mark syntax errors in QuickJetPsiCheckerTest --- .../jet/checkers/CheckerTestUtil.java | 89 ++++++++++++++++++- .../jet/lang/resolve/AnalyzingUtils.java | 17 ++++ .../quick/Constructors.jet | 4 +- .../checkerWithErrorTypes/quick/Return.jet | 4 +- .../checkerWithErrorTypes/quick/Super.jet | 4 +- .../quick/SyntaxErrorInTestHighlighting.jet | 5 ++ .../SyntaxErrorInTestHighlightingEof.jet | 1 + .../quick/cast/WhenErasedDisallowFromAny.jet | 2 +- .../regressions/kt328DuplicatedByKt329.jet | 3 +- .../jet/checkers/CheckerTestUtilTest.java | 5 +- .../jet/checkers/QuickJetPsiCheckerTest.java | 6 +- .../actions/CopyAsDiagnosticTestAction.java | 7 +- 12 files changed, 128 insertions(+), 19 deletions(-) create mode 100644 compiler/testData/checkerWithErrorTypes/quick/SyntaxErrorInTestHighlighting.jet create mode 100644 compiler/testData/checkerWithErrorTypes/quick/SyntaxErrorInTestHighlightingEof.jet diff --git a/compiler/frontend/src/org/jetbrains/jet/checkers/CheckerTestUtil.java b/compiler/frontend/src/org/jetbrains/jet/checkers/CheckerTestUtil.java index 9360fb27083..d002d67284d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/checkers/CheckerTestUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/checkers/CheckerTestUtil.java @@ -2,8 +2,13 @@ package org.jetbrains.jet.checkers; import com.google.common.collect.*; import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.diagnostics.Diagnostic; +import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory; +import org.jetbrains.jet.lang.diagnostics.Severity; +import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.BindingContext; import java.util.*; @@ -32,6 +37,15 @@ public class CheckerTestUtil { private static final Pattern RANGE_START_OR_END_PATTERN = Pattern.compile("()|()"); private static final Pattern INDIVIDUAL_DIAGNOSTIC_PATTERN = Pattern.compile("\\w+"); + public static List getDiagnosticsIncludingSyntaxErrors(BindingContext bindingContext, PsiElement root) { + ArrayList diagnostics = new ArrayList(); + diagnostics.addAll(bindingContext.getDiagnostics()); + for (TextRange textRange : AnalyzingUtils.getSyntaxErrorRanges(root)) { + diagnostics.add(new SyntaxErrorDiagnostic(textRange)); + } + return diagnostics; + } + public interface DiagnosticDiffCallbacks { void missingDiagnostic(String type, int expectedStart, int expectedEnd); void unexpectedDiagnostic(String type, int actualStart, int actualEnd); @@ -144,7 +158,7 @@ public class CheckerTestUtil { Matcher diagnosticTypeMatcher = INDIVIDUAL_DIAGNOSTIC_PATTERN.matcher(matchedText); DiagnosedRange range = new DiagnosedRange(effectiveOffset); while (diagnosticTypeMatcher.find()) { - range.addDiagnostic(diagnosticTypeMatcher.group()); + range.addDiagnostic(diagnosticTypeMatcher.group()); } opened.push(range); result.add(range); @@ -158,9 +172,17 @@ public class CheckerTestUtil { return matcher.replaceAll(""); } - public static StringBuffer addDiagnosticMarkersToText(PsiFile psiFile, BindingContext bindingContext) { - Collection diagnostics = bindingContext.getDiagnostics(); + public static StringBuffer addDiagnosticMarkersToText(PsiFile psiFile, BindingContext bindingContext, List syntaxErrors) { + Collection diagnostics = new ArrayList(); + diagnostics.addAll(bindingContext.getDiagnostics()); + for (TextRange syntaxError : syntaxErrors) { + diagnostics.add(new SyntaxErrorDiagnostic(syntaxError)); + } + return addDiagnosticMarkersToText(psiFile, diagnostics); + } + + public static StringBuffer addDiagnosticMarkersToText(PsiFile psiFile, Collection diagnostics) { StringBuffer result = new StringBuffer(); String text = psiFile.getText(); if (!diagnostics.isEmpty()) { @@ -193,6 +215,14 @@ public class CheckerTestUtil { } result.append(c); } + + if (currentDescriptor != null) { + assert currentDescriptor.start == text.length(); + assert currentDescriptor.end == text.length(); + openDiagnosticsString(result, currentDescriptor); + opened.push(currentDescriptor); + } + while (!opened.isEmpty() && text.length() == opened.peek().end) { closeDiagnosticString(result); opened.pop(); @@ -223,6 +253,55 @@ public class CheckerTestUtil { result.append(""); } + private static class SyntaxErrorDiagnosticFactory implements DiagnosticFactory { + private static final SyntaxErrorDiagnosticFactory instance = new SyntaxErrorDiagnosticFactory(); + + @NotNull + @Override + public TextRange getTextRange(@NotNull Diagnostic diagnostic) { + return ((SyntaxErrorDiagnostic) diagnostic).textRange; + } + + @NotNull + @Override + public PsiFile getPsiFile(@NotNull Diagnostic diagnostic) { + throw new IllegalStateException(); + } + + @NotNull + @Override + public String getName() { + return "SYNTAX"; + } + } + + public static class SyntaxErrorDiagnostic implements Diagnostic { + + private final TextRange textRange; + + public SyntaxErrorDiagnostic(TextRange textRange) { + this.textRange = textRange; + } + + @NotNull + @Override + public DiagnosticFactory getFactory() { + return SyntaxErrorDiagnosticFactory.instance; + } + + @NotNull + @Override + public String getMessage() { + throw new IllegalStateException(); + } + + @NotNull + @Override + public Severity getSeverity() { + throw new IllegalStateException(); + } + } + private static List getSortedDiagnosticDescriptors(Collection diagnostics) { List list = Lists.newArrayList(diagnostics); Collections.sort(list, DIAGNOSTIC_COMPARATOR); @@ -282,6 +361,10 @@ public class CheckerTestUtil { public List getDiagnostics() { return diagnostics; } + + public TextRange getTextRange() { + return new TextRange(start, end); + } } public static class DiagnosedRange { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index 483a5673739..da5cb3020b5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -4,6 +4,7 @@ import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Maps; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiErrorElement; @@ -45,6 +46,22 @@ public class AnalyzingUtils { } }); } + + public static List getSyntaxErrorRanges(@NotNull PsiElement root) { + final ArrayList r = new ArrayList(); + root.acceptChildren(new PsiElementVisitor() { + @Override + public void visitElement(PsiElement element) { + element.acceptChildren(this); + } + + @Override + public void visitErrorElement(PsiErrorElement element) { + r.add(element.getTextRange()); + } + }); + return r; + } public static void throwExceptionOnErrors(BindingContext bindingContext) { for (Diagnostic diagnostic : bindingContext.getDiagnostics()) { diff --git a/compiler/testData/checkerWithErrorTypes/quick/Constructors.jet b/compiler/testData/checkerWithErrorTypes/quick/Constructors.jet index 85a218569ac..e6ce2e54a41 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/Constructors.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/Constructors.jet @@ -28,7 +28,7 @@ class WithPC1(a : Int) { } -class Foo() : WithPC0, this() { +class Foo() : WithPC0, this() { } @@ -47,4 +47,4 @@ class NoCPI { var ab = 1 get() = 1 set(v) {} -} \ No newline at end of file +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/Return.jet b/compiler/testData/checkerWithErrorTypes/quick/Return.jet index 905a88ed092..2426ecb933c 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/Return.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/Return.jet @@ -1,4 +1,4 @@ -namespace return +namespace return class A { fun outer() { @@ -14,4 +14,4 @@ class A { return@inner return@outer } -} \ No newline at end of file +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/Super.jet b/compiler/testData/checkerWithErrorTypes/quick/Super.jet index 7a3095d820f..c7fc54a8b58 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/Super.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/Super.jet @@ -32,7 +32,7 @@ class A() : C(), T { super<E>.bar() super<E>@A.bar() super<Int>.foo() - super<>.foo() + super<>.foo() super<fun() : Unit>.foo() super<()>.foo() super@B.foo() @@ -86,4 +86,4 @@ class A1 { fun test() { super.equals(null) } -} \ No newline at end of file +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/SyntaxErrorInTestHighlighting.jet b/compiler/testData/checkerWithErrorTypes/quick/SyntaxErrorInTestHighlighting.jet new file mode 100644 index 00000000000..373cfbceda4 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/SyntaxErrorInTestHighlighting.jet @@ -0,0 +1,5 @@ +// dummy test of syntax error highlighing in tests + +fun get() { + 1 + 2 2 3 4 +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/SyntaxErrorInTestHighlightingEof.jet b/compiler/testData/checkerWithErrorTypes/quick/SyntaxErrorInTestHighlightingEof.jet new file mode 100644 index 00000000000..7114933f970 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/SyntaxErrorInTestHighlightingEof.jet @@ -0,0 +1 @@ +fun f() { diff --git a/compiler/testData/checkerWithErrorTypes/quick/cast/WhenErasedDisallowFromAny.jet b/compiler/testData/checkerWithErrorTypes/quick/cast/WhenErasedDisallowFromAny.jet index af0653dd699..2f424e3b9ad 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/cast/WhenErasedDisallowFromAny.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/cast/WhenErasedDisallowFromAny.jet @@ -4,5 +4,5 @@ import java.util.List; fun ff(l: Any) = when(l) { is List => 1 - else 2 + else 2 } diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt328DuplicatedByKt329.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt328DuplicatedByKt329.jet index 35a66da2884..5e562547174 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt328DuplicatedByKt329.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt328DuplicatedByKt329.jet @@ -3,5 +3,4 @@ fun block(f : fun() : Unit) = f() fun bar() = block{ foo() // <-- missing closing curly bracket -fun foo() = block{ bar() } - +fun foo() = block{ bar() } diff --git a/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java b/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java index cdf385d3158..72d7364ca5e 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java +++ b/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.checkers; import com.google.common.collect.Lists; +import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiFile; import org.jetbrains.jet.JetLiteFixture; import org.jetbrains.jet.lang.diagnostics.Diagnostic; @@ -82,12 +83,12 @@ public class CheckerTestUtilTest extends JetLiteFixture { public void test(PsiFile psiFile) { BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(ImportingStrategy.NONE), (JetFile) psiFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); - String expectedText = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString(); + String expectedText = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, CheckerTestUtil.getDiagnosticsIncludingSyntaxErrors(bindingContext, psiFile)).toString(); List diagnosedRanges = Lists.newArrayList(); CheckerTestUtil.parseDiagnosedRanges(expectedText, diagnosedRanges); - List diagnostics = Lists.newArrayList(bindingContext.getDiagnostics()); + List diagnostics = CheckerTestUtil.getDiagnosticsIncludingSyntaxErrors(bindingContext, psiFile); Collections.sort(diagnostics, CheckerTestUtil.DIAGNOSTIC_COMPARATOR); makeTestData(diagnostics, diagnosedRanges); diff --git a/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java b/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java index d7ae428139f..fc1609e2865 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java +++ b/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java @@ -47,7 +47,7 @@ public class QuickJetPsiCheckerTest extends JetLiteFixture { BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(importingStrategy), jetFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); - CheckerTestUtil.diagnosticsDiff(diagnosedRanges, bindingContext.getDiagnostics(), new CheckerTestUtil.DiagnosticDiffCallbacks() { + CheckerTestUtil.diagnosticsDiff(diagnosedRanges, CheckerTestUtil.getDiagnosticsIncludingSyntaxErrors(bindingContext, jetFile), new CheckerTestUtil.DiagnosticDiffCallbacks() { @Override public void missingDiagnostic(String type, int expectedStart, int expectedEnd) { String message = "Missing " + type + DiagnosticUtils.atLocation(myFile, new TextRange(expectedStart, expectedEnd)); @@ -61,14 +61,14 @@ public class QuickJetPsiCheckerTest extends JetLiteFixture { } }); - String actualText = CheckerTestUtil.addDiagnosticMarkersToText(jetFile, bindingContext).toString(); + String actualText = CheckerTestUtil.addDiagnosticMarkersToText(jetFile, bindingContext, AnalyzingUtils.getSyntaxErrorRanges(jetFile)).toString(); assertEquals(expectedText, actualText); // convert(new File(myFullDataPath + "/../../checker/"), new File(myFullDataPath)); } -// private void convert(File src, File dest) throws IOException { + // private void convert(File src, File dest) throws IOException { // File[] files = src.listFiles(); // for (File file : files) { // try { diff --git a/idea/src/org/jetbrains/jet/plugin/actions/CopyAsDiagnosticTestAction.java b/idea/src/org/jetbrains/jet/plugin/actions/CopyAsDiagnosticTestAction.java index 7e3844b4c4d..a7de5694715 100644 --- a/idea/src/org/jetbrains/jet/plugin/actions/CopyAsDiagnosticTestAction.java +++ b/idea/src/org/jetbrains/jet/plugin/actions/CopyAsDiagnosticTestAction.java @@ -6,11 +6,12 @@ import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiFile; import org.jetbrains.jet.checkers.CheckerTestUtil; import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import java.awt.*; @@ -18,6 +19,7 @@ import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; +import java.util.List; /** * @author abreslav @@ -30,8 +32,9 @@ public class CopyAsDiagnosticTestAction extends AnAction { assert editor != null && psiFile != null; BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) psiFile); + List syntaxError = AnalyzingUtils.getSyntaxErrorRanges(psiFile); - String result = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString(); + String result = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext, syntaxError).toString(); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(new StringSelection(result), new ClipboardOwner() { From e787d94b96bf7b98c374bcc3fd1db96e8c1f35da Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 29 Nov 2011 09:35:11 +0200 Subject: [PATCH 4/6] ++/-- performance optimization --- .../jet/codegen/ExpressionCodegen.java | 12 ++- .../org/jetbrains/jet/codegen/StackValue.java | 48 ++++++++++++ .../jet/codegen/intrinsics/Increment.java | 3 +- examples/src/benchmarks/BinaryTrees.java | 74 +++++++++++++++++++ examples/src/benchmarks/BinaryTrees.kt | 52 +++++++++++++ examples/src/benchmarks/Quicksort.java | 48 ++++++++++++ examples/src/benchmarks/Quicksort.kt | 47 ++++++++++++ 7 files changed, 280 insertions(+), 4 deletions(-) create mode 100644 examples/src/benchmarks/BinaryTrees.java create mode 100644 examples/src/benchmarks/BinaryTrees.kt create mode 100644 examples/src/benchmarks/Quicksort.java create mode 100644 examples/src/benchmarks/Quicksort.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 3ab8cc82519..44ad1093d19 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1905,8 +1905,16 @@ public class ExpressionCodegen extends JetVisitor { DeclarationDescriptor cls = op.getContainingDeclaration(); if (isNumberPrimitive(cls) && (op.getName().equals("inc") || op.getName().equals("dec"))) { receiver.put(receiver.type, v); - gen(expression.getBaseExpression(), asmType); // old value - generateIncrement(op, asmType, expression.getBaseExpression(), receiver); // increment in-place + JetExpression operand = expression.getBaseExpression(); + if (operand instanceof JetReferenceExpression) { + final int index = indexOfLocal((JetReferenceExpression) operand); + if (index >= 0 && JetTypeMapper.isIntPrimitive(asmType)) { + int increment = op.getName().equals("inc") ? 1 : -1; + return StackValue.postIncrement(index, increment); + } + } + gen(operand, asmType); // old value + generateIncrement(op, asmType, operand, receiver); // increment in-place return StackValue.onStack(asmType); // old value } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index 189ee230b7f..c969955151f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -256,6 +256,14 @@ public abstract class StackValue { return new ThisOuter(codegen, descriptor); } + public static StackValue postIncrement(int index, int increment) { + return new PostIncrement(index, increment); + } + + public static StackValue preIncrement(int index, int increment) { + return new PreIncrement(index, increment); + } + private static class None extends StackValue { public static None INSTANCE = new None(); private None() { @@ -963,4 +971,44 @@ public abstract class StackValue { codegen.generateThisOrOuter(descriptor); } } + + private static class PostIncrement extends StackValue { + private int index; + private int increment; + + public PostIncrement(int index, int increment) { + super(Type.INT_TYPE); + this.index = index; + this.increment = increment; + } + + @Override + public void put(Type type, InstructionAdapter v) { + if(!type.equals(Type.VOID_TYPE)) { + v.load(index, Type.INT_TYPE); + coerce(type, v); + } + v.iinc(index, increment); + } + } + + private static class PreIncrement extends StackValue { + private int index; + private int increment; + + public PreIncrement(int index, int increment) { + super(Type.INT_TYPE); + this.index = index; + this.increment = increment; + } + + @Override + public void put(Type type, InstructionAdapter v) { + v.iinc(index, increment); + if(!type.equals(Type.VOID_TYPE)) { + v.load(index, Type.INT_TYPE); + coerce(type, v); + } + } + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Increment.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Increment.java index fc1292cf899..a53c8791f80 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Increment.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Increment.java @@ -31,8 +31,7 @@ public class Increment implements IntrinsicMethod { if (operand instanceof JetReferenceExpression) { final int index = codegen.indexOfLocal((JetReferenceExpression) operand); if (index >= 0 && JetTypeMapper.isIntPrimitive(expectedType)) { - v.iinc(index, myDelta); - return StackValue.local(index, expectedType); + return StackValue.preIncrement(index, myDelta); } } StackValue value = codegen.genQualified(receiver, operand); diff --git a/examples/src/benchmarks/BinaryTrees.java b/examples/src/benchmarks/BinaryTrees.java new file mode 100644 index 00000000000..635ab88b8d4 --- /dev/null +++ b/examples/src/benchmarks/BinaryTrees.java @@ -0,0 +1,74 @@ +public class BinaryTrees { + + private final static int minDepth = 4; + + public static void main(String[] args){ + final long millis = System.currentTimeMillis(); + + int n = 20; + if (args.length > 0) n = Integer.parseInt(args[0]); + + int maxDepth = (minDepth + 2 > n) ? minDepth + 2 : n; + int stretchDepth = maxDepth + 1; + + int check = (TreeNode.bottomUpTree(0,stretchDepth)).itemCheck(); + System.out.println("stretch tree of depth "+stretchDepth+"\t check: " + check); + + TreeNode longLivedTree = TreeNode.bottomUpTree(0,maxDepth); + + for (int depth=minDepth; depth<=maxDepth; depth+=2){ + int iterations = 1 << (maxDepth - depth + minDepth); + check = 0; + + for (int i=1; i<=iterations; i++){ + check += (TreeNode.bottomUpTree(i,depth)).itemCheck(); + check += (TreeNode.bottomUpTree(-i,depth)).itemCheck(); + } + System.out.println((iterations*2) + "\t trees of depth " + depth + "\t check: " + check); + } + System.out.println("long lived tree of depth " + maxDepth + "\t check: "+ longLivedTree.itemCheck()); + + long total = System.currentTimeMillis() - millis; + System.out.println("[Binary Trees-" + System.getProperty("project.name")+ " Benchmark Result: " + total + "]"); + } + + + private static class TreeNode + { + private TreeNode left, right; + private int item; + + TreeNode(int item){ + this.item = item; + } + + private static TreeNode bottomUpTree(int item, int depth){ + if (depth>0){ + return new TreeNode( + bottomUpTree(2*item-1, depth-1) + , bottomUpTree(2*item, depth-1) + , item + ); + } + else { + return new TreeNode(item); + } + } + + TreeNode(TreeNode left, TreeNode right, int item){ + this.left = left; + this.right = right; + this.item = item; + } + + private int itemCheck(){ + // if necessary deallocate here + if (left==null) + return item; + else { + return item + left.itemCheck() - right.itemCheck(); + } + } + } +} + diff --git a/examples/src/benchmarks/BinaryTrees.kt b/examples/src/benchmarks/BinaryTrees.kt new file mode 100644 index 00000000000..89ab735995b --- /dev/null +++ b/examples/src/benchmarks/BinaryTrees.kt @@ -0,0 +1,52 @@ +val minDepth = 4 + +fun main(args: Array) { + val millis = System.currentTimeMillis() + + val n = if (args.size > 0) Integer.parseInt(args[0]) else 20; + + val maxDepth = if (minDepth + 2 > n) minDepth + 2 else n + val stretchDepth = maxDepth + 1 + + var check = bottomUpTree(0,stretchDepth).itemCheck() + System.out?.println("stretch tree of depth "+stretchDepth+"\t check: " + check); + + val longLivedTree = bottomUpTree(0,maxDepth); + + var depth = minDepth + while(depth<=maxDepth){ + val iterations = 1 shl (maxDepth - depth + minDepth) + check = 0 + + for (i in 1..iterations){ + check += bottomUpTree(i,depth).itemCheck() + check += bottomUpTree(-i,depth).itemCheck() + } + System.out?.println("${iterations*2}\t trees of depth $depth\t check: $check") + depth+=2 + } + System.out?.println("long lived tree of depth " + maxDepth + "\t check: "+ longLivedTree.itemCheck()); + + val total = System.currentTimeMillis() - millis + System.out?.println("[Binary Trees-" + System.getProperty("project.name") + " Benchmark Result: " + total + "]"); +} + +fun bottomUpTree(item: Int, depth: Int) : TreeNode = + if (depth>0){ + TreeNode(item, bottomUpTree(2*item-1, depth-1), bottomUpTree(2*item, depth-1)) + } + else { + TreeNode(item, null, null) + } + +class TreeNode(val item: Int, val left: TreeNode?, val right: TreeNode?) { + + fun itemCheck() : Int { + var res = item + if(left != null) + res += left.itemCheck() + if(right != null) + res -= right.itemCheck() + return res + } +} diff --git a/examples/src/benchmarks/Quicksort.java b/examples/src/benchmarks/Quicksort.java new file mode 100644 index 00000000000..32d9e9689da --- /dev/null +++ b/examples/src/benchmarks/Quicksort.java @@ -0,0 +1,48 @@ +public class Quicksort { + + public static void swap(int[] a, int i, int j) { + int temp = a[i]; + a[i] = a[j]; + a[j] = temp; + } + + public static void quicksort(int[] a, int L, int R) { + int m = a[(L + R) / 2]; + int i = L; + int j = R; + while (i <= j) { + while (a[i] < m) + i++; + while (a[j] > m) + j--; + if (i <= j) { + swap(a, i++, j--); + } + } + if (L < j) + quicksort(a, L, j); + if (R > i) + quicksort(a, i, R); + } + + public static void quicksort(int[] a) { + quicksort(a, 0, a.length - 1); + } + + public static void main(String[] args) { + // Sample data + int[] a = new int[100000000]; + for (int i = 0; i < a.length; i++) { + a[i] = i * 3 / 2 + 1; + if (i % 3 == 0) + a[i] = -a[i]; + } + + long start = System.currentTimeMillis(); + + quicksort(a); + + long total = System.currentTimeMillis() - start; + System.out.println("[Quicksort-" + System.getProperty("project.name")+ " Benchmark Result: " + total + "]"); + } +} \ No newline at end of file diff --git a/examples/src/benchmarks/Quicksort.kt b/examples/src/benchmarks/Quicksort.kt new file mode 100644 index 00000000000..31119549fa9 --- /dev/null +++ b/examples/src/benchmarks/Quicksort.kt @@ -0,0 +1,47 @@ +namespace quicksort + +fun IntArray.swap(i:Int, j:Int) { + val temp = this[i] + this[i] = this[j] + this[j] = temp +} + +fun IntArray.quicksort() = quicksort(0, size-1) + +fun IntArray.quicksort(L: Int, R:Int) { + val m = this[(L + R) / 2] + var i = L + var j = R + while (i <= j) { + while (this[i] < m) + i++ + while (this[j] > m) + j-- + if (i <= j) { KT-5 + swap(i++, j--) + } + } + if (L < j) + quicksort(L, j) + if (R > i) + quicksort(i, R) +} + +fun main(array: Array) { + val a = IntArray(100000000) + var i = 0 + val len = a.size + while (i < len) { + a[i] = i * 3 / 2 + 1 + if (i % 3 == 0) + a[i] = -a[i] + i++ + } + + val start = System.currentTimeMillis() + + a.quicksort() + + val total = System.currentTimeMillis() - start + System.out?.println("[Quicksort-" + System.getProperty("project.name")+ " Benchmark Result: " + total + "]"); +} From 84cb0a179ab4c33b8ad6e714f2e370a8867e301c Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Tue, 29 Nov 2011 12:48:08 +0400 Subject: [PATCH 5/6] KT-622 Add when without condition. (Only changes for parsing were added. A special task for semantic level is KT-657) --- .../lang/parsing/JetExpressionParsing.java | 28 ++-- .../jet/lang/psi/JetWhenExpression.java | 2 +- compiler/testData/psi/When.jet | 11 ++ compiler/testData/psi/When.txt | 137 ++++++++++++++++++ grammar/src/when.grm | 2 +- 5 files changed, 166 insertions(+), 14 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java index 26217d9ec9f..cf8e51c37e8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java @@ -670,7 +670,7 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * when - * : "when" "(" (modifiers "val" SimpleName "=")? element ")" "{" + * : "when" ("(" (modifiers "val" SimpleName "=")? element ")")? "{" * whenEntry* * "}" * ; @@ -682,22 +682,26 @@ public class JetExpressionParsing extends AbstractJetParsing { advance(); // WHEN_KEYWORD + // Parse condition myBuilder.disableNewlines(); - expect(LPAR, "Expecting '('"); + if (at(LPAR)) { + advanceAt(LPAR); - int valPos = matchTokenStreamPredicate(new FirstBefore(new At(VAL_KEYWORD), new AtSet(RPAR, LBRACE, RBRACE, SEMICOLON, EQ))); - if (valPos >= 0) { - PsiBuilder.Marker property = mark(); - myJetParsing.parseModifierList(MODIFIER_LIST, true); - myJetParsing.parseProperty(true); - property.done(PROPERTY); - } else { - parseExpression(); + int valPos = matchTokenStreamPredicate(new FirstBefore(new At(VAL_KEYWORD), new AtSet(RPAR, LBRACE, RBRACE, SEMICOLON, EQ))); + if (valPos >= 0) { + PsiBuilder.Marker property = mark(); + myJetParsing.parseModifierList(MODIFIER_LIST, true); + myJetParsing.parseProperty(true); + property.done(PROPERTY); + } else { + parseExpression(); + } + + expect(RPAR, "Expecting ')'"); } - - expect(RPAR, "Expecting ')'"); myBuilder.restoreNewlinesState(); + // Parse when block myBuilder.enableNewlines(); expect(LBRACE, "Expecting '{'"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetWhenExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetWhenExpression.java index 97c736e507c..bbec3d4075c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetWhenExpression.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetWhenExpression.java @@ -20,7 +20,7 @@ public class JetWhenExpression extends JetExpression { return findChildrenByType(JetNodeTypes.WHEN_ENTRY); } - @Nullable @IfNotParsed + @Nullable public JetExpression getSubjectExpression() { return findChildByClass(JetExpression.class); } diff --git a/compiler/testData/psi/When.jet b/compiler/testData/psi/When.jet index a169a11155c..48f1055329c 100644 --- a/compiler/testData/psi/When.jet +++ b/compiler/testData/psi/When.jet @@ -70,3 +70,14 @@ fun foo() { is a.a @ (val b, b) => c } } + +fun whenWithoutCondition(i : Int) { + val j = 12 + when { + 3 => -1 + i == 3 => -1 + j < i, j == i => -1 + i is Int => 1 + else => 2 + } +} diff --git a/compiler/testData/psi/When.txt b/compiler/testData/psi/When.txt index 110bad28a3f..7abeb1afcb3 100644 --- a/compiler/testData/psi/When.txt +++ b/compiler/testData/psi/When.txt @@ -1205,4 +1205,141 @@ JetFile: When.jet PsiWhiteSpace('\n ') PsiElement(RBRACE)('}') PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('whenWithoutCondition') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('i') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('j') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('12') + PsiWhiteSpace('\n ') + WHEN + PsiElement(when)('when') + PsiWhiteSpace(' ') + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + WHEN_ENTRY + WHEN_CONDITION_IS_PATTERN + EXPRESSION_PATTERN + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('3') + PsiWhiteSpace(' ') + PsiElement(DOUBLE_ARROW)('=>') + PsiWhiteSpace(' ') + PREFIX_EXPRESSION + OPERATION_REFERENCE + PsiElement(MINUS)('-') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n ') + WHEN_ENTRY + WHEN_CONDITION_IS_PATTERN + EXPRESSION_PATTERN + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('i') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(EQEQ)('==') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('3') + PsiWhiteSpace(' ') + PsiElement(DOUBLE_ARROW)('=>') + PsiWhiteSpace(' ') + PREFIX_EXPRESSION + OPERATION_REFERENCE + PsiElement(MINUS)('-') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n ') + WHEN_ENTRY + WHEN_CONDITION_IS_PATTERN + EXPRESSION_PATTERN + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('j') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(LT)('<') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('i') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + WHEN_CONDITION_IS_PATTERN + EXPRESSION_PATTERN + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('j') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(EQEQ)('==') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('i') + PsiWhiteSpace(' ') + PsiElement(DOUBLE_ARROW)('=>') + PsiWhiteSpace(' ') + PREFIX_EXPRESSION + OPERATION_REFERENCE + PsiElement(MINUS)('-') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n ') + WHEN_ENTRY + WHEN_CONDITION_IS_PATTERN + EXPRESSION_PATTERN + BINARY_WITH_PATTERN + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('i') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(is)('is') + PsiWhiteSpace(' ') + TYPE_PATTERN + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiWhiteSpace(' ') + PsiElement(DOUBLE_ARROW)('=>') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n ') + WHEN_ENTRY + PsiElement(else)('else') + PsiWhiteSpace(' ') + PsiElement(DOUBLE_ARROW)('=>') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('2') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/grammar/src/when.grm b/grammar/src/when.grm index 4b0dd363a83..864f1602161 100644 --- a/grammar/src/when.grm +++ b/grammar/src/when.grm @@ -5,7 +5,7 @@ bq. See [Pattern matching] */ when - : "when" "(" (modifiers "val" SimpleName "=")? expression ")" "{" + : "when" ("(" (modifiers "val" SimpleName "=")? expression ")")? "{" whenEntry* "}" ; From ce1718e5182a34efadda24e37cae7e61ac1ea0b6 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 29 Nov 2011 11:56:30 +0200 Subject: [PATCH 6/6] better handling of empty if/else blocks --- .../jet/codegen/ExpressionCodegen.java | 57 +++++++++++++++---- .../codegen/controlStructures/quicksort.jet | 42 ++++++++++++++ .../testData/codegen/regressions/kt239.jet | 4 +- .../jet/codegen/ControlStructuresTest.java | 5 ++ .../jet/codegen/PrimitiveTypesTest.java | 2 +- examples/src/benchmarks/Quicksort.java | 4 +- examples/src/benchmarks/Quicksort.kt | 6 +- 7 files changed, 101 insertions(+), 19 deletions(-) create mode 100644 compiler/testData/codegen/controlStructures/quicksort.jet diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 44ad1093d19..9edbcab7a40 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -155,6 +155,19 @@ public class ExpressionCodegen extends JetVisitor { return genQualified(receiver, expression.getBaseExpression()); } + private static boolean isEmptyExpression(JetElement expr) { + if(expr == null) + return true; + if(expr instanceof JetBlockExpression) { + JetBlockExpression blockExpression = (JetBlockExpression) expr; + List statements = blockExpression.getStatements(); + if(statements.size() == 0 || statements.size() == 1 && isEmptyExpression(statements.get(0))) { + return true; + } + } + return false; + } + @Override public StackValue visitIfExpression(JetIfExpression expression, StackValue receiver) { Type asmType = expressionType(expression); @@ -167,27 +180,36 @@ public class ExpressionCodegen extends JetVisitor { throw new CompilationException(); } - if (thenExpression == null) { + if (isEmptyExpression(thenExpression)) { + if (isEmptyExpression(elseExpression)) { + condition.put(asmType, v); + return StackValue.onStack(asmType); + } return generateSingleBranchIf(condition, elseExpression, false); } - - if (elseExpression == null) { - return generateSingleBranchIf(condition, thenExpression, true); + else { + if (isEmptyExpression(elseExpression)) { + return generateSingleBranchIf(condition, thenExpression, true); + } } Label elseLabel = new Label(); condition.condJump(elseLabel, true, v); // == 0, i.e. false + Label end = continueLabel == null ? new Label() : continueLabel; + gen(thenExpression, asmType); - Label endLabel = new Label(); - v.goTo(endLabel); + v.goTo(end); v.mark(elseLabel); gen(elseExpression, asmType); - v.mark(endLabel); + if(end != continueLabel) + v.mark(end); + else + v.goTo(end); return StackValue.onStack(asmType); } @@ -198,16 +220,21 @@ public class ExpressionCodegen extends JetVisitor { myContinueTargets.push(condition); v.mark(condition); - Label end = new Label(); + Label end = continueLabel != null ? continueLabel : new Label(); myBreakTargets.push(end); + Label savedContinueLabel = continueLabel; + continueLabel = condition; + final StackValue conditionValue = gen(expression.getCondition()); conditionValue.condJump(end, true, v); gen(expression.getBody(), Type.VOID_TYPE); v.goTo(condition); - v.mark(end); + continueLabel = savedContinueLabel; + if(end != continueLabel) + v.mark(end); myBreakTargets.pop(); myContinueTargets.pop(); @@ -519,13 +546,14 @@ public class ExpressionCodegen extends JetVisitor { } private StackValue generateSingleBranchIf(StackValue condition, JetExpression expression, boolean inverse) { - Label endLabel = new Label(); + Label end = continueLabel != null ? continueLabel : new Label(); - condition.condJump(endLabel, inverse, v); + condition.condJump(end, inverse, v); gen(expression, Type.VOID_TYPE); - v.mark(endLabel); + if(continueLabel != end) + v.mark(end); return StackValue.none(); } @@ -655,6 +683,8 @@ public class ExpressionCodegen extends JetVisitor { return StackValue.onStack(Type.getObjectType(closure.getClassname())); } + private Label continueLabel; + private StackValue generateBlock(List statements) { Label blockStart = new Label(); v.mark(blockStart); @@ -671,9 +701,12 @@ public class ExpressionCodegen extends JetVisitor { } StackValue answer = StackValue.none(); + Label savedContinueLabel = continueLabel; + continueLabel = null; for (int i = 0, statementsSize = statements.size(); i < statementsSize; i++) { JetElement statement = statements.get(i); if (i == statements.size() - 1 /*&& statement instanceof JetExpression && !bindingContext.get(BindingContext.STATEMENT, statement)*/) { + continueLabel = savedContinueLabel; answer = gen(statement); } else { diff --git a/compiler/testData/codegen/controlStructures/quicksort.jet b/compiler/testData/codegen/controlStructures/quicksort.jet new file mode 100644 index 00000000000..96813b62c10 --- /dev/null +++ b/compiler/testData/codegen/controlStructures/quicksort.jet @@ -0,0 +1,42 @@ +fun IntArray.swap(i:Int, j:Int) { + val temp = this[i] + this[i] = this[j] + this[j] = temp +} + +fun IntArray.quicksort() = quicksort(0, size-1) + +fun IntArray.quicksort(L: Int, R:Int) { + val m = this[(L + R) / 2] + var i = L + var j = R + while (i <= j) { + while (this[i] < m) + i++ + while (this[j] > m) + j-- + if (i <= j) { + swap(i++, j--) + } + else { + } + } + if (L < j) + quicksort(L, j) + if (R > i) + quicksort(i, R) +} + +fun box() : String { + val a = IntArray(10) + for(i in 0..4) { + a[2*i] = 2*i + a[2*i+1] = -2*i-1 + } + a.quicksort() + for(i in 0..9) { + System.out?.print(a[i]) + System.out?.print(' ') + } + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/regressions/kt239.jet b/compiler/testData/codegen/regressions/kt239.jet index ca9e1cc1d5e..f36b32743d8 100644 --- a/compiler/testData/codegen/regressions/kt239.jet +++ b/compiler/testData/codegen/regressions/kt239.jet @@ -1,3 +1,5 @@ -fun box(i: Int?) { +fun box() : String { + val i : Int? = 0 val j = i?.plus(3) //verify error + return "OK" } diff --git a/compiler/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java b/compiler/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java index 0c1d8f4aa41..a1bf84af9d6 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java @@ -220,4 +220,9 @@ public class ControlStructuresTest extends CodegenTestCase { createEnvironmentWithFullJdk(); blackBoxFile("regressions/kt434.jet"); } + + public void testQuicksort() throws Exception { + blackBoxFile("controlStructures/quicksort.jet"); +// System.out.println(generateToText()); + } } diff --git a/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java b/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java index e98e1b17a8b..d52a2e3c488 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java @@ -266,7 +266,7 @@ public class PrimitiveTypesTest extends CodegenTestCase { } public void testKt239 () throws Exception { - blackBoxFile("regressions/kt242.jet"); + blackBoxFile("regressions/kt239.jet"); } public void testKt243 () throws Exception { diff --git a/examples/src/benchmarks/Quicksort.java b/examples/src/benchmarks/Quicksort.java index 32d9e9689da..20b53bec4fb 100644 --- a/examples/src/benchmarks/Quicksort.java +++ b/examples/src/benchmarks/Quicksort.java @@ -30,6 +30,8 @@ public class Quicksort { } public static void main(String[] args) { + long start = System.currentTimeMillis(); + // Sample data int[] a = new int[100000000]; for (int i = 0; i < a.length; i++) { @@ -38,8 +40,6 @@ public class Quicksort { a[i] = -a[i]; } - long start = System.currentTimeMillis(); - quicksort(a); long total = System.currentTimeMillis() - start; diff --git a/examples/src/benchmarks/Quicksort.kt b/examples/src/benchmarks/Quicksort.kt index 31119549fa9..2d98fe82335 100644 --- a/examples/src/benchmarks/Quicksort.kt +++ b/examples/src/benchmarks/Quicksort.kt @@ -17,7 +17,7 @@ fun IntArray.quicksort(L: Int, R:Int) { i++ while (this[j] > m) j-- - if (i <= j) { KT-5 + if (i <= j) { swap(i++, j--) } } @@ -28,6 +28,8 @@ fun IntArray.quicksort(L: Int, R:Int) { } fun main(array: Array) { + val start = System.currentTimeMillis() + val a = IntArray(100000000) var i = 0 val len = a.size @@ -38,8 +40,6 @@ fun main(array: Array) { i++ } - val start = System.currentTimeMillis() - a.quicksort() val total = System.currentTimeMillis() - start