You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Rust runtime: java.nio.file, File and zip in crate::jrt, so fernflower's translated tests can run #203
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.
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.
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.
Activity
bnaudts commentedon Nov 12, 2026
Progress on the branch
ws/maddi-bug, not yet ondevel.Runtime (
crate::jrt)File,PathandFilesonstd::fs/std::path(eab4a52).FileandPathare cloned values.PrintStreamwithSystem.out/System.err(e097db2), andSystem.getProperty(cd32255).ZipFileis still opaque, so the 4 jar tests stay blocked.Printer
Derefs to its base (cd3026a). An enum gets itsvalueOf(5922ed5).Default::default()(8998f04). On fernflower that halved the E0277Defaulterrors, from 42 to 21.this.Fernflowergives itself toStructContext, andConsoleDecompilergives itself toFernflower, 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 withShared::new_cyclic(93e3fe9, b067af0, ab14775, cd3dd0c).provideris independent, yetLazyLoaderkeeps it.PrintStreamLogger extends IFernflowerLoggerand the tests'TestConsoleDecompiler extends ConsoleDecompilerwere composed because their packages differ. That lost Java's dispatch:IFernflowerLogger.writeMessagewasunimplemented!(). It also lost the upcast, since aShared<Sub>is noShared<Base>. Members are now printed with the root, in the root's module.doTest("pkg/X")failed to compile in 165 tests.Map.ofEntries, and the values of aMap<K, Object>boxed asBox<dyn Any>(d43b57f).Where fernflower stands
172 of the 174 fixture tests now get through
DecompilerTestFixtureandConsoleDecompiler. They stop inFernflower's constructor, which still has 7 errors:ClassesProcessoris built from theStructContextfield before the struct exists.StructContexthas two holders, so it probably wants to beShared.IFernflowerPreferences.DEFAULTSis typedHashMap<String, String>where it is aMap<String, Object>(2 errors).Box<dyn IMemberIdentifierRenamer>is passed where the trait is expected. The trait needs an impl for itsBox.Class.forName(...).newInstance()for the renamer factory: reflection, which needs a decision.Rcwhere the field is aBox(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
Rust: java.io.File, java.nio.file.Path and Files on std::fs (#203)
Rust: System.out as a held PrintStream, Object values copied, self-ca…
Rust: System.getProperty and String.stripTrailing (#203)
Rust: a composed subclass Derefs to its base; File and Path are clone…
Rust: an enum's valueOf (#203)
Rust: a constructor's field without an empty value takes its assignme…
Rust: a constructor handing out 'this' builds its object with Shared:…
Rust: a subclass of a class handing out 'this' passes its own handle …
Rust: only a cyclic superclass is composed without its Shared handle (#…
Rust: a closed hierarchy may span packages (#203)
Rust: a back-link is any 'this' the callee stores, whatever its indep…
Rust: a source method's varargs are packed into its slice (#203)
Rust: Map.ofEntries, and a Map<K, Object>'s values boxed (#203)