use crate::diagnostics::{ImportSuggestion, TypoSuggestion};
+use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
use crate::late::{LateResolutionVisitor, RibKind};
use crate::path_names_to_string;
use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
use rustc::session::config::nightly_options;
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, DiagnosticBuilder};
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
+use rustc_hir as hir;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, DefKind};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
AssocItem,
}
+crate enum MissingLifetimeSpot<'tcx> {
+ Generics(&'tcx hir::Generics<'tcx>),
+ HigherRanked { span: Span, span_type: ForLifetimeSpanType },
+}
+
+crate enum ForLifetimeSpanType {
+ BoundEmpty,
+ BoundTail,
+ TypeEmpty,
+ TypeTail,
+}
+
+impl ForLifetimeSpanType {
+ crate fn descr(&self) -> &'static str {
+ match self {
+ Self::BoundEmpty | Self::BoundTail => "bound",
+ Self::TypeEmpty | Self::TypeTail => "type",
+ }
+ }
+
+ crate fn suggestion(&self, sugg: &str) -> String {
+ match self {
+ Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg),
+ Self::BoundTail | Self::TypeTail => format!(", {}", sugg),
+ }
+ }
+}
+
+impl<'tcx> Into<MissingLifetimeSpot<'tcx>> for &'tcx hir::Generics<'tcx> {
+ fn into(self) -> MissingLifetimeSpot<'tcx> {
+ MissingLifetimeSpot::Generics(self)
+ }
+}
+
fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper
}
None
}
}
+
+impl<'tcx> LifetimeContext<'_, 'tcx> {
+ crate fn report_missing_lifetime_specifiers(
+ &self,
+ span: Span,
+ count: usize,
+ ) -> DiagnosticBuilder<'tcx> {
+ struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0106,
+ "missing lifetime specifier{}",
+ pluralize!(count)
+ )
+ }
+
+ crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) {
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ lifetime_ref.span,
+ E0261,
+ "use of undeclared lifetime name `{}`",
+ lifetime_ref
+ );
+ err.span_label(lifetime_ref.span, "undeclared lifetime");
+ for missing in &self.missing_named_lifetime_spots {
+ match missing {
+ MissingLifetimeSpot::Generics(generics) => {
+ let (span, sugg) = if let Some(param) =
+ generics.params.iter().find(|p| match p.kind {
+ hir::GenericParamKind::Type {
+ synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
+ ..
+ } => false,
+ _ => true,
+ }) {
+ (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
+ } else {
+ (generics.span, format!("<{}>", lifetime_ref))
+ };
+ err.span_suggestion(
+ span,
+ &format!("consider introducing lifetime `{}` here", lifetime_ref),
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ MissingLifetimeSpot::HigherRanked { span, span_type } => {
+ err.span_suggestion(
+ *span,
+ &format!(
+ "consider making the {} lifetime-generic with a new `{}` lifetime",
+ span_type.descr(),
+ lifetime_ref
+ ),
+ span_type.suggestion(&lifetime_ref.to_string()),
+ Applicability::MaybeIncorrect,
+ );
+ err.note(
+ "for more information on higher-ranked polymorphism, visit \
+ https://doc.rust-lang.org/nomicon/hrtb.html",
+ );
+ }
+ }
+ }
+ err.emit();
+ }
+
+ crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool {
+ if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res {
+ if [
+ self.tcx.lang_items().fn_once_trait(),
+ self.tcx.lang_items().fn_trait(),
+ self.tcx.lang_items().fn_mut_trait(),
+ ]
+ .contains(&Some(did))
+ {
+ let (span, span_type) = match &trait_ref.bound_generic_params {
+ [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty),
+ [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail),
+ };
+ self.missing_named_lifetime_spots
+ .push(MissingLifetimeSpot::HigherRanked { span, span_type });
+ return true;
+ }
+ };
+ false
+ }
+
+ crate fn add_missing_lifetime_specifiers_label(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ span: Span,
+ count: usize,
+ lifetime_names: &FxHashSet<ast::Ident>,
+ params: &[ElisionFailureInfo],
+ ) {
+ if count > 1 {
+ err.span_label(span, format!("expected {} lifetime parameters", count));
+ } else {
+ let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok();
+ let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| {
+ err.span_suggestion(
+ span,
+ "consider using the named lifetime",
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+ };
+ let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg: &str| {
+ err.span_label(span, "expected named lifetime parameter");
+
+ for missing in self.missing_named_lifetime_spots.iter().rev() {
+ let mut introduce_suggestion = vec![];
+ let msg;
+ let should_break;
+ introduce_suggestion.push(match missing {
+ MissingLifetimeSpot::Generics(generics) => {
+ msg = "consider introducing a named lifetime parameter".to_string();
+ should_break = true;
+ if let Some(param) = generics.params.iter().find(|p| match p.kind {
+ hir::GenericParamKind::Type {
+ synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
+ ..
+ } => false,
+ _ => true,
+ }) {
+ (param.span.shrink_to_lo(), "'a, ".to_string())
+ } else {
+ (generics.span, "<'a>".to_string())
+ }
+ }
+ MissingLifetimeSpot::HigherRanked { span, span_type } => {
+ msg = format!(
+ "consider making the {} lifetime-generic with a new `'a` lifetime",
+ span_type.descr(),
+ );
+ should_break = false;
+ err.note(
+ "for more information on higher-ranked polymorphism, visit \
+ https://doc.rust-lang.org/nomicon/hrtb.html",
+ );
+ (*span, span_type.suggestion("'a"))
+ }
+ });
+ for param in params {
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span)
+ {
+ if snippet.starts_with("&") && !snippet.starts_with("&'") {
+ introduce_suggestion
+ .push((param.span, format!("&'a {}", &snippet[1..])));
+ } else if snippet.starts_with("&'_ ") {
+ introduce_suggestion
+ .push((param.span, format!("&'a {}", &snippet[4..])));
+ }
+ }
+ }
+ introduce_suggestion.push((span, sugg.to_string()));
+ err.multipart_suggestion(
+ &msg,
+ introduce_suggestion,
+ Applicability::MaybeIncorrect,
+ );
+ if should_break {
+ break;
+ }
+ }
+ };
+
+ match (
+ lifetime_names.len(),
+ lifetime_names.iter().next(),
+ snippet.as_ref().map(|s| s.as_str()),
+ ) {
+ (1, Some(name), Some("&")) => {
+ suggest_existing(err, format!("&{} ", name));
+ }
+ (1, Some(name), Some("'_")) => {
+ suggest_existing(err, name.to_string());
+ }
+ (1, Some(name), Some(snippet)) if !snippet.ends_with(">") => {
+ suggest_existing(err, format!("{}<{}>", snippet, name));
+ }
+ (0, _, Some("&")) => {
+ suggest_new(err, "&'a ");
+ }
+ (0, _, Some("'_")) => {
+ suggest_new(err, "'a");
+ }
+ (0, _, Some(snippet)) if !snippet.ends_with(">") => {
+ suggest_new(err, &format!("{}<'a>", snippet));
+ }
+ _ => {
+ err.span_label(span, "expected lifetime parameter");
+ }
+ }
+ }
+ }
+}