Skip to content

Commit 53dda8e

Browse files
committed
Added fully elaborated type label for inferred arguments.
1 parent 41ce2e9 commit 53dda8e

File tree

6 files changed

+112
-16
lines changed

6 files changed

+112
-16
lines changed

src/librustc/infer/error_reporting/need_type_info.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
7474

7575

7676
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
77-
fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
77+
pub fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
7878
if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty {
7979
let ty_vars = self.type_variables.borrow();
8080
if let TypeVariableOrigin::TypeParameterDefinition(_, name) =

src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,9 +404,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
404404

405405
let counter = &mut 1;
406406
let fr_name = self.give_region_a_name(
407-
infcx.tcx, mir, mir_def_id, fr, counter, &mut diag);
407+
infcx, mir, mir_def_id, fr, counter, &mut diag);
408408
let outlived_fr_name = self.give_region_a_name(
409-
infcx.tcx, mir, mir_def_id, outlived_fr, counter, &mut diag);
409+
infcx, mir, mir_def_id, outlived_fr, counter, &mut diag);
410410

411411
match (category, outlived_fr_is_local, fr_is_local) {
412412
(ConstraintCategory::Return, true, _) => {

src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use borrow_check::nll::region_infer::RegionInferenceContext;
1212
use borrow_check::nll::ToRegionVid;
1313
use rustc::hir;
1414
use rustc::hir::def_id::DefId;
15+
use rustc::infer::InferCtxt;
1516
use rustc::mir::Mir;
1617
use rustc::ty::subst::{Substs, UnpackedKind};
1718
use rustc::ty::{self, RegionVid, Ty, TyCtxt};
@@ -48,7 +49,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
4849
/// and then return the name `'1` for us to use.
4950
crate fn give_region_a_name(
5051
&self,
51-
tcx: TyCtxt<'_, '_, 'tcx>,
52+
infcx: &InferCtxt<'_, '_, 'tcx>,
5253
mir: &Mir<'tcx>,
5354
mir_def_id: DefId,
5455
fr: RegionVid,
@@ -59,17 +60,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
5960

6061
assert!(self.universal_regions.is_universal_region(fr));
6162

62-
self.give_name_from_error_region(tcx, mir_def_id, fr, counter, diag)
63+
self.give_name_from_error_region(infcx.tcx, mir_def_id, fr, counter, diag)
6364
.or_else(|| {
6465
self.give_name_if_anonymous_region_appears_in_arguments(
65-
tcx, mir, mir_def_id, fr, counter, diag)
66+
infcx, mir, mir_def_id, fr, counter, diag)
6667
})
6768
.or_else(|| {
6869
self.give_name_if_anonymous_region_appears_in_upvars(
69-
tcx, mir, fr, counter, diag)
70+
infcx.tcx, mir, fr, counter, diag)
7071
})
7172
.or_else(|| {
72-
self.give_name_if_anonymous_region_appears_in_output(tcx, mir, fr, counter, diag)
73+
self.give_name_if_anonymous_region_appears_in_output(
74+
infcx.tcx, mir, fr, counter, diag)
7375
})
7476
.unwrap_or_else(|| span_bug!(mir.span, "can't make a name for free region {:?}", fr))
7577
}
@@ -130,20 +132,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
130132
/// ```
131133
fn give_name_if_anonymous_region_appears_in_arguments(
132134
&self,
133-
tcx: TyCtxt<'_, '_, 'tcx>,
135+
infcx: &InferCtxt<'_, '_, 'tcx>,
134136
mir: &Mir<'tcx>,
135137
mir_def_id: DefId,
136138
fr: RegionVid,
137139
counter: &mut usize,
138140
diag: &mut DiagnosticBuilder<'_>,
139141
) -> Option<InternedString> {
140142
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
141-
let argument_index = self.get_argument_index_for_region(tcx, fr)?;
143+
let argument_index = self.get_argument_index_for_region(infcx.tcx, fr)?;
142144

143145
let arg_ty =
144146
self.universal_regions.unnormalized_input_tys[implicit_inputs + argument_index];
145147
if let Some(region_name) = self.give_name_if_we_can_match_hir_ty_from_argument(
146-
tcx,
148+
infcx,
147149
mir_def_id,
148150
fr,
149151
arg_ty,
@@ -169,25 +171,31 @@ impl<'tcx> RegionInferenceContext<'tcx> {
169171

170172
fn give_name_if_we_can_match_hir_ty_from_argument(
171173
&self,
172-
tcx: TyCtxt<'_, '_, 'tcx>,
174+
infcx: &InferCtxt<'_, '_, 'tcx>,
173175
mir_def_id: DefId,
174176
needle_fr: RegionVid,
175177
argument_ty: Ty<'tcx>,
176178
argument_index: usize,
177179
counter: &mut usize,
178180
diag: &mut DiagnosticBuilder<'_>,
179181
) -> Option<InternedString> {
180-
let mir_node_id = tcx.hir.as_local_node_id(mir_def_id)?;
181-
let fn_decl = tcx.hir.fn_decl(mir_node_id)?;
182+
let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id)?;
183+
let fn_decl = infcx.tcx.hir.fn_decl(mir_node_id)?;
182184
let argument_hir_ty: &hir::Ty = &fn_decl.inputs[argument_index];
183185
match argument_hir_ty.node {
184186
// This indicates a variable with no type annotation, like
185187
// `|x|`... in that case, we can't highlight the type but
186188
// must highlight the variable.
187-
hir::TyKind::Infer => None,
189+
hir::TyKind::Infer => self.give_name_if_we_cannot_match_hir_ty(
190+
infcx,
191+
argument_ty,
192+
argument_hir_ty,
193+
counter,
194+
diag,
195+
),
188196

189197
_ => self.give_name_if_we_can_match_hir_ty(
190-
tcx,
198+
infcx.tcx,
191199
needle_fr,
192200
argument_ty,
193201
argument_hir_ty,
@@ -197,6 +205,40 @@ impl<'tcx> RegionInferenceContext<'tcx> {
197205
}
198206
}
199207

208+
/// Attempts to highlight the specific part of a type in an argument
209+
/// that has no type annotation.
210+
/// For example, we might produce an annotation like this:
211+
///
212+
/// ```
213+
/// | foo(|a, b| b)
214+
/// | - -
215+
/// | | |
216+
/// | | has type `&'1 u32`
217+
/// | has type `&'2 u32`
218+
/// ```
219+
fn give_name_if_we_cannot_match_hir_ty(
220+
&self,
221+
infcx: &InferCtxt<'_, '_, 'tcx>,
222+
argument_ty: Ty<'tcx>,
223+
argument_hir_ty: &hir::Ty,
224+
counter: &mut usize,
225+
diag: &mut DiagnosticBuilder<'_>,
226+
) -> Option<InternedString> {
227+
let mut type_name = infcx.extract_type_name(&argument_ty);
228+
229+
type_name.find("&").map(|index| {
230+
let region_name = self.synthesize_region_name(counter).as_str();
231+
type_name.insert_str(index + 1, &format!("{} ", region_name));
232+
233+
diag.span_label(
234+
argument_hir_ty.span,
235+
format!("has type `{}`", type_name),
236+
);
237+
238+
region_name.as_interned_str()
239+
})
240+
}
241+
200242
/// Attempts to highlight the specific part of a type annotation
201243
/// that contains the anonymous reference we want to give a name
202244
/// to. For example, we might produce an annotation like this:

src/test/ui/issue-52533.nll.stderr

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
warning: not reporting region error due to nll
2+
--> $DIR/issue-52533.rs:15:16
3+
|
4+
LL | foo(|a, b| b)
5+
| ^
6+
7+
error: unsatisfied lifetime constraints
8+
--> $DIR/issue-52533.rs:15:16
9+
|
10+
LL | foo(|a, b| b)
11+
| - - ^ free region requires that `'1` must outlive `'2`
12+
| | |
13+
| | lifetime `'1` appears in this argument
14+
| lifetime `'2` appears in this argument
15+
16+
error: aborting due to previous error
17+

src/test/ui/issue-52533.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2018 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+
fn foo(_: impl for<'a> FnOnce(&'a u32, &u32) -> &'a u32) {
12+
}
13+
14+
fn main() {
15+
foo(|a, b| b)
16+
//~^ ERROR lifetime of reference outlives lifetime of borrowed content...
17+
}

src/test/ui/issue-52533.stderr

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
2+
--> $DIR/issue-52533.rs:15:16
3+
|
4+
LL | foo(|a, b| b)
5+
| ^
6+
|
7+
note: ...the reference is valid for the anonymous lifetime #2 defined on the body at 15:9...
8+
--> $DIR/issue-52533.rs:15:9
9+
|
10+
LL | foo(|a, b| b)
11+
| ^^^^^^^^
12+
note: ...but the borrowed content is only valid for the anonymous lifetime #3 defined on the body at 15:9
13+
--> $DIR/issue-52533.rs:15:9
14+
|
15+
LL | foo(|a, b| b)
16+
| ^^^^^^^^
17+
18+
error: aborting due to previous error
19+
20+
For more information about this error, try `rustc --explain E0312`.

0 commit comments

Comments
 (0)