diff --git a/platform/script-debugger/backend/src/org/jetbrains/concurrency/AsyncPromise.java b/platform/script-debugger/backend/src/org/jetbrains/concurrency/AsyncPromise.java index edfb854d96d5..a9df79ecf0d1 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/concurrency/AsyncPromise.java +++ b/platform/script-debugger/backend/src/org/jetbrains/concurrency/AsyncPromise.java @@ -1,14 +1,18 @@ package org.jetbrains.concurrency; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Getter; import com.intellij.util.Consumer; import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; public class AsyncPromise extends Promise implements Getter { + private static final Logger LOG = Logger.getInstance(AsyncPromise.class); + private volatile Consumer done; private volatile Consumer rejected; @@ -25,6 +29,10 @@ public class AsyncPromise extends Promise implements Getter { @NotNull @Override public Promise done(@NotNull Consumer done) { + if (isObsolete(done)) { + return this; + } + switch (state) { case PENDING: break; @@ -84,7 +92,9 @@ public class AsyncPromise extends Promise implements Getter { if (list != null) { for (Consumer consumer : list) { - consumer.consume(t); + if (!isObsolete(consumer)) { + consumer.consume(t); + } } } } @@ -213,6 +223,7 @@ public class AsyncPromise extends Promise implements Getter { return promise; } + @Override @NotNull public Promise processed(@NotNull final AsyncPromise fulfilled) { switch (state) { @@ -275,11 +286,15 @@ public class AsyncPromise extends Promise implements Getter { Consumer done = this.done; clearHandlers(); - if (done != null) { + if (done != null && !isObsolete(done)) { done.consume(result); } } + static boolean isObsolete(@Nullable Consumer done) { + return done instanceof ObsolescentConsumer && ((ObsolescentConsumer)done).isObsolete(); + } + public void setError(@NotNull Throwable error) { if (state != State.PENDING) { return; @@ -293,6 +308,9 @@ public class AsyncPromise extends Promise implements Getter { if (rejected != null) { rejected.consume(error); } + else if (!(error instanceof MessageError)) { + LOG.error(error); + } } private void clearHandlers() { diff --git a/platform/script-debugger/backend/src/org/jetbrains/concurrency/DonePromise.java b/platform/script-debugger/backend/src/org/jetbrains/concurrency/DonePromise.java index 5a689594c947..3653bd6f634f 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/concurrency/DonePromise.java +++ b/platform/script-debugger/backend/src/org/jetbrains/concurrency/DonePromise.java @@ -15,7 +15,9 @@ class DonePromise extends Promise implements Getter { @NotNull @Override public Promise done(@NotNull Consumer done) { - done.consume(result); + if (!AsyncPromise.isObsolete(done)) { + done.consume(result); + } return this; } @@ -26,21 +28,26 @@ class DonePromise extends Promise implements Getter { return this; } + @Override + public void processed(@NotNull Consumer processed) { + done(processed); + } + @NotNull @Override public Promise rejected(@NotNull Consumer rejected) { return this; } - @Override - public void processed(@NotNull Consumer processed) { - processed.consume(result); - } - @NotNull @Override public Promise then(@NotNull Function done) { - return Promise.resolve(done.fun(result)); + if (done instanceof ObsolescentFunction && ((ObsolescentFunction)done).isObsolete()) { + return Promise.reject("obsolete"); + } + else { + return Promise.resolve(done.fun(result)); + } } @NotNull diff --git a/platform/script-debugger/backend/src/org/jetbrains/concurrency/ObsolescentConsumer.java b/platform/script-debugger/backend/src/org/jetbrains/concurrency/ObsolescentConsumer.java new file mode 100644 index 000000000000..51442709a714 --- /dev/null +++ b/platform/script-debugger/backend/src/org/jetbrains/concurrency/ObsolescentConsumer.java @@ -0,0 +1,7 @@ +package org.jetbrains.concurrency; + +import com.intellij.util.Consumer; + +public interface ObsolescentConsumer extends Consumer { + boolean isObsolete(); +} diff --git a/platform/script-debugger/backend/src/org/jetbrains/concurrency/PromiseManager.java b/platform/script-debugger/backend/src/org/jetbrains/concurrency/PromiseManager.java index 5fc5a36df047..f6821f9e074e 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/concurrency/PromiseManager.java +++ b/platform/script-debugger/backend/src/org/jetbrains/concurrency/PromiseManager.java @@ -22,7 +22,7 @@ public abstract class PromiseManager { return true; } - public abstract Promise load(@NotNull HOST host, Promise promise); + public abstract Promise load(@NotNull HOST host); public final void reset(HOST host) { fieldUpdater.set(host, null); @@ -52,6 +52,7 @@ public abstract class PromiseManager { return getOrCreateAsyncResult(host, checkFreshness, true); } + @NotNull private Promise getOrCreateAsyncResult(HOST host, boolean checkFreshness, boolean load) { Promise promise = fieldUpdater.get(host); if (promise == null) { @@ -89,14 +90,14 @@ public abstract class PromiseManager { return getPromise(host, load, promise); } + @NotNull private Promise getPromise(HOST host, boolean load, Promise promise) { - if (load) { - Promise effectivePromise = load(host, promise); - if (effectivePromise != promise) { - ((AsyncPromise)effectivePromise).notify((AsyncPromise)promise); - } - return effectivePromise; + if (!load) { + return promise; } - return promise; + + Promise effectivePromise = load(host); + ((AsyncPromise)effectivePromise).notify((AsyncPromise)promise); + return effectivePromise; } } \ No newline at end of file diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/DeclarativeScope.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/DeclarativeScope.java index 2aae26df93fb..fa7f76383f86 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/DeclarativeScope.java +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/DeclarativeScope.java @@ -20,7 +20,7 @@ public abstract class DeclarativeScope extend @NotNull @Override - public Promise> load(@NotNull DeclarativeScope host, @NotNull Promise> promise) { + public Promise> load(@NotNull DeclarativeScope host) { //noinspection unchecked return host.loadVariables(); } diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/EvaluateContext.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/EvaluateContext.java index 2126775e07a4..0fba1f42eb89 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/EvaluateContext.java +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/EvaluateContext.java @@ -11,18 +11,20 @@ import java.util.Map; * of suspended process, but may also be detached from any stack frame */ public interface EvaluateContext { - /** * Evaluates an arbitrary {@code expression} in the particular context. * Previously loaded {@link org.jetbrains.debugger.values.ObjectValue}s can be addressed from the expression if listed in * additionalContext parameter. */ @NotNull - Promise evaluate(@NotNull String expression, @Nullable Map additionalContext); + Promise evaluate(@NotNull String expression, @Nullable Map additionalContext, boolean enableBreak); @NotNull Promise evaluate(@NotNull String expression); + @NotNull + Promise evaluate(@NotNull String expression, boolean enableBreak); + /** * optional to implement, some protocols, WIP for example, require you to release remote objects */ diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/EvaluateContextBase.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/EvaluateContextBase.java index d30b3ce35f10..812f24d5d0f5 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/EvaluateContextBase.java +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/EvaluateContextBase.java @@ -17,7 +17,13 @@ public abstract class EvaluateContextBase im @NotNull @Override public Promise evaluate(@NotNull String expression) { - return evaluate(expression, null); + return evaluate(expression, null, false); + } + + @NotNull + @Override + public Promise evaluate(@NotNull String expression, boolean enableBreak) { + return evaluate(expression, null, true); } @NotNull @@ -32,7 +38,7 @@ public abstract class EvaluateContextBase im @NotNull @Override - public abstract Promise evaluate(@NotNull String expression, @Nullable Map additionalContext); + public abstract Promise evaluate(@NotNull String expression, @Nullable Map additionalContext, boolean enableBreak); @NotNull public final VALUE_MANAGER getValueManager() { diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/ScriptManagerBase.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/ScriptManagerBase.java index 5b1de9c9ea2f..9b3a225e4272 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/ScriptManagerBase.java +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/ScriptManagerBase.java @@ -13,7 +13,7 @@ public abstract class ScriptManagerBase