@@ -26,7 +26,6 @@ use rustc_middle::ty::{self, RegionVid, Ty};
26
26
use rustc_middle:: ty:: { Region , TyCtxt } ;
27
27
use rustc_span:: symbol:: { kw, Ident } ;
28
28
use rustc_span:: Span ;
29
- use rustc_trait_selection:: infer:: type_variable:: TypeVariableOrigin ;
30
29
use rustc_trait_selection:: infer:: InferCtxtExt ;
31
30
use rustc_trait_selection:: traits:: { Obligation , ObligationCtxt } ;
32
31
@@ -813,7 +812,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
813
812
self . add_static_impl_trait_suggestion ( & mut diag, * fr, fr_name, * outlived_fr) ;
814
813
self . suggest_adding_lifetime_params ( & mut diag, * fr, * outlived_fr) ;
815
814
self . suggest_move_on_borrowing_closure ( & mut diag) ;
816
- self . suggest_deref_closure_value ( & mut diag) ;
815
+ self . suggest_deref_closure_return ( & mut diag) ;
817
816
818
817
diag
819
818
}
@@ -1048,115 +1047,107 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
1048
1047
/// When encountering a lifetime error caused by the return type of a closure, check the
1049
1048
/// corresponding trait bound and see if dereferencing the closure return value would satisfy
1050
1049
/// 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 < ' _ > ) {
1052
1051
let tcx = self . infcx . tcx ;
1053
- let map = tcx. hir ( ) ;
1054
1052
1055
1053
// 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 {
1060
1061
return ;
1061
1062
} ;
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 ( ) ) ;
1068
1080
1069
1081
// 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 ( ) ;
1071
1084
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 ;
1074
1087
count += 1 ;
1075
1088
}
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 ) {
1077
1090
return ;
1078
1091
}
1079
1092
1080
1093
// 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 ( ) ;
1087
1094
let closure_sig_as_fn_ptr_ty = Ty :: new_fn_ptr (
1088
1095
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
+ ) ) ,
1104
1103
) ;
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 (
1111
1105
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 ,
1118
1117
) ;
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 )
1128
1121
else {
1129
1122
return ;
1130
1123
} ;
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
-
1135
1124
// Get the type for the parameter corresponding to the argument the closure with the
1136
1125
// 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
1138
1130
. fn_sig ( method_def_id)
1139
- . instantiate_identity ( )
1131
+ . skip_binder ( )
1140
1132
. inputs ( )
1141
1133
. skip_binder ( )
1142
1134
// 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 )
1144
1136
else {
1145
1137
return ;
1146
1138
} ;
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 } ;
1151
1141
1152
1142
// 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 } ;
1153
1144
let args = GenericArgs :: for_item ( tcx, method_def_id, |param, _| {
1154
1145
if param. index == 0 {
1155
1146
possible_rcvr_ty. into ( )
1156
1147
} else if param. index == closure_param. index {
1157
1148
closure_ty. into ( )
1158
1149
} else {
1159
- self . infcx . var_for_def ( expr . span , param)
1150
+ self . infcx . var_for_def ( parent_expr . span , param)
1160
1151
}
1161
1152
} ) ;
1162
1153
@@ -1170,7 +1161,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
1170
1161
1171
1162
if ocx. select_all_or_error ( ) . is_empty ( ) {
1172
1163
diag. span_suggestion_verbose (
1173
- value. span . shrink_to_lo ( ) ,
1164
+ tcx . hir ( ) . body ( * body ) . value . peel_blocks ( ) . span . shrink_to_lo ( ) ,
1174
1165
"dereference the return value" ,
1175
1166
"*" . repeat ( count) ,
1176
1167
Applicability :: MachineApplicable ,
0 commit comments