1
1
use super :: on_unimplemented:: { AppendConstMessage , OnUnimplementedNote } ;
2
2
use super :: suggestions:: get_explanation_based_on_obligation;
3
3
use crate :: error_reporting:: infer:: TyCategory ;
4
- use crate :: error_reporting:: traits:: infer_ctxt_ext:: InferCtxtExt ;
5
4
use crate :: error_reporting:: traits:: report_object_safety_error;
6
5
use crate :: error_reporting:: TypeErrCtxt ;
7
6
use crate :: errors:: {
@@ -2602,7 +2601,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
2602
2601
} )
2603
2602
. unwrap_or ( ( found_span, None , found) ) ;
2604
2603
2605
- self . infcx . report_arg_count_mismatch (
2604
+ self . report_arg_count_mismatch (
2606
2605
span,
2607
2606
closure_span,
2608
2607
expected,
@@ -2614,6 +2613,238 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
2614
2613
)
2615
2614
}
2616
2615
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
+
2617
2848
fn report_not_const_evaluatable_error (
2618
2849
& self ,
2619
2850
obligation : & PredicateObligation < ' tcx > ,
0 commit comments