Skip to content

Commit bedda9d

Browse files
committed
Move code to diagnostics.rs
1 parent 33513e6 commit bedda9d

File tree

2 files changed

+214
-200
lines changed

2 files changed

+214
-200
lines changed

src/librustc_resolve/diagnostics.rs

+207-91
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc::ty::{self, DefIdTree};
77
use rustc_data_structures::fx::FxHashSet;
88
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
99
use rustc_feature::BUILTIN_ATTRIBUTES;
10+
use rustc_hir as hir;
1011
use rustc_hir::def::Namespace::{self, *};
1112
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind};
1213
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
@@ -19,7 +20,7 @@ use syntax::print::pprust;
1920
use syntax::util::lev_distance::find_best_match_for_name;
2021

2122
use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
22-
use crate::lifetimes::{ElisionFailureInfo, MissingLifetimeSpot};
23+
use crate::lifetimes::{ElisionFailureInfo, LifetimeContext};
2324
use crate::path_names_to_string;
2425
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind};
2526
use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot};
@@ -48,6 +49,40 @@ crate struct ImportSuggestion {
4849
pub path: Path,
4950
}
5051

52+
crate enum MissingLifetimeSpot<'tcx> {
53+
Generics(&'tcx hir::Generics<'tcx>),
54+
HigherRanked { span: Span, span_type: ForLifetimeSpanType },
55+
}
56+
57+
crate enum ForLifetimeSpanType {
58+
BoundEmpty,
59+
BoundTail,
60+
TypeEmpty,
61+
TypeTail,
62+
}
63+
64+
impl ForLifetimeSpanType {
65+
crate fn descr(&self) -> &'static str {
66+
match self {
67+
Self::BoundEmpty | Self::BoundTail => "bound",
68+
Self::TypeEmpty | Self::TypeTail => "type",
69+
}
70+
}
71+
72+
crate fn suggestion(&self, sugg: &str) -> String {
73+
match self {
74+
Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg),
75+
Self::BoundTail | Self::TypeTail => format!(", {}", sugg),
76+
}
77+
}
78+
}
79+
80+
impl<'tcx> Into<MissingLifetimeSpot<'tcx>> for &'tcx hir::Generics<'tcx> {
81+
fn into(self) -> MissingLifetimeSpot<'tcx> {
82+
MissingLifetimeSpot::Generics(self)
83+
}
84+
}
85+
5186
/// Adjust the impl span so that just the `impl` keyword is taken by removing
5287
/// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and
5388
/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`).
@@ -1452,104 +1487,185 @@ crate fn show_candidates(
14521487
}
14531488
}
14541489

1455-
crate fn report_missing_lifetime_specifiers(
1456-
sess: &Session,
1457-
span: Span,
1458-
count: usize,
1459-
) -> DiagnosticBuilder<'_> {
1460-
struct_span_err!(sess, span, E0106, "missing lifetime specifier{}", pluralize!(count))
1461-
}
1490+
impl<'tcx> LifetimeContext<'_, 'tcx> {
1491+
crate fn report_missing_lifetime_specifiers(
1492+
&self,
1493+
span: Span,
1494+
count: usize,
1495+
) -> DiagnosticBuilder<'tcx> {
1496+
struct_span_err!(
1497+
self.tcx.sess,
1498+
span,
1499+
E0106,
1500+
"missing lifetime specifier{}",
1501+
pluralize!(count)
1502+
)
1503+
}
14621504

1463-
crate fn add_missing_lifetime_specifiers_label(
1464-
err: &mut DiagnosticBuilder<'_>,
1465-
source_map: &SourceMap,
1466-
span: Span,
1467-
count: usize,
1468-
lifetime_names: &FxHashSet<ast::Ident>,
1469-
snippet: Option<&str>,
1470-
missing_named_lifetime_spots: &[MissingLifetimeSpot<'_>],
1471-
params: &[ElisionFailureInfo],
1472-
) {
1473-
if count > 1 {
1474-
err.span_label(span, format!("expected {} lifetime parameters", count));
1475-
} else {
1476-
let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| {
1477-
err.span_suggestion(
1478-
span,
1479-
"consider using the named lifetime",
1480-
sugg,
1481-
Applicability::MaybeIncorrect,
1482-
);
1505+
crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) {
1506+
let mut err = struct_span_err!(
1507+
self.tcx.sess,
1508+
lifetime_ref.span,
1509+
E0261,
1510+
"use of undeclared lifetime name `{}`",
1511+
lifetime_ref
1512+
);
1513+
err.span_label(lifetime_ref.span, "undeclared lifetime");
1514+
for missing in &self.missing_named_lifetime_spots {
1515+
match missing {
1516+
MissingLifetimeSpot::Generics(generics) => {
1517+
let (span, sugg) = match &generics.params {
1518+
[] => (generics.span, format!("<{}>", lifetime_ref)),
1519+
[param, ..] => (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)),
1520+
};
1521+
err.span_suggestion(
1522+
span,
1523+
&format!("consider introducing lifetime `{}` here", lifetime_ref),
1524+
sugg,
1525+
Applicability::MaybeIncorrect,
1526+
);
1527+
}
1528+
MissingLifetimeSpot::HigherRanked { span, span_type } => {
1529+
err.span_suggestion(
1530+
*span,
1531+
&format!(
1532+
"consider making the {} lifetime-generic with a new `{}` lifetime",
1533+
span_type.descr(),
1534+
lifetime_ref
1535+
),
1536+
span_type.suggestion(&lifetime_ref.to_string()),
1537+
Applicability::MaybeIncorrect,
1538+
);
1539+
err.note(
1540+
"for more information on higher-ranked polymorphism, visit \
1541+
https://doc.rust-lang.org/nomicon/hrtb.html",
1542+
);
1543+
}
1544+
}
1545+
}
1546+
err.emit();
1547+
}
1548+
1549+
crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool {
1550+
if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res {
1551+
if [
1552+
self.tcx.lang_items().fn_once_trait(),
1553+
self.tcx.lang_items().fn_trait(),
1554+
self.tcx.lang_items().fn_mut_trait(),
1555+
]
1556+
.contains(&Some(did))
1557+
{
1558+
let (span, span_type) = match &trait_ref.bound_generic_params {
1559+
[] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty),
1560+
[.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail),
1561+
};
1562+
self.missing_named_lifetime_spots
1563+
.push(MissingLifetimeSpot::HigherRanked { span, span_type });
1564+
return true;
1565+
}
14831566
};
1484-
let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg: &str| {
1485-
err.span_label(span, "expected named lifetime parameter");
1486-
1487-
for missing in missing_named_lifetime_spots.iter().rev() {
1488-
let mut introduce_suggestion = vec![];
1489-
let msg;
1490-
let should_break;
1491-
introduce_suggestion.push(match missing {
1492-
MissingLifetimeSpot::Generics(generics) => {
1493-
msg = "consider introducing a named lifetime parameter".to_string();
1494-
should_break = true;
1495-
match &generics.params {
1496-
[] => (generics.span, "<'a>".to_string()),
1497-
[param, ..] => (param.span.shrink_to_lo(), "'a, ".to_string()),
1567+
false
1568+
}
1569+
1570+
crate fn add_missing_lifetime_specifiers_label(
1571+
&self,
1572+
err: &mut DiagnosticBuilder<'_>,
1573+
span: Span,
1574+
count: usize,
1575+
lifetime_names: &FxHashSet<ast::Ident>,
1576+
params: &[ElisionFailureInfo],
1577+
) {
1578+
if count > 1 {
1579+
err.span_label(span, format!("expected {} lifetime parameters", count));
1580+
} else {
1581+
let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok();
1582+
let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| {
1583+
err.span_suggestion(
1584+
span,
1585+
"consider using the named lifetime",
1586+
sugg,
1587+
Applicability::MaybeIncorrect,
1588+
);
1589+
};
1590+
let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg: &str| {
1591+
err.span_label(span, "expected named lifetime parameter");
1592+
1593+
for missing in self.missing_named_lifetime_spots.iter().rev() {
1594+
let mut introduce_suggestion = vec![];
1595+
let msg;
1596+
let should_break;
1597+
introduce_suggestion.push(match missing {
1598+
MissingLifetimeSpot::Generics(generics) => {
1599+
msg = "consider introducing a named lifetime parameter".to_string();
1600+
should_break = true;
1601+
match &generics.params {
1602+
[] => (generics.span, "<'a>".to_string()),
1603+
[param, ..] => (param.span.shrink_to_lo(), "'a, ".to_string()),
1604+
}
14981605
}
1499-
}
1500-
MissingLifetimeSpot::HigherRanked { span, span_type } => {
1501-
msg = format!(
1502-
"consider making the {} lifetime-generic with a new `'a` lifetime",
1503-
span_type.descr(),
1504-
);
1505-
should_break = false;
1506-
err.note(
1507-
"for more information on higher-ranked polymorphism, visit \
1606+
MissingLifetimeSpot::HigherRanked { span, span_type } => {
1607+
msg = format!(
1608+
"consider making the {} lifetime-generic with a new `'a` lifetime",
1609+
span_type.descr(),
1610+
);
1611+
should_break = false;
1612+
err.note(
1613+
"for more information on higher-ranked polymorphism, visit \
15081614
https://doc.rust-lang.org/nomicon/hrtb.html",
1509-
);
1510-
(*span, span_type.suggestion("'a"))
1511-
}
1512-
});
1513-
for param in params {
1514-
if let Ok(snippet) = source_map.span_to_snippet(param.span) {
1515-
if snippet.starts_with("&") && !snippet.starts_with("&'") {
1516-
introduce_suggestion
1517-
.push((param.span, format!("&'a {}", &snippet[1..])));
1518-
} else if snippet.starts_with("&'_ ") {
1519-
introduce_suggestion
1520-
.push((param.span, format!("&'a {}", &snippet[4..])));
1615+
);
1616+
(*span, span_type.suggestion("'a"))
1617+
}
1618+
});
1619+
for param in params {
1620+
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span)
1621+
{
1622+
if snippet.starts_with("&") && !snippet.starts_with("&'") {
1623+
introduce_suggestion
1624+
.push((param.span, format!("&'a {}", &snippet[1..])));
1625+
} else if snippet.starts_with("&'_ ") {
1626+
introduce_suggestion
1627+
.push((param.span, format!("&'a {}", &snippet[4..])));
1628+
}
15211629
}
15221630
}
1631+
introduce_suggestion.push((span, sugg.to_string()));
1632+
err.multipart_suggestion(
1633+
&msg,
1634+
introduce_suggestion,
1635+
Applicability::MaybeIncorrect,
1636+
);
1637+
if should_break {
1638+
break;
1639+
}
15231640
}
1524-
introduce_suggestion.push((span, sugg.to_string()));
1525-
err.multipart_suggestion(&msg, introduce_suggestion, Applicability::MaybeIncorrect);
1526-
if should_break {
1527-
break;
1528-
}
1529-
}
1530-
};
1641+
};
15311642

