]>
Commit | Line | Data |
---|---|---|
3b2f2976 XL |
1 | //! Helper functions corresponding to lifetime errors due to |
2 | //! anonymous regions. | |
b7449926 | 3 | |
9fa01778 | 4 | use crate::infer::error_reporting::nice_region_error::NiceRegionError; |
04454e1e | 5 | use crate::infer::TyCtxt; |
dfeec247 | 6 | use rustc_hir as hir; |
f035d41b | 7 | use rustc_hir::def_id::LocalDefId; |
353b0b11 | 8 | use rustc_middle::ty::{self, Binder, Region, Ty, TypeVisitable}; |
dfeec247 | 9 | use rustc_span::Span; |
3b2f2976 | 10 | |
3dfed10e | 11 | /// Information about the anonymous region we are searching for. |
ea8adc8c | 12 | #[derive(Debug)] |
04454e1e | 13 | pub struct AnonymousParamInfo<'tcx> { |
3dfed10e | 14 | /// The parameter corresponding to the anonymous region. |
dfeec247 | 15 | pub param: &'tcx hir::Param<'tcx>, |
3dfed10e | 16 | /// The type corresponding to the anonymous region parameter. |
e1599b0c | 17 | pub param_ty: Ty<'tcx>, |
fc512014 XL |
18 | /// The ty::BoundRegionKind corresponding to the anonymous region. |
19 | pub bound_region: ty::BoundRegionKind, | |
3dfed10e | 20 | /// The `Span` of the parameter type. |
dfeec247 | 21 | pub param_ty_span: Span, |
3dfed10e | 22 | /// Signals that the argument is the first parameter in the declaration. |
3b2f2976 XL |
23 | pub is_first: bool, |
24 | } | |
25 | ||
04454e1e FG |
26 | // This method walks the Type of the function body parameters using |
27 | // `fold_regions()` function and returns the | |
28 | // &hir::Param of the function parameter corresponding to the anonymous | |
29 | // region and the Ty corresponding to the named region. | |
30 | // Currently only the case where the function declaration consists of | |
31 | // one named region and one anonymous region is handled. | |
32 | // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32` | |
33 | // Here, we would return the hir::Param for y, we return the type &'a | |
34 | // i32, which is the type of y but with the anonymous region replaced | |
35 | // with 'a, the corresponding bound region and is_first which is true if | |
36 | // the hir::Param is the first parameter in the function declaration. | |
923072b8 | 37 | #[instrument(skip(tcx), level = "debug")] |
04454e1e FG |
38 | pub fn find_param_with_region<'tcx>( |
39 | tcx: TyCtxt<'tcx>, | |
40 | anon_region: Region<'tcx>, | |
41 | replace_region: Region<'tcx>, | |
42 | ) -> Option<AnonymousParamInfo<'tcx>> { | |
43 | let (id, bound_region) = match *anon_region { | |
44 | ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region), | |
45 | ty::ReEarlyBound(ebr) => { | |
46 | (tcx.parent(ebr.def_id), ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name)) | |
47 | } | |
48 | _ => return None, // not a free region | |
49 | }; | |
50 | ||
51 | let hir = &tcx.hir(); | |
064997fb FG |
52 | let def_id = id.as_local()?; |
53 | let hir_id = hir.local_def_id_to_hir_id(def_id); | |
923072b8 | 54 | |
064997fb | 55 | // FIXME: use def_kind |
923072b8 FG |
56 | // Don't perform this on closures |
57 | match hir.get(hir_id) { | |
58 | hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { | |
59 | return None; | |
60 | } | |
61 | _ => {} | |
62 | } | |
63 | ||
064997fb FG |
64 | let body_id = hir.maybe_body_owned_by(def_id)?; |
65 | ||
04454e1e | 66 | let owner_id = hir.body_owner(body_id); |
add651ee FG |
67 | let fn_decl = hir.fn_decl_by_hir_id(owner_id)?; |
68 | let poly_fn_sig = tcx.fn_sig(id).instantiate_identity(); | |
923072b8 | 69 | |
04454e1e | 70 | let fn_sig = tcx.liberate_late_bound_regions(id, poly_fn_sig); |
064997fb | 71 | let body = hir.body(body_id); |
04454e1e FG |
72 | body.params |
73 | .iter() | |
74 | .take(if fn_sig.c_variadic { | |
75 | fn_sig.inputs().len() | |
76 | } else { | |
77 | assert_eq!(fn_sig.inputs().len(), body.params.len()); | |
78 | body.params.len() | |
79 | }) | |
80 | .enumerate() | |
81 | .find_map(|(index, param)| { | |
82 | // May return None; sometimes the tables are not yet populated. | |
83 | let ty = fn_sig.inputs()[index]; | |
84 | let mut found_anon_region = false; | |
064997fb | 85 | let new_param_ty = tcx.fold_regions(ty, |r, _| { |
04454e1e FG |
86 | if r == anon_region { |
87 | found_anon_region = true; | |
88 | replace_region | |
89 | } else { | |
90 | r | |
91 | } | |
92 | }); | |
9ffffee4 | 93 | found_anon_region.then(|| { |
04454e1e FG |
94 | let ty_hir_id = fn_decl.inputs[index].hir_id; |
95 | let param_ty_span = hir.span(ty_hir_id); | |
96 | let is_first = index == 0; | |
9ffffee4 | 97 | AnonymousParamInfo { |
04454e1e FG |
98 | param, |
99 | param_ty: new_param_ty, | |
100 | param_ty_span, | |
101 | bound_region, | |
102 | is_first, | |
9ffffee4 FG |
103 | } |
104 | }) | |
04454e1e FG |
105 | }) |
106 | } | |
107 | ||
dc9dc135 | 108 | impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { |
e1599b0c | 109 | pub(super) fn find_param_with_region( |
ff7c6d11 XL |
110 | &self, |
111 | anon_region: Region<'tcx>, | |
112 | replace_region: Region<'tcx>, | |
923072b8 | 113 | ) -> Option<AnonymousParamInfo<'tcx>> { |
04454e1e | 114 | find_param_with_region(self.tcx(), anon_region, replace_region) |
3b2f2976 XL |
115 | } |
116 | ||
3b2f2976 | 117 | // Here, we check for the case where the anonymous region |
5099ac24 | 118 | // is in the return type as written by the user. |
3b2f2976 | 119 | // FIXME(#42703) - Need to handle certain cases here. |
ff7c6d11 XL |
120 | pub(super) fn is_return_type_anon( |
121 | &self, | |
f035d41b | 122 | scope_def_id: LocalDefId, |
fc512014 | 123 | br: ty::BoundRegionKind, |
5099ac24 | 124 | hir_sig: &hir::FnSig<'_>, |
ff7c6d11 | 125 | ) -> Option<Span> { |
add651ee | 126 | let fn_ty = self.tcx().type_of(scope_def_id).instantiate_identity(); |
5099ac24 FG |
127 | if let ty::FnDef(_, _) = fn_ty.kind() { |
128 | let ret_ty = fn_ty.fn_sig(self.tcx()).output(); | |
129 | let span = hir_sig.decl.output.span(); | |
130 | let future_output = if hir_sig.header.is_async() { | |
2b03887a | 131 | ret_ty.map_bound(|ty| self.cx.get_impl_future_output_ty(ty)).transpose() |
5099ac24 FG |
132 | } else { |
133 | None | |
134 | }; | |
135 | return match future_output { | |
136 | Some(output) if self.includes_region(output, br) => Some(span), | |
137 | None if self.includes_region(ret_ty, br) => Some(span), | |
138 | _ => None, | |
139 | }; | |
3b2f2976 | 140 | } |
ea8adc8c | 141 | None |
3b2f2976 | 142 | } |
8faf50e0 | 143 | |
5099ac24 FG |
144 | fn includes_region( |
145 | &self, | |
9ffffee4 | 146 | ty: Binder<'tcx, impl TypeVisitable<TyCtxt<'tcx>>>, |
5099ac24 FG |
147 | region: ty::BoundRegionKind, |
148 | ) -> bool { | |
149 | let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&ty); | |
487cf647 FG |
150 | // We are only checking is any region meets the condition so order doesn't matter |
151 | #[allow(rustc::potential_query_instability)] | |
5099ac24 FG |
152 | late_bound_regions.iter().any(|r| *r == region) |
153 | } | |
154 | ||
3b2f2976 XL |
155 | // Here we check for the case where anonymous region |
156 | // corresponds to self and if yes, we display E0312. | |
157 | // FIXME(#42700) - Need to format self properly to | |
158 | // enable E0621 for it. | |
f035d41b | 159 | pub(super) fn is_self_anon(&self, is_first: bool, scope_def_id: LocalDefId) -> bool { |
ff7c6d11 | 160 | is_first |
f035d41b XL |
161 | && self |
162 | .tcx() | |
163 | .opt_associated_item(scope_def_id.to_def_id()) | |
164 | .map(|i| i.fn_has_self_parameter) | |
dfeec247 | 165 | == Some(true) |
3b2f2976 | 166 | } |
3b2f2976 | 167 | } |