@@ -8,15 +8,14 @@ use rustc_hir as hir;
88use rustc_hir:: def:: { CtorOf , DefKind } ;
99use rustc_hir:: lang_items:: LangItem ;
1010use rustc_hir:: {
11- Expr , ExprKind , GenericBound , ItemKind , Node , Path , QPath , Stmt , StmtKind , TyKind ,
12- WherePredicate ,
11+ Expr , ExprKind , GenericBound , Node , Path , QPath , Stmt , StmtKind , TyKind , WherePredicate ,
1312} ;
1413use rustc_infer:: infer:: { self , TyCtxtInferExt } ;
1514use rustc_infer:: traits;
1615use rustc_middle:: lint:: in_external_macro;
1716use rustc_middle:: ty:: subst:: GenericArgKind ;
18- use rustc_middle:: ty:: { self , Binder , IsSuggestable , ToPredicate , Ty } ;
19- use rustc_span:: symbol:: { kw , sym} ;
17+ use rustc_middle:: ty:: { self , Binder , IsSuggestable , Subst , ToPredicate , Ty } ;
18+ use rustc_span:: symbol:: sym;
2019use rustc_span:: Span ;
2120use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
2221
@@ -78,124 +77,88 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7877 expected : Ty < ' tcx > ,
7978 found : Ty < ' tcx > ,
8079 ) -> bool {
81- let hir = self . tcx . hir ( ) ;
82- let ( def_id, sig) = match * found. kind ( ) {
83- ty:: FnDef ( def_id, _) => ( def_id, found. fn_sig ( self . tcx ) ) ,
84- ty:: Closure ( def_id, substs) => ( def_id, substs. as_closure ( ) . sig ( ) ) ,
80+ let ( def_id, output, inputs) = match * found. kind ( ) {
81+ ty:: FnDef ( def_id, _) => {
82+ let fn_sig = found. fn_sig ( self . tcx ) ;
83+ ( def_id, fn_sig. output ( ) , fn_sig. inputs ( ) . skip_binder ( ) . len ( ) )
84+ }
85+ ty:: Closure ( def_id, substs) => {
86+ let fn_sig = substs. as_closure ( ) . sig ( ) ;
87+ ( def_id, fn_sig. output ( ) , fn_sig. inputs ( ) . skip_binder ( ) . len ( ) - 1 )
88+ }
89+ ty:: Opaque ( def_id, substs) => {
90+ let sig = self . tcx . bound_item_bounds ( def_id) . subst ( self . tcx , substs) . iter ( ) . find_map ( |pred| {
91+ if let ty:: PredicateKind :: Projection ( proj) = pred. kind ( ) . skip_binder ( )
92+ && Some ( proj. projection_ty . item_def_id ) == self . tcx . lang_items ( ) . fn_once_output ( )
93+ // args tuple will always be substs[1]
94+ && let ty:: Tuple ( args) = proj. projection_ty . substs . type_at ( 1 ) . kind ( )
95+ {
96+ Some ( (
97+ pred. kind ( ) . rebind ( proj. term . ty ( ) . unwrap ( ) ) ,
98+ args. len ( ) ,
99+ ) )
100+ } else {
101+ None
102+ }
103+ } ) ;
104+ if let Some ( ( output, inputs) ) = sig {
105+ ( def_id, output, inputs)
106+ } else {
107+ return false ;
108+ }
109+ }
85110 _ => return false ,
86111 } ;
87112
88- let sig = self . replace_bound_vars_with_fresh_vars ( expr. span , infer:: FnCall , sig) ;
89- let sig = self . normalize_associated_types_in ( expr. span , sig) ;
90- if self . can_coerce ( sig. output ( ) , expected) {
91- let ( mut sugg_call, applicability) = if sig. inputs ( ) . is_empty ( ) {
92- ( String :: new ( ) , Applicability :: MachineApplicable )
93- } else {
94- ( "..." . to_string ( ) , Applicability :: HasPlaceholders )
113+ let output = self . replace_bound_vars_with_fresh_vars ( expr. span , infer:: FnCall , output) ;
114+ let output = self . normalize_associated_types_in ( expr. span , output) ;
115+ if !output. is_ty_var ( ) && self . can_coerce ( output, expected) {
116+ let ( sugg_call, mut applicability) = match inputs {
117+ 0 => ( "" . to_string ( ) , Applicability :: MachineApplicable ) ,
118+ 1 ..=4 => (
119+ ( 0 ..inputs) . map ( |_| "_" ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ,
120+ Applicability :: MachineApplicable ,
121+ ) ,
122+ _ => ( "..." . to_string ( ) , Applicability :: HasPlaceholders ) ,
95123 } ;
96- let mut msg = "call this function" ;
97- match hir. get_if_local ( def_id) {
98- Some (
99- Node :: Item ( hir:: Item { kind : ItemKind :: Fn ( .., body_id) , .. } )
100- | Node :: ImplItem ( hir:: ImplItem {
101- kind : hir:: ImplItemKind :: Fn ( _, body_id) , ..
102- } )
103- | Node :: TraitItem ( hir:: TraitItem {
104- kind : hir:: TraitItemKind :: Fn ( .., hir:: TraitFn :: Provided ( body_id) ) ,
105- ..
106- } ) ,
107- ) => {
108- let body = hir. body ( * body_id) ;
109- sugg_call = body
110- . params
111- . iter ( )
112- . map ( |param| match & param. pat . kind {
113- hir:: PatKind :: Binding ( _, _, ident, None )
114- if ident. name != kw:: SelfLower =>
115- {
116- ident. to_string ( )
117- }
118- _ => "_" . to_string ( ) ,
119- } )
120- . collect :: < Vec < _ > > ( )
121- . join ( ", " ) ;
122- }
123- Some ( Node :: Expr ( hir:: Expr {
124- kind : ExprKind :: Closure { body : body_id, .. } ,
125- span : full_closure_span,
126- ..
127- } ) ) => {
128- if * full_closure_span == expr. span {
129- return false ;
130- }
131- msg = "call this closure" ;
132- let body = hir. body ( * body_id) ;
133- sugg_call = body
134- . params
135- . iter ( )
136- . map ( |param| match & param. pat . kind {
137- hir:: PatKind :: Binding ( _, _, ident, None )
138- if ident. name != kw:: SelfLower =>
139- {
140- ident. to_string ( )
141- }
142- _ => "_" . to_string ( ) ,
143- } )
144- . collect :: < Vec < _ > > ( )
145- . join ( ", " ) ;
146- }
147- Some ( Node :: Ctor ( hir:: VariantData :: Tuple ( fields, _) ) ) => {
148- sugg_call = fields. iter ( ) . map ( |_| "_" ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
149- match def_id. as_local ( ) . map ( |def_id| self . tcx . def_kind ( def_id) ) {
150- Some ( DefKind :: Ctor ( hir:: def:: CtorOf :: Variant , _) ) => {
151- msg = "instantiate this tuple variant" ;
152- }
153- Some ( DefKind :: Ctor ( CtorOf :: Struct , _) ) => {
154- msg = "instantiate this tuple struct" ;
155- }
156- _ => { }
157- }
124+
125+ let msg = match self . tcx . def_kind ( def_id) {
126+ DefKind :: Fn => "call this function" ,
127+ DefKind :: Closure | DefKind :: OpaqueTy => "call this closure" ,
128+ DefKind :: Ctor ( CtorOf :: Struct , _) => "instantiate this tuple struct" ,
129+ DefKind :: Ctor ( CtorOf :: Variant , _) => "instantiate this tuple variant" ,
130+ _ => "call this function" ,
131+ } ;
132+
133+ let sugg = match expr. kind {
134+ hir:: ExprKind :: Call ( ..)
135+ | hir:: ExprKind :: Path ( ..)
136+ | hir:: ExprKind :: Index ( ..)
137+ | hir:: ExprKind :: Lit ( ..) => {
138+ vec ! [ ( expr. span. shrink_to_hi( ) , format!( "({sugg_call})" ) ) ]
158139 }
159- Some ( Node :: ForeignItem ( hir:: ForeignItem {
160- kind : hir:: ForeignItemKind :: Fn ( _, idents, _) ,
161- ..
162- } ) ) => {
163- sugg_call = idents
164- . iter ( )
165- . map ( |ident| {
166- if ident. name != kw:: SelfLower {
167- ident. to_string ( )
168- } else {
169- "_" . to_string ( )
170- }
171- } )
172- . collect :: < Vec < _ > > ( )
173- . join ( ", " )
140+ hir:: ExprKind :: Closure { .. } => {
141+ // Might be `{ expr } || { bool }`
142+ applicability = Applicability :: MaybeIncorrect ;
143+ vec ! [
144+ ( expr. span. shrink_to_lo( ) , "(" . to_string( ) ) ,
145+ ( expr. span. shrink_to_hi( ) , format!( ")({sugg_call})" ) ) ,
146+ ]
174147 }
175- Some ( Node :: TraitItem ( hir:: TraitItem {
176- kind : hir:: TraitItemKind :: Fn ( .., hir:: TraitFn :: Required ( idents) ) ,
177- ..
178- } ) ) => {
179- sugg_call = idents
180- . iter ( )
181- . map ( |ident| {
182- if ident. name != kw:: SelfLower {
183- ident. to_string ( )
184- } else {
185- "_" . to_string ( )
186- }
187- } )
188- . collect :: < Vec < _ > > ( )
189- . join ( ", " )
148+ _ => {
149+ vec ! [
150+ ( expr. span. shrink_to_lo( ) , "(" . to_string( ) ) ,
151+ ( expr. span. shrink_to_hi( ) , format!( ")({sugg_call})" ) ) ,
152+ ]
190153 }
191- _ => { }
192- }
193- err. span_suggestion_verbose (
194- expr. span . shrink_to_hi ( ) ,
195- & format ! ( "use parentheses to {}" , msg) ,
196- format ! ( "({})" , sugg_call) ,
154+ } ;
155+
156+ err. multipart_suggestion_verbose (
157+ format ! ( "use parentheses to {msg}" ) ,
158+ sugg,
197159 applicability,
198160 ) ;
161+
199162 return true ;
200163 }
201164 false
0 commit comments