Skip to content

A lambda given to stream().filter() that modifies the elements leaves the source list @NotModified #115

Closed

Description

@bnaudts

fernflower (test-oss/fernflower, main sources; maddi 8a38863c8, maddi-mod 6ed8f49f), GenericMain:

public static List<TypeAnnotationWriteHelper> getGenericTypeAnnotations(
    int argIndex, List<TypeAnnotationWriteHelper> typeAnnWriteHelpers) {
  return typeAnnWriteHelpers.stream().filter(typeAnnWriteHelper -> {
    StructTypePathEntry entry = typeAnnWriteHelper.getPaths().peek();
    boolean inGeneric = entry != null && entry.getTypeArgumentIndex() == argIndex
                        && entry.getTypePathEntryKind() == StructTypePathEntry.Kind.TYPE.getId();
    if (inGeneric) typeAnnWriteHelper.getPaths().pop();   // modifies the element's own Deque
    return inGeneric;
  }).collect(Collectors.toList());
}

with TypeAnnotationWriteHelper.getPaths() returning its private final Deque<StructTypePathEntry> paths field.

Results: typeAnnWriteHelpers has unmodifiedParameter: 1 and structurallyUnmodifiedParameter: 1. The structural
claim may stand (the helpers are the list's elements, hidden content), but the deep one does not: every element for
which inGeneric holds has its paths deque popped. The modification happens in a lambda that Stream.filter
applies to the stream's elements, which are the list's elements, and it does not reach the parameter.
ExprProcessor.writeTypeAnnotationBeforeType has the same shape and the same result for its list of helpers.

🤖 Generated with Claude Code

Activity

  1. added a commit that references this issue on Nov 13, 2026
  2. bnaudts commented on Nov 13, 2026

    @bnaudts
    Author

    Fixed on devel (merge 00b2a40): dba2405 (a lazy stream stage's lambda that modifies the element modifies the stream's source, gate NOLAZYSTAGEELEMENT). Its first gate exposed an uncontracted PathMatcher.matches (TestKotlinPredicatesVsJava), now contracted @notmodified in maddi 26c0b6d63. Gate green on devel after the merge (laser1, 2026-11-13).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions