Skip to content

Commit 83cafab

Browse files
committed
Split astconv's error report code in check functions to mod errors.
Move some error report codes to mod `astconv/errors.rs`
1 parent 6e1f7b5 commit 83cafab

File tree

4 files changed

+185
-133
lines changed

4 files changed

+185
-133
lines changed

compiler/rustc_hir_analysis/src/astconv/errors.rs

+158-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::astconv::AstConv;
2+
use crate::errors::TraitObjectDeclaredWithNoTraits;
23
use crate::errors::{
34
self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
45
ParenthesizedFnTraitExpansion,
@@ -8,6 +9,7 @@ use crate::traits::error_reporting::report_object_safety_error;
89
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
910
use rustc_data_structures::sorted_map::SortedMap;
1011
use rustc_data_structures::unord::UnordMap;
12+
use rustc_errors::MultiSpan;
1113
use rustc_errors::{
1214
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
1315
};
@@ -16,11 +18,22 @@ use rustc_hir::def_id::{DefId, LocalDefId};
1618
use rustc_infer::traits::FulfillmentError;
1719
use rustc_middle::query::Key;
1820
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt};
21+
use rustc_middle::ty::{Binder, TraitRef};
1922
use rustc_session::parse::feature_err;
2023
use rustc_span::edit_distance::find_best_match_for_name;
2124
use rustc_span::symbol::{sym, Ident};
2225
use rustc_span::{Span, Symbol, DUMMY_SP};
23-
use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
26+
use rustc_trait_selection::traits::{
27+
object_safety_violations_for_assoc_item, TraitAliasExpansionInfo,
28+
};
29+
30+
#[derive(PartialEq, Eq, Hash)]
31+
pub enum ProhibitGenericsArg {
32+
Lifetime,
33+
Type,
34+
Const,
35+
Infer,
36+
}
2437

