Skip to content

Commit 6310e40

Browse files
Get rid of infer_ctxt_ext
1 parent 20f23ab commit 6310e40

File tree

5 files changed

+237
-252
lines changed

5 files changed

+237
-252
lines changed

compiler/rustc_hir_typeck/src/closure.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use rustc_span::def_id::LocalDefId;
1818
use rustc_span::Span;
1919
use rustc_target::spec::abi::Abi;
2020
use rustc_trait_selection::error_reporting::traits::ArgKind;
21-
use rustc_trait_selection::error_reporting::traits::InferCtxtExt as _;
2221
use rustc_trait_selection::traits;
2322
use rustc_type_ir::ClosureKind;
2423
use std::iter;
@@ -734,13 +733,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
734733
.map(|ty| ArgKind::from_expected_ty(*ty, None))
735734
.collect();
736735
let (closure_span, closure_arg_span, found_args) =
737-
match self.get_fn_like_arguments(expr_map_node) {
736+
match self.err_ctxt().get_fn_like_arguments(expr_map_node) {
738737
Some((sp, arg_sp, args)) => (Some(sp), arg_sp, args),
739738
None => (None, None, Vec::new()),
740739
};
741740
let expected_span =
742741
expected_sig.cause_span.unwrap_or_else(|| self.tcx.def_span(expr_def_id));
743742
let guar = self
743+
.err_ctxt()
744744
.report_arg_count_mismatch(
745745
expected_span,
746746
closure_span,

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

+233-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote};
22
use super::suggestions::get_explanation_based_on_obligation;
33
use crate::error_reporting::infer::TyCategory;
4-
use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt;
54
use crate::error_reporting::traits::report_object_safety_error;
65
use crate::error_reporting::TypeErrCtxt;
76
use crate::errors::{
@@ -2602,7 +2601,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
26022601
})
26032602
.unwrap_or((found_span, None, found));
26042603

2605-
self.infcx.report_arg_count_mismatch(
2604+
self.report_arg_count_mismatch(
26062605
span,
26072606
closure_span,
26082607
expected,
@@ -2614,6 +2613,238 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
26142613
)
26152614
}
26162615

