about summary refs log tree commit diff
diff options
context:
space:
mode:
authorZachary S <zasample18+github@gmail.com>2024-08-09 23:28:40 -0500
committerZachary S <zasample18+github@gmail.com>2024-08-12 12:54:18 -0500
commit1b6df71192db3e0d635754e3810def977e28092f (patch)
tree8cabbfff4db2473b0d00c6ac4f270c2b08dea60f
parent730d5d4095a264ef5f7c0a0781eea68c15431d45 (diff)
downloadrust-1b6df71192db3e0d635754e3810def977e28092f.tar.gz
rust-1b6df71192db3e0d635754e3810def977e28092f.zip
Explicitly specify type parameter on FromResidual impls in stdlib.
To work around coherence issue. Also adds regression test.
-rw-r--r--library/core/src/ops/control_flow.rs4
-rw-r--r--library/core/src/option.rs4
-rw-r--r--library/core/tests/ops.rs1
-rw-r--r--library/core/tests/ops/from_residual.rs26
-rw-r--r--tests/ui/try-trait/bad-interconversion.stderr4
-rw-r--r--tests/ui/try-trait/option-to-result.stderr2
6 files changed, 36 insertions, 5 deletions
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index a2709c66b06..ab73dc19fcc 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -116,7 +116,9 @@ impl<B, C> ops::Try for ControlFlow<B, C> {
 }
 
 #[unstable(feature = "try_trait_v2", issue = "84277")]
-impl<B, C> ops::FromResidual for ControlFlow<B, C> {
+// Note: manually specifying the residual type instead of using the default to work around
+// https://github.com/rust-lang/rust/issues/99940
+impl<B, C> ops::FromResidual<ControlFlow<B, convert::Infallible>> for ControlFlow<B, C> {
     #[inline]
     fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {
         match residual {
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 6c89c810180..9cec79c17ca 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -2495,7 +2495,9 @@ impl<T> ops::Try for Option<T> {
 }
 
 #[unstable(feature = "try_trait_v2", issue = "84277")]
-impl<T> ops::FromResidual for Option<T> {
+// Note: manually specifying the residual type instead of using the default to work around
+// https://github.com/rust-lang/rust/issues/99940
+impl<T> ops::FromResidual<Option<convert::Infallible>> for Option<T> {
     #[inline]
     fn from_residual(residual: Option<convert::Infallible>) -> Self {
         match residual {
diff --git a/library/core/tests/ops.rs b/library/core/tests/ops.rs
index 2ee0abd399b..501e0f33fe4 100644
--- a/library/core/tests/ops.rs
+++ b/library/core/tests/ops.rs
@@ -1,4 +1,5 @@
 mod control_flow;
+mod from_residual;
 
 use core::ops::{
     Bound, Deref, DerefMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
diff --git a/library/core/tests/ops/from_residual.rs b/library/core/tests/ops/from_residual.rs
new file mode 100644
index 00000000000..d5c86ccbcd3
--- /dev/null
+++ b/library/core/tests/ops/from_residual.rs
@@ -0,0 +1,26 @@
+//! Regression test that Option and ControlFlow can have downstream FromResidual impls.
+//! cc https://github.com/rust-lang/rust/issues/99940,
+//! This does NOT test that issue in general; Option and ControlFlow's FromResidual
+//! impls in core were changed to not be affected by that issue.
+
+use core::ops::{ControlFlow, FromResidual};
+
+struct Local;
+
+impl<T> FromResidual<Local> for Option<T> {
+    fn from_residual(_: Local) -> Option<T> {
+        unimplemented!()
+    }
+}
+
+impl<B, C> FromResidual<Local> for ControlFlow<B, C> {
+    fn from_residual(_: Local) -> ControlFlow<B, C> {
+        unimplemented!()
+    }
+}
+
+impl<T, E> FromResidual<Local> for Result<T, E> {
+    fn from_residual(_: Local) -> Result<T, E> {
+        unimplemented!()
+    }
+}
diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr
index 642a93d64e2..9aab2cf6ab8 100644
--- a/tests/ui/try-trait/bad-interconversion.stderr
+++ b/tests/ui/try-trait/bad-interconversion.stderr
@@ -45,7 +45,7 @@ LL |     Some(Err("hello")?)
    |                      ^ use `.ok()?` if you want to discard the `Result<Infallible, &str>` error information
    |
    = help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `Option<u16>`
-   = help: the trait `FromResidual` is implemented for `Option<T>`
+   = help: the trait `FromResidual<Option<Infallible>>` is implemented for `Option<T>`
 
 error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
   --> $DIR/bad-interconversion.rs:27:33
@@ -56,7 +56,7 @@ LL |     Some(ControlFlow::Break(123)?)
    |                                 ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Option<u64>`
    |
    = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Option<u64>`
-   = help: the trait `FromResidual` is implemented for `Option<T>`
+   = help: the trait `FromResidual<Option<Infallible>>` is implemented for `Option<T>`
 
 error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
   --> $DIR/bad-interconversion.rs:32:39
diff --git a/tests/ui/try-trait/option-to-result.stderr b/tests/ui/try-trait/option-to-result.stderr
index 8055b2a0b04..1a5a925f92f 100644
--- a/tests/ui/try-trait/option-to-result.stderr
+++ b/tests/ui/try-trait/option-to-result.stderr
@@ -20,7 +20,7 @@ LL |     a?;
    |      ^ use `.ok()?` if you want to discard the `Result<Infallible, i32>` error information
    |
    = help: the trait `FromResidual<Result<Infallible, i32>>` is not implemented for `Option<i32>`
-   = help: the trait `FromResidual` is implemented for `Option<T>`
+   = help: the trait `FromResidual<Option<Infallible>>` is implemented for `Option<T>`
 
 error: aborting due to 2 previous errors