]>
Commit | Line | Data |
---|---|---|
3b2f2976 XL |
1 | //! Helper functions corresponding to lifetime errors due to |
2 | //! anonymous regions. | |
b7449926 | 3 | |
9fa01778 XL |
4 | use crate::hir; |
5 | use crate::infer::error_reporting::nice_region_error::NiceRegionError; | |
6 | use crate::ty::{self, Region, Ty}; | |
7 | use crate::hir::def_id::DefId; | |
ea8adc8c | 8 | use syntax_pos::Span; |
3b2f2976 | 9 | |
3b2f2976 XL |
10 | // The struct contains the information about the anonymous region |
11 | // we are searching for. | |
ea8adc8c | 12 | #[derive(Debug)] |
ff7c6d11 | 13 | pub(super) struct AnonymousArgInfo<'tcx> { |
3b2f2976 XL |
14 | // the argument corresponding to the anonymous region |
15 | pub arg: &'tcx hir::Arg, | |
16 | // the type corresponding to the anonymopus region argument | |
ea8adc8c | 17 | pub arg_ty: Ty<'tcx>, |
3b2f2976 XL |
18 | // the ty::BoundRegion corresponding to the anonymous region |
19 | pub bound_region: ty::BoundRegion, | |
b7449926 XL |
20 | // arg_ty_span contains span of argument type |
21 | pub arg_ty_span : Span, | |
3b2f2976 XL |
22 | // corresponds to id the argument is the first parameter |
23 | // in the declaration | |
24 | pub is_first: bool, | |
25 | } | |
26 | ||
ff7c6d11 | 27 | impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { |
3b2f2976 XL |
28 | // This method walks the Type of the function body arguments using |
29 | // `fold_regions()` function and returns the | |
30 | // &hir::Arg of the function argument corresponding to the anonymous | |
31 | // region and the Ty corresponding to the named region. | |
32 | // Currently only the case where the function declaration consists of | |
33 | // one named region and one anonymous region is handled. | |
34 | // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32` | |
35 | // Here, we would return the hir::Arg for y, we return the type &'a | |
36 | // i32, which is the type of y but with the anonymous region replaced | |
37 | // with 'a, the corresponding bound region and is_first which is true if | |
38 | // the hir::Arg is the first argument in the function declaration. | |
ff7c6d11 XL |
39 | pub(super) fn find_arg_with_region( |
40 | &self, | |
41 | anon_region: Region<'tcx>, | |
42 | replace_region: Region<'tcx>, | |
0bf4aa26 | 43 | ) -> Option<AnonymousArgInfo<'_>> { |
ea8adc8c XL |
44 | let (id, bound_region) = match *anon_region { |
45 | ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region), | |
ff7c6d11 | 46 | ty::ReEarlyBound(ref ebr) => ( |
9fa01778 | 47 | self.tcx().parent_def_id(ebr.def_id).unwrap(), |
ff7c6d11 XL |
48 | ty::BoundRegion::BrNamed(ebr.def_id, ebr.name), |
49 | ), | |
ea8adc8c XL |
50 | _ => return None, // not a free region |
51 | }; | |
52 | ||
9fa01778 | 53 | let hir = &self.tcx().hir(); |
ea8adc8c XL |
54 | if let Some(node_id) = hir.as_local_node_id(id) { |
55 | if let Some(body_id) = hir.maybe_body_owned_by(node_id) { | |
56 | let body = hir.body(body_id); | |
b7449926 XL |
57 | let owner_id = hir.body_owner(body_id); |
58 | let fn_decl = hir.fn_decl(owner_id).unwrap(); | |
ff7c6d11 | 59 | if let Some(tables) = self.tables { |
ea8adc8c XL |
60 | body.arguments |
61 | .iter() | |
62 | .enumerate() | |
63 | .filter_map(|(index, arg)| { | |
ff7c6d11 | 64 | // May return None; sometimes the tables are not yet populated. |
b7449926 XL |
65 | let ty_hir_id = fn_decl.inputs[index].hir_id; |
66 | let arg_ty_span = hir.span(hir.hir_to_node_id(ty_hir_id)); | |
9fa01778 | 67 | let ty = tables.node_type_opt(arg.hir_id)?; |
ea8adc8c | 68 | let mut found_anon_region = false; |
9fa01778 | 69 | let new_arg_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| { |
ff7c6d11 | 70 | if *r == *anon_region { |
ea8adc8c XL |
71 | found_anon_region = true; |
72 | replace_region | |
3b2f2976 | 73 | } else { |
ea8adc8c | 74 | r |
ff7c6d11 XL |
75 | } |
76 | }); | |
ea8adc8c XL |
77 | if found_anon_region { |
78 | let is_first = index == 0; | |
79 | Some(AnonymousArgInfo { | |
ff7c6d11 XL |
80 | arg: arg, |
81 | arg_ty: new_arg_ty, | |
b7449926 | 82 | arg_ty_span : arg_ty_span, |
ff7c6d11 XL |
83 | bound_region: bound_region, |
84 | is_first: is_first, | |
85 | }) | |
ea8adc8c XL |
86 | } else { |
87 | None | |
88 | } | |
89 | }) | |
90 | .next() | |
3b2f2976 XL |
91 | } else { |
92 | None | |
93 | } | |
94 | } else { | |
95 | None | |
96 | } | |
97 | } else { | |
98 | None | |
99 | } | |
100 | } | |
101 | ||
3b2f2976 XL |
102 | // Here, we check for the case where the anonymous region |
103 | // is in the return type. | |
104 | // FIXME(#42703) - Need to handle certain cases here. | |
ff7c6d11 XL |
105 | pub(super) fn is_return_type_anon( |
106 | &self, | |
107 | scope_def_id: DefId, | |
108 | br: ty::BoundRegion, | |
109 | decl: &hir::FnDecl, | |
110 | ) -> Option<Span> { | |
9fa01778 | 111 | let ret_ty = self.tcx().type_of(scope_def_id); |
0bf4aa26 | 112 | if let ty::FnDef(_, _) = ret_ty.sty { |
9fa01778 XL |
113 | let sig = ret_ty.fn_sig(self.tcx()); |
114 | let late_bound_regions = self.tcx() | |
0bf4aa26 XL |
115 | .collect_referenced_late_bound_regions(&sig.output()); |
116 | if late_bound_regions.iter().any(|r| *r == br) { | |
117 | return Some(decl.output.span()); | |
3b2f2976 | 118 | } |
3b2f2976 | 119 | } |
ea8adc8c | 120 | None |
3b2f2976 | 121 | } |
8faf50e0 | 122 | |
3b2f2976 XL |
123 | // Here we check for the case where anonymous region |
124 | // corresponds to self and if yes, we display E0312. | |
125 | // FIXME(#42700) - Need to format self properly to | |
126 | // enable E0621 for it. | |
ff7c6d11 XL |
127 | pub(super) fn is_self_anon(&self, is_first: bool, scope_def_id: DefId) -> bool { |
128 | is_first | |
9fa01778 | 129 | && self.tcx() |
0bf4aa26 XL |
130 | .opt_associated_item(scope_def_id) |
131 | .map(|i| i.method_has_self_argument) == Some(true) | |
3b2f2976 XL |
132 | } |
133 | ||
3b2f2976 | 134 | } |