Repository: Stebalien/tempfile (rust)

Issue:
The generic version of NamedTempFile can break compilation 
The more generic version of `NamedTempFile` introduced in #177 by @jasonwhite can break compilation in some cases without even being involved itself. It seems to happen in some cases with generic where it will turn into a infinitely recursive type.

Example: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=671872049ef51f20f8bcc976177c6b62

if you comment the line `use tempfile;` the code will compile as expected.

edit: Made the MRE smaller.

Pull request description:
NamedTempFile: Fix infinite recursion in trait bounds
Due to bug rust-lang/rust#96634, these generic bounds may cause an infinite recursion in the compiler, even in unrelated code.

This specializes the `Write for &NamedTempFile<F>` impl on `File` instead. This keeps the API the same as before the generic parameter `F` was added in #177, so it shouldn't break any code. If/when the compiler bug is fixed, we can switch it back to the more generic version. Very few types implement `Write for &T`, however. The only other one I know of is `UnixStream`, which probably wouldn't be used with `NamedTempFile` anyway (it's counterpart `UnixListener` is used instead).

Fixes #224.

Patch:
diff --git a/src/file/mod.rs b/src/file/mod.rs
index 059ac40..023acd2 100644
--- a/src/file/mod.rs
+++ b/src/file/mod.rs
@@ -918,10 +918,7 @@ impl<F: Read> Read for NamedTempFile<F> {
     }
 }
 
-impl<'a, F> Read for &'a NamedTempFile<F>
-where
-    &'a F: Read,
-{
+impl Read for &NamedTempFile<File> {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.as_file().read(buf).with_err_path(|| self.path())
     }
@@ -937,10 +934,7 @@ impl<F: Write> Write for NamedTempFile<F> {
     }
 }
 
-impl<'a, F> Write for &'a NamedTempFile<F>
-where
-    &'a F: Write,
-{
+impl Write for &NamedTempFile<File> {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         self.as_file().write(buf).with_err_path(|| self.path())
     }
@@ -956,10 +950,7 @@ impl<F: Seek> Seek for NamedTempFile<F> {
     }
 }
 
-impl<'a, F> Seek for &'a NamedTempFile<F>
-where
-    &'a F: Seek,
-{
+impl Seek for &NamedTempFile<File> {
     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
         self.as_file().seek(pos).with_err_path(|| self.path())
     }


Test patch:
diff --git a/tests/namedtempfile.rs b/tests/namedtempfile.rs
index 22ec6a4..54396c3 100644
--- a/tests/namedtempfile.rs
+++ b/tests/namedtempfile.rs
@@ -439,3 +439,28 @@ fn test_make_uds_conflict() {
         assert!(socket.path().exists());
     }
 }
+
+// Issue #224.
+#[test]
+fn test_overly_generic_bounds() {
+    pub struct Foo<T>(T);
+
+    impl<T> Foo<T>
+    where
+        T: Sync + Send + 'static,
+        for<'a> &'a T: Write + Read,
+    {
+        pub fn new(foo: T) -> Self {
+            Self(foo)
+        }
+    }
+
+    // Don't really need to run this. Only care if it compiles.
+    if let Ok(file) = File::open("i_do_not_exist") {
+        let mut f;
+        let _x = {
+            f = Foo::new(file);
+            &mut f
+        };
+    }
+}