Point out custom Fn-family trait impl
This commit is contained in:
parent
ddb7003b79
commit
d25abdc0c5
@ -128,6 +128,14 @@ impl<'tcx> ClosureKind {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_def_id(&self, tcx: TyCtxt<'_>) -> DefId {
|
||||||
|
match self {
|
||||||
|
ClosureKind::Fn => tcx.lang_items().fn_once_trait().unwrap(),
|
||||||
|
ClosureKind::FnMut => tcx.lang_items().fn_mut_trait().unwrap(),
|
||||||
|
ClosureKind::FnOnce => tcx.lang_items().fn_trait().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A composite describing a `Place` that is captured by a closure.
|
/// A composite describing a `Place` that is captured by a closure.
|
||||||
|
@ -21,6 +21,7 @@ use rustc_hir::def_id::DefId;
|
|||||||
use rustc_hir::{ExprKind, Node, QPath};
|
use rustc_hir::{ExprKind, Node, QPath};
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
|
use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
|
||||||
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_infer::infer::InferOk;
|
use rustc_infer::infer::InferOk;
|
||||||
use rustc_infer::infer::TypeTrace;
|
use rustc_infer::infer::TypeTrace;
|
||||||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||||
@ -29,7 +30,9 @@ use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty};
|
|||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
use rustc_span::{self, Span};
|
use rustc_span::{self, Span};
|
||||||
use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpression};
|
use rustc_trait_selection::traits::{
|
||||||
|
self, ObligationCauseCode, SelectionContext, StatementAsExpression,
|
||||||
|
};
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
@ -393,6 +396,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !call_appears_satisfied {
|
if !call_appears_satisfied {
|
||||||
|
let compatibility_diagonal = IndexVec::from_raw(compatibility_diagonal);
|
||||||
|
let provided_args = IndexVec::from_iter(provided_args.iter().take(if c_variadic {
|
||||||
|
minimum_input_count
|
||||||
|
} else {
|
||||||
|
provided_arg_count
|
||||||
|
}));
|
||||||
|
debug_assert_eq!(
|
||||||
|
formal_input_tys.len(),
|
||||||
|
expected_input_tys.len(),
|
||||||
|
"expected formal_input_tys to be the same size as expected_input_tys"
|
||||||
|
);
|
||||||
|
let formal_and_expected_inputs = IndexVec::from_iter(
|
||||||
|
formal_input_tys
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.zip(expected_input_tys.iter().copied())
|
||||||
|
.map(|vars| self.resolve_vars_if_possible(vars)),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.report_arg_errors(
|
||||||
|
compatibility_diagonal,
|
||||||
|
formal_and_expected_inputs,
|
||||||
|
provided_args,
|
||||||
|
c_variadic,
|
||||||
|
err_code,
|
||||||
|
fn_def_id,
|
||||||
|
call_span,
|
||||||
|
call_expr,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn report_arg_errors(
|
||||||
|
&self,
|
||||||
|
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
|
||||||
|
formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||||
|
provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>,
|
||||||
|
c_variadic: bool,
|
||||||
|
err_code: &str,
|
||||||
|
fn_def_id: Option<DefId>,
|
||||||
|
call_span: Span,
|
||||||
|
call_expr: &hir::Expr<'tcx>,
|
||||||
|
) {
|
||||||
// Next, let's construct the error
|
// Next, let's construct the error
|
||||||
let (error_span, full_call_span, ctor_of) = match &call_expr.kind {
|
let (error_span, full_call_span, ctor_of) = match &call_expr.kind {
|
||||||
hir::ExprKind::Call(
|
hir::ExprKind::Call(
|
||||||
@ -428,55 +474,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
None => "function",
|
None => "function",
|
||||||
};
|
};
|
||||||
|
|
||||||
let compatibility_diagonal = IndexVec::from_raw(compatibility_diagonal);
|
|
||||||
let provided_args = IndexVec::from_iter(provided_args.iter().take(if c_variadic {
|
|
||||||
minimum_input_count
|
|
||||||
} else {
|
|
||||||
provided_arg_count
|
|
||||||
}));
|
|
||||||
debug_assert_eq!(
|
|
||||||
formal_input_tys.len(),
|
|
||||||
expected_input_tys.len(),
|
|
||||||
"expected formal_input_tys to be the same size as expected_input_tys"
|
|
||||||
);
|
|
||||||
let formal_and_expected_inputs = IndexVec::from_iter(
|
|
||||||
formal_input_tys
|
|
||||||
.iter()
|
|
||||||
.copied()
|
|
||||||
.zip(expected_input_tys.iter().copied())
|
|
||||||
.map(|vars| self.resolve_vars_if_possible(vars)),
|
|
||||||
);
|
|
||||||
|
|
||||||
self.report_arg_errors(
|
|
||||||
compatibility_diagonal,
|
|
||||||
formal_and_expected_inputs,
|
|
||||||
provided_args,
|
|
||||||
full_call_span,
|
|
||||||
error_span,
|
|
||||||
args_span,
|
|
||||||
call_name,
|
|
||||||
c_variadic,
|
|
||||||
err_code,
|
|
||||||
fn_def_id,
|
|
||||||
call_expr,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn report_arg_errors(
|
|
||||||
&self,
|
|
||||||
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
|
|
||||||
formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
|
|
||||||
provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>,
|
|
||||||
full_call_span: Span,
|
|
||||||
error_span: Span,
|
|
||||||
args_span: Span,
|
|
||||||
call_name: &str,
|
|
||||||
c_variadic: bool,
|
|
||||||
err_code: &str,
|
|
||||||
fn_def_id: Option<DefId>,
|
|
||||||
call_expr: &hir::Expr<'tcx>,
|
|
||||||
) {
|
|
||||||
// Don't print if it has error types or is just plain `_`
|
// Don't print if it has error types or is just plain `_`
|
||||||
fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
|
fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
|
||||||
tys.into_iter().any(|ty| ty.references_error() || ty.is_ty_var())
|
tys.into_iter().any(|ty| ty.references_error() || ty.is_ty_var())
|
||||||
@ -1818,17 +1815,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
fn label_fn_like(
|
fn label_fn_like(
|
||||||
&self,
|
&self,
|
||||||
err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>,
|
err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>,
|
||||||
def_id: Option<DefId>,
|
callable_def_id: Option<DefId>,
|
||||||
callee_ty: Option<Ty<'tcx>>,
|
callee_ty: Option<Ty<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let Some(mut def_id) = def_id else {
|
let Some(mut def_id) = callable_def_id else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(assoc_item) = self.tcx.opt_associated_item(def_id)
|
if let Some(assoc_item) = self.tcx.opt_associated_item(def_id)
|
||||||
&& let trait_def_id = assoc_item.trait_item_def_id.unwrap_or_else(|| self.tcx.parent(def_id))
|
// Possibly points at either impl or trait item, so try to get it
|
||||||
|
// to point to trait item, then get the parent.
|
||||||
|
// This parent might be an impl in the case of an inherent function,
|
||||||
|
// but the next check will fail.
|
||||||
|
&& let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id)
|
||||||
|
&& let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id)
|
||||||
// Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce"
|
// Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce"
|
||||||
&& ty::ClosureKind::from_def_id(self.tcx, trait_def_id).is_some()
|
&& let Some(call_kind) = ty::ClosureKind::from_def_id(self.tcx, maybe_trait_def_id)
|
||||||
&& let Some(callee_ty) = callee_ty
|
&& let Some(callee_ty) = callee_ty
|
||||||
{
|
{
|
||||||
let callee_ty = callee_ty.peel_refs();
|
let callee_ty = callee_ty.peel_refs();
|
||||||
@ -1853,7 +1855,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
std::iter::zip(instantiated.predicates, instantiated.spans)
|
std::iter::zip(instantiated.predicates, instantiated.spans)
|
||||||
{
|
{
|
||||||
if let ty::PredicateKind::Trait(pred) = predicate.kind().skip_binder()
|
if let ty::PredicateKind::Trait(pred) = predicate.kind().skip_binder()
|
||||||
&& pred.self_ty() == callee_ty
|
&& pred.self_ty().peel_refs() == callee_ty
|
||||||
&& ty::ClosureKind::from_def_id(self.tcx, pred.def_id()).is_some()
|
&& ty::ClosureKind::from_def_id(self.tcx, pred.def_id()).is_some()
|
||||||
{
|
{
|
||||||
err.span_note(span, "callable defined here");
|
err.span_note(span, "callable defined here");
|
||||||
@ -1862,14 +1864,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Opaque(new_def_id, _) | ty::Closure(new_def_id, _) | ty::FnDef(new_def_id, _) => {
|
ty::Opaque(new_def_id, _)
|
||||||
|
| ty::Closure(new_def_id, _)
|
||||||
|
| ty::FnDef(new_def_id, _) => {
|
||||||
def_id = new_def_id;
|
def_id = new_def_id;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
// Look for a user-provided impl of a `Fn` trait, and point to it.
|
||||||
|
let new_def_id = self.probe(|_| {
|
||||||
|
let trait_ref = ty::TraitRef::new(
|
||||||
|
call_kind.to_def_id(self.tcx),
|
||||||
|
self.tcx.mk_substs([
|
||||||
|
ty::GenericArg::from(callee_ty),
|
||||||
|
self.next_ty_var(TypeVariableOrigin {
|
||||||
|
kind: TypeVariableOriginKind::MiscVariable,
|
||||||
|
span: rustc_span::DUMMY_SP,
|
||||||
|
})
|
||||||
|
.into(),
|
||||||
|
].into_iter()),
|
||||||
|
);
|
||||||
|
let obligation = traits::Obligation::new(
|
||||||
|
traits::ObligationCause::dummy(),
|
||||||
|
self.param_env,
|
||||||
|
ty::Binder::dummy(ty::TraitPredicate {
|
||||||
|
trait_ref,
|
||||||
|
constness: ty::BoundConstness::NotConst,
|
||||||
|
polarity: ty::ImplPolarity::Positive,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
match SelectionContext::new(&self).select(&obligation) {
|
||||||
|
Ok(Some(traits::ImplSource::UserDefined(impl_source))) => {
|
||||||
|
Some(impl_source.impl_def_id)
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if let Some(new_def_id) = new_def_id {
|
||||||
|
def_id = new_def_id;
|
||||||
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(def_span) = self.tcx.def_ident_span(def_id) && !def_span.is_dummy() {
|
if let Some(def_span) = self.tcx.def_ident_span(def_id) && !def_span.is_dummy() {
|
||||||
let mut spans: MultiSpan = def_span.into();
|
let mut spans: MultiSpan = def_span.into();
|
||||||
@ -1888,8 +1925,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
let def_kind = self.tcx.def_kind(def_id);
|
let def_kind = self.tcx.def_kind(def_id);
|
||||||
err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
|
err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
|
||||||
} else if let def_kind @ (DefKind::Closure | DefKind::OpaqueTy) = self.tcx.def_kind(def_id)
|
} else {
|
||||||
{
|
let def_kind = self.tcx.def_kind(def_id);
|
||||||
err.span_note(
|
err.span_note(
|
||||||
self.tcx.def_span(def_id),
|
self.tcx.def_span(def_id),
|
||||||
&format!("{} defined here", def_kind.descr(def_id)),
|
&format!("{} defined here", def_kind.descr(def_id)),
|
||||||
|
@ -5,6 +5,12 @@ LL | let ans = s("what");
|
|||||||
| - ^^^^^^ expected `isize`, found `&str`
|
| - ^^^^^^ expected `isize`, found `&str`
|
||||||
| |
|
| |
|
||||||
| arguments to this function are incorrect
|
| arguments to this function are incorrect
|
||||||
|
|
|
||||||
|
note: implementation defined here
|
||||||
|
--> $DIR/overloaded-calls-bad.rs:10:1
|
||||||
|
|
|
||||||
|
LL | impl FnMut<(isize,)> for S {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0057]: this function takes 1 argument but 0 arguments were supplied
|
error[E0057]: this function takes 1 argument but 0 arguments were supplied
|
||||||
--> $DIR/overloaded-calls-bad.rs:29:15
|
--> $DIR/overloaded-calls-bad.rs:29:15
|
||||||
@ -12,6 +18,11 @@ error[E0057]: this function takes 1 argument but 0 arguments were supplied
|
|||||||
LL | let ans = s();
|
LL | let ans = s();
|
||||||
| ^-- an argument of type `isize` is missing
|
| ^-- an argument of type `isize` is missing
|
||||||
|
|
|
|
||||||
|
note: implementation defined here
|
||||||
|
--> $DIR/overloaded-calls-bad.rs:10:1
|
||||||
|
|
|
||||||
|
LL | impl FnMut<(isize,)> for S {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
help: provide the argument
|
help: provide the argument
|
||||||
|
|
|
|
||||||
LL | let ans = s(/* isize */);
|
LL | let ans = s(/* isize */);
|
||||||
@ -25,6 +36,11 @@ LL | let ans = s("burma", "shave");
|
|||||||
| |
|
| |
|
||||||
| expected `isize`, found `&str`
|
| expected `isize`, found `&str`
|
||||||
|
|
|
|
||||||
|
note: implementation defined here
|
||||||
|
--> $DIR/overloaded-calls-bad.rs:10:1
|
||||||
|
|
|
||||||
|
LL | impl FnMut<(isize,)> for S {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
help: remove the extra argument
|
help: remove the extra argument
|
||||||
|
|
|
|
||||||
LL | let ans = s(/* isize */);
|
LL | let ans = s(/* isize */);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user