2538
impl<'tcx> dyn AstConv<'tcx> + '_ {
2639
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
@@ -1024,6 +1037,150 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
10241037
Ok(())
10251038
}
10261039
}
1040+
1041+
pub fn report_prohibit_generics_error<'a>(
1042+
&self,
1043+
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
1044+
prohibit_args: FxIndexSet<ProhibitGenericsArg>,
1045+
extend: impl Fn(&mut Diag<'_>),
1046+
) {
1047+
let types_and_spans: Vec<_> = segments
1048+
.clone()
1049+
.flat_map(|segment| {
1050+
if segment.args().args.is_empty() {
1051+
None
1052+
} else {
1053+
Some((
1054+
match segment.res {
1055+
hir::def::Res::PrimTy(ty) => {
1056+
format!("{} `{}`", segment.res.descr(), ty.name())
1057+
}
1058+
hir::def::Res::Def(_, def_id)
1059+
if let Some(name) = self.tcx().opt_item_name(def_id) =>
1060+
{
1061+
format!("{} `{name}`", segment.res.descr())
1062+
}
1063+
hir::def::Res::Err => "this type".to_string(),
1064+
_ => segment.res.descr().to_string(),
1065+
},
1066+
segment.ident.span,
1067+
))
1068+
}
1069+
})
1070+
.collect();
1071+
let this_type = match &types_and_spans[..] {
1072+
[.., _, (last, _)] => format!(
1073+
"{} and {last}",
1074+
types_and_spans[..types_and_spans.len() - 1]
1075+
.iter()
1076+
.map(|(x, _)| x.as_str())
1077+
.intersperse(", ")
1078+
.collect::<String>()
1079+
),
1080+
[(only, _)] => only.to_string(),
1081+
[] => "this type".to_string(),
1082+
};
1083+
1084+
let arg_spans: Vec<Span> = segments
1085+
.clone()
1086+
.flat_map(|segment| segment.args().args)
1087+
.map(|arg| arg.span())
1088+
.collect();
1089+
1090+
let mut kinds = Vec::with_capacity(4);
1091+
prohibit_args.iter().for_each(|arg| match arg {
1092+
ProhibitGenericsArg::Lifetime => kinds.push("lifetime"),
1093+
ProhibitGenericsArg::Type => kinds.push("type"),
1094+
ProhibitGenericsArg::Const => kinds.push("const"),
1095+
ProhibitGenericsArg::Infer => kinds.push("generic"),
1096+
});
1097+
1098+
let (kind, s) = match kinds[..] {
1099+
[.., _, last] => (
1100+
format!(
1101+
"{} and {last}",
1102+
kinds[..kinds.len() - 1]
1103+
.iter()
1104+
.map(|&x| x)
1105+
.intersperse(", ")
1106+
.collect::<String>()
1107+
),
1108+
"s",
1109+
),
1110+
[only] => (only.to_string(), ""),
1111+
[] => unreachable!("expected at least one generic to prohibit"),
1112+
};
1113+
let last_span = *arg_spans.last().unwrap();
1114+
let span: MultiSpan = arg_spans.into();
1115+
let mut err = struct_span_code_err!(
1116+
self.tcx().dcx(),
1117+
span,
1118+
E0109,
1119+
"{kind} arguments are not allowed on {this_type}",
1120+
);
1121+
err.span_label(last_span, format!("{kind} argument{s} not allowed"));
1122+
for (what, span) in types_and_spans {
1123+
err.span_label(span, format!("not allowed on {what}"));
1124+
}
1125+
extend(&mut err);
1126+
self.set_tainted_by_errors(err.emit());
1127+
}
1128+
1129+
pub fn report_trait_object_addition_traits_error(
1130+
&self,
1131+
span: Span,
1132+
trait_bounds: &Vec<(Binder<'tcx, TraitRef<'tcx>>, Span)>,
1133+
auto_traits: &Vec<TraitAliasExpansionInfo<'_>>,
1134+
regular_traits: &Vec<TraitAliasExpansionInfo<'_>>,
1135+
) -> Option<ErrorGuaranteed> {
1136+
let tcx = self.tcx();
1137+
if regular_traits.len() > 1 {
1138+
let first_trait = &regular_traits[0];
1139+
let additional_trait = &regular_traits[1];
1140+
let mut err = struct_span_code_err!(
1141+
tcx.dcx(),
1142+
additional_trait.bottom().1,
1143+
E0225,
1144+
"only auto traits can be used as additional traits in a trait object"
1145+
);
1146+
additional_trait.label_with_exp_info(
1147+
&mut err,
1148+
"additional non-auto trait",
1149+
"additional use",
1150+
);
1151+
first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
1152+
err.help(format!(
1153+
"consider creating a new trait with all of these as supertraits and using that \
1154+
trait here instead: `trait NewTrait: {} {{}}`",
1155+
regular_traits
1156+
.iter()
1157+
// FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
1158+
.map(|t| t.trait_ref().print_only_trait_path().to_string())
1159+
.collect::<Vec<_>>()
1160+
.join(" + "),
1161+
));
1162+
err.note(
1163+
"auto-traits like `Send` and `Sync` are traits that have special properties; \
1164+
for more information on them, visit \
1165+
<https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
1166+
);
1167+
self.set_tainted_by_errors(err.emit());
1168+
}
1169+
1170+
if regular_traits.is_empty() && auto_traits.is_empty() {
1171+
let trait_alias_span = trait_bounds
1172+
.iter()
1173+
.map(|&(trait_ref, _)| trait_ref.def_id())
1174+
.find(|&trait_ref| tcx.is_trait_alias(trait_ref))
1175+
.map(|trait_ref| tcx.def_span(trait_ref));
1176+
let reported =
1177+
tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
1178+
self.set_tainted_by_errors(reported);
1179+
return Some(reported);
1180+
}
1181+
1182+
None
1183+
}
10271184
}
10281185

10291186
/// Emits an error regarding forbidden type binding associations

compiler/rustc_hir_analysis/src/astconv/mod.rs

+13-92
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ pub mod generics;
88
mod lint;
99
mod object_safety;
1010