2616+
/// Given some node representing a fn-like thing in the HIR map,
2617+
/// returns a span and `ArgKind` information that describes the
2618+
/// arguments it expects. This can be supplied to
2619+
/// `report_arg_count_mismatch`.
2620+
pub fn get_fn_like_arguments(
2621+
&self,
2622+
node: Node<'_>,
2623+
) -> Option<(Span, Option<Span>, Vec<ArgKind>)> {
2624+
let sm = self.tcx.sess.source_map();
2625+
let hir = self.tcx.hir();
2626+
Some(match node {
2627+
Node::Expr(&hir::Expr {
2628+
kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, fn_arg_span, .. }),
2629+
..
2630+
}) => (
2631+
fn_decl_span,
2632+
fn_arg_span,
2633+
hir.body(body)
2634+
.params
2635+
.iter()
2636+
.map(|arg| {
2637+
if let hir::Pat { kind: hir::PatKind::Tuple(args, _), span, .. } = *arg.pat
2638+
{
2639+
Some(ArgKind::Tuple(
2640+
Some(span),
2641+
args.iter()
2642+
.map(|pat| {
2643+
sm.span_to_snippet(pat.span)
2644+
.ok()
2645+
.map(|snippet| (snippet, "_".to_owned()))
2646+
})
2647+
.collect::<Option<Vec<_>>>()?,
2648+
))
2649+
} else {
2650+
let name = sm.span_to_snippet(arg.pat.span).ok()?;
2651+
Some(ArgKind::Arg(name, "_".to_owned()))
2652+
}
2653+
})
2654+
.collect::<Option<Vec<ArgKind>>>()?,
2655+
),
2656+
Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. })
2657+
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. })
2658+
| Node::TraitItem(&hir::TraitItem {
2659+
kind: hir::TraitItemKind::Fn(ref sig, _), ..
2660+
}) => (
2661+
sig.span,
2662+
None,
2663+
sig.decl
2664+
.inputs
2665+
.iter()
2666+
.map(|arg| match arg.kind {
2667+
hir::TyKind::Tup(tys) => ArgKind::Tuple(
2668+
Some(arg.span),
2669+
vec![("_".to_owned(), "_".to_owned()); tys.len()],
2670+
),
2671+
_ => ArgKind::empty(),
2672+
})
2673+
.collect::<Vec<ArgKind>>(),
2674+
),
2675+
Node::Ctor(variant_data) => {
2676+
let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
2677+
(span, None, vec![ArgKind::empty(); variant_data.fields().len()])
2678+
}
2679+
_ => panic!("non-FnLike node found: {node:?}"),
2680+
})
2681+
}
2682+
2683+
/// Reports an error when the number of arguments needed by a
2684+
/// trait match doesn't match the number that the expression
2685+
/// provides.
2686+
pub fn report_arg_count_mismatch(
2687+
&self,
2688+
span: Span,
2689+
found_span: Option<Span>,
2690+
expected_args: Vec<ArgKind>,
2691+
found_args: Vec<ArgKind>,
2692+
is_closure: bool,
2693+
closure_arg_span: Option<Span>,
2694+
) -> Diag<'a> {
2695+
let kind = if is_closure { "closure" } else { "function" };
2696+
2697+
let args_str = |arguments: &[ArgKind], other: &[ArgKind]| {
2698+
let arg_length = arguments.len();
2699+
let distinct = matches!(other, &[ArgKind::Tuple(..)]);
2700+
match (arg_length, arguments.get(0)) {
2701+
(1, Some(ArgKind::Tuple(_, fields))) => {
2702+
format!("a single {}-tuple as argument", fields.len())
2703+
}
2704+
_ => format!(
2705+
"{} {}argument{}",
2706+
arg_length,
2707+
if distinct && arg_length > 1 { "distinct " } else { "" },
2708+
pluralize!(arg_length)
2709+
),
2710+
}
2711+
};
2712+
2713+
let expected_str = args_str(&expected_args, &found_args);
2714+
let found_str = args_str(&found_args, &expected_args);
2715+
2716+
let mut err = struct_span_code_err!(
2717+
self.dcx(),
2718+
span,
2719+
E0593,
2720+
"{} is expected to take {}, but it takes {}",
2721+
kind,
2722+
expected_str,
2723+
found_str,
2724+
);
2725+
2726+
err.span_label(span, format!("expected {kind} that takes {expected_str}"));
2727+
2728+
if let Some(found_span) = found_span {
2729+
err.span_label(found_span, format!("takes {found_str}"));
2730+
2731+
// Suggest to take and ignore the arguments with expected_args_length `_`s if
2732+
// found arguments is empty (assume the user just wants to ignore args in this case).
2733+
// For example, if `expected_args_length` is 2, suggest `|_, _|`.
2734+
if found_args.is_empty() && is_closure {
2735+
let underscores = vec!["_"; expected_args.len()].join(", ");
2736+
err.span_suggestion_verbose(
2737+
closure_arg_span.unwrap_or(found_span),
2738+
format!(
2739+
"consider changing the closure to take and ignore the expected argument{}",
2740+
pluralize!(expected_args.len())
2741+
),
2742+
format!("|{underscores}|"),
2743+
Applicability::MachineApplicable,
2744+
);
2745+
}
2746+
2747+
if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] {
2748+
if fields.len() == expected_args.len() {
2749+
let sugg = fields
2750+
.iter()
2751+
.map(|(name, _)| name.to_owned())
2752+
.collect::<Vec<String>>()
2753+
.join(", ");
2754+
err.span_suggestion_verbose(
2755+
found_span,
2756+
"change the closure to take multiple arguments instead of a single tuple",
2757+
format!("|{sugg}|"),
2758+
Applicability::MachineApplicable,
2759+
);
2760+
}
2761+
}
2762+
if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..]
2763+
&& fields.len() == found_args.len()
2764+
&& is_closure
2765+
{
2766+
let sugg = format!(
2767+
"|({}){}|",
2768+
found_args
2769+
.iter()
2770+
.map(|arg| match arg {
2771+
ArgKind::Arg(name, _) => name.to_owned(),
2772+
_ => "_".to_owned(),
2773+
})
2774+
.collect::<Vec<String>>()
2775+
.join(", "),
2776+
// add type annotations if available
2777+
if found_args.iter().any(|arg| match arg {
2778+
ArgKind::Arg(_, ty) => ty != "_",
2779+
_ => false,
2780+
}) {
2781+
format!(
2782+
": ({})",
2783+
fields
2784+
.iter()
2785+
.map(|(_, ty)| ty.to_owned())
2786+
.collect::<Vec<String>>()
2787+
.join(", ")
2788+
)
2789+
} else {
2790+
String::new()
2791+
},
2792+
);
2793+
err.span_suggestion_verbose(
2794+
found_span,
2795+
"change the closure to accept a tuple instead of individual arguments",
2796+
sugg,
2797+
Applicability::MachineApplicable,
2798+
);
2799+
}
2800+
}
2801+
2802+
err
2803+
}
2804+
2805+
/// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
2806+
/// in that order, and returns the generic type corresponding to the
2807+
/// argument of that trait (corresponding to the closure arguments).
2808+
pub fn type_implements_fn_trait(
2809+
&self,
2810+
param_env: ty::ParamEnv<'tcx>,
2811+
ty: ty::Binder<'tcx, Ty<'tcx>>,
2812+
polarity: ty::PredicatePolarity,
2813+
) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> {
2814+
self.commit_if_ok(|_| {
2815+
for trait_def_id in [
2816+
self.tcx.lang_items().fn_trait(),
2817+
self.tcx.lang_items().fn_mut_trait(),
2818+
self.tcx.lang_items().fn_once_trait(),
2819+
] {
2820+
let Some(trait_def_id) = trait_def_id else { continue };
2821+
// Make a fresh inference variable so we can determine what the generic parameters
2822+
// of the trait are.
2823+
let var = self.next_ty_var(DUMMY_SP);
2824+
// FIXME(effects)
2825+
let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]);
2826+
let obligation = Obligation::new(
2827+
self.tcx,
2828+
ObligationCause::dummy(),
2829+
param_env,
2830+
ty.rebind(ty::TraitPredicate { trait_ref, polarity }),
2831+
);
2832+
let ocx = ObligationCtxt::new(self);
2833+
ocx.register_obligation(obligation);
2834+
if ocx.select_all_or_error().is_empty() {
2835+
return Ok((
2836+
self.tcx
2837+
.fn_trait_kind_from_def_id(trait_def_id)
2838+
.expect("expected to map DefId to ClosureKind"),
2839+
ty.rebind(self.resolve_vars_if_possible(var)),
2840+
));
2841+
}
2842+
}
2843+
2844+
Err(())
2845+
})
2846+
}
2847+
26172848
fn report_not_const_evaluatable_error(
26182849
&self,
26192850
obligation: &PredicateObligation<'tcx>,

0 commit comments

Comments
 (0)