Skip to content

Commit e9ef8c6

Browse files
committed
review comments: move error reporting to their own methods
1 parent a89f03d commit e9ef8c6

File tree

1 file changed

+192
-162
lines changed

1 file changed

+192
-162
lines changed

src/librustc_typeck/astconv.rs

Lines changed: 192 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -743,57 +743,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
743743
}
744744
},
745745
);
746-
if !missing_type_params.is_empty() {
747-
let display = missing_type_params.iter()
748-
.map(|n| format!("`{}`", n))
749-
.collect::<Vec<_>>().join(", ");
750-
let mut err = struct_span_err!(tcx.sess, span, E0393,
751-
"the type parameter{} {} must be explicitly specified",
752-
pluralize!(missing_type_params.len()),
753-
display,
754-
);
755-
err.span_label(self.tcx().def_span(def_id), &format!(
756-
"type parameter{} {} must be specified for this",
757-
pluralize!(missing_type_params.len()),
758-
display,
759-
));
760-
let mut suggested = false;
761-
if let (Ok(snippet), true) = (
762-
tcx.sess.source_map().span_to_snippet(span),
763-
// Don't suggest setting the type params if there are some already: the order is
764-
// tricky to get right and the user will already know what the syntax is.
765-
generic_args.args.is_empty(),
766-
) {
767-
if snippet.ends_with('>') {
768-
// The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion
769-
// we would have to preserve the right order. For now, as clearly the user is
770-
// aware of the syntax, we do nothing.
771-
} else {
772-
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
773-
// least we can clue them to the correct syntax `Iterator<Type>`.
774-
err.span_suggestion(
775-
span,
776-
&format!(
777-
"set the type parameter{plural} to the desired type{plural}",
778-
plural=pluralize!(missing_type_params.len()),
779-
),
780-
format!("{}<{}>", snippet, missing_type_params.join(", ")),
781-
Applicability::HasPlaceholders,
782-
);
783-
suggested = true;
784-
}
785-
}
786-
if !suggested {
787-
err.span_label(span, format!(
788-
"missing reference{} to {}",
789-
pluralize!(missing_type_params.len()),
790-
display,
791-
));
792-
}
793-
err.note(&format!("because of the default `Self` reference, type parameters must be \
794-
specified on object types"));
795-
err.emit();
796-
}
746+
747+
self.complain_about_missing_type_params(
748+
missing_type_params,
749+
def_id,
750+
span,
751+
generic_args.args.is_empty(),
752+
);
797753

798754
// Convert associated-type bindings or constraints into a separate vector.
799755
// Example: Given this:
@@ -826,6 +782,67 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
826782
(substs, assoc_bindings, potential_assoc_types)
827783
}
828784

785+
fn complain_about_missing_type_params(
786+
&self,
787+
missing_type_params: Vec<String>,
788+
def_id: DefId,
789+
span: Span,
790+
empty_generic_args: bool,
791+
) {
792+
if missing_type_params.is_empty() {
793+
return;
794+
}
795+
let display = missing_type_params.iter()
796+
.map(|n| format!("`{}`", n))
797+
.collect::<Vec<_>>().join(", ");
798+
let mut err = struct_span_err!(self.tcx().sess, span, E0393,
799+
"the type parameter{} {} must be explicitly specified",
800+
pluralize!(missing_type_params.len()),
801+
display,
802+
);
803+
err.span_label(self.tcx().def_span(def_id), &format!(
804+
"type parameter{} {} must be specified for this",
805+
pluralize!(missing_type_params.len()),
806+
display,
807+
));
808+
let mut suggested = false;
809+
if let (Ok(snippet), true) = (
810+
self.tcx().sess.source_map().span_to_snippet(span),
811+
// Don't suggest setting the type params if there are some already: the order is
812+
// tricky to get right and the user will already know what the syntax is.
813+
empty_generic_args,
814+
) {
815+
if snippet.ends_with('>') {
816+
// The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion
817+
// we would have to preserve the right order. For now, as clearly the user is
818+
// aware of the syntax, we do nothing.
819+
} else {
820+
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
821+
// least we can clue them to the correct syntax `Iterator<Type>`.
822+
err.span_suggestion(
823+
span,
824+
&format!(
825+
"set the type parameter{plural} to the desired type{plural}",
826+
plural=pluralize!(missing_type_params.len()),
827+
),
828+
format!("{}<{}>", snippet, missing_type_params.join(", ")),
829+
Applicability::HasPlaceholders,
830+
);
831+
suggested = true;
832+
}
833+
}
834+
if !suggested {
835+
err.span_label(span, format!(
836+
"missing reference{} to {}",
837+
pluralize!(missing_type_params.len()),
838+
display,
839+
));
840+
}
841+
err.note(&format!("because of the default `Self` reference, type parameters must be \
842+
specified on object types"));
843+
err.emit();
844+
}
845+
829846
/// Instantiates the path for the given trait reference, assuming that it's
830847
/// bound to a valid trait type. Returns the `DefId` of the defining trait.
831848
/// The type _cannot_ be a type other than a trait type.
@@ -859,13 +876,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
859876

860877
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
861878

862-
let path_span = if trait_ref.path.segments.len() == 1 {
879+
let path_span = if let [segment] = &trait_ref.path.segments[..] {
863880
// FIXME: `trait_ref.path.span` can point to a full path with multiple
864881
// segments, even though `trait_ref.path.segments` is of length `1`. Work
865882
// around that bug here, even though it should be fixed elsewhere.
866883
// This would otherwise cause an invalid suggestion. For an example, look at
867884
// `src/test/ui/issues/issue-28344.rs`.
868-
trait_ref.path.segments[0].ident.span
885+
segment.ident.span
869886
} else {
870887
trait_ref.path.span
871888
};
@@ -1397,115 +1414,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
13971414
associated_types.remove(&projection_bound.projection_def_id());
13981415
}
13991416

1400-
if !associated_types.is_empty() {
1401-
// Account for things like `dyn Foo + 'a` by pointing at the `TraitRef.path`
1402-
// `Span` instead of the `PolyTraitRef` `Span`. That way the suggestion will
1403-
// be valid, otherwise we would suggest `dyn Foo + 'a<A = Type>`. See tests
1404-
// `issue-22434.rs` and `issue-22560.rs` for examples.
1405-
let sugg_span = if potential_assoc_types.is_empty() && trait_bounds.len() == 1 {
1406-
if trait_bounds[0].trait_ref.path.segments.len() == 1 &&
1407-
trait_bounds[0].trait_ref.path.segments[0].args.is_none()
1408-
{
1409-
// FIXME: `trait_ref.path.span` can point to a full path with multiple
1410-
// segments, even though `trait_ref.path.segments` is of length `1`. Work
1411-
// around that bug here, even though it should be fixed elsewhere.
1412-
// This would otherwise cause an invalid suggestion. For an example, look at
1413-
// `src/test/ui/issues/issue-28344.rs`.
1414-
trait_bounds[0].trait_ref.path.segments[0].ident.span
1415-
} else {
1416-
trait_bounds[0].trait_ref.path.span
1417-
}
1418-
} else {
1419-
span
1420-
};
1421-
let names = associated_types.iter().map(|item_def_id| {
1422-
let assoc_item = tcx.associated_item(*item_def_id);
1423-
let trait_def_id = assoc_item.container.id();
1424-
format!("`{}` (from trait `{}`)", assoc_item.ident, tcx.def_path_str(trait_def_id))
1425-
}).collect::<Vec<_>>().join(", ");
1426-
let mut err = struct_span_err!(
1427-
tcx.sess,
1428-
sugg_span,
1429-
E0191,
1430-
"the value of the associated type{} {} must be specified",
1431-
pluralize!(associated_types.len()),
1432-
names,
1433-
);
1434-
let mut suggestions = Vec::new();
1435-
let mut applicability = Applicability::MaybeIncorrect;
1436-
for (i, item_def_id) in associated_types.iter().enumerate() {
1437-
let assoc_item = tcx.associated_item(*item_def_id);
1438-
if let Some(sp) = tcx.hir().span_if_local(*item_def_id) {
1439-
err.span_label(sp, format!("`{}` defined here", assoc_item.ident));
1440-
}
1441-
if potential_assoc_types.len() == associated_types.len() {
1442-
// Only suggest when the amount of missing associated types equals the number of
1443-
// extra type arguments present, as that gives us a relatively high confidence
1444-
// that the user forgot to give the associtated type's name. The canonical
1445-
// example would be trying to use `Iterator<isize>` instead of
1446-
// `Iterator<Item = isize>`.
1447-
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(
1448-
potential_assoc_types[i],
1449-
) {
1450-
suggestions.push((
1451-
potential_assoc_types[i],
1452-
format!("{} = {}", assoc_item.ident, snippet),
1453-
));
1454-
}
1455-
}
1456-
}
1457-
let mut suggestions_len = suggestions.len();
1458-
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sugg_span) {
1459-
if potential_assoc_types.is_empty() && trait_bounds.len() == 1 &&
1460-
// Do not attempt to suggest when we don't know which path segment needs the
1461-
// type parameter set.
1462-
trait_bounds[0].trait_ref.path.segments.len() == 1
1463-
{
1464-
debug!("path segments {:?}", trait_bounds[0].trait_ref.path.segments);
1465-
applicability = Applicability::HasPlaceholders;
1466-
let assoc_types: Vec<String> = associated_types.iter()
1467-
.map(|item_def_id| {
1468-
let assoc_item = tcx.associated_item(*item_def_id);
1469-
format!("{} = Type", assoc_item.ident)
1470-
})
1471-
.collect();
1472-
let sugg = assoc_types.join(", ");
1473-
if snippet.ends_with('>') {
1474-
// The user wrote `Trait<'a>` or similar and we don't have a type we can
1475-
// suggest, but at least we can clue them to the correct syntax
1476-
// `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
1477-
// suggestion.
1478-
suggestions.push((sugg_span, format!(
1479-
"{}, {}>",
1480-
&snippet[..snippet.len()-1],
1481-
sugg,
1482-
)));
1483-
} else {
1484-
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
1485-
// least we can clue them to the correct syntax `Iterator<Item = Type>`.
1486-
suggestions.push((sugg_span, format!("{}<{}>", snippet, sugg)));
1487-
}
1488-
suggestions_len = assoc_types.len();
1489-
}
1490-
}
1491-
if suggestions.len() != 1 {
1492-
// We don't need this label if there's an inline suggestion, show otherwise.
1493-
let names = associated_types.iter()
1494-
.map(|t| format!("`{}`", tcx.associated_item(*t).ident))
1495-
.collect::<Vec<_>>()
1496-
.join(", ");
1497-
err.span_label(span, format!(
1498-
"associated type{} {} must be specified",
1499-
pluralize!(associated_types.len()),
1500-
names,
1501-
));
1502-
}
1503-
if !suggestions.is_empty() {
1504-
let msg = format!("specify the associated type{}", pluralize!(suggestions_len));
1505-
err.multipart_suggestion(&msg, suggestions, applicability);
1506-
}
1507-
err.emit();
1508-
}
1417+
self.complain_about_missing_associated_types(
1418+
span,
1419+
associated_types,
1420+
potential_assoc_types,
1421+
trait_bounds,
1422+
);
15091423

15101424
// De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
15111425
// `dyn Trait + Send`.
@@ -1585,6 +1499,122 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
15851499
ty
15861500
}
15871501

1502+
fn complain_about_missing_associated_types(
1503+
&self,
1504+
span: Span,
1505+
associated_types: BTreeSet<DefId>,
1506+
potential_assoc_types: Vec<Span>,
1507+
trait_bounds: &[hir::PolyTraitRef],
1508+
) {
1509+
if associated_types.is_empty() {
1510+
return;
1511+
}
1512+
// Account for things like `dyn Foo + 'a` by pointing at the `TraitRef.path`
1513+
// `Span` instead of the `PolyTraitRef` `Span`. That way the suggestion will
1514+
// be valid, otherwise we would suggest `dyn Foo + 'a<A = Type>`. See tests
1515+
// `issue-22434.rs` and `issue-22560.rs` for examples.
1516+
let sugg_span = match (&potential_assoc_types[..], &trait_bounds) {
1517+
([], [bound]) => match &bound.trait_ref.path.segments[..] {
1518+
// FIXME: `trait_ref.path.span` can point to a full path with multiple
1519+
// segments, even though `trait_ref.path.segments` is of length `1`. Work
1520+
// around that bug here, even though it should be fixed elsewhere.
1521+
// This would otherwise cause an invalid suggestion. For an example, look at
1522+
// `src/test/ui/issues/issue-28344.rs`.
1523+
[segment] if segment.args.is_none() => segment.ident.span,
1524+
_ => bound.trait_ref.path.span,
1525+
},
1526+
_ => span,
1527+
};
1528+
let tcx = self.tcx();
1529+
let names = associated_types.iter().map(|item_def_id| {
1530+
let assoc_item = tcx.associated_item(*item_def_id);
1531+
let trait_def_id = assoc_item.container.id();
1532+
format!("`{}` (from trait `{}`)", assoc_item.ident, tcx.def_path_str(trait_def_id))
1533+
}).collect::<Vec<_>>().join(", ");
1534+
let mut err = struct_span_err!(
1535+
tcx.sess,
1536+
sugg_span,
1537+
E0191,
1538+
"the value of the associated type{} {} must be specified",
1539+
pluralize!(associated_types.len()),
1540+
names,
1541+
);
1542+
let mut suggestions = Vec::new();
1543+
let mut applicability = Applicability::MaybeIncorrect;
1544+
for (i, item_def_id) in associated_types.iter().enumerate() {
1545+
let assoc_item = tcx.associated_item(*item_def_id);
1546+
if let Some(sp) = tcx.hir().span_if_local(*item_def_id) {
1547+
err.span_label(sp, format!("`{}` defined here", assoc_item.ident));
1548+
}
1549+
if potential_assoc_types.len() == associated_types.len() {
1550+
// Only suggest when the amount of missing associated types equals the number of
1551+
// extra type arguments present, as that gives us a relatively high confidence
1552+
// that the user forgot to give the associtated type's name. The canonical
1553+
// example would be trying to use `Iterator<isize>` instead of
1554+
// `Iterator<Item = isize>`.
1555+
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(
1556+
potential_assoc_types[i],
1557+
) {
1558+
suggestions.push((
1559+
potential_assoc_types[i],
1560+
format!("{} = {}", assoc_item.ident, snippet),
1561+
));
1562+
}
1563+
}
1564+
}
1565+
let mut suggestions_len = suggestions.len();
1566+
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sugg_span) {
1567+
if potential_assoc_types.is_empty() && trait_bounds.len() == 1 &&
1568+
// Do not attempt to suggest when we don't know which path segment needs the
1569+
// type parameter set.
1570+
trait_bounds[0].trait_ref.path.segments.len() == 1
1571+
{
1572+
debug!("path segments {:?}", trait_bounds[0].trait_ref.path.segments);
1573+
applicability = Applicability::HasPlaceholders;
1574+
let assoc_types: Vec<String> = associated_types.iter()
1575+
.map(|item_def_id| {
1576+
let assoc_item = tcx.associated_item(*item_def_id);
1577+
format!("{} = Type", assoc_item.ident)
1578+
})
1579+
.collect();
1580+
let sugg = assoc_types.join(", ");
1581+
if snippet.ends_with('>') {
1582+
// The user wrote `Trait<'a>` or similar and we don't have a type we can
1583+
// suggest, but at least we can clue them to the correct syntax
1584+
// `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
1585+
// suggestion.
1586+
suggestions.push((sugg_span, format!(
1587+
"{}, {}>",
1588+
&snippet[..snippet.len()-1],
1589+
sugg,
1590+
)));
1591+
} else {
1592+
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
1593+
// least we can clue them to the correct syntax `Iterator<Item = Type>`.
1594+
suggestions.push((sugg_span, format!("{}<{}>", snippet, sugg)));
1595+
}
1596+
suggestions_len = assoc_types.len();
1597+
}
1598+
}
1599+
if suggestions.len() != 1 {
1600+
// We don't need this label if there's an inline suggestion, show otherwise.
1601+
let names = associated_types.iter()
1602+
.map(|t| format!("`{}`", tcx.associated_item(*t).ident))
1603+
.collect::<Vec<_>>()
1604+
.join(", ");
1605+
err.span_label(span, format!(
1606+
"associated type{} {} must be specified",
1607+
pluralize!(associated_types.len()),
1608+
names,
1609+
));
1610+
}
1611+
if !suggestions.is_empty() {
1612+
let msg = format!("specify the associated type{}", pluralize!(suggestions_len));
1613+
err.multipart_suggestion(&msg, suggestions, applicability);
1614+
}
1615+
err.emit();
1616+
}
1617+
15881618
fn report_ambiguous_associated_type(
15891619
&self,
15901620
span: Span,

0 commit comments

Comments
 (0)