11-
use crate::astconv::errors::prohibit_assoc_ty_binding;
11+
use crate::astconv::errors::{prohibit_assoc_ty_binding, ProhibitGenericsArg};
1212
use crate::astconv::generics::{check_generic_arg_count, create_args_for_parent_generic_args};
1313
use crate::bounds::Bounds;
1414
use crate::collect::HirPlaceholderCollector;
1515
use crate::errors::AmbiguousLifetimeBound;
1616
use crate::middle::resolve_bound_vars as rbv;
1717
use crate::require_c_abi_if_c_variadic;
1818
use rustc_ast::TraitObjectSyntax;
19-
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
19+
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
2020
use rustc_errors::{
2121
codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError, MultiSpan,
2222
};
@@ -1578,98 +1578,19 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
15781578
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
15791579
extend: impl Fn(&mut Diag<'_>),
15801580
) -> bool {
1581-
let args = segments.clone().flat_map(|segment| segment.args().args);
1582-
1583-
let (lt, ty, ct, inf) =
1584-
args.clone().fold((false, false, false, false), |(lt, ty, ct, inf), arg| match arg {
1585-
hir::GenericArg::Lifetime(_) => (true, ty, ct, inf),
1586-
hir::GenericArg::Type(_) => (lt, true, ct, inf),
1587-
hir::GenericArg::Const(_) => (lt, ty, true, inf),
1588-
hir::GenericArg::Infer(_) => (lt, ty, ct, true),
1589-
});
1590-
let mut emitted = false;
1591-
if lt || ty || ct || inf {
1592-
let types_and_spans: Vec<_> = segments
1593-
.clone()
1594-
.flat_map(|segment| {
1595-
if segment.args().args.is_empty() {
1596-
None
1597-
} else {
1598-
Some((
1599-
match segment.res {
1600-
Res::PrimTy(ty) => {
1601-
format!("{} `{}`", segment.res.descr(), ty.name())
1602-
}
1603-
Res::Def(_, def_id)
1604-
if let Some(name) = self.tcx().opt_item_name(def_id) =>
1605-
{
1606-
format!("{} `{name}`", segment.res.descr())
1607-
}
1608-
Res::Err => "this type".to_string(),
1609-
_ => segment.res.descr().to_string(),
1610-
},
1611-
segment.ident.span,
1612-
))
1613-
}
1614-
})
1615-
.collect();
1616-
let this_type = match &types_and_spans[..] {
1617-
[.., _, (last, _)] => format!(
1618-
"{} and {last}",
1619-
types_and_spans[..types_and_spans.len() - 1]
1620-
.iter()
1621-
.map(|(x, _)| x.as_str())
1622-
.intersperse(", ")
1623-
.collect::<String>()
1624-
),
1625-
[(only, _)] => only.to_string(),
1626-
[] => "this type".to_string(),
1581+
let mut prohibit_args = FxIndexSet::default();
1582+
segments.clone().flat_map(|segment| segment.args().args).for_each(|arg| {
1583+
match arg {
1584+
hir::GenericArg::Lifetime(_) => prohibit_args.insert(ProhibitGenericsArg::Lifetime),
1585+
hir::GenericArg::Type(_) => prohibit_args.insert(ProhibitGenericsArg::Type),
1586+
hir::GenericArg::Const(_) => prohibit_args.insert(ProhibitGenericsArg::Const),
1587+
hir::GenericArg::Infer(_) => prohibit_args.insert(ProhibitGenericsArg::Infer),
16271588
};
1589+
});
16281590

1629-
let arg_spans: Vec<Span> = args.map(|arg| arg.span()).collect();
1630-
1631-
let mut kinds = Vec::with_capacity(4);
1632-
if lt {
1633-
kinds.push("lifetime");
1634-
}
1635-
if ty {
1636-
kinds.push("type");
1637-
}
1638-
if ct {
1639-
kinds.push("const");
1640-
}
1641-
if inf {
1642-
kinds.push("generic");
1643-
}
1644-
let (kind, s) = match kinds[..] {
1645-
[.., _, last] => (
1646-
format!(
1647-
"{} and {last}",
1648-
kinds[..kinds.len() - 1]
1649-
.iter()
1650-
.map(|&x| x)
1651-
.intersperse(", ")
1652-
.collect::<String>()
1653-
),
1654-
"s",
1655-
),
1656-
[only] => (only.to_string(), ""),
1657-
[] => unreachable!("expected at least one generic to prohibit"),
1658-
};
1659-
let last_span = *arg_spans.last().unwrap();
1660-
let span: MultiSpan = arg_spans.into();
1661-
let mut err = struct_span_code_err!(
1662-
self.tcx().dcx(),
1663-
span,
1664-
E0109,
1665-
"{kind} arguments are not allowed on {this_type}",
1666-
);
1667-
err.span_label(last_span, format!("{kind} argument{s} not allowed"));
1668-
for (what, span) in types_and_spans {
1669-
err.span_label(span, format!("not allowed on {what}"));
1670-
}
1671-
extend(&mut err);
1672-
self.set_tainted_by_errors(err.emit());
1591+
let mut emitted = false;
1592+
if !prohibit_args.is_empty() {
1593+
self.report_prohibit_generics_error(segments.clone(), prohibit_args, extend);
16731594
emitted = true;
16741595
}
16751596

compiler/rustc_hir_analysis/src/astconv/object_safety.rs

+13-39
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::astconv::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
22
use crate::bounds::Bounds;
3-
use crate::errors::TraitObjectDeclaredWithNoTraits;
43
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
54
use rustc_errors::{codes::*, struct_span_code_err};
65
use rustc_hir as hir;
@@ -84,48 +83,23 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
8483
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
8584
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
8685
if regular_traits.len() > 1 {
87-
let first_trait = &regular_traits[0];
88-
let additional_trait = &regular_traits[1];
89-
let mut err = struct_span_code_err!(
90-
tcx.dcx(),
91-
additional_trait.bottom().1,
92-
E0225,
93-
"only auto traits can be used as additional traits in a trait object"
86+
self.report_trait_object_addition_traits_error(
87+
span,
88+
&trait_bounds,
89+
&auto_traits,
90+
&regular_traits,
9491
);
95-
additional_trait.label_with_exp_info(
96-
&mut err,
97-
"additional non-auto trait",
98-
"additional use",
99-
);
100-
first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
101-
err.help(format!(
102-
"consider creating a new trait with all of these as supertraits and using that \
103-
trait here instead: `trait NewTrait: {} {{}}`",
104-
regular_traits
105-
.iter()
106-
// FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
107-
.map(|t| t.trait_ref().print_only_trait_path().to_string())
108-
.collect::<Vec<_>>()
109-
.join(" + "),
110-
));
111-
err.note(
112-
"auto-traits like `Send` and `Sync` are traits that have special properties; \
113-
for more information on them, visit \
114-
<https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
115-
);
116-
self.set_tainted_by_errors(err.emit());
11792
}
11893

11994
if regular_traits.is_empty() && auto_traits.is_empty() {
120-
let trait_alias_span = trait_bounds
121-
.iter()
122-
.map(|&(trait_ref, _)| trait_ref.def_id())
123-
.find(|&trait_ref| tcx.is_trait_alias(trait_ref))
124-
.map(|trait_ref| tcx.def_span(trait_ref));
125-
let reported =
126-
tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
127-
self.set_tainted_by_errors(reported);
128-
return Ty::new_error(tcx, reported);
95+
if let Some(reported) = self.report_trait_object_addition_traits_error(
96+
span,
97+
&trait_bounds,
98+
&auto_traits,
99+
&regular_traits,
100+
) {
101+
return Ty::new_error(tcx, reported);
102+
}
129103
}
130104

131105
// Check that there are no gross object safety violations;

compiler/rustc_trait_selection/src/traits/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pub use self::util::{
6565
check_args_compatible, supertrait_def_ids, supertraits, transitive_bounds,
6666
transitive_bounds_that_define_assoc_item, SupertraitDefIds,
6767
};
68-
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
68+
pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo};
6969
pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
7070
pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
7171

0 commit comments

Comments
 (0)