From ccb92bd07e4adf88dd49b60d3bd71688f37cca51 Mon Sep 17 00:00:00 2001 From: Fabian Meumertzheim Date: Wed, 15 Jan 2025 10:08:51 +0100 Subject: [PATCH] Show a conflict warning --- .../java/net/starlark/java/eval/Debug.java | 24 +++++++++++++++++++ .../starlark/java/eval/StarlarkThread.java | 21 +++++++++++++--- .../eval/StarlarkThreadDebuggingTest.java | 2 +- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/starlark/java/eval/Debug.java b/src/main/java/net/starlark/java/eval/Debug.java index e820b1469a6361..4b05a4349b04fb 100644 --- a/src/main/java/net/starlark/java/eval/Debug.java +++ b/src/main/java/net/starlark/java/eval/Debug.java @@ -19,6 +19,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; import javax.annotation.Nullable; +import net.starlark.java.annot.StarlarkBuiltin; import net.starlark.java.syntax.Location; /** Debugger API. */ @@ -37,6 +38,29 @@ public interface Debugger { void close(); } + /** A distinguished value that carries a message. */ + @StarlarkBuiltin( + name = "debugger_message", + doc = "A distinguished value that carries a message.", + documented = false) + public static final class DebuggerMessage implements StarlarkValue { + private final String message; + + public DebuggerMessage(String message) { + this.message = message; + } + + @Override + public String toString() { + return "<" + message + ">"; + } + + @Override + public void repr(Printer printer) { + printer.append("<").append(message).append(">"); + } + } + /** A Starlark value that can expose additional information to a debugger. */ public interface ValueWithDebugAttributes extends StarlarkValue { /** diff --git a/src/main/java/net/starlark/java/eval/StarlarkThread.java b/src/main/java/net/starlark/java/eval/StarlarkThread.java index 66bfe737b8d0f3..f2083bf56d596d 100644 --- a/src/main/java/net/starlark/java/eval/StarlarkThread.java +++ b/src/main/java/net/starlark/java/eval/StarlarkThread.java @@ -19,7 +19,9 @@ import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; @@ -182,8 +184,15 @@ public Location getLocation() { @Override public ImmutableMap getLocals() { + // TODO: List comprehensions introduce new locals that can shadow outer locals. Find a way to + // accurately represent them and their values in a situation such as: + // + // def foo(x): + // x += [[j(x) for x in i(x)] + h(x) for x in f(x) if g(x)] + // return k(x) + // // TODO(adonovan): provide a more efficient API. - ImmutableMap.Builder env = ImmutableMap.builder(); + LinkedHashMap env = new LinkedHashMap<>(); if (fn instanceof StarlarkFunction) { for (int i = 0; i < locals.length; i++) { Object local = locals[i]; @@ -191,11 +200,17 @@ public ImmutableMap getLocals() { local = ((StarlarkFunction.Cell) local).x; } if (local != null) { - env.put(((StarlarkFunction) fn).rfn.getLocals().get(i).getName(), local); + env.merge( + ((StarlarkFunction) fn).rfn.getLocals().get(i).getName(), + local, + (oldValue, newValue) -> + Objects.equals(oldValue, newValue) + ? oldValue + : new Debug.DebuggerMessage("different values in scope")); } } } - return env.buildKeepingLast(); + return ImmutableMap.copyOf(env); } @Override diff --git a/src/test/java/net/starlark/java/eval/StarlarkThreadDebuggingTest.java b/src/test/java/net/starlark/java/eval/StarlarkThreadDebuggingTest.java index a2cf9f0598cbdf..025ec044b130a3 100644 --- a/src/test/java/net/starlark/java/eval/StarlarkThreadDebuggingTest.java +++ b/src/test/java/net/starlark/java/eval/StarlarkThreadDebuggingTest.java @@ -315,7 +315,7 @@ def g(a, y, z): .isEqualTo( """ @ main.star:5:2 local={} - g @ main.star:4:4 local={a=[0, 1, 2, 3, 4, 5], y=5, z=6, x=5} + g @ main.star:4:4 local={a=[0, 1, 2, 3, 4, 5], y=5, z=6, x=} f @ builtin:12 local={} """); }