Skip to content

Commit fc11ee0

Browse files
committed
Auto merge of #106171 - compiler-errors:consolidate-extract_callable_info, r=estebank,lcnr
Consolidate two almost duplicated fn info extraction routines Moves `extract_callable_info` up to trait selection, because it was being (almost) duplicated fully there for similar diagnostic purposes. This also generalizes the diagnostics we can give slightly (see UI test).
2 parents bbb36fe + c1a7dbc commit fc11ee0

File tree

7 files changed

+183
-185
lines changed

7 files changed

+183
-185
lines changed

compiler/rustc_hir_typeck/src/callee.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -659,8 +659,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
659659
};
660660

661661
if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
662-
if let Some((maybe_def, output_ty, _)) =
663-
self.extract_callable_info(callee_expr, callee_ty)
662+
if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty)
664663
&& !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
665664
{
666665
let descr = match maybe_def {

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+6-97
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use rustc_hir::{
1111
Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
1212
};
1313
use rustc_hir_analysis::astconv::AstConv;
14-
use rustc_infer::infer;
1514
use rustc_infer::traits::{self, StatementAsExpression};
1615
use rustc_middle::lint::in_external_macro;
1716
use rustc_middle::ty::{
@@ -23,9 +22,9 @@ use rustc_span::source_map::Spanned;
2322
use rustc_span::symbol::{sym, Ident};
2423
use rustc_span::{Span, Symbol};
2524
use rustc_trait_selection::infer::InferCtxtExt;
25+
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
2626
use rustc_trait_selection::traits::error_reporting::DefIdOrName;
2727
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
28-
use rustc_trait_selection::traits::NormalizeExt;
2928

3029
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3130
pub(crate) fn body_fn_sig(&self) -> Option<ty::FnSig<'tcx>> {
@@ -94,7 +93,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9493
found: Ty<'tcx>,
9594
can_satisfy: impl FnOnce(Ty<'tcx>) -> bool,
9695
) -> bool {
97-
let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(expr, found)
96+
let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(found)
9897
else { return false; };
9998
if can_satisfy(output) {
10099
let (sugg_call, mut applicability) = match inputs.len() {
@@ -163,99 +162,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
163162
/// because the callable type must also be well-formed to be called.
164163
pub(in super::super) fn extract_callable_info(
165164
&self,
166-
expr: &Expr<'_>,
167-
found: Ty<'tcx>,
165+
ty: Ty<'tcx>,
168166
) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
169-
// Autoderef is useful here because sometimes we box callables, etc.
170-
let Some((def_id_or_name, output, inputs)) = self.autoderef(expr.span, found).silence_errors().find_map(|(found, _)| {
171-
match *found.kind() {
172-
ty::FnPtr(fn_sig) =>
173-
Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())),
174-
ty::FnDef(def_id, _) => {
175-
let fn_sig = found.fn_sig(self.tcx);
176-
Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
177-
}
178-
ty::Closure(def_id, substs) => {
179-
let fn_sig = substs.as_closure().sig();
180-
Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..])))
181-
}
182-
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
183-
self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
184-
if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
185-
&& Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
186-
// args tuple will always be substs[1]
187-
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
188-
{
189-
Some((
190-
DefIdOrName::DefId(def_id),
191-
pred.kind().rebind(proj.term.ty().unwrap()),
192-
pred.kind().rebind(args.as_slice()),
193-
))
194-
} else {
195-
None
196-
}
197-
})
198-
}
199-
ty::Dynamic(data, _, ty::Dyn) => {
200-
data.iter().find_map(|pred| {
201-
if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
202-
&& Some(proj.def_id) == self.tcx.lang_items().fn_once_output()
203-
// for existential projection, substs are shifted over by 1
204-
&& let ty::Tuple(args) = proj.substs.type_at(0).kind()
205-
{
206-
Some((
207-
DefIdOrName::Name("trait object"),
208-
pred.rebind(proj.term.ty().unwrap()),
209-
pred.rebind(args.as_slice()),
210-
))
211-
} else {
212-
None
213-
}
214-
})
215-
}
216-
ty::Param(param) => {
217-
let def_id = self.tcx.generics_of(self.body_id.owner).type_param(&param, self.tcx).def_id;
218-
self.tcx.predicates_of(self.body_id.owner).predicates.iter().find_map(|(pred, _)| {
219-
if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
220-
&& Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
221-
&& proj.projection_ty.self_ty() == found
222-
// args tuple will always be substs[1]
223-
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
224-
{
225-
Some((
226-
DefIdOrName::DefId(def_id),
227-
pred.kind().rebind(proj.term.ty().unwrap()),
228-
pred.kind().rebind(args.as_slice()),
229-
))
230-
} else {
231-
None
232-
}
233-
})
234-
}
235-
_ => None,
236-
}
237-
}) else { return None; };
238-
239-
let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output);
240-
let inputs = inputs
241-
.skip_binder()
242-
.iter()
243-
.map(|ty| {
244-
self.replace_bound_vars_with_fresh_vars(
245-
expr.span,
246-
infer::FnCall,
247-
inputs.rebind(*ty),
248-
)
249-
})
250-
.collect();
251-
252-
// We don't want to register any extra obligations, which should be
253-
// implied by wf, but also because that would possibly result in
254-
// erroneous errors later on.
255-
let infer::InferOk { value: output, obligations: _ } =
256-
self.at(&self.misc(expr.span), self.param_env).normalize(output);
257-
258-
if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }
167+
self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty)
259168
}
260169

261170
pub fn suggest_two_fn_call(
@@ -267,9 +176,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
267176
rhs_ty: Ty<'tcx>,
268177
can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool,
269178
) -> bool {
270-
let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_expr, lhs_ty)
179+
let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_ty)
271180
else { return false; };
272-
let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_expr, rhs_ty)
181+
let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_ty)
273182
else { return false; };
274183

275184
if can_satisfy(lhs_output_ty, rhs_output_ty) {

compiler/rustc_hir_typeck/src/method/suggest.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -2700,8 +2700,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
27002700
found: Ty<'tcx>,
27012701
expected: Ty<'tcx>,
27022702
) -> bool {
2703-
let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(expr, found)
2704-
else { return false; };
2703+
let Some((_def_id_or_name, output, _inputs)) =
2704+
self.extract_callable_info(found) else {
2705+
return false;
2706+
};
27052707

27062708
if !self.can_coerce(output, expected) {
27072709
return false;

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2937,6 +2937,7 @@ impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor {
29372937
}
29382938
}
29392939

2940+
#[derive(Copy, Clone)]
29402941
pub enum DefIdOrName {
29412942
DefId(DefId),
29422943
Name(&'static str),

0 commit comments

Comments
 (0)