diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index dbcb63addb84..693219ec4b03 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String { + pub fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String { if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty { let ty_vars = self.type_variables.borrow(); if let TypeVariableOrigin::TypeParameterDefinition(_, name) = diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs index 836eaa23f685..7ba1e50cef34 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs @@ -404,9 +404,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { let counter = &mut 1; let fr_name = self.give_region_a_name( - infcx.tcx, mir, mir_def_id, fr, counter, &mut diag); + infcx, mir, mir_def_id, fr, counter, &mut diag); let outlived_fr_name = self.give_region_a_name( - infcx.tcx, mir, mir_def_id, outlived_fr, counter, &mut diag); + infcx, mir, mir_def_id, outlived_fr, counter, &mut diag); match (category, outlived_fr_is_local, fr_is_local) { (ConstraintCategory::Return, true, _) => { diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index c0eca026331b..05ac130f0004 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -12,6 +12,7 @@ use borrow_check::nll::region_infer::RegionInferenceContext; use borrow_check::nll::ToRegionVid; use rustc::hir; use rustc::hir::def_id::DefId; +use rustc::infer::InferCtxt; use rustc::mir::Mir; use rustc::ty::subst::{Substs, UnpackedKind}; use rustc::ty::{self, RegionVid, Ty, TyCtxt}; @@ -48,7 +49,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// and then return the name `'1` for us to use. crate fn give_region_a_name( &self, - tcx: TyCtxt<'_, '_, 'tcx>, + infcx: &InferCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>, mir_def_id: DefId, fr: RegionVid, @@ -59,17 +60,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { assert!(self.universal_regions.is_universal_region(fr)); - self.give_name_from_error_region(tcx, mir_def_id, fr, counter, diag) + self.give_name_from_error_region(infcx.tcx, mir_def_id, fr, counter, diag) .or_else(|| { self.give_name_if_anonymous_region_appears_in_arguments( - tcx, mir, mir_def_id, fr, counter, diag) + infcx, mir, mir_def_id, fr, counter, diag) }) .or_else(|| { self.give_name_if_anonymous_region_appears_in_upvars( - tcx, mir, fr, counter, diag) + infcx.tcx, mir, fr, counter, diag) }) .or_else(|| { - self.give_name_if_anonymous_region_appears_in_output(tcx, mir, fr, counter, diag) + self.give_name_if_anonymous_region_appears_in_output( + infcx.tcx, mir, fr, counter, diag) }) .unwrap_or_else(|| span_bug!(mir.span, "can't make a name for free region {:?}", fr)) } @@ -130,7 +132,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// ``` fn give_name_if_anonymous_region_appears_in_arguments( &self, - tcx: TyCtxt<'_, '_, 'tcx>, + infcx: &InferCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>, mir_def_id: DefId, fr: RegionVid, @@ -138,12 +140,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { diag: &mut DiagnosticBuilder<'_>, ) -> Option { let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs(); - let argument_index = self.get_argument_index_for_region(tcx, fr)?; + let argument_index = self.get_argument_index_for_region(infcx.tcx, fr)?; let arg_ty = self.universal_regions.unnormalized_input_tys[implicit_inputs + argument_index]; if let Some(region_name) = self.give_name_if_we_can_match_hir_ty_from_argument( - tcx, + infcx, mir_def_id, fr, arg_ty, @@ -169,7 +171,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn give_name_if_we_can_match_hir_ty_from_argument( &self, - tcx: TyCtxt<'_, '_, 'tcx>, + infcx: &InferCtxt<'_, '_, 'tcx>, mir_def_id: DefId, needle_fr: RegionVid, argument_ty: Ty<'tcx>, @@ -177,17 +179,23 @@ impl<'tcx> RegionInferenceContext<'tcx> { counter: &mut usize, diag: &mut DiagnosticBuilder<'_>, ) -> Option { - let mir_node_id = tcx.hir.as_local_node_id(mir_def_id)?; - let fn_decl = tcx.hir.fn_decl(mir_node_id)?; + let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id)?; + let fn_decl = infcx.tcx.hir.fn_decl(mir_node_id)?; let argument_hir_ty: &hir::Ty = &fn_decl.inputs[argument_index]; match argument_hir_ty.node { // This indicates a variable with no type annotation, like // `|x|`... in that case, we can't highlight the type but // must highlight the variable. - hir::TyKind::Infer => None, + hir::TyKind::Infer => self.give_name_if_we_cannot_match_hir_ty( + infcx, + argument_ty, + argument_hir_ty, + counter, + diag, + ), _ => self.give_name_if_we_can_match_hir_ty( - tcx, + infcx.tcx, needle_fr, argument_ty, argument_hir_ty, @@ -197,6 +205,40 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } + /// Attempts to highlight the specific part of a type in an argument + /// that has no type annotation. + /// For example, we might produce an annotation like this: + /// + /// ``` + /// | foo(|a, b| b) + /// | - - + /// | | | + /// | | has type `&'1 u32` + /// | has type `&'2 u32` + /// ``` + fn give_name_if_we_cannot_match_hir_ty( + &self, + infcx: &InferCtxt<'_, '_, 'tcx>, + argument_ty: Ty<'tcx>, + argument_hir_ty: &hir::Ty, + counter: &mut usize, + diag: &mut DiagnosticBuilder<'_>, + ) -> Option { + let mut type_name = infcx.extract_type_name(&argument_ty); + + type_name.find("&").map(|index| { + let region_name = self.synthesize_region_name(counter).as_str(); + type_name.insert_str(index + 1, &format!("{} ", region_name)); + + diag.span_label( + argument_hir_ty.span, + format!("has type `{}`", type_name), + ); + + region_name.as_interned_str() + }) + } + /// Attempts to highlight the specific part of a type annotation /// that contains the anonymous reference we want to give a name /// to. For example, we might produce an annotation like this: diff --git a/src/test/ui/issue-52533.nll.stderr b/src/test/ui/issue-52533.nll.stderr new file mode 100644 index 000000000000..7931bc320b10 --- /dev/null +++ b/src/test/ui/issue-52533.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to nll + --> $DIR/issue-52533.rs:15:16 + | +LL | foo(|a, b| b) + | ^ + +error: unsatisfied lifetime constraints + --> $DIR/issue-52533.rs:15:16 + | +LL | foo(|a, b| b) + | - - ^ free region requires that `'1` must outlive `'2` + | | | + | | lifetime `'1` appears in this argument + | lifetime `'2` appears in this argument + +error: aborting due to previous error + diff --git a/src/test/ui/issue-52533.rs b/src/test/ui/issue-52533.rs new file mode 100644 index 000000000000..08f2805cefd6 --- /dev/null +++ b/src/test/ui/issue-52533.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo(_: impl for<'a> FnOnce(&'a u32, &u32) -> &'a u32) { +} + +fn main() { + foo(|a, b| b) + //~^ ERROR lifetime of reference outlives lifetime of borrowed content... +} diff --git a/src/test/ui/issue-52533.stderr b/src/test/ui/issue-52533.stderr new file mode 100644 index 000000000000..76a2470a2e03 --- /dev/null +++ b/src/test/ui/issue-52533.stderr @@ -0,0 +1,20 @@ +error[E0312]: lifetime of reference outlives lifetime of borrowed content... + --> $DIR/issue-52533.rs:15:16 + | +LL | foo(|a, b| b) + | ^ + | +note: ...the reference is valid for the anonymous lifetime #2 defined on the body at 15:9... + --> $DIR/issue-52533.rs:15:9 + | +LL | foo(|a, b| b) + | ^^^^^^^^ +note: ...but the borrowed content is only valid for the anonymous lifetime #3 defined on the body at 15:9 + --> $DIR/issue-52533.rs:15:9 + | +LL | foo(|a, b| b) + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0312`.