1
Fork 0

Ensure async trait impls are async (or otherwise return an opaque type)

As a workaround for the full `#[refine]` semantics not being implemented
yet, forbit returning a concrete future type like `Box<dyn Future>` or a
manually implemented Future.

`-> impl Future` is still permitted; while that can also cause
accidental refinement, that's behind a different feature gate
(`return_position_impl_trait_in_trait`) and that problem exists
regardless of whether the trait method is async, so will have to be
solved more generally.

Fixes #102745
This commit is contained in:
Dan Johnson 2022-11-02 17:45:08 -07:00
parent b70baa4f92
commit da98ef9a5d
12 changed files with 146 additions and 25 deletions

View file

@ -67,6 +67,10 @@ pub(crate) fn compare_impl_method<'tcx>(
return;
}
if let Err(_) = compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span) {
return;
}
if let Err(_) = compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
{
return;
@ -323,6 +327,34 @@ fn compare_predicate_entailment<'tcx>(
Ok(())
}
fn compare_asyncness<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m: &ty::AssocItem,
impl_m_span: Span,
trait_m: &ty::AssocItem,
trait_item_span: Option<Span>,
) -> Result<(), ErrorGuaranteed> {
if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
match tcx.fn_sig(impl_m.def_id).skip_binder().output().kind() {
ty::Alias(ty::Opaque, ..) => {
// allow both `async fn foo()` and `fn foo() -> impl Future`
}
ty::Error(rustc_errors::ErrorGuaranteed { .. }) => {
// We don't know if it's ok, but at least it's already an error.
}
_ => {
return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync {
span: impl_m_span,
method_name: trait_m.name,
trait_item_span,
}));
}
};
}
Ok(())
}
#[instrument(skip(tcx), level = "debug", ret)]
pub fn collect_trait_impl_trait_tys<'tcx>(
tcx: TyCtxt<'tcx>,

View file

@ -51,6 +51,17 @@ pub struct LifetimesOrBoundsMismatchOnTrait {
pub ident: Ident,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_async_trait_impl_should_be_async)]
pub struct AsyncTraitImplShouldBeAsync {
#[primary_span]
// #[label]
pub span: Span,
#[label(trait_item_label)]
pub trait_item_span: Option<Span>,
pub method_name: Symbol,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_drop_impl_on_wrong_item, code = "E0120")]
pub struct DropImplOnWrongItem {