use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
use rustc_feature::BUILTIN_ATTRIBUTES;
+use rustc_hir as hir;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use syntax::util::lev_distance::find_best_match_for_name;
use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
-use crate::lifetimes::{ElisionFailureInfo, MissingLifetimeSpot};
+use crate::lifetimes::{ElisionFailureInfo, LifetimeContext};
use crate::path_names_to_string;
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind};
use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot};
pub path: Path,
}
+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)
+ }
+}
+
/// Adjust the impl span so that just the `impl` keyword is taken by removing
/// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and
/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`).
}
}
-crate fn report_missing_lifetime_specifiers(
- sess: &Session,
- span: Span,
- count: usize,
-) -> DiagnosticBuilder<'_> {
- struct_span_err!(sess, span, E0106, "missing lifetime specifier{}", pluralize!(count))
-}
+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 add_missing_lifetime_specifiers_label(
- err: &mut DiagnosticBuilder<'_>,
- source_map: &SourceMap,
- span: Span,
- count: usize,
- lifetime_names: &FxHashSet<ast::Ident>,
- snippet: Option<&str>,
- missing_named_lifetime_spots: &[MissingLifetimeSpot<'_>],
- params: &[ElisionFailureInfo],
-) {
- if count > 1 {
- err.span_label(span, format!("expected {} lifetime parameters", count));
- } else {
- let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| {
- err.span_suggestion(
- span,
- "consider using the named lifetime",
- sugg,
- Applicability::MaybeIncorrect,
- );
+ 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) = match &generics.params {
+ [] => (generics.span, format!("<{}>", lifetime_ref)),
+ [param, ..] => (param.span.shrink_to_lo(), 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;
+ }
};
- let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg: &str| {
- err.span_label(span, "expected named lifetime parameter");
-
- for missing in 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;
- match &generics.params {
- [] => (generics.span, "<'a>".to_string()),
- [param, ..] => (param.span.shrink_to_lo(), "'a, ".to_string()),
+ 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;
+ match &generics.params {
+ [] => (generics.span, "<'a>".to_string()),
+ [param, ..] => (param.span.shrink_to_lo(), "'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 \
+ 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) = 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..])));
+ );
+ (*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;
+ }
}
- 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) {
- (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");
+ 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");
+ }
}
}
}
//! used between functions, and they operate in a purely top-down
//! way. Therefore, we break lifetime name resolution into a separate pass.
-use crate::diagnostics::{
- add_missing_lifetime_specifiers_label, report_missing_lifetime_specifiers,
-};
+use crate::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
use rustc::hir::map::Map;
use rustc::lint;
use rustc::middle::resolve_lifetime::*;
object_lifetime_defaults: HirIdMap<Vec<ObjectLifetimeDefault>>,
}
-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)
- }
-}
-
-struct LifetimeContext<'a, 'tcx> {
- tcx: TyCtxt<'tcx>,
+crate struct LifetimeContext<'a, 'tcx> {
+ crate tcx: TyCtxt<'tcx>,
map: &'a mut NamedRegionMap,
scope: ScopeRef<'a>,
/// When encountering an undefined named lifetime, we will suggest introducing it in these
/// places.
- missing_named_lifetime_spots: Vec<MissingLifetimeSpot<'tcx>>,
+ crate missing_named_lifetime_spots: Vec<MissingLifetimeSpot<'tcx>>,
}
#[derive(Debug)]
self.insert_lifetime(lifetime_ref, def);
} else {
- 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) = match &generics.params {
- [] => (generics.span, format!("<{}>", lifetime_ref)),
- [param, ..] => {
- (param.span.shrink_to_lo(), 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();
+ self.emit_undeclared_lifetime_error(lifetime_ref);
}
}
}
};
- let mut err = report_missing_lifetime_specifiers(self.tcx.sess, span, lifetime_refs.len());
+ let mut err = self.report_missing_lifetime_specifiers(span, lifetime_refs.len());
let mut add_label = true;
if let Some(params) = error {
}
}
if add_label {
- add_missing_lifetime_specifiers_label(
+ self.add_missing_lifetime_specifiers_label(
&mut err,
- self.tcx.sess.source_map(),
span,
lifetime_refs.len(),
&lifetime_names,
- self.tcx.sess.source_map().span_to_snippet(span).ok().as_ref().map(|s| s.as_str()),
- &self.missing_named_lifetime_spots,
error.map(|p| &p[..]).unwrap_or(&[]),
);
}
let old_value = self.map.defs.remove(&lifetime_ref.hir_id);
assert_eq!(old_value, Some(bad_def));
}
-
- fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool {
- if let 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
- }
}
/// Detects late-bound lifetimes and inserts them into