@@ -3709,7 +3709,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3709
3709
self . consider_hint_about_removing_semicolon ( blk, expected_ty, err) ;
3710
3710
}
3711
3711
if let Some ( fn_span) = fn_span {
3712
- err. span_label ( fn_span, "this function's body doesn't return" ) ;
3712
+ err. span_label (
3713
+ fn_span,
3714
+ "implicitly returns `()` as its body has no tail or `return` \
3715
+ expression",
3716
+ ) ;
3713
3717
}
3714
3718
} , false ) ;
3715
3719
}
@@ -3819,6 +3823,101 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3819
3823
pointing_at_return_type
3820
3824
}
3821
3825
3826
+ /// When encountering an fn-like ctor that needs to unify with a value, check whether calling
3827
+ /// the ctor would successfully solve the type mismatch and if so, suggest it:
3828
+ /// ```
3829
+ /// fn foo(x: usize) -> usize { x }
3830
+ /// let x: usize = foo; // suggest calling the `foo` function: `foo(42)`
3831
+ /// ```
3832
+ fn suggest_fn_call (
3833
+ & self ,
3834
+ err : & mut DiagnosticBuilder < ' tcx > ,
3835
+ expr : & hir:: Expr ,
3836
+ expected : Ty < ' tcx > ,
3837
+ found : Ty < ' tcx > ,
3838
+ ) -> bool {
3839
+ match found. sty {
3840
+ ty:: FnDef ( ..) | ty:: FnPtr ( _) => { }
3841
+ _ => return false ,
3842
+ }
3843
+ let hir = self . tcx . hir ( ) ;
3844
+
3845
+ let sig = found. fn_sig ( self . tcx ) ;
3846
+ let sig = self
3847
+ . replace_bound_vars_with_fresh_vars ( expr. span , infer:: FnCall , & sig)
3848
+ . 0 ;
3849
+ let sig = self . normalize_associated_types_in ( expr. span , & sig) ;
3850
+ if let Ok ( _) = self . try_coerce ( expr, sig. output ( ) , expected, AllowTwoPhase :: No ) {
3851
+ let ( mut sugg_call, applicability) = if sig. inputs ( ) . is_empty ( ) {
3852
+ ( String :: new ( ) , Applicability :: MachineApplicable )
3853
+ } else {
3854
+ ( "..." . to_string ( ) , Applicability :: HasPlaceholders )
3855
+ } ;
3856
+ let mut msg = "call this function" ;
3857
+ if let ty:: FnDef ( def_id, ..) = found. sty {
3858
+ match hir. get_if_local ( def_id) {
3859
+ Some ( Node :: Item ( hir:: Item {
3860
+ node : ItemKind :: Fn ( .., body_id) ,
3861
+ ..
3862
+ } ) ) |
3863
+ Some ( Node :: ImplItem ( hir:: ImplItem {
3864
+ node : hir:: ImplItemKind :: Method ( _, body_id) ,
3865
+ ..
3866
+ } ) ) |
3867
+ Some ( Node :: TraitItem ( hir:: TraitItem {
3868
+ node : hir:: TraitItemKind :: Method ( .., hir:: TraitMethod :: Provided ( body_id) ) ,
3869
+ ..
3870
+ } ) ) => {
3871
+ let body = hir. body ( * body_id) ;
3872
+ sugg_call = body. arguments . iter ( )
3873
+ . map ( |arg| match & arg. pat . node {
3874
+ hir:: PatKind :: Binding ( _, _, ident, None )
3875
+ if ident. name != kw:: SelfLower => ident. to_string ( ) ,
3876
+ _ => "_" . to_string ( ) ,
3877
+ } ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
3878
+ }
3879
+ Some ( Node :: Ctor ( hir:: VariantData :: Tuple ( fields, _) ) ) => {
3880
+ sugg_call = fields. iter ( ) . map ( |_| "_" ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
3881
+ match hir. as_local_hir_id ( def_id) . and_then ( |hir_id| hir. def_kind ( hir_id) ) {
3882
+ Some ( hir:: def:: DefKind :: Ctor ( hir:: def:: CtorOf :: Variant , _) ) => {
3883
+ msg = "instantiate this tuple variant" ;
3884
+ }
3885
+ Some ( hir:: def:: DefKind :: Ctor ( hir:: def:: CtorOf :: Struct , _) ) => {
3886
+ msg = "instantiate this tuple struct" ;
3887
+ }
3888
+ _ => { }
3889
+ }
3890
+ }
3891
+ Some ( Node :: ForeignItem ( hir:: ForeignItem {
3892
+ node : hir:: ForeignItemKind :: Fn ( _, idents, _) ,
3893
+ ..
3894
+ } ) ) |
3895
+ Some ( Node :: TraitItem ( hir:: TraitItem {
3896
+ node : hir:: TraitItemKind :: Method ( .., hir:: TraitMethod :: Required ( idents) ) ,
3897
+ ..
3898
+ } ) ) => sugg_call = idents. iter ( )
3899
+ . map ( |ident| if ident. name != kw:: SelfLower {
3900
+ ident. to_string ( )
3901
+ } else {
3902
+ "_" . to_string ( )
3903
+ } ) . collect :: < Vec < _ > > ( )
3904
+ . join ( ", " ) ,
3905
+ _ => { }
3906
+ }
3907
+ } ;
3908
+ if let Ok ( code) = self . sess ( ) . source_map ( ) . span_to_snippet ( expr. span ) {
3909
+ err. span_suggestion (
3910
+ expr. span ,
3911
+ & format ! ( "use parentheses to {}" , msg) ,
3912
+ format ! ( "{}({})" , code, sugg_call) ,
3913
+ applicability,
3914
+ ) ;
3915
+ return true ;
3916
+ }
3917
+ }
3918
+ false
3919
+ }
3920
+
3822
3921
pub fn suggest_ref_or_into (
3823
3922
& self ,
3824
3923
err : & mut DiagnosticBuilder < ' tcx > ,
@@ -3833,6 +3932,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3833
3932
suggestion,
3834
3933
Applicability :: MachineApplicable ,
3835
3934
) ;
3935
+ } else if let ( ty:: FnDef ( def_id, ..) , true ) = (
3936
+ & found. sty ,
3937
+ self . suggest_fn_call ( err, expr, expected, found) ,
3938
+ ) {
3939
+ if let Some ( sp) = self . tcx . hir ( ) . span_if_local ( * def_id) {
3940
+ let sp = self . sess ( ) . source_map ( ) . def_span ( sp) ;
3941
+ err. span_label ( sp, & format ! ( "{} defined here" , found) ) ;
3942
+ }
3836
3943
} else if !self . check_for_cast ( err, expr, found, expected) {
3837
3944
let is_struct_pat_shorthand_field = self . is_hir_id_from_struct_pattern_shorthand_field (
3838
3945
expr. hir_id ,
0 commit comments