Point out incompatible closure bounds
This commit is contained in:
parent
1a7c203e7f
commit
693485373b
@ -1255,6 +1255,7 @@ fn report_selection_error(
|
|||||||
found_span,
|
found_span,
|
||||||
found_trait_ref,
|
found_trait_ref,
|
||||||
expected_trait_ref,
|
expected_trait_ref,
|
||||||
|
obligation.cause.code(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let (closure_span, found) = found_did
|
let (closure_span, found) = found_did
|
||||||
|
@ -254,8 +254,15 @@ fn report_closure_arg_mismatch(
|
|||||||
found_span: Option<Span>,
|
found_span: Option<Span>,
|
||||||
found: ty::PolyTraitRef<'tcx>,
|
found: ty::PolyTraitRef<'tcx>,
|
||||||
expected: ty::PolyTraitRef<'tcx>,
|
expected: ty::PolyTraitRef<'tcx>,
|
||||||
|
cause: &ObligationCauseCode<'tcx>,
|
||||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
|
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
|
||||||
|
|
||||||
|
fn note_conflicting_closure_bounds(
|
||||||
|
&self,
|
||||||
|
cause: &ObligationCauseCode<'tcx>,
|
||||||
|
err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
||||||
|
);
|
||||||
|
|
||||||
fn suggest_fully_qualified_path(
|
fn suggest_fully_qualified_path(
|
||||||
&self,
|
&self,
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
@ -1584,6 +1591,7 @@ fn report_closure_arg_mismatch(
|
|||||||
found_span: Option<Span>,
|
found_span: Option<Span>,
|
||||||
found: ty::PolyTraitRef<'tcx>,
|
found: ty::PolyTraitRef<'tcx>,
|
||||||
expected: ty::PolyTraitRef<'tcx>,
|
expected: ty::PolyTraitRef<'tcx>,
|
||||||
|
cause: &ObligationCauseCode<'tcx>,
|
||||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||||
pub(crate) fn build_fn_sig_ty<'tcx>(
|
pub(crate) fn build_fn_sig_ty<'tcx>(
|
||||||
infcx: &InferCtxt<'tcx>,
|
infcx: &InferCtxt<'tcx>,
|
||||||
@ -1645,9 +1653,68 @@ pub(crate) fn build_fn_sig_ty<'tcx>(
|
|||||||
let signature_kind = format!("{argument_kind} signature");
|
let signature_kind = format!("{argument_kind} signature");
|
||||||
err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str);
|
err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str);
|
||||||
|
|
||||||
|
self.note_conflicting_closure_bounds(cause, &mut err);
|
||||||
|
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a note if there are two `Fn`-family bounds that have conflicting argument
|
||||||
|
// requirements, which will always cause a closure to have a type error.
|
||||||
|
fn note_conflicting_closure_bounds(
|
||||||
|
&self,
|
||||||
|
cause: &ObligationCauseCode<'tcx>,
|
||||||
|
err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
||||||
|
) {
|
||||||
|
// First, look for an `ExprBindingObligation`, which means we can get
|
||||||
|
// the unsubstituted predicate list of the called function. And check
|
||||||
|
// that the predicate that we failed to satisfy is a `Fn`-like trait.
|
||||||
|
if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = cause
|
||||||
|
&& let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
|
||||||
|
&& let Some(pred) = predicates.predicates.get(*idx)
|
||||||
|
&& let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder()
|
||||||
|
&& ty::ClosureKind::from_def_id(self.tcx, trait_pred.def_id()).is_some()
|
||||||
|
{
|
||||||
|
let expected_self =
|
||||||
|
self.tcx.anonymize_late_bound_regions(pred.kind().rebind(trait_pred.self_ty()));
|
||||||
|
let expected_substs = self
|
||||||
|
.tcx
|
||||||
|
.anonymize_late_bound_regions(pred.kind().rebind(trait_pred.trait_ref.substs));
|
||||||
|
|
||||||
|
// Find another predicate whose self-type is equal to the expected self type,
|
||||||
|
// but whose substs don't match.
|
||||||
|
let other_pred = std::iter::zip(&predicates.predicates, &predicates.spans)
|
||||||
|
.enumerate()
|
||||||
|
.find(|(other_idx, (pred, _))| match pred.kind().skip_binder() {
|
||||||
|
ty::PredicateKind::Trait(trait_pred)
|
||||||
|
if ty::ClosureKind::from_def_id(self.tcx, trait_pred.def_id())
|
||||||
|
.is_some()
|
||||||
|
&& other_idx != idx
|
||||||
|
// Make sure that the self type matches
|
||||||
|
// (i.e. constraining this closure)
|
||||||
|
&& expected_self
|
||||||
|
== self.tcx.anonymize_late_bound_regions(
|
||||||
|
pred.kind().rebind(trait_pred.self_ty()),
|
||||||
|
)
|
||||||
|
// But the substs don't match (i.e. incompatible args)
|
||||||
|
&& expected_substs
|
||||||
|
!= self.tcx.anonymize_late_bound_regions(
|
||||||
|
pred.kind().rebind(trait_pred.trait_ref.substs),
|
||||||
|
) =>
|
||||||
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
});
|
||||||
|
// If we found one, then it's very likely the cause of the error.
|
||||||
|
if let Some((_, (_, other_pred_span))) = other_pred {
|
||||||
|
err.span_note(
|
||||||
|
*other_pred_span,
|
||||||
|
"closure inferred to have a different signature due to this bound",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn suggest_fully_qualified_path(
|
fn suggest_fully_qualified_path(
|
||||||
&self,
|
&self,
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
|
15
src/test/ui/closures/multiple-fn-bounds.rs
Normal file
15
src/test/ui/closures/multiple-fn-bounds.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
fn foo<F: Fn(&char) -> bool + Fn(char) -> bool>(f: F) {
|
||||||
|
//~^ NOTE required by a bound in `foo`
|
||||||
|
//~| NOTE required by this bound in `foo`
|
||||||
|
//~| NOTE closure inferred to have a different signature due to this bound
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let v = true;
|
||||||
|
foo(move |x| v);
|
||||||
|
//~^ ERROR type mismatch in closure arguments
|
||||||
|
//~| NOTE expected closure signature
|
||||||
|
//~| NOTE expected due to this
|
||||||
|
//~| NOTE found signature defined here
|
||||||
|
}
|
24
src/test/ui/closures/multiple-fn-bounds.stderr
Normal file
24
src/test/ui/closures/multiple-fn-bounds.stderr
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
error[E0631]: type mismatch in closure arguments
|
||||||
|
--> $DIR/multiple-fn-bounds.rs:10:5
|
||||||
|
|
|
||||||
|
LL | foo(move |x| v);
|
||||||
|
| ^^^ -------- found signature defined here
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
|
||||||
|
= note: expected closure signature `fn(char) -> _`
|
||||||
|
found closure signature `for<'a> fn(&'a char) -> _`
|
||||||
|
note: closure inferred to have a different signature due to this bound
|
||||||
|
--> $DIR/multiple-fn-bounds.rs:1:11
|
||||||
|
|
|
||||||
|
LL | fn foo<F: Fn(&char) -> bool + Fn(char) -> bool>(f: F) {
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
note: required by a bound in `foo`
|
||||||
|
--> $DIR/multiple-fn-bounds.rs:1:31
|
||||||
|
|
|
||||||
|
LL | fn foo<F: Fn(&char) -> bool + Fn(char) -> bool>(f: F) {
|
||||||
|
| ^^^^^^^^^^^^^^^^ required by this bound in `foo`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0631`.
|
Loading…
Reference in New Issue
Block a user