]>
Commit | Line | Data |
---|---|---|
8faf50e0 XL |
1 | // Copyright 2017 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use borrow_check::nll::region_infer::RegionInferenceContext; | |
b7449926 | 12 | use borrow_check::nll::universal_regions::DefiningTy; |
8faf50e0 XL |
13 | use borrow_check::nll::ToRegionVid; |
14 | use rustc::hir; | |
15 | use rustc::hir::def_id::DefId; | |
16 | use rustc::infer::InferCtxt; | |
17 | use rustc::mir::Mir; | |
18 | use rustc::ty::subst::{Substs, UnpackedKind}; | |
b7449926 | 19 | use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt}; |
8faf50e0 XL |
20 | use rustc::util::ppaux::with_highlight_region; |
21 | use rustc_errors::DiagnosticBuilder; | |
b7449926 | 22 | use syntax::ast::{Name, DUMMY_NODE_ID}; |
8faf50e0 XL |
23 | use syntax::symbol::keywords; |
24 | use syntax_pos::symbol::InternedString; | |
25 | ||
26 | impl<'tcx> RegionInferenceContext<'tcx> { | |
27 | /// Maps from an internal MIR region vid to something that we can | |
28 | /// report to the user. In some cases, the region vids will map | |
29 | /// directly to lifetimes that the user has a name for (e.g., | |
30 | /// `'static`). But frequently they will not, in which case we | |
31 | /// have to find some way to identify the lifetime to the user. To | |
32 | /// that end, this function takes a "diagnostic" so that it can | |
33 | /// create auxiliary notes as needed. | |
34 | /// | |
35 | /// Example (function arguments): | |
36 | /// | |
37 | /// Suppose we are trying to give a name to the lifetime of the | |
38 | /// reference `x`: | |
39 | /// | |
40 | /// ``` | |
41 | /// fn foo(x: &u32) { .. } | |
42 | /// ``` | |
43 | /// | |
44 | /// This function would create a label like this: | |
45 | /// | |
46 | /// ``` | |
47 | /// | fn foo(x: &u32) { .. } | |
48 | /// ------- fully elaborated type of `x` is `&'1 u32` | |
49 | /// ``` | |
50 | /// | |
51 | /// and then return the name `'1` for us to use. | |
52 | crate fn give_region_a_name( | |
53 | &self, | |
54 | infcx: &InferCtxt<'_, '_, 'tcx>, | |
55 | mir: &Mir<'tcx>, | |
56 | mir_def_id: DefId, | |
57 | fr: RegionVid, | |
58 | counter: &mut usize, | |
59 | diag: &mut DiagnosticBuilder, | |
60 | ) -> InternedString { | |
61 | debug!("give_region_a_name(fr={:?}, counter={})", fr, counter); | |
62 | ||
63 | assert!(self.universal_regions.is_universal_region(fr)); | |
64 | ||
b7449926 | 65 | let value = self.give_name_from_error_region(infcx.tcx, mir_def_id, fr, counter, diag) |
8faf50e0 XL |
66 | .or_else(|| { |
67 | self.give_name_if_anonymous_region_appears_in_arguments( | |
b7449926 XL |
68 | infcx, mir, mir_def_id, fr, counter, diag, |
69 | ) | |
8faf50e0 XL |
70 | }) |
71 | .or_else(|| { | |
72 | self.give_name_if_anonymous_region_appears_in_upvars( | |
b7449926 XL |
73 | infcx.tcx, mir, fr, counter, diag, |
74 | ) | |
8faf50e0 XL |
75 | }) |
76 | .or_else(|| { | |
77 | self.give_name_if_anonymous_region_appears_in_output( | |
b7449926 XL |
78 | infcx, mir, mir_def_id, fr, counter, diag, |
79 | ) | |
8faf50e0 | 80 | }) |
b7449926 XL |
81 | .unwrap_or_else(|| span_bug!(mir.span, "can't make a name for free region {:?}", fr)); |
82 | ||
83 | debug!("give_region_a_name: gave name {:?}", value); | |
84 | value | |
8faf50e0 XL |
85 | } |
86 | ||
87 | /// Check for the case where `fr` maps to something that the | |
88 | /// *user* has a name for. In that case, we'll be able to map | |
89 | /// `fr` to a `Region<'tcx>`, and that region will be one of | |
90 | /// named variants. | |
91 | fn give_name_from_error_region( | |
92 | &self, | |
93 | tcx: TyCtxt<'_, '_, 'tcx>, | |
94 | mir_def_id: DefId, | |
95 | fr: RegionVid, | |
96 | counter: &mut usize, | |
97 | diag: &mut DiagnosticBuilder<'_>, | |
98 | ) -> Option<InternedString> { | |
99 | let error_region = self.to_error_region(fr)?; | |
b7449926 | 100 | |
8faf50e0 XL |
101 | debug!("give_region_a_name: error_region = {:?}", error_region); |
102 | match error_region { | |
b7449926 XL |
103 | ty::ReEarlyBound(ebr) => { |
104 | if ebr.has_name() { | |
105 | self.highlight_named_span(tcx, error_region, &ebr.name, diag); | |
106 | Some(ebr.name) | |
107 | } else { | |
108 | None | |
109 | } | |
110 | } | |
8faf50e0 XL |
111 | |
112 | ty::ReStatic => Some(keywords::StaticLifetime.name().as_interned_str()), | |
113 | ||
114 | ty::ReFree(free_region) => match free_region.bound_region { | |
b7449926 XL |
115 | ty::BoundRegion::BrNamed(_, name) => { |
116 | self.highlight_named_span(tcx, error_region, &name, diag); | |
117 | Some(name) | |
118 | } | |
8faf50e0 XL |
119 | |
120 | ty::BoundRegion::BrEnv => { | |
b7449926 XL |
121 | let mir_node_id = tcx.hir.as_local_node_id(mir_def_id).expect("non-local mir"); |
122 | let def_ty = self.universal_regions.defining_ty; | |
123 | ||
124 | if let DefiningTy::Closure(def_id, substs) = def_ty { | |
125 | let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) = | |
126 | tcx.hir.expect_expr(mir_node_id).node | |
127 | { | |
128 | span | |
129 | } else { | |
130 | bug!("Closure is not defined by a closure expr"); | |
131 | }; | |
132 | let region_name = self.synthesize_region_name(counter); | |
133 | diag.span_label( | |
134 | args_span, | |
135 | format!("lifetime `{}` represents this closure's body", region_name), | |
136 | ); | |
137 | ||
138 | let closure_kind_ty = substs.closure_kind_ty(def_id, tcx); | |
139 | let note = match closure_kind_ty.to_opt_closure_kind() { | |
140 | Some(ty::ClosureKind::Fn) => { | |
141 | "closure implements `Fn`, so references to captured variables \ | |
142 | can't escape the closure" | |
143 | } | |
144 | Some(ty::ClosureKind::FnMut) => { | |
145 | "closure implements `FnMut`, so references to captured variables \ | |
146 | can't escape the closure" | |
147 | } | |
148 | Some(ty::ClosureKind::FnOnce) => { | |
149 | bug!("BrEnv in a `FnOnce` closure"); | |
150 | } | |
151 | None => bug!("Closure kind not inferred in borrow check"), | |
152 | }; | |
153 | ||
154 | diag.note(note); | |
155 | ||
156 | Some(region_name) | |
157 | } else { | |
158 | // Can't have BrEnv in functions, constants or generators. | |
159 | bug!("BrEnv outside of closure."); | |
160 | } | |
8faf50e0 XL |
161 | } |
162 | ||
163 | ty::BoundRegion::BrAnon(_) | ty::BoundRegion::BrFresh(_) => None, | |
164 | }, | |
165 | ||
166 | ty::ReLateBound(..) | |
167 | | ty::ReScope(..) | |
168 | | ty::ReVar(..) | |
169 | | ty::ReSkolemized(..) | |
170 | | ty::ReEmpty | |
171 | | ty::ReErased | |
172 | | ty::ReClosureBound(..) | |
173 | | ty::ReCanonical(..) => None, | |
174 | } | |
175 | } | |
176 | ||
b7449926 XL |
177 | /// Highlight a named span to provide context for error messages that |
178 | /// mention that span, for example: | |
179 | /// | |
180 | /// ``` | |
181 | /// | | |
182 | /// | fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T) | |
183 | /// | -- -- lifetime `'b` defined here | |
184 | /// | | | |
185 | /// | lifetime `'a` defined here | |
186 | /// | | |
187 | /// | with_signature(cell, t, |cell, t| require(cell, t)); | |
188 | /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must | |
189 | /// | outlive `'a` | |
190 | /// ``` | |
191 | fn highlight_named_span( | |
192 | &self, | |
193 | tcx: TyCtxt<'_, '_, 'tcx>, | |
194 | error_region: &RegionKind, | |
195 | name: &InternedString, | |
196 | diag: &mut DiagnosticBuilder<'_>, | |
197 | ) { | |
198 | let cm = tcx.sess.source_map(); | |
199 | ||
200 | let scope = error_region.free_region_binding_scope(tcx); | |
201 | let node = tcx.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID); | |
202 | ||
203 | let mut sp = cm.def_span(tcx.hir.span(node)); | |
204 | if let Some(param) = tcx.hir | |
205 | .get_generics(scope) | |
206 | .and_then(|generics| generics.get_named(name)) | |
207 | { | |
208 | sp = param.span; | |
209 | } | |
210 | ||
211 | diag.span_label(sp, format!("lifetime `{}` defined here", name)); | |
212 | } | |
213 | ||
8faf50e0 XL |
214 | /// Find an argument that contains `fr` and label it with a fully |
215 | /// elaborated type, returning something like `'1`. Result looks | |
216 | /// like: | |
217 | /// | |
218 | /// ``` | |
219 | /// | fn foo(x: &u32) { .. } | |
220 | /// ------- fully elaborated type of `x` is `&'1 u32` | |
221 | /// ``` | |
222 | fn give_name_if_anonymous_region_appears_in_arguments( | |
223 | &self, | |
224 | infcx: &InferCtxt<'_, '_, 'tcx>, | |
225 | mir: &Mir<'tcx>, | |
226 | mir_def_id: DefId, | |
227 | fr: RegionVid, | |
228 | counter: &mut usize, | |
229 | diag: &mut DiagnosticBuilder<'_>, | |
230 | ) -> Option<InternedString> { | |
231 | let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs(); | |
232 | let argument_index = self.get_argument_index_for_region(infcx.tcx, fr)?; | |
233 | ||
234 | let arg_ty = | |
235 | self.universal_regions.unnormalized_input_tys[implicit_inputs + argument_index]; | |
236 | if let Some(region_name) = self.give_name_if_we_can_match_hir_ty_from_argument( | |
237 | infcx, | |
238 | mir, | |
239 | mir_def_id, | |
240 | fr, | |
241 | arg_ty, | |
242 | argument_index, | |
243 | counter, | |
244 | diag, | |
245 | ) { | |
246 | return Some(region_name); | |
247 | } | |
248 | ||
b7449926 | 249 | self.give_name_if_we_cannot_match_hir_ty(infcx, mir, fr, arg_ty, counter, diag) |
8faf50e0 XL |
250 | } |
251 | ||
252 | fn give_name_if_we_can_match_hir_ty_from_argument( | |
253 | &self, | |
254 | infcx: &InferCtxt<'_, '_, 'tcx>, | |
255 | mir: &Mir<'tcx>, | |
256 | mir_def_id: DefId, | |
257 | needle_fr: RegionVid, | |
258 | argument_ty: Ty<'tcx>, | |
259 | argument_index: usize, | |
260 | counter: &mut usize, | |
261 | diag: &mut DiagnosticBuilder<'_>, | |
262 | ) -> Option<InternedString> { | |
263 | let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id)?; | |
264 | let fn_decl = infcx.tcx.hir.fn_decl(mir_node_id)?; | |
265 | let argument_hir_ty: &hir::Ty = &fn_decl.inputs[argument_index]; | |
266 | match argument_hir_ty.node { | |
267 | // This indicates a variable with no type annotation, like | |
268 | // `|x|`... in that case, we can't highlight the type but | |
269 | // must highlight the variable. | |
270 | hir::TyKind::Infer => self.give_name_if_we_cannot_match_hir_ty( | |
271 | infcx, | |
272 | mir, | |
273 | needle_fr, | |
274 | argument_ty, | |
275 | counter, | |
276 | diag, | |
277 | ), | |
278 | ||
279 | _ => self.give_name_if_we_can_match_hir_ty( | |
280 | infcx.tcx, | |
281 | needle_fr, | |
282 | argument_ty, | |
283 | argument_hir_ty, | |
284 | counter, | |
285 | diag, | |
286 | ), | |
287 | } | |
288 | } | |
289 | ||
290 | /// Attempts to highlight the specific part of a type in an argument | |
291 | /// that has no type annotation. | |
292 | /// For example, we might produce an annotation like this: | |
293 | /// | |
294 | /// ``` | |
295 | /// | foo(|a, b| b) | |
296 | /// | - - | |
297 | /// | | | | |
298 | /// | | has type `&'1 u32` | |
299 | /// | has type `&'2 u32` | |
300 | /// ``` | |
301 | fn give_name_if_we_cannot_match_hir_ty( | |
302 | &self, | |
303 | infcx: &InferCtxt<'_, '_, 'tcx>, | |
304 | mir: &Mir<'tcx>, | |
305 | needle_fr: RegionVid, | |
306 | argument_ty: Ty<'tcx>, | |
307 | counter: &mut usize, | |
308 | diag: &mut DiagnosticBuilder<'_>, | |
309 | ) -> Option<InternedString> { | |
310 | let type_name = with_highlight_region(needle_fr, *counter, || { | |
311 | infcx.extract_type_name(&argument_ty) | |
312 | }); | |
313 | ||
b7449926 XL |
314 | debug!( |
315 | "give_name_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", | |
316 | type_name, needle_fr | |
317 | ); | |
8faf50e0 XL |
318 | let assigned_region_name = if type_name.find(&format!("'{}", counter)).is_some() { |
319 | // Only add a label if we can confirm that a region was labelled. | |
320 | let argument_index = self.get_argument_index_for_region(infcx.tcx, needle_fr)?; | |
321 | let (_, span) = self.get_argument_name_and_span_for_region(mir, argument_index); | |
322 | diag.span_label(span, format!("has type `{}`", type_name)); | |
323 | ||
324 | // This counter value will already have been used, so this function will increment it | |
325 | // so the next value will be used next and return the region name that would have been | |
326 | // used. | |
327 | Some(self.synthesize_region_name(counter)) | |
328 | } else { | |
329 | None | |
330 | }; | |
331 | ||
332 | assigned_region_name | |
333 | } | |
334 | ||
335 | /// Attempts to highlight the specific part of a type annotation | |
336 | /// that contains the anonymous reference we want to give a name | |
337 | /// to. For example, we might produce an annotation like this: | |
338 | /// | |
339 | /// ``` | |
340 | /// | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> { | |
341 | /// | - let's call the lifetime of this reference `'1` | |
342 | /// ``` | |
343 | /// | |
344 | /// the way this works is that we match up `argument_ty`, which is | |
345 | /// a `Ty<'tcx>` (the internal form of the type) with | |
346 | /// `argument_hir_ty`, a `hir::Ty` (the syntax of the type | |
347 | /// annotation). We are descending through the types stepwise, | |
348 | /// looking in to find the region `needle_fr` in the internal | |
349 | /// type. Once we find that, we can use the span of the `hir::Ty` | |
350 | /// to add the highlight. | |
351 | /// | |
352 | /// This is a somewhat imperfect process, so long the way we also | |
353 | /// keep track of the **closest** type we've found. If we fail to | |
354 | /// find the exact `&` or `'_` to highlight, then we may fall back | |
355 | /// to highlighting that closest type instead. | |
356 | fn give_name_if_we_can_match_hir_ty( | |
357 | &self, | |
358 | tcx: TyCtxt<'_, '_, 'tcx>, | |
359 | needle_fr: RegionVid, | |
360 | argument_ty: Ty<'tcx>, | |
361 | argument_hir_ty: &hir::Ty, | |
362 | counter: &mut usize, | |
363 | diag: &mut DiagnosticBuilder<'_>, | |
364 | ) -> Option<InternedString> { | |
365 | let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty)> = &mut Vec::new(); | |
366 | ||
367 | search_stack.push((argument_ty, argument_hir_ty)); | |
368 | ||
8faf50e0 | 369 | while let Some((ty, hir_ty)) = search_stack.pop() { |
8faf50e0 XL |
370 | match (&ty.sty, &hir_ty.node) { |
371 | // Check if the `argument_ty` is `&'X ..` where `'X` | |
372 | // is the region we are looking for -- if so, and we have a `&T` | |
373 | // on the RHS, then we want to highlight the `&` like so: | |
374 | // | |
375 | // & | |
376 | // - let's call the lifetime of this reference `'1` | |
377 | ( | |
b7449926 | 378 | ty::Ref(region, referent_ty, _), |
8faf50e0 XL |
379 | hir::TyKind::Rptr(_lifetime, referent_hir_ty), |
380 | ) => { | |
381 | if region.to_region_vid() == needle_fr { | |
382 | let region_name = self.synthesize_region_name(counter); | |
383 | ||
384 | // Just grab the first character, the `&`. | |
b7449926 XL |
385 | let source_map = tcx.sess.source_map(); |
386 | let ampersand_span = source_map.start_point(hir_ty.span); | |
8faf50e0 XL |
387 | |
388 | diag.span_label( | |
389 | ampersand_span, | |
390 | format!( | |
391 | "let's call the lifetime of this reference `{}`", | |
392 | region_name | |
393 | ), | |
394 | ); | |
395 | ||
396 | return Some(region_name); | |
397 | } | |
398 | ||
399 | // Otherwise, let's descend into the referent types. | |
400 | search_stack.push((referent_ty, &referent_hir_ty.ty)); | |
401 | } | |
402 | ||
403 | // Match up something like `Foo<'1>` | |
404 | ( | |
b7449926 | 405 | ty::Adt(_adt_def, substs), |
8faf50e0 XL |
406 | hir::TyKind::Path(hir::QPath::Resolved(None, path)), |
407 | ) => { | |
408 | if let Some(last_segment) = path.segments.last() { | |
409 | if let Some(name) = self.match_adt_and_segment( | |
410 | substs, | |
411 | needle_fr, | |
412 | last_segment, | |
413 | counter, | |
414 | diag, | |
415 | search_stack, | |
416 | ) { | |
417 | return Some(name); | |
418 | } | |
419 | } | |
420 | } | |
421 | ||
422 | // The following cases don't have lifetimes, so we | |
423 | // just worry about trying to match up the rustc type | |
424 | // with the HIR types: | |
b7449926 | 425 | (ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => { |
8faf50e0 XL |
426 | search_stack.extend(elem_tys.iter().cloned().zip(elem_hir_tys)); |
427 | } | |
428 | ||
b7449926 XL |
429 | (ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty)) |
430 | | (ty::Array(elem_ty, _), hir::TyKind::Array(elem_hir_ty, _)) => { | |
8faf50e0 XL |
431 | search_stack.push((elem_ty, elem_hir_ty)); |
432 | } | |
433 | ||
b7449926 | 434 | (ty::RawPtr(mut_ty), hir::TyKind::Ptr(mut_hir_ty)) => { |
8faf50e0 XL |
435 | search_stack.push((mut_ty.ty, &mut_hir_ty.ty)); |
436 | } | |
437 | ||
438 | _ => { | |
439 | // FIXME there are other cases that we could trace | |
440 | } | |
441 | } | |
442 | } | |
443 | ||
b7449926 | 444 | return None; |
8faf50e0 XL |
445 | } |
446 | ||
447 | /// We've found an enum/struct/union type with the substitutions | |
448 | /// `substs` and -- in the HIR -- a path type with the final | |
449 | /// segment `last_segment`. Try to find a `'_` to highlight in | |
450 | /// the generic args (or, if not, to produce new zipped pairs of | |
451 | /// types+hir to search through). | |
452 | fn match_adt_and_segment<'hir>( | |
453 | &self, | |
454 | substs: &'tcx Substs<'tcx>, | |
455 | needle_fr: RegionVid, | |
456 | last_segment: &'hir hir::PathSegment, | |
457 | counter: &mut usize, | |
458 | diag: &mut DiagnosticBuilder<'_>, | |
459 | search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty)>, | |
460 | ) -> Option<InternedString> { | |
461 | // Did the user give explicit arguments? (e.g., `Foo<..>`) | |
462 | let args = last_segment.args.as_ref()?; | |
463 | let lifetime = self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?; | |
464 | match lifetime.name { | |
465 | hir::LifetimeName::Param(_) | |
466 | | hir::LifetimeName::Static | |
467 | | hir::LifetimeName::Underscore => { | |
468 | let region_name = self.synthesize_region_name(counter); | |
469 | let ampersand_span = lifetime.span; | |
470 | diag.span_label(ampersand_span, format!("let's call this `{}`", region_name)); | |
471 | return Some(region_name); | |
472 | } | |
473 | ||
474 | hir::LifetimeName::Implicit => { | |
475 | // In this case, the user left off the lifetime; so | |
476 | // they wrote something like: | |
477 | // | |
478 | // ``` | |
479 | // x: Foo<T> | |
480 | // ``` | |
481 | // | |
482 | // where the fully elaborated form is `Foo<'_, '1, | |
483 | // T>`. We don't consider this a match; instead we let | |
484 | // the "fully elaborated" type fallback above handle | |
485 | // it. | |
486 | return None; | |
487 | } | |
488 | } | |
489 | } | |
490 | ||
491 | /// We've found an enum/struct/union type with the substitutions | |
492 | /// `substs` and -- in the HIR -- a path with the generic | |
493 | /// arguments `args`. If `needle_fr` appears in the args, return | |
494 | /// the `hir::Lifetime` that corresponds to it. If not, push onto | |
495 | /// `search_stack` the types+hir to search through. | |
496 | fn try_match_adt_and_generic_args<'hir>( | |
497 | &self, | |
498 | substs: &'tcx Substs<'tcx>, | |
499 | needle_fr: RegionVid, | |
500 | args: &'hir hir::GenericArgs, | |
501 | search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty)>, | |
502 | ) -> Option<&'hir hir::Lifetime> { | |
503 | for (kind, hir_arg) in substs.iter().zip(&args.args) { | |
504 | match (kind.unpack(), hir_arg) { | |
505 | (UnpackedKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => { | |
506 | if r.to_region_vid() == needle_fr { | |
507 | return Some(lt); | |
508 | } | |
509 | } | |
510 | ||
511 | (UnpackedKind::Type(ty), hir::GenericArg::Type(hir_ty)) => { | |
512 | search_stack.push((ty, hir_ty)); | |
513 | } | |
514 | ||
515 | (UnpackedKind::Lifetime(_), _) | (UnpackedKind::Type(_), _) => { | |
516 | // I *think* that HIR lowering should ensure this | |
517 | // doesn't happen, even in erroneous | |
518 | // programs. Else we should use delay-span-bug. | |
519 | span_bug!( | |
520 | hir_arg.span(), | |
521 | "unmatched subst and hir arg: found {:?} vs {:?}", | |
522 | kind, | |
523 | hir_arg, | |
524 | ); | |
525 | } | |
526 | } | |
527 | } | |
528 | ||
529 | None | |
530 | } | |
531 | ||
532 | /// Find a closure upvar that contains `fr` and label it with a | |
533 | /// fully elaborated type, returning something like `'1`. Result | |
534 | /// looks like: | |
535 | /// | |
536 | /// ``` | |
537 | /// | let x = Some(&22); | |
538 | /// - fully elaborated type of `x` is `Option<&'1 u32>` | |
539 | /// ``` | |
540 | fn give_name_if_anonymous_region_appears_in_upvars( | |
541 | &self, | |
542 | tcx: TyCtxt<'_, '_, 'tcx>, | |
543 | mir: &Mir<'tcx>, | |
544 | fr: RegionVid, | |
545 | counter: &mut usize, | |
546 | diag: &mut DiagnosticBuilder<'_>, | |
547 | ) -> Option<InternedString> { | |
548 | let upvar_index = self.get_upvar_index_for_region(tcx, fr)?; | |
b7449926 XL |
549 | let (upvar_name, upvar_span) = |
550 | self.get_upvar_name_and_span_for_region(tcx, mir, upvar_index); | |
8faf50e0 XL |
551 | let region_name = self.synthesize_region_name(counter); |
552 | ||
553 | diag.span_label( | |
554 | upvar_span, | |
b7449926 XL |
555 | format!( |
556 | "lifetime `{}` appears in the type of `{}`", | |
557 | region_name, upvar_name | |
558 | ), | |
8faf50e0 XL |
559 | ); |
560 | ||
561 | Some(region_name) | |
562 | } | |
563 | ||
564 | /// Check for arguments appearing in the (closure) return type. It | |
565 | /// must be a closure since, in a free fn, such an argument would | |
566 | /// have to either also appear in an argument (if using elision) | |
567 | /// or be early bound (named, not in argument). | |
568 | fn give_name_if_anonymous_region_appears_in_output( | |
569 | &self, | |
b7449926 | 570 | infcx: &InferCtxt<'_, '_, 'tcx>, |
8faf50e0 | 571 | mir: &Mir<'tcx>, |
b7449926 | 572 | mir_def_id: DefId, |
8faf50e0 XL |
573 | fr: RegionVid, |
574 | counter: &mut usize, | |
575 | diag: &mut DiagnosticBuilder<'_>, | |
576 | ) -> Option<InternedString> { | |
b7449926 XL |
577 | let tcx = infcx.tcx; |
578 | ||
8faf50e0 XL |
579 | let return_ty = self.universal_regions.unnormalized_output_ty; |
580 | debug!( | |
581 | "give_name_if_anonymous_region_appears_in_output: return_ty = {:?}", | |
582 | return_ty | |
583 | ); | |
b7449926 XL |
584 | if !infcx |
585 | .tcx | |
586 | .any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) | |
587 | { | |
8faf50e0 XL |
588 | return None; |
589 | } | |
590 | ||
b7449926 XL |
591 | let type_name = with_highlight_region(fr, *counter, || infcx.extract_type_name(&return_ty)); |
592 | ||
593 | let mir_node_id = tcx.hir.as_local_node_id(mir_def_id).expect("non-local mir"); | |
594 | ||
595 | let (return_span, mir_description) = | |
596 | if let hir::ExprKind::Closure(_, _, _, span, gen_move) = | |
597 | tcx.hir.expect_expr(mir_node_id).node | |
598 | { | |
599 | ( | |
600 | tcx.sess.source_map().end_point(span), | |
601 | if gen_move.is_some() { | |
602 | " of generator" | |
603 | } else { | |
604 | " of closure" | |
605 | }, | |
606 | ) | |
607 | } else { | |
608 | // unreachable? | |
609 | (mir.span, "") | |
610 | }; | |
611 | ||
8faf50e0 | 612 | diag.span_label( |
b7449926 XL |
613 | return_span, |
614 | format!("return type{} is {}", mir_description, type_name), | |
8faf50e0 XL |
615 | ); |
616 | ||
b7449926 XL |
617 | // This counter value will already have been used, so this function will increment it |
618 | // so the next value will be used next and return the region name that would have been | |
619 | // used. | |
620 | Some(self.synthesize_region_name(counter)) | |
8faf50e0 XL |
621 | } |
622 | ||
623 | /// Create a synthetic region named `'1`, incrementing the | |
624 | /// counter. | |
625 | fn synthesize_region_name(&self, counter: &mut usize) -> InternedString { | |
626 | let c = *counter; | |
627 | *counter += 1; | |
628 | ||
629 | Name::intern(&format!("'{:?}", c)).as_interned_str() | |
630 | } | |
631 | } |