Skip to content

Commit 00838b3

Browse files
Make suggest_deref_closure_return more idiomatic/easier to understand
1 parent 63f70b3 commit 00838b3

File tree

1 file changed

+64
-73
lines changed

1 file changed

+64
-73
lines changed

compiler/rustc_borrowck/src/diagnostics/region_errors.rs

+64-73
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ use rustc_middle::ty::{self, RegionVid, Ty};
2626
use rustc_middle::ty::{Region, TyCtxt};
2727
use rustc_span::symbol::{kw, Ident};
2828
use rustc_span::Span;
29-
use rustc_trait_selection::infer::type_variable::TypeVariableOrigin;
3029
use rustc_trait_selection::infer::InferCtxtExt;
3130
use 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

Comments
 (0)