Skip to content

Rust runtime: java.nio.file, File and zip in crate::jrt, so fernflower's translated tests can run #203

Open

Description

@bnaudts

fernflower's tests now translate to Rust (#[test] runners; 217 tests from helper and manual), and the helper tests compile and run.

170 of the other tests stop in DecompilerTestFixture.setUp on the first file-system call. In crate::jrt, Files, Path, File, ZipFile, ZipEntry, ZipOutputStream, FileOutputStream, PrintStream and Manifest are opaque stand-ins without methods. The decompiler's own I/O, in ConsoleDecompiler and InterpreterUtil.copyFile/getBytes, is blocked by the same gap.

What the tests need first, roughly:

  • Files.createTempDirectory, createDirectories, isRegularFile, readString, walk/list, delete;
  • Path.resolve/toFile/getFileName, and File exists/isDirectory/listFiles/getName/getAbsolutePath;
  • reading a class file's bytes;
  • ZipFile/JarFile for the jar tests.

Most of this maps directly onto std::fs and std::path; zip needs a crate or a small reader.

This is necessary but not enough. Behind the fixture, the decompiler's core (ClassWriter.classToJava, ClassesProcessor.loadClasses) is still stubbed for struct-level reasons; those are listed in #202.

🤖 Generated with Claude Code

Activity

  1. bnaudts commented on Nov 12, 2026

    @bnaudts
    ContributorAuthor

    Progress on the branch ws/maddi-bug, not yet on devel.

    Runtime (crate::jrt)

    • File, Path and Files on std::fs/std::path (eab4a52). File and Path are cloned values.
    • PrintStream with System.out/System.err (e097db2), and System.getProperty (cd32255).
    • ZipFile is still opaque, so the 4 jar tests stay blocked.

    Printer

    • A composed subclass Derefs to its base (cd3026a). An enum gets its valueOf (5922ed5).
    • A constructor field without an empty value takes its assignment's value more often, instead of Default::default() (8998f04). On fernflower that halved the E0277 Default errors, from 42 to 21.
    • A constructor that hands out this. Fernflower gives itself to StructContext, and ConsoleDecompiler gives itself to Fernflower, in their constructors. The receiving interface becomes a back-link, crate::jrt::WeakShared<dyn I>: a weak handle that reaches the object without keeping it alive. The class is built with Shared::new_cyclic (93e3fe9, b067af0, ab14775, cd3dd0c).
      • What counts is whether the callee stores the parameter, not its independence verdict. Fernflower's provider is independent, yet LazyLoader keeps it.
    • A closed hierarchy may span packages (7bb4092). PrintStreamLogger extends IFernflowerLogger and the tests' TestConsoleDecompiler extends ConsoleDecompiler were composed because their packages differ. That lost Java's dispatch: IFernflowerLogger.writeMessage was unimplemented!(). It also lost the upcast, since a Shared<Sub> is no Shared<Base>. Members are now printed with the root, in the root's module.
    • Varargs of a source method are packed into its slice (84abe9c). doTest("pkg/X") failed to compile in 165 tests.
    • Map.ofEntries, and the values of a Map<K, Object> boxed as Box<dyn Any> (d43b57f).

    Where fernflower stands

    before now
    rustc errors in the translated crate 1990 1935
    functions rustc rejects (stubbed one by one) 949 930

    172 of the 174 fixture tests now get through DecompilerTestFixture and ConsoleDecompiler. They stop in Fernflower's constructor, which still has 7 errors:

    • ClassesProcessor is built from the StructContext field before the struct exists. StructContext has two holders, so it probably wants to be Shared.
    • IFernflowerPreferences.DEFAULTS is typed HashMap<String, String> where it is a Map<String, Object> (2 errors).
    • A Box<dyn IMemberIdentifierRenamer> is passed where the trait is expected. The trait needs an impl for its Box.
    • Class.forName(...).newInstance() for the renamer factory: reflection, which needs a decision.
    • The variable-naming factory is created as an Rc where the field is a Box (2 errors).

    Behind the constructor, the decompiler's core (loadClasses, classToJava, codeToJava) is still stubbed for the struct-level reasons in #202. So passing tests need more than these 7.

    🤖 Generated with Claude Code

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

    enhancementNew feature or requestfront-end:rustrelated to the translation of Java into Rust

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions