about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-02-27 06:11:51 +0100
committerGitHub <noreply@github.com>2023-02-27 06:11:51 +0100
commit3a6c5429c29074961080cd9f368a2e46fdb371ff (patch)
treedccec39a468457dc70bbb569645d54782fa1737c
parent58136ffa92c81ec9e6ac1f91773254914da2ca01 (diff)
parent9bf32c40b4c1b7558aee3421ed3e8e73ef518dd9 (diff)
downloadrust-3a6c5429c29074961080cd9f368a2e46fdb371ff.tar.gz
rust-3a6c5429c29074961080cd9f368a2e46fdb371ff.zip
Rollup merge of #108319 - compiler-errors:dont-project-to-specializable-rpitits, r=lcnr
Don't project specializable RPITIT projection

This effective rejects specialization + RPITIT/AFIT (usages of `impl Trait` in traits) because the implementation is significantly complicated over making regular "default" trait method bodies work.

I have another PR that experimentally fixes all this, but the code may not be worth investing in.
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs27
-rw-r--r--tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs71
-rw-r--r--tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr26
4 files changed, 126 insertions, 5 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 89b4e6227bd..b0dc6b1dcac 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -648,6 +648,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
             tcx.fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
         )
         .fold_with(&mut collector);
+
+    debug_assert_ne!(
+        collector.types.len(),
+        0,
+        "expect >1 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`"
+    );
+
     let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
     trait_sig.error_reported()?;
     let trait_return_ty = trait_sig.output();
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index e5b0f9d3300..d542240be9b 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1307,21 +1307,38 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
         let _ = selcx.infcx.commit_if_ok(|_| {
             match selcx.select(&obligation.with(tcx, trait_predicate)) {
                 Ok(Some(super::ImplSource::UserDefined(data))) => {
-                    candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data));
-                    Ok(())
+                    let Ok(leaf_def) = specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) else {
+                        return Err(());
+                    };
+                    // Only reveal a specializable default if we're past type-checking
+                    // and the obligation is monomorphic, otherwise passes such as
+                    // transmute checking and polymorphic MIR optimizations could
+                    // get a result which isn't correct for all monomorphizations.
+                    if leaf_def.is_final()
+                        || (obligation.param_env.reveal() == Reveal::All
+                            && !selcx
+                                .infcx
+                                .resolve_vars_if_possible(obligation.predicate.trait_ref(tcx))
+                                .still_further_specializable())
+                    {
+                        candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data));
+                        Ok(())
+                    } else {
+                        Err(())
+                    }
                 }
                 Ok(None) => {
                     candidate_set.mark_ambiguous();
-                    return Err(());
+                    Err(())
                 }
                 Ok(Some(_)) => {
                     // Don't know enough about the impl to provide a useful signature
-                    return Err(());
+                    Err(())
                 }
                 Err(e) => {
                     debug!(error = ?e, "selection error");
                     candidate_set.mark_error(e);
-                    return Err(());
+                    Err(())
                 }
             }
         });
diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs
new file mode 100644
index 00000000000..afd3db5e052
--- /dev/null
+++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs
@@ -0,0 +1,71 @@
+// edition: 2021
+// known-bug: #108309
+
+#![feature(async_fn_in_trait)]
+#![feature(min_specialization)]
+
+struct MyStruct;
+
+trait MyTrait<T> {
+    async fn foo(_: T) -> &'static str;
+}
+
+impl<T> MyTrait<T> for MyStruct {
+    default async fn foo(_: T) -> &'static str {
+        "default"
+    }
+}
+
+impl MyTrait<i32> for MyStruct {
+    async fn foo(_: i32) -> &'static str {
+        "specialized"
+    }
+}
+
+async fn async_main() {
+    assert_eq!(MyStruct::foo(42).await, "specialized");
+    assert_eq!(indirection(42).await, "specialized");
+}
+
+async fn indirection<T>(x: T) -> &'static str {
+    //explicit type coercion is currently necessary
+    // because of https://github.com/rust-lang/rust/issues/67918
+    <MyStruct as MyTrait<T>>::foo(x).await
+}
+
+// ------------------------------------------------------------------------- //
+// Implementation Details Below...
+
+use std::future::Future;
+use std::pin::Pin;
+use std::task::*;
+
+pub fn noop_waker() -> Waker {
+    let raw = RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE);
+
+    // SAFETY: the contracts for RawWaker and RawWakerVTable are upheld
+    unsafe { Waker::from_raw(raw) }
+}
+
+const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
+
+unsafe fn noop_clone(_p: *const ()) -> RawWaker {
+    RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE)
+}
+
+unsafe fn noop(_p: *const ()) {}
+
+fn main() {
+    let mut fut = async_main();
+
+    // Poll loop, just to test the future...
+    let waker = noop_waker();
+    let ctx = &mut Context::from_waker(&waker);
+
+    loop {
+        match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } {
+            Poll::Pending => {}
+            Poll::Ready(()) => break,
+        }
+    }
+}
diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr
new file mode 100644
index 00000000000..371122ea71e
--- /dev/null
+++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr
@@ -0,0 +1,26 @@
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/dont-project-to-specializable-projection.rs:4:12
+   |
+LL | #![feature(async_fn_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0053]: method `foo` has an incompatible type for trait
+  --> $DIR/dont-project-to-specializable-projection.rs:14:35
+   |
+LL |     default async fn foo(_: T) -> &'static str {
+   |                                   ^^^^^^^^^^^^ expected associated type, found future
+   |
+note: type in trait
+  --> $DIR/dont-project-to-specializable-projection.rs:10:27
+   |
+LL |     async fn foo(_: T) -> &'static str;
+   |                           ^^^^^^^^^^^^
+   = note: expected signature `fn(_) -> impl Future<Output = &'static str>`
+              found signature `fn(_) -> impl Future<Output = &'static str>`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0053`.