From 33a8c563ea985de89998fdf049bd39a4674fa67e Mon Sep 17 00:00:00 2001 From: mariano Date: Thu, 30 Jul 2026 18:39:02 -0500 Subject: [PATCH] chore(internal): IntelliJ-guided cleanups + two arity repairs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Style cleanups from IDE inspections: eachIterable.modify rewritten as a null-tolerant pattern switch, MhIso.Leaf converted from a hand-rolled class to a record (accessors and ctor generated), and ContainerView tidied. Two of the inspections removed code that looked dead but was load-bearing; repaired without undoing the cleanups: - eachOptional's getter lost its null guard (a null Optional FIELD must focus nothing — the documented container contract, pinned by FoldLaws). Restored as Objects.requireNonNullElse, which the inspection accepts. - throwConversion's "unused" Object parameter existed to align catch-handler arity for MethodHandles.catchException. The slimmer 3-arg handler is kept: labelFailures now binds from/to at positions 1,2, leaving a legal (Throwable) -> Object handler with an empty target-param prefix; the handler javadoc describes the new shape. Full :core and :internal suites green. --- .../eschizoid/telescope/internal/MhIso.java | 56 ++++++------------- .../optics/collections/Traversals.java | 29 ++++++---- .../internal/pairing/ContainerView.java | 2 +- 3 files changed, 36 insertions(+), 51 deletions(-) diff --git a/internal/src/main/java/io/github/eschizoid/telescope/internal/MhIso.java b/internal/src/main/java/io/github/eschizoid/telescope/internal/MhIso.java index c8ca524a..5aa66cb5 100644 --- a/internal/src/main/java/io/github/eschizoid/telescope/internal/MhIso.java +++ b/internal/src/main/java/io/github/eschizoid/telescope/internal/MhIso.java @@ -161,7 +161,7 @@ private static boolean constructibleBy(final Class cls) { THROW_CONVERSION = lk.findStatic( MhIso.class, "throwConversion", - MethodType.methodType(Object.class, Throwable.class, Object.class, Class.class, Class.class) + MethodType.methodType(Object.class, Throwable.class, Class.class, Class.class) ); } catch (final ReflectiveOperationException e) { throw new ExceptionInInitializerError(e); @@ -235,31 +235,14 @@ public static Iso pair( * per element, and label a per-element failure with {@link #sourceClass()} / {@link * #targetClass()}. */ - private static final class Leaf implements Iso { - - private final Class sourceClass; - private final Class targetClass; - private final Function forward; - private final Function backward; - private final MethodHandle rawFwd; - private final MethodHandle rawBwd; - - Leaf( - final Class sourceClass, - final Class targetClass, - final Function forward, - final Function backward, - final MethodHandle rawFwd, - final MethodHandle rawBwd - ) { - this.sourceClass = sourceClass; - this.targetClass = targetClass; - this.forward = forward; - this.backward = backward; - this.rawFwd = rawFwd; - this.rawBwd = rawBwd; - } - + private record Leaf( + Class sourceClass, + Class targetClass, + Function forward, + Function backward, + MethodHandle rawFwd, + MethodHandle rawBwd + ) implements Iso { @Override public T to(final S source) { return forward.apply(source); @@ -277,14 +260,6 @@ MethodHandle rawForward() { MethodHandle rawBackward() { return rawBwd; } - - Class sourceClass() { - return sourceClass; - } - - Class targetClass() { - return targetClass; - } } /** @@ -620,7 +595,10 @@ private static MethodHandle guardElement(final MethodHandle rawElem) { * so the fused handle stays one composed tree with no SAM boundary; the happy path pays nothing. */ private static MethodHandle labelFailures(final MethodHandle raw, final Class from, final Class to) { - final MethodHandle handler = MethodHandles.insertArguments(THROW_CONVERSION, 2, from, to); + // THROW_CONVERSION is (Throwable, Class, Class) -> Object; binding from/to at positions 1,2 + // leaves (Throwable) -> Object — a legal catchException handler (the handler may accept just + // the exception and an empty prefix of the target's parameters). + final MethodHandle handler = MethodHandles.insertArguments(THROW_CONVERSION, 1, from, to); return MethodHandles.catchException( raw.asType(MethodType.methodType(Object.class, Object.class)), Throwable.class, @@ -629,11 +607,11 @@ private static MethodHandle labelFailures(final MethodHandle raw, final Class } /** - * {@code (Throwable, Object) -> Object} catch handler (bound to {@code from}/{@code to}): always - * throws, relabelling the failure via {@link #rethrow}. The {@code Object} argument is the leaf's - * input, ignored — it only aligns the handler arity with the guarded handle. + * {@code (Throwable, Class, Class) -> Object} catch handler; {@code from}/{@code to} are bound as + * constants at combinator-build time, leaving a {@code (Throwable) -> Object} handler that always + * throws, relabelling the failure via {@link #rethrow}. */ - private static Object throwConversion(final Throwable t, final Object input, final Class from, final Class to) { + private static Object throwConversion(final Throwable t, final Class from, final Class to) { throw rethrow(from, to, t); } diff --git a/internal/src/main/java/io/github/eschizoid/telescope/internal/optics/collections/Traversals.java b/internal/src/main/java/io/github/eschizoid/telescope/internal/optics/collections/Traversals.java index 883e4185..00bed47c 100644 --- a/internal/src/main/java/io/github/eschizoid/telescope/internal/optics/collections/Traversals.java +++ b/internal/src/main/java/io/github/eschizoid/telescope/internal/optics/collections/Traversals.java @@ -8,6 +8,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Function; @@ -127,7 +128,7 @@ public static Affine, A> eachOptional() { // A null Optional FIELD (not an empty Optional) focuses nothing, matching every other // container traversal's null-source contract; the write side likewise leaves null alone. return Affine.of( - source -> source == null ? Optional.empty() : source, + source -> Objects.requireNonNullElse(source, Optional.empty()), (source, a) -> source != null && source.isPresent() ? Optional.of(a) : source ); } @@ -168,16 +169,22 @@ public boolean visitWhile(final C source, final Predicate visitor) { @Override public C modify(final C source, final Function f) { - if (source == null) return null; - if (source instanceof final List list) { - final var out = new ArrayList(list.size()); - for (final var e : source) out.add(f.apply(e)); - return (C) Collections.unmodifiableList(out); - } - if (source instanceof final Set set) { - final var out = new LinkedHashSet(set.size()); - for (final var e : source) out.add(f.apply(e)); - return (C) Collections.unmodifiableSet(out); + switch (source) { + case null -> { + return null; + } + case final List list -> { + final var out = new ArrayList(list.size()); + for (final var e : source) out.add(f.apply(e)); + return (C) Collections.unmodifiableList(out); + } + case final Set set -> { + final var out = new LinkedHashSet(set.size()); + for (final var e : source) out.add(f.apply(e)); + return (C) Collections.unmodifiableSet(out); + } + default -> { + } } // No safe rebuild for other Iterable shapes — the (C) cast would succeed on a List but // throw ClassCastException downstream when callers store it into a field typed as e.g. diff --git a/internal/src/main/java/io/github/eschizoid/telescope/internal/pairing/ContainerView.java b/internal/src/main/java/io/github/eschizoid/telescope/internal/pairing/ContainerView.java index 8b50610e..dc49c639 100644 --- a/internal/src/main/java/io/github/eschizoid/telescope/internal/pairing/ContainerView.java +++ b/internal/src/main/java/io/github/eschizoid/telescope/internal/pairing/ContainerView.java @@ -19,7 +19,7 @@ public enum Kind { } public ContainerView { - if ((keyType != null) != (kind == Kind.MAP_VALUES)) { + if ((keyType == null) == (kind == Kind.MAP_VALUES)) { throw new IllegalArgumentException( "keyType is required for MAP_VALUES and forbidden otherwise (kind=" + kind + ")" );