diff options
| author | bors <bors@rust-lang.org> | 2024-02-16 00:03:46 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-02-16 00:03:46 +0000 |
| commit | cefa14bf2fc4cbc23a0f5e7d1daa04d258f8d62b (patch) | |
| tree | 4afce272f4cc64bd5125481e2503988a4010d18a /compiler/rustc_trait_selection/src | |
| parent | a4472498d7e88041f6206faf4503eb1f246fd427 (diff) | |
| parent | 2a216bb53bc17cfc4474589accbc8f0f497764ca (diff) | |
| download | rust-cefa14bf2fc4cbc23a0f5e7d1daa04d258f8d62b.tar.gz rust-cefa14bf2fc4cbc23a0f5e7d1daa04d258f8d62b.zip | |
Auto merge of #121169 - GuillaumeGomez:rollup-oxk5d5j, r=GuillaumeGomez
Rollup of 10 pull requests Successful merges: - #120777 (Bump Unicode to version 15.1.0, regenerate tables) - #120971 (Fix comment in core/src/str/validations.rs) - #121095 (Add extra indent spaces for rust-playground link) - #121109 (Add an ErrorGuaranteed to ast::TyKind::Err (attempt 2)) - #121119 (Make `async Fn` trait kind errors better) - #121141 (Fix closure kind docs) - #121145 (Update aarch64 target feature docs to match LLVM) - #121146 (Only point out non-diverging arms for match suggestions) - #121147 (Avoid debug logging entire MIR body) - #121155 (doc: add note about panicking examples for strict_overflow_ops) r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_trait_selection/src')
| -rw-r--r-- | compiler/rustc_trait_selection/src/errors.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs | 123 |
2 files changed, 108 insertions, 25 deletions
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 20cd573f46e..407fff03e15 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -135,6 +135,8 @@ pub struct ClosureKindMismatch { #[label(trait_selection_closure_kind_requirement)] pub cause_span: Span, + pub trait_prefix: &'static str, + #[subdiagnostic] pub fn_once_label: Option<ClosureFnOnceLabel>, @@ -157,3 +159,11 @@ pub struct ClosureFnMutLabel { pub span: Span, pub place: String, } + +#[derive(Diagnostic)] +#[diag(trait_selection_async_closure_not_fn)] +pub(crate) struct AsyncClosureNotFn { + #[primary_span] + pub span: Span, + pub kind: &'static str, +} diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 73effb33560..68b1a0d4e61 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -2,7 +2,9 @@ use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _}; use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _}; -use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch}; +use crate::errors::{ + AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, +}; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxtExt as _; @@ -959,34 +961,102 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn emit_specialized_closure_kind_error( &self, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + mut trait_ref: ty::PolyTraitRef<'tcx>, ) -> Option<ErrorGuaranteed> { - let self_ty = trait_ref.self_ty().skip_binder(); - if let ty::Closure(closure_def_id, closure_args) = *self_ty.kind() - && let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) - && let Some(found_kind) = self.closure_kind(self_ty) + // If `AsyncFnKindHelper` is not implemented, that means that the closure kind + // doesn't extend the goal kind. This is worth reporting, but we can only do so + // if we actually know which closure this goal comes from, so look at the cause + // to see if we can extract that information. + if Some(trait_ref.def_id()) == self.tcx.lang_items().async_fn_kind_helper() + && let Some(found_kind) = trait_ref.skip_binder().args.type_at(0).to_opt_closure_kind() + && let Some(expected_kind) = + trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind() && !found_kind.extends(expected_kind) - && let sig = closure_args.as_closure().sig() - && self.can_sub( - obligation.param_env, - trait_ref, - sig.map_bound(|sig| { - ty::TraitRef::new( - self.tcx, - trait_ref.def_id(), - [trait_ref.self_ty().skip_binder(), sig.inputs()[0]], - ) - }), - ) { - let mut err = - self.report_closure_error(&obligation, closure_def_id, found_kind, expected_kind); - self.note_obligation_cause(&mut err, &obligation); - self.point_at_returns_when_relevant(&mut err, &obligation); - Some(err.emit()) - } else { - None + if let Some((_, Some(parent))) = obligation.cause.code().parent() { + // If we have a derived obligation, then the parent will be a `AsyncFn*` goal. + trait_ref = parent.to_poly_trait_ref(); + } else if let &ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = + obligation.cause.code() + && let Some(typeck_results) = &self.typeck_results + && let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) = + *typeck_results.node_type(arg_hir_id).kind() + { + // Otherwise, extract the closure kind from the obligation. + let mut err = self.report_closure_error( + &obligation, + closure_def_id, + found_kind, + expected_kind, + "async ", + ); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + return Some(err.emit()); + } + } + + let self_ty = trait_ref.self_ty().skip_binder(); + + if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) { + let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() { + ty::Closure(def_id, args) => { + (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None) + } + ty::CoroutineClosure(def_id, args) => ( + def_id, + args.as_coroutine_closure() + .coroutine_closure_sig() + .map_bound(|sig| sig.tupled_inputs_ty), + Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()), + ), + _ => return None, + }; + + let expected_args = trait_ref.map_bound(|trait_ref| trait_ref.args.type_at(1)); + + // Verify that the arguments are compatible. If the signature is + // mismatched, then we have a totally different error to report. + if self.enter_forall(found_args, |found_args| { + self.enter_forall(expected_args, |expected_args| { + !self.can_sub(obligation.param_env, expected_args, found_args) + }) + }) { + return None; + } + + if let Some(found_kind) = self.closure_kind(self_ty) + && !found_kind.extends(expected_kind) + { + let mut err = self.report_closure_error( + &obligation, + closure_def_id, + found_kind, + expected_kind, + "", + ); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + return Some(err.emit()); + } + + // If the closure has captures, then perhaps the reason that the trait + // is unimplemented is because async closures don't implement `Fn`/`FnMut` + // if they have captures. + if let Some(by_ref_captures) = by_ref_captures + && let ty::FnPtr(sig) = by_ref_captures.kind() + && !sig.skip_binder().output().is_unit() + { + let mut err = self.tcx.dcx().create_err(AsyncClosureNotFn { + span: self.tcx.def_span(closure_def_id), + kind: expected_kind.as_str(), + }); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + return Some(err.emit()); + } } + None } fn fn_arg_obligation( @@ -1493,6 +1563,7 @@ pub(super) trait InferCtxtPrivExt<'tcx> { closure_def_id: DefId, found_kind: ty::ClosureKind, kind: ty::ClosureKind, + trait_prefix: &'static str, ) -> DiagnosticBuilder<'tcx>; fn report_cyclic_signature_error( @@ -3376,6 +3447,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { closure_def_id: DefId, found_kind: ty::ClosureKind, kind: ty::ClosureKind, + trait_prefix: &'static str, ) -> DiagnosticBuilder<'tcx> { let closure_span = self.tcx.def_span(closure_def_id); @@ -3384,6 +3456,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { expected: kind, found: found_kind, cause_span: obligation.cause.span, + trait_prefix, fn_once_label: None, fn_mut_label: None, }; |