1532-
match (lifetime_names.len(), lifetime_names.iter().next(), snippet) {
1533-
(1, Some(name), Some("&")) => {
1534-
suggest_existing(err, format!("&{} ", name));
1535-
}
1536-
(1, Some(name), Some("'_")) => {
1537-
suggest_existing(err, name.to_string());
1538-
}
1539-
(1, Some(name), Some(snippet)) if !snippet.ends_with(">") => {
1540-
suggest_existing(err, format!("{}<{}>", snippet, name));
1541-
}
1542-
(0, _, Some("&")) => {
1543-
suggest_new(err, "&'a ");
1544-
}
1545-
(0, _, Some("'_")) => {
1546-
suggest_new(err, "'a");
1547-
}
1548-
(0, _, Some(snippet)) if !snippet.ends_with(">") => {
1549-
suggest_new(err, &format!("{}<'a>", snippet));
1550-
}
1551-
_ => {
1552-
err.span_label(span, "expected lifetime parameter");
1643+
match (
1644+
lifetime_names.len(),
1645+
lifetime_names.iter().next(),
1646+
snippet.as_ref().map(|s| s.as_str()),
1647+
) {
1648+
(1, Some(name), Some("&")) => {
1649+
suggest_existing(err, format!("&{} ", name));
1650+
}
1651+
(1, Some(name), Some("'_")) => {
1652+
suggest_existing(err, name.to_string());
1653+
}
1654+
(1, Some(name), Some(snippet)) if !snippet.ends_with(">") => {
1655+
suggest_existing(err, format!("{}<{}>", snippet, name));
1656+
}
1657+
(0, _, Some("&")) => {
1658+
suggest_new(err, "&'a ");
1659+
}
1660+
(0, _, Some("'_")) => {
1661+
suggest_new(err, "'a");
1662+
}
1663+
(0, _, Some(snippet)) if !snippet.ends_with(">") => {
1664+
suggest_new(err, &format!("{}<'a>", snippet));
1665+
}
1666+
_ => {
1667+
err.span_label(span, "expected lifetime parameter");
1668+
}
15531669
}
15541670
}
15551671
}

0 commit comments

Comments
 (0)