gleam-lang/gleam · error
InMemoryFileSystem::into_files called on a clone
Error message
InMemoryFileSystem::into_files called on a clone
What it means
InMemoryFileSystem keeps its files in Rc<RefCell<HashMap<...>>>; into_contents consumes self and calls Rc::try_unwrap(...).expect("InMemoryFileSystem::into_files called on a clone") to take sole ownership (memory.rs:63). Because cloning the filesystem is a cheap Rc clone, any clone still alive anywhere (a test variable, a struct field, a dropped-later scope) makes try_unwrap fail and this panic fire. The # Panics doc on the function states exactly this contract.
Source
Thrown at compiler-core/src/io/memory.rs:63
impl InMemoryFileSystem {
pub fn new() -> Self {
Self::default()
}
pub fn reset(&self) {
self.files.deref().borrow_mut().clear();
}
/// Returns the contents of each file, excluding directories.
///
/// # Panics
///
/// Panics if this is not the only reference to the underlying files.
///
pub fn into_contents(self) -> HashMap<Utf8PathBuf, Content> {
Rc::try_unwrap(self.files)
.expect("InMemoryFileSystem::into_files called on a clone")
.into_inner()
.into_iter()
.filter_map(|(path, file)| file.into_content().map(|content| (path, content)))
.collect()
}
/// All files currently in the filesystem (directories are not included).
pub fn files(&self) -> Vec<Utf8PathBuf> {
self.files
.borrow()
.iter()
.filter(|(_, f)| !f.is_directory())
.map(|(path, _)| path)
.cloned()
.collect()
}
#[cfg(test)]View on GitHub (pinned to 7e623aa83d)
Solutions
- Drop every clone before converting: `drop(fs_clone);` or structure the test so clones go out of scope before `fs.into_contents()`.
- Don't clone at all — use the non-consuming `fs.files()` / `fs.read_bytes()` for inspection and save into_contents for the final ownership handoff.
- If a wrapper type holds a clone, redesign it to borrow (&InMemoryFileSystem) instead of owning a clone.
- For maintainers: consider returning Result or exposing a strong_count check instead of panicking.
Example fix
// before: clone alive during conversion let fs = InMemoryFileSystem::new(); let snapshot = fs.clone(); // ...compile with fs... let files = fs.into_contents(); // panics: Rc::try_unwrap fails // after: drop the clone first, or don't clone let fs = InMemoryFileSystem::new(); // ...compile with fs... let names = fs.files(); // inspect without consuming drop(snapshot); // if you must clone, drop it first let files = fs.into_contents();
Defensive patterns
Strategy: validation
Validate before calling
// Enforce the single-owner contract before converting (library authors with
// access to the internals):
fn into_contents_if_sole(fs: InMemoryFileSystem) -> Result<HashMap<Utf8PathBuf, Content>, InMemoryFileSystem> {
// cheap structural check: clone discipline is on you; track clones manually
// e.g. wrap InMemoryFileSystem and count clones handed out, require count == 0 here
}
// Practical caller-side validation: audit that no clone exists
drop(snapshot_writer); // every variable/field holding fs.clone()
let files = fs.into_contents(); Prevention
- Never keep an InMemoryFileSystem clone alive across into_contents(); scope clones so they drop first.
- Prefer the non-consuming API (files(), read_bytes()) for assertions; reserve into_contents for the final handoff.
- In tests, hand ownership of the fs to the compiler and inspect results via the returned files map instead of cloning for peeking.
When it happens
Trigger: Any code that does `let fs2 = fs.clone()` (tests, wrappers, the test-package-compiler/test-project-compiler harnesses) and then calls fs.into_contents() while fs2 is still in scope or moved into another object. Also a clone captured by a closure or held in a Reader/Writer wrapper.
Common situations: Writing unit tests against gleam_core with the in-memory IO: you clone the filesystem to hand to the compiler and keep another copy for assertions, then call into_contents for golden-file comparison (as native_file_copier/tests.rs does dozens of times).
Related errors
- InMemoryFile::into_content called with multiple references
- channel buffer write
- JavaScript generator could not identify imported module name
- Custom type must have at least one definition here
- `panic` expression evaluated.
AI-assisted analysis of gleam-lang/gleam@7e623aa83d (2026-08-17).
Data as JSON: /api/errors/c7f8ae2ab2318068.
Report an issue: GitHub.