use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
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::ty::{self, TyCtxt, Region, RegionKind, RegionVid};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_errors::{Diagnostic, DiagnosticBuilder};
use std::collections::VecDeque;
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, _),
+ if let (Some(f), Some(ty::RegionKind::ReStatic)) = (fr_region, outlived_fr_region) {
+ if let Some(ty::TyS {
+ sty: ty::TyKind::Anon(did, substs),
..
- }) = self.return_type_impl_trait(infcx, f) {
+ }) = infcx.tcx.is_suitable_region(f)
+ .map(|r| r.def_id)
+ .map(|id| infcx.tcx.return_type_impl_trait(id))
+ .unwrap_or(None)
+ {
+ let has_static_predicate = {
+ let predicates_of = infcx.tcx.predicates_of(*did);
+ let bounds = predicates_of.instantiate(infcx.tcx, substs);
+
+ let mut found = false;
+ for predicate in bounds.predicates {
+ if let ty::Predicate::TypeOutlives(binder) = predicate {
+ if let ty::OutlivesPredicate(
+ _,
+ RegionKind::ReStatic
+ ) = binder.skip_binder() {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ found
+ };
+
+ debug!("add_static_impl_trait_suggestion: has_static_predicate={:?}",
+ has_static_predicate);
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 `{}` and match `{}`",
- static_str, fr_name,
- ),
- match fr_name {
- RegionName::Named(name) => format!("{} + {}", snippet, name),
- RegionName::Synthesized(_) => format!("{} + '_", snippet),
- },
- );
+ if has_static_predicate {
+ let span = self.get_span_of_named_region(infcx.tcx, f, &fr_name);
+ 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 definition of `{}` to require it \
+ outlive `{}`",
+ fr_name, static_str,
+ ),
+ format!("{}: {}", snippet, static_str),
+ );
+ }
+ } else {
+ 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 `{}` and match `{}`",
+ static_str, fr_name,
+ ),
+ match fr_name {
+ RegionName::Named(name) => format!("{} + {}", snippet, name),
+ RegionName::Synthesized(_) => format!("{} + '_", snippet),
+ },
+ );
+ }
}
}
}
let (_, span, _) = self.best_blame_constraint(mir, tcx, fr1, |r| r == fr2);
span
}
-
- fn return_type_impl_trait<'cx>(
- &self,
- infcx: &'cx InferCtxt<'_, '_, 'tcx>,
- outlived_fr_region: Region<'tcx>,
- ) -> Option<Ty<'cx>> {
- infcx.tcx.is_suitable_region(outlived_fr_region)
- .map(|r| r.def_id)
- .map(|id| infcx.tcx.return_type_impl_trait(id))
- .unwrap_or(None)
- }
}
use rustc_errors::DiagnosticBuilder;
use syntax::ast::{Name, DUMMY_NODE_ID};
use syntax::symbol::keywords;
+use syntax_pos::Span;
use syntax_pos::symbol::InternedString;
/// Name of a region used in error reporting. Variants denote the source of the region name -
Synthesized(InternedString),
}
+impl RegionName {
+ fn as_interned_string(&self) -> &InternedString {
+ match self {
+ RegionName::Named(name) | RegionName::Synthesized(name) => name,
+ }
+ }
+}
+
impl Display for RegionName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
match error_region {
ty::ReEarlyBound(ebr) => {
if ebr.has_name() {
- self.highlight_named_span(tcx, error_region, &ebr.name, diag);
- Some(RegionName::Named(ebr.name))
+ let name = RegionName::Named(ebr.name);
+ self.highlight_named_span(tcx, error_region, &name, diag);
+ Some(name)
} else {
None
}
ty::ReFree(free_region) => match free_region.bound_region {
ty::BoundRegion::BrNamed(_, name) => {
+ let name = RegionName::Named(name);
self.highlight_named_span(tcx, error_region, &name, diag);
- Some(RegionName::Named(name))
+ Some(name)
},
ty::BoundRegion::BrEnv => {
}
}
+ /// Get the span of a named region.
+ pub(super) fn get_span_of_named_region(
+ &self,
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ error_region: &RegionKind,
+ name: &RegionName,
+ ) -> Span {
+ let scope = error_region.free_region_binding_scope(tcx);
+ let node = tcx.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID);
+
+ let span = tcx.sess.source_map().def_span(tcx.hir.span(node));
+ if let Some(param) = tcx.hir.get_generics(scope).and_then(|generics| {
+ generics.get_named(name.as_interned_string())
+ }) {
+ param.span
+ } else {
+ span
+ }
+ }
+
/// Highlight a named span to provide context for error messages that
/// mention that span, for example:
///
&self,
tcx: TyCtxt<'_, '_, 'tcx>,
error_region: &RegionKind,
- name: &InternedString,
+ name: &RegionName,
diag: &mut DiagnosticBuilder<'_>,
) {
- let cm = tcx.sess.source_map();
-
- let scope = error_region.free_region_binding_scope(tcx);
- let node = tcx.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID);
-
- let mut sp = cm.def_span(tcx.hir.span(node));
- if let Some(param) = tcx.hir
- .get_generics(scope)
- .and_then(|generics| generics.get_named(name))
- {
- sp = param.span;
- }
+ let span = self.get_span_of_named_region(tcx, error_region, name);
- diag.span_label(sp, format!("lifetime `{}` defined here", name));
+ diag.span_label(
+ span,
+ format!("lifetime `{}` defined here", name),
+ );
}
/// Find an argument that contains `fr` and label it with a fully