@@ -26,7 +26,6 @@ use rustc_middle::ty::{self, RegionVid, Ty};
2626use rustc_middle:: ty:: { Region , TyCtxt } ;
2727use rustc_span:: symbol:: { kw, Ident } ;
2828use rustc_span:: Span ;
29- use rustc_trait_selection:: infer:: type_variable:: TypeVariableOrigin ;
3029use rustc_trait_selection:: infer:: InferCtxtExt ;
3130use rustc_trait_selection:: traits:: { Obligation , ObligationCtxt } ;
3231
@@ -813,7 +812,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
813812 self . add_static_impl_trait_suggestion ( & mut diag, * fr, fr_name, * outlived_fr) ;
814813 self . suggest_adding_lifetime_params ( & mut diag, * fr, * outlived_fr) ;
815814 self . suggest_move_on_borrowing_closure ( & mut diag) ;
816- self . suggest_deref_closure_value ( & mut diag) ;
815+ self . suggest_deref_closure_return ( & mut diag) ;
817816
818817 diag
819818 }
@@ -1048,115 +1047,107 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
10481047 /// When encountering a lifetime error caused by the return type of a closure, check the
10491048 /// corresponding trait bound and see if dereferencing the closure return value would satisfy
10501049 /// them. If so, we produce a structured suggestion.
1051- fn suggest_deref_closure_value ( & self , diag : & mut Diag < ' _ > ) {
1050+ fn suggest_deref_closure_return ( & self , diag : & mut Diag < ' _ > ) {
10521051 let tcx = self . infcx . tcx ;
1053- let map = tcx. hir ( ) ;
10541052
10551053 // Get the closure return value and type.
1056- let body_id = map. body_owned_by ( self . mir_def_id ( ) ) ;
1057- let body = & map. body ( body_id) ;
1058- let value = & body. value . peel_blocks ( ) ;
1059- let hir:: Node :: Expr ( closure_expr) = tcx. hir_node_by_def_id ( self . mir_def_id ( ) ) else {
1054+ let closure_def_id = self . mir_def_id ( ) ;
1055+ let hir:: Node :: Expr (
1056+ closure_expr @ hir:: Expr {
1057+ kind : hir:: ExprKind :: Closure ( hir:: Closure { body, .. } ) , ..
1058+ } ,
1059+ ) = tcx. hir_node_by_def_id ( closure_def_id)
1060+ else {
10601061 return ;
10611062 } ;
1062- let fn_call_id = tcx. parent_hir_id ( self . mir_hir_id ( ) ) ;
1063- let hir:: Node :: Expr ( expr) = tcx. hir_node ( fn_call_id) else { return } ;
1064- let def_id = map. enclosing_body_owner ( fn_call_id) ;
1065- let tables = tcx. typeck ( def_id) ;
1066- let Some ( return_value_ty) = tables. node_type_opt ( value. hir_id ) else { return } ;
1067- let return_value_ty = self . infcx . resolve_vars_if_possible ( return_value_ty) ;
1063+ let ty:: Closure ( _, args) = * tcx. type_of ( closure_def_id) . instantiate_identity ( ) . kind ( )
1064+ else {
1065+ return ;
1066+ } ;
1067+ let args = args. as_closure ( ) ;
1068+
1069+ // Make sure that the parent expression is a method call.
1070+ let parent_expr_id = tcx. parent_hir_id ( self . mir_hir_id ( ) ) ;
1071+ let hir:: Node :: Expr (
1072+ parent_expr @ hir:: Expr {
1073+ kind : hir:: ExprKind :: MethodCall ( _, rcvr, call_args, _) , ..
1074+ } ,
1075+ ) = tcx. hir_node ( parent_expr_id)
1076+ else {
1077+ return ;
1078+ } ;
1079+ let typeck_results = tcx. typeck ( self . mir_def_id ( ) ) ;
10681080
10691081 // We don't use `ty.peel_refs()` to get the number of `*`s needed to get the root type.
1070- let mut ty = return_value_ty;
1082+ let liberated_sig = tcx. liberate_late_bound_regions ( closure_def_id. to_def_id ( ) , args. sig ( ) ) ;
1083+ let mut peeled_ty = liberated_sig. output ( ) ;
10711084 let mut count = 0 ;
1072- while let ty:: Ref ( _, t , _) = ty . kind ( ) {
1073- ty = * t ;
1085+ while let ty:: Ref ( _, ref_ty , _) = * peeled_ty . kind ( ) {
1086+ peeled_ty = ref_ty ;
10741087 count += 1 ;
10751088 }
1076- if !self . infcx . type_is_copy_modulo_regions ( self . param_env , ty ) {
1089+ if !self . infcx . type_is_copy_modulo_regions ( self . param_env , peeled_ty ) {
10771090 return ;
10781091 }
10791092
10801093 // Build a new closure where the return type is an owned value, instead of a ref.
1081- let Some ( ty:: Closure ( did, args) ) =
1082- tables. node_type_opt ( closure_expr. hir_id ) . as_ref ( ) . map ( |ty| ty. kind ( ) )
1083- else {
1084- return ;
1085- } ;
1086- let sig = args. as_closure ( ) . sig ( ) ;
10871094 let closure_sig_as_fn_ptr_ty = Ty :: new_fn_ptr (
10881095 tcx,
1089- sig. map_bound ( |s| {
1090- let unsafety = hir:: Unsafety :: Normal ;
1091- use rustc_target:: spec:: abi;
1092- tcx. mk_fn_sig (
1093- [ s. inputs ( ) [ 0 ] ] ,
1094- s. output ( ) . peel_refs ( ) ,
1095- s. c_variadic ,
1096- unsafety,
1097- abi:: Abi :: Rust ,
1098- )
1099- } ) ,
1100- ) ;
1101- let parent_args = GenericArgs :: identity_for_item (
1102- tcx,
1103- tcx. typeck_root_def_id ( self . mir_def_id ( ) . to_def_id ( ) ) ,
1096+ ty:: Binder :: dummy ( tcx. mk_fn_sig (
1097+ liberated_sig. inputs ( ) . iter ( ) . copied ( ) ,
1098+ peeled_ty,
1099+ liberated_sig. c_variadic ,
1100+ hir:: Unsafety :: Normal ,
1101+ rustc_target:: spec:: abi:: Abi :: Rust ,
1102+ ) ) ,
11041103 ) ;
1105- let closure_kind = args. as_closure ( ) . kind ( ) ;
1106- let closure_kind_ty = Ty :: from_closure_kind ( tcx, closure_kind) ;
1107- let tupled_upvars_ty = self
1108- . infcx
1109- . next_ty_var ( TypeVariableOrigin { param_def_id : None , span : closure_expr. span } ) ;
1110- let closure_args = ty:: ClosureArgs :: new (
1104+ let closure_ty = Ty :: new_closure (
11111105 tcx,
1112- ty:: ClosureArgsParts {
1113- parent_args,
1114- closure_kind_ty,
1115- closure_sig_as_fn_ptr_ty,
1116- tupled_upvars_ty,
1117- } ,
1106+ closure_def_id. to_def_id ( ) ,
1107+ ty:: ClosureArgs :: new (
1108+ tcx,
1109+ ty:: ClosureArgsParts {
1110+ parent_args : args. parent_args ( ) ,
1111+ closure_kind_ty : args. kind_ty ( ) ,
1112+ tupled_upvars_ty : args. tupled_upvars_ty ( ) ,
1113+ closure_sig_as_fn_ptr_ty,
1114+ } ,
1115+ )
1116+ . args ,
11181117 ) ;
1119- let closure_ty = Ty :: new_closure ( tcx, * did, closure_args. args ) ;
1120- let closure_ty = tcx. erase_regions ( closure_ty) ;
1121-
1122- let hir:: ExprKind :: MethodCall ( _, rcvr, args, _) = expr. kind else { return } ;
1123- let Some ( pos) = args
1124- . iter ( )
1125- . enumerate ( )
1126- . find ( |( _, arg) | arg. hir_id == closure_expr. hir_id )
1127- . map ( |( i, _) | i)
1118+
1119+ let Some ( ( closure_arg_pos, _) ) =
1120+ call_args. iter ( ) . enumerate ( ) . find ( |( _, arg) | arg. hir_id == closure_expr. hir_id )
11281121 else {
11291122 return ;
11301123 } ;
1131- // The found `Self` type of the method call.
1132- let Some ( possible_rcvr_ty) = tables. node_type_opt ( rcvr. hir_id ) else { return } ;
1133- let Some ( method_def_id) = tables. type_dependent_def_id ( expr. hir_id ) else { return } ;
1134-
11351124 // Get the type for the parameter corresponding to the argument the closure with the
11361125 // lifetime error we had.
1137- let Some ( input) = tcx
1126+ let Some ( method_def_id) = typeck_results. type_dependent_def_id ( parent_expr. hir_id ) else {
1127+ return ;
1128+ } ;
1129+ let Some ( input_arg) = tcx
11381130 . fn_sig ( method_def_id)
1139- . instantiate_identity ( )
1131+ . skip_binder ( )
11401132 . inputs ( )
11411133 . skip_binder ( )
11421134 // Methods have a `self` arg, so `pos` is actually `+ 1` to match the method call arg.
1143- . get ( pos + 1 )
1135+ . get ( closure_arg_pos + 1 )
11441136 else {
11451137 return ;
11461138 } ;
1147-
1148- trace ! ( ?input) ;
1149-
1150- let ty:: Param ( closure_param) = input. kind ( ) else { return } ;
1139+ // If this isn't a param, then we can't substitute a new closure.
1140+ let ty:: Param ( closure_param) = input_arg. kind ( ) else { return } ;
11511141
11521142 // Get the arguments for the found method, only specifying that `Self` is the receiver type.
1143+ let Some ( possible_rcvr_ty) = typeck_results. node_type_opt ( rcvr. hir_id ) else { return } ;
11531144 let args = GenericArgs :: for_item ( tcx, method_def_id, |param, _| {
11541145 if param. index == 0 {
11551146 possible_rcvr_ty. into ( )
11561147 } else if param. index == closure_param. index {
11571148 closure_ty. into ( )
11581149 } else {
1159- self . infcx . var_for_def ( expr . span , param)
1150+ self . infcx . var_for_def ( parent_expr . span , param)
11601151 }
11611152 } ) ;
11621153
@@ -1170,7 +1161,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
11701161
11711162 if ocx. select_all_or_error ( ) . is_empty ( ) {
11721163 diag. span_suggestion_verbose (
1173- value. span . shrink_to_lo ( ) ,
1164+ tcx . hir ( ) . body ( * body ) . value . peel_blocks ( ) . span . shrink_to_lo ( ) ,
11741165 "dereference the return value" ,
11751166 "*" . repeat ( count) ,
11761167 Applicability :: MachineApplicable ,
0 commit comments