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.
This commit is contained in:
commit
3a6c5429c2
4 changed files with 126 additions and 5 deletions
|
@ -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();
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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`.
|
Loading…
Add table
Reference in a new issue