From 61edcf8adb78c78f96dba34151f95664730089fb Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Mon, 9 Mar 2026 11:16:21 +0100 Subject: [PATCH 1/3] Fix signatures and help CF type inference. --- rascal-lsp/src/main/checkerframework/rascal.astub | 11 +++++++++++ .../InterpretedLanguageContributions.java | 2 +- .../LanguageContributionsMultiplexer.java | 9 +-------- .../parametric/ParametricTextDocumentService.java | 3 ++- .../lsp/rascal/RascalTextDocumentService.java | 13 ++++++------- .../vscode/lsp/rascal/conversion/Diagnostics.java | 2 +- .../lsp/util/concurrent/CompletableFutureUtils.java | 8 ++++---- .../lsp/util/concurrent/InterruptibleFuture.java | 5 ++--- 8 files changed, 28 insertions(+), 25 deletions(-) diff --git a/rascal-lsp/src/main/checkerframework/rascal.astub b/rascal-lsp/src/main/checkerframework/rascal.astub index ec523a30c..c11166d44 100644 --- a/rascal-lsp/src/main/checkerframework/rascal.astub +++ b/rascal-lsp/src/main/checkerframework/rascal.astub @@ -20,3 +20,14 @@ public abstract class TreeVisitor extends IdentityVisitor T call(IValue... parameters) { } +} diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/InterpretedLanguageContributions.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/InterpretedLanguageContributions.java index cccc33b44..bd6266655 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/InterpretedLanguageContributions.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/InterpretedLanguageContributions.java @@ -622,7 +622,7 @@ public InterruptibleFuture execution(String command) { ), exec); } - private InterruptibleFuture execFunction(String name, CompletableFuture<@Nullable IFunction> target, T defaultResult, IValue... args) { + private InterruptibleFuture execFunction(String name, CompletableFuture<@Nullable IFunction> target, T defaultResult, IValue... args) { if (target == null) { return InterruptibleFuture.completedFuture(defaultResult, exec); } diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/LanguageContributionsMultiplexer.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/LanguageContributionsMultiplexer.java index 329c51faf..644d85b3b 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/LanguageContributionsMultiplexer.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/LanguageContributionsMultiplexer.java @@ -230,16 +230,9 @@ private CompletableFuture anyTrue(Function CompletableFuture anyTrue( Function> predicate, T falsy, BinaryOperator or) { - - var result = CompletableFutureUtils.completedFuture(falsy, exec); // no short-circuiting, but it's not problem, it's only triggered at the beginning of a registry // pretty soon the future will be completed. - for (var c: contributions) { - var checkCurrent = predicate.apply(c.contrib) - .exceptionally(e -> falsy); - result = result.thenCombine(checkCurrent, or); - } - return result; + return CompletableFutureUtils.reduce(contributions.stream().map(c -> predicate.apply(c.contrib).exceptionally(_e -> falsy)), CompletableFutureUtils.completedFuture(falsy, exec), Function.identity(), or); } @Override diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ParametricTextDocumentService.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ParametricTextDocumentService.java index c5115f234..bcf144c42 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ParametricTextDocumentService.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ParametricTextDocumentService.java @@ -53,6 +53,7 @@ import org.apache.logging.log4j.core.util.IOUtils; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.PolyNull; import org.eclipse.lsp4j.ApplyWorkspaceEditParams; import org.eclipse.lsp4j.CallHierarchyIncomingCall; import org.eclipse.lsp4j.CallHierarchyIncomingCallsParams; @@ -629,7 +630,7 @@ public CompletableFuture> inlayHint(InlayHintParams params) { } - private static CompletableFuture recoverExceptions(CompletableFuture future, Supplier defaultValue) { + private static CompletableFuture<@PolyNull T> recoverExceptions(CompletableFuture<@PolyNull T> future, Supplier<@PolyNull T> defaultValue) { return future .exceptionally(e -> { logger.error("Operation failed with", e); diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java index e581a3273..6aa298187 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java @@ -45,6 +45,7 @@ import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.PolyNull; import org.eclipse.lsp4j.ApplyWorkspaceEditParams; import org.eclipse.lsp4j.ApplyWorkspaceEditResponse; import org.eclipse.lsp4j.ClientCapabilities; @@ -346,10 +347,10 @@ public CompletableFuture, List s == null ? Collections.emptyList() : s.getDefinition(params.getPosition())) .thenApply(Either::forLeft) - , () -> Either.forLeft(Collections.emptyList())); + , () -> Either.forLeft(Collections.emptyList())); } else { - return CompletableFutureUtils.completedFuture(Either.forLeft(Collections.emptyList()), exec); + return CompletableFutureUtils.completedFuture(Either.forLeft(Collections.emptyList()), exec); } } @@ -670,9 +671,7 @@ public CompletableFuture> codeLens(CodeLensParams param return recoverExceptions(f.getLastTreeAsync(false) .thenApply(Versioned::get) .thenApplyAsync(availableRascalServices()::locateCodeLenses, exec) - .thenApply(List::stream) - .thenApply(res -> res.map(this::makeRunCodeLens)) - .thenApply(s -> s.collect(Collectors.toList())), () -> null) + .thenApply(lenses -> lenses.stream().map(this::makeRunCodeLens).collect(Collectors.toList())), () -> null) ; } @@ -724,7 +723,7 @@ public CompletableFuture executeCommand(String extension, String command return availableRascalServices().executeCommand(command).get(); } - private static CompletableFuture recoverExceptions(CompletableFuture future, Supplier defaultValue) { + private static CompletableFuture<@PolyNull T> recoverExceptions(CompletableFuture<@PolyNull T> future, Supplier<@PolyNull S> defaultValue) { return future .exceptionally(e -> { if (e instanceof ResponseErrorException) { @@ -735,7 +734,7 @@ private static CompletableFuture recoverExceptions(Completab }); } - private static CompletableFuture> recoverExceptions(CompletableFuture> future) { + private static CompletableFuture> recoverExceptions(CompletableFuture> future) { return recoverExceptions(future, Collections::emptyList); } diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/conversion/Diagnostics.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/conversion/Diagnostics.java index c5ba8b86f..807de94e6 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/conversion/Diagnostics.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/conversion/Diagnostics.java @@ -256,7 +256,7 @@ private static List translateDiagnostics(ICollection messages, Co .collect(Collectors.toList()); } - public static Map> translateMessages(ICollection messages, ColumnMaps cm) { + public static Map> translateMessages(IList messages, ColumnMaps cm) { return messages.stream() .filter(IConstructor.class::isInstance) .map(IConstructor.class::cast) diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/CompletableFutureUtils.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/CompletableFutureUtils.java index 3a412336d..91274236d 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/CompletableFutureUtils.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/CompletableFutureUtils.java @@ -41,7 +41,7 @@ public class CompletableFutureUtils { private CompletableFutureUtils() {/* hidden */ } - public static CompletableFuture completedFuture(T value, Executor exec) { + public static CompletableFuture<@PolyNull T> completedFuture(@PolyNull T value, Executor exec) { return CompletableFuture.supplyAsync(() -> value, exec); } @@ -133,7 +133,7 @@ public static CompletableFuture reduce(Stream> fu */ public static CompletableFuture reduce(Iterable> futures, CompletableFuture identity, Function map, BinaryOperator concat) { - CompletableFuture result = identity; + var result = identity; for (var fut : futures) { result = result.thenCombine(fut, (acc, t) -> concat.apply(acc, map.apply(t))); } @@ -141,7 +141,7 @@ public static CompletableFuture reduce(Iterable> return result; } - private static List<@PolyNull T> concat(List<@PolyNull T> l, List<@PolyNull T> r) { + private static List concat(List l, List r) { if (r.isEmpty()) { return l; } @@ -149,7 +149,7 @@ public static CompletableFuture reduce(Iterable> return r; } - var ls = new LinkedList<@PolyNull T>(l); + var ls = new LinkedList(l); ls.addAll(r); return ls; } diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/InterruptibleFuture.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/InterruptibleFuture.java index 7fa8e25f2..0f5373b58 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/InterruptibleFuture.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/InterruptibleFuture.java @@ -32,7 +32,6 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; -import org.checkerframework.checker.nullness.qual.PolyNull; public class InterruptibleFuture { @@ -102,9 +101,9 @@ public static InterruptibleFuture completedFuture(T result, Executor exec * Turn an completable future with a interruptible future inside into a * normal interruptible future by inlining them */ - public static InterruptibleFuture<@PolyNull T> flatten(CompletableFuture> f, Executor exec) { + public static InterruptibleFuture flatten(CompletableFuture> f, Executor exec) { return new InterruptibleFuture<>( - f.<@PolyNull T>thenCompose(InterruptibleFuture::get), + f.thenCompose(InterruptibleFuture::get), () -> f.thenAcceptAsync(InterruptibleFuture::interrupt, exec) // schedule interrupt async so that we don't deadlock during interrupt ); } From a60cb100d8ac7d242cf4be58dcaf909bcd40e7b8 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Mon, 9 Mar 2026 14:39:56 +0100 Subject: [PATCH 2/3] More nullability fixes. --- .../lsp/parametric/ParametricTextDocumentService.java | 6 +++--- .../lsp/parametric/capabilities/CapabilityRegistration.java | 2 +- .../vscode/lsp/rascal/RascalTextDocumentService.java | 4 ++-- .../rascalmpl/vscode/lsp/rascal/conversion/CodeActions.java | 2 +- .../vscode/lsp/util/concurrent/CompletableFutureUtils.java | 2 +- .../vscode/lsp/util/concurrent/InterruptibleFuture.java | 2 +- .../vscode/lsp/util/concurrent/ReplaceableFuture.java | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ParametricTextDocumentService.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ParametricTextDocumentService.java index bcf144c42..52afa7371 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ParametricTextDocumentService.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ParametricTextDocumentService.java @@ -442,7 +442,7 @@ public CompletableFuture> codeLens(CodeLensParams param .thenApply(s -> s.stream() .map(e -> locCommandTupleToCodeLense(contrib.getName(), e)) .collect(Collectors.toList()) - ), () -> null); + ), Collections::emptyList); } @@ -626,7 +626,7 @@ public CompletableFuture> inlayHint(InlayHintParams params) { .thenApply(s -> s.stream() .map(this::rowToInlayHint) .collect(Collectors.toList()) - ), () -> null); + ), Collections::emptyList); } @@ -871,7 +871,7 @@ public CompletableFuture> foldingRange(FoldingRangeRequestPar return recoverExceptions(file.getCurrentTreeAsync(true).thenApply(Versioned::get).thenApply(FoldingRanges::getFoldingRanges) .whenComplete((r, e) -> logger.trace("Folding regions success, reporting {} regions back", r == null ? 0 : r.size()) - ), Collections::emptyList); + ), Collections::emptyList); } @Override diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/capabilities/CapabilityRegistration.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/capabilities/CapabilityRegistration.java index cb5c6fb72..b2df79872 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/capabilities/CapabilityRegistration.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/capabilities/CapabilityRegistration.java @@ -65,7 +65,7 @@ public class CapabilityRegistration { private final LanguageClient client; private final Executor exec; - private final CompletableFuture noop; + private final CompletableFuture<@Nullable Void> noop; private final Set> dynamicCapabilities; private final Set> staticCapabilities; diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java index 6aa298187..f957e9163 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java @@ -414,7 +414,7 @@ public CompletableFuture Locations.toRange(TreeAdapter.getLocation(cur), columns)) - .thenApply(Either3::forFirst), () -> null); + .thenApply(Either3::forFirst), () -> Either3.forSecond(new PrepareRenameResult())); } @Override @@ -723,7 +723,7 @@ public CompletableFuture executeCommand(String extension, String command return availableRascalServices().executeCommand(command).get(); } - private static CompletableFuture<@PolyNull T> recoverExceptions(CompletableFuture<@PolyNull T> future, Supplier<@PolyNull S> defaultValue) { + private static CompletableFuture<@PolyNull T> recoverExceptions(CompletableFuture<@PolyNull T> future, Supplier<@PolyNull T> defaultValue) { return future .exceptionally(e -> { if (e instanceof ResponseErrorException) { diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/conversion/CodeActions.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/conversion/CodeActions.java index 9d80a818a..684c67a62 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/conversion/CodeActions.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/conversion/CodeActions.java @@ -88,7 +88,7 @@ public static CompletableFuture> extractActionsFromDiagnostics(Co /* merges two streams of CodeAction terms and then converts them to LSP objects */ public static CompletableFuture>> mergeAndConvertCodeActions(IBaseTextDocumentService doc, String dedicatedLanguageName, String languageName, CompletableFuture> quickfixes, CompletableFuture> codeActions) { return codeActions.thenCombine(quickfixes, (actions, quicks) -> - Stream.concat(quicks, actions) + Stream.concat(quicks, actions) .map(IConstructor.class::cast) .map(cons -> constructorToCodeAction(doc, dedicatedLanguageName, languageName, cons)) .map(Either::forRight) diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/CompletableFutureUtils.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/CompletableFutureUtils.java index 91274236d..6a154acdf 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/CompletableFutureUtils.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/CompletableFutureUtils.java @@ -42,7 +42,7 @@ public class CompletableFutureUtils { private CompletableFutureUtils() {/* hidden */ } public static CompletableFuture<@PolyNull T> completedFuture(@PolyNull T value, Executor exec) { - return CompletableFuture.supplyAsync(() -> value, exec); + return CompletableFuture.<@PolyNull T>supplyAsync(() -> value, exec); } /** diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/InterruptibleFuture.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/InterruptibleFuture.java index 0f5373b58..82e5793bb 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/InterruptibleFuture.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/InterruptibleFuture.java @@ -94,7 +94,7 @@ public InterruptibleFuture thenCombineAsync( } public static InterruptibleFuture completedFuture(T result, Executor exec) { - return new InterruptibleFuture<>(CompletableFutureUtils.completedFuture(result, exec), () -> {}); + return new InterruptibleFuture<>(CompletableFutureUtils.completedFuture(result, exec), () -> {}); } /** diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/ReplaceableFuture.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/ReplaceableFuture.java index 33ad5924d..aa828b472 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/ReplaceableFuture.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/ReplaceableFuture.java @@ -31,8 +31,8 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicReference; - import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.PolyNull; /** * A wrapper around CompletableFuture's that allow for us to replace the results of a still running future, and call an @@ -111,7 +111,7 @@ public InterruptibleFuture replace(InterruptibleFuture with) { return new InterruptibleFuture<>(result, with::interrupt); } - public static ReplaceableFuture completedFuture(T result, Executor exec) { + public static ReplaceableFuture<@PolyNull T> completedFuture(@PolyNull T result, Executor exec) { return new ReplaceableFuture<>(CompletableFutureUtils.completedFuture(result, exec)); } } From 1fd0c66c3f5f6d29b85a2d5b4fa477d10a4823f2 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Wed, 8 Apr 2026 14:16:23 +0200 Subject: [PATCH 3/3] Remove some annotations. --- .../vscode/lsp/util/concurrent/CompletableFutureUtils.java | 5 ++--- .../vscode/lsp/util/concurrent/InterruptibleFuture.java | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/CompletableFutureUtils.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/CompletableFutureUtils.java index 6a154acdf..368adf497 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/CompletableFutureUtils.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/CompletableFutureUtils.java @@ -36,13 +36,12 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.checkerframework.checker.nullness.qual.PolyNull; public class CompletableFutureUtils { private CompletableFutureUtils() {/* hidden */ } - public static CompletableFuture<@PolyNull T> completedFuture(@PolyNull T value, Executor exec) { - return CompletableFuture.<@PolyNull T>supplyAsync(() -> value, exec); + public static CompletableFuture completedFuture(T value, Executor exec) { + return CompletableFuture.supplyAsync(() -> value, exec); } /** diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/InterruptibleFuture.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/InterruptibleFuture.java index 82e5793bb..0f5373b58 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/InterruptibleFuture.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/concurrent/InterruptibleFuture.java @@ -94,7 +94,7 @@ public InterruptibleFuture thenCombineAsync( } public static InterruptibleFuture completedFuture(T result, Executor exec) { - return new InterruptibleFuture<>(CompletableFutureUtils.completedFuture(result, exec), () -> {}); + return new InterruptibleFuture<>(CompletableFutureUtils.completedFuture(result, exec), () -> {}); } /**