Skip to content

Commit

Permalink
Don't suggest adding a synthesized region name.
Browse files Browse the repository at this point in the history
  • Loading branch information
davidtwco committed Sep 13, 2018
1 parent 6bf131f commit 65e2539
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 25 deletions.
Expand Up @@ -17,14 +17,17 @@ use rustc::infer::InferCtxt;
use rustc::mir::{self, Location, Mir, Place, Rvalue, StatementKind, TerminatorKind};
use rustc::ty::{TyCtxt, Ty, TyS, TyKind, Region, RegionKind, RegionVid};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_errors::Diagnostic;
use rustc_errors::{Diagnostic, DiagnosticBuilder};
use std::collections::VecDeque;
use std::fmt;
use syntax::symbol::keywords;
use syntax_pos::Span;

mod region_name;
mod var_name;

use self::region_name::RegionName;

/// Constraints that are considered interesting can be categorized to
/// determine why they are interesting. Order of variants indicates
/// sort order of the category, thereby influencing diagnostic output.
Expand Down Expand Up @@ -473,27 +476,44 @@ impl<'tcx> RegionInferenceContext<'tcx> {
},
}

self.add_static_impl_trait_suggestion(
infcx, &mut diag, fr_name, fr_region, outlived_fr_region
);

diag.buffer(errors_buffer);
}

fn add_static_impl_trait_suggestion(
&self,
infcx: &InferCtxt<'_, '_, 'tcx>,
diag: &mut DiagnosticBuilder<'_>,
fr_name: RegionName,
fr_region: Option<Region<'tcx>>,
outlived_fr_region: Option<Region<'tcx>>,
) {
if let (Some(f), Some(RegionKind::ReStatic)) = (fr_region, outlived_fr_region) {
if let Some(TyS {
sty: TyKind::Anon(did, _),
..
}) = self.return_type_impl_trait(infcx, f) {
let static_str = keywords::StaticLifetime.name();
let span = infcx.tcx.def_span(*did);
if let Ok(snippet) = infcx.tcx.sess.source_map().span_to_snippet(span) {
diag.span_suggestion(
span,
&format!(
"you can add a constraint to the return type to make it last \
less than `'static` and match {}",
fr_name,
less than `{}` and match `{}`",
static_str, fr_name,
),
format!("{} + {}", snippet, fr_name),
match fr_name {
RegionName::Named(name) => format!("{} + {}", snippet, name),
RegionName::Synthesized(_) => format!("{} + '_", snippet),
},
);
}
}
}

diag.buffer(errors_buffer);
}

// Finds some region R such that `fr1: R` and `R` is live at
Expand Down
Expand Up @@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt::{self, Display};
use borrow_check::nll::region_infer::RegionInferenceContext;
use borrow_check::nll::universal_regions::DefiningTy;
use borrow_check::nll::ToRegionVid;
Expand All @@ -23,6 +24,24 @@ use syntax::ast::{Name, DUMMY_NODE_ID};
use syntax::symbol::keywords;
use syntax_pos::symbol::InternedString;

/// Name of a region used in error reporting. Variants denote the source of the region name -
/// whether it was synthesized for the error message and therefore should not be used in
/// suggestions; or whether it was found from the region.
#[derive(Debug)]
pub(crate) enum RegionName {
Named(InternedString),
Synthesized(InternedString),
}

impl Display for RegionName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RegionName::Named(name) | RegionName::Synthesized(name) =>
write!(f, "{}", name),
}
}
}

impl<'tcx> RegionInferenceContext<'tcx> {
/// Maps from an internal MIR region vid to something that we can
/// report to the user. In some cases, the region vids will map
Expand Down Expand Up @@ -57,7 +76,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder,
) -> InternedString {
) -> RegionName {
debug!("give_region_a_name(fr={:?}, counter={})", fr, counter);

assert!(self.universal_regions.is_universal_region(fr));
Expand Down Expand Up @@ -95,27 +114,29 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<InternedString> {
) -> Option<RegionName> {
let error_region = self.to_error_region(fr)?;

debug!("give_region_a_name: error_region = {:?}", error_region);
match error_region {
ty::ReEarlyBound(ebr) => {
if ebr.has_name() {
self.highlight_named_span(tcx, error_region, &ebr.name, diag);
Some(ebr.name)
Some(RegionName::Named(ebr.name))
} else {
None
}
}

ty::ReStatic => Some(keywords::StaticLifetime.name().as_interned_str()),
ty::ReStatic => Some(RegionName::Named(
keywords::StaticLifetime.name().as_interned_str()
)),

ty::ReFree(free_region) => match free_region.bound_region {
ty::BoundRegion::BrNamed(_, name) => {
self.highlight_named_span(tcx, error_region, &name, diag);
Some(name)
}
Some(RegionName::Named(name))
},

ty::BoundRegion::BrEnv => {
let mir_node_id = tcx.hir.as_local_node_id(mir_def_id).expect("non-local mir");
Expand All @@ -132,7 +153,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let region_name = self.synthesize_region_name(counter);
diag.span_label(
args_span,
format!("lifetime `{}` represents this closure's body", region_name),
format!(
"lifetime `{}` represents this closure's body",
region_name
),
);

let closure_kind_ty = substs.closure_kind_ty(def_id, tcx);
Expand Down Expand Up @@ -227,7 +251,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<InternedString> {
) -> Option<RegionName> {
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
let argument_index = self.get_argument_index_for_region(infcx.tcx, fr)?;

Expand Down Expand Up @@ -259,7 +283,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
argument_index: usize,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<InternedString> {
) -> Option<RegionName> {
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];
Expand Down Expand Up @@ -306,7 +330,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
argument_ty: Ty<'tcx>,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<InternedString> {
) -> Option<RegionName> {
let type_name = with_highlight_region(needle_fr, *counter, || {
infcx.extract_type_name(&argument_ty)
});
Expand Down Expand Up @@ -361,7 +385,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
argument_hir_ty: &hir::Ty,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<InternedString> {
) -> Option<RegionName> {
let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty)> = &mut Vec::new();

search_stack.push((argument_ty, argument_hir_ty));
Expand Down Expand Up @@ -457,7 +481,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty)>,
) -> Option<InternedString> {
) -> Option<RegionName> {
// Did the user give explicit arguments? (e.g., `Foo<..>`)
let args = last_segment.args.as_ref()?;
let lifetime = self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
Expand All @@ -467,7 +491,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
| hir::LifetimeName::Underscore => {
let region_name = self.synthesize_region_name(counter);
let ampersand_span = lifetime.span;
diag.span_label(ampersand_span, format!("let's call this `{}`", region_name));
diag.span_label(
ampersand_span,
format!("let's call this `{}`", region_name)
);
return Some(region_name);
}

Expand Down Expand Up @@ -544,7 +571,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<InternedString> {
) -> Option<RegionName> {
let upvar_index = self.get_upvar_index_for_region(tcx, fr)?;
let (upvar_name, upvar_span) =
self.get_upvar_name_and_span_for_region(tcx, mir, upvar_index);
Expand Down Expand Up @@ -573,7 +600,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<InternedString> {
) -> Option<RegionName> {
let tcx = infcx.tcx;

let return_ty = self.universal_regions.unnormalized_output_ty;
Expand Down Expand Up @@ -622,10 +649,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {

/// Create a synthetic region named `'1`, incrementing the
/// counter.
fn synthesize_region_name(&self, counter: &mut usize) -> InternedString {
fn synthesize_region_name(&self, counter: &mut usize) -> RegionName {
let c = *counter;
*counter += 1;

Name::intern(&format!("'{:?}", c)).as_interned_str()
RegionName::Synthesized(Name::intern(&format!("'{:?}", c)).as_interned_str())
}
}
Expand Up @@ -11,7 +11,7 @@ error: unsatisfied lifetime constraints
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
help: you can add a constraint to the return type to make it last less than `'static` and match 'a
help: you can add a constraint to the return type to make it last less than `'static` and match `'a`
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ^^^^^^^^^^^^^^
Expand All @@ -21,7 +21,7 @@ error: unsatisfied lifetime constraints
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
help: you can add a constraint to the return type to make it last less than `'static` and match 'a
help: you can add a constraint to the return type to make it last less than `'static` and match `'a`
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static + 'a { x }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down

0 comments on commit 65e2539

Please sign in to comment.