Skip to content

Commit

Permalink
Don't project specializable RPITIT projection
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Feb 23, 2023
1 parent 02b3664 commit 9bf32c4
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 5 deletions.
27 changes: 22 additions & 5 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
}
});
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
}
}
}
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 9bf32c4

Please sign in to comment.