diff options
| author | Dan Johnson <computerdruid@google.com> | 2022-11-02 17:45:08 -0700 |
|---|---|---|
| committer | Dan Johnson <computerdruid@google.com> | 2022-12-14 16:38:21 -0800 |
| commit | da98ef9a5d0b8a4fb90e1d845506880fae9e7352 (patch) | |
| tree | 255ffbbb7f63e882d7d1173c08f9ad81b7f9134c /compiler/rustc_hir_analysis | |
| parent | b70baa4f922a1809d79caeaeb902800c3be283b9 (diff) | |
| download | rust-da98ef9a5d0b8a4fb90e1d845506880fae9e7352.tar.gz rust-da98ef9a5d0b8a4fb90e1d845506880fae9e7352.zip | |
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
Diffstat (limited to 'compiler/rustc_hir_analysis')
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/compare_method.rs | 32 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/errors.rs | 11 |
2 files changed, 43 insertions, 0 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index ba7d31cea2e..bfa37c05a19 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -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>, diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index d9697c63c56..d383fcacb3a 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -52,6 +52,17 @@ pub struct LifetimesOrBoundsMismatchOnTrait { } #[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 { #[primary_span] |
