11use super :: on_unimplemented:: { AppendConstMessage , OnUnimplementedNote } ;
22use super :: suggestions:: get_explanation_based_on_obligation;
33use crate :: error_reporting:: infer:: TyCategory ;
4- use crate :: error_reporting:: traits:: infer_ctxt_ext:: InferCtxtExt ;
54use crate :: error_reporting:: traits:: report_object_safety_error;
65use crate :: error_reporting:: TypeErrCtxt ;
76use 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