Skip to content

Commit 71fd305

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 c3b05c6 commit 71fd305

File tree

5 files changed

+337
-255
lines changed

5 files changed

+337
-255
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

+275-6
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,33 @@
11
use crate::errors::{
22
self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
3-
ParenthesizedFnTraitExpansion,
3+
ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
44
};
55
use crate::fluent_generated as fluent;
66
use crate::hir_ty_lowering::HirTyLowerer;
77
use crate::traits::error_reporting::report_object_safety_error;
88
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
99
use rustc_data_structures::sorted_map::SortedMap;
1010
use rustc_data_structures::unord::UnordMap;
11+
use rustc_errors::MultiSpan;
1112
use rustc_errors::{
1213
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
1314
};
1415
use rustc_hir as hir;
16+
use rustc_hir::def::{DefKind, Res};
1517
use rustc_hir::def_id::{DefId, LocalDefId};
1618
use rustc_infer::traits::FulfillmentError;
1719
use rustc_middle::query::Key;
18-
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt};
20+
use rustc_middle::ty::{self, suggest_constraining_type_param};
21+
use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt};
22+
use rustc_middle::ty::{Binder, TraitRef};
1923
use rustc_session::parse::feature_err;
2024
use rustc_span::edit_distance::find_best_match_for_name;
21-
use rustc_span::symbol::{sym, Ident};
25+
use rustc_span::symbol::{kw, sym, Ident};
26+
use rustc_span::BytePos;
2227
use rustc_span::{Span, Symbol, DUMMY_SP};
23-
use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
28+
use rustc_trait_selection::traits::{
29+
object_safety_violations_for_assoc_item, TraitAliasExpansionInfo,
30+
};
2431

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

10291204
/// Emits an error regarding forbidden type binding associations
10301205
pub fn prohibit_assoc_item_binding(
10311206
tcx: TyCtxt<'_>,
10321207
span: Span,
10331208
segment: Option<(&hir::PathSegment<'_>, Span)>,
1034-
) {
1035-
tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
1209+
) -> ErrorGuaranteed {
1210+
return tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
10361211
span,
10371212
fn_trait_expansion: if let Some((segment, span)) = segment
10381213
&& segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
@@ -1099,3 +1274,97 @@ pub(crate) fn fn_trait_to_string(
10991274
format!("{}<{}, Output={}>", trait_segment.ident, args, ret)
11001275
}
11011276
}
1277+
1278+
/// Used for extending enum variants generics error.
1279+
pub struct EnumVariantsGenericsErrExtend<'tcx> {
1280+
pub tcx: TyCtxt<'tcx>,
1281+
pub qself: &'tcx hir::Ty<'tcx>,
1282+
pub assoc_segment: &'tcx hir::PathSegment<'tcx>,
1283+
pub adt_def: AdtDef<'tcx>,
1284+
}
1285+
1286+
pub fn enum_variants_generics_error_extend(
1287+
err: &mut Diag<'_>,
1288+
enum_variants_extend: EnumVariantsGenericsErrExtend<'_>,
1289+
) {
1290+
err.note("enum variants can't have type parameters");
1291+
let type_name = enum_variants_extend.tcx.item_name(enum_variants_extend.adt_def.did());
1292+
let msg = format!(
1293+
"you might have meant to specify type parameters on enum \
1294+
`{type_name}`"
1295+
);
1296+
let Some(args) = enum_variants_extend.assoc_segment.args else {
1297+
return;
1298+
};
1299+
// Get the span of the generics args *including* the leading `::`.
1300+
// We do so by stretching args.span_ext to the left by 2. Earlier
1301+
// it was done based on the end of assoc segment but that sometimes
1302+
// led to impossible spans and caused issues like #116473
1303+
let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
1304+
if enum_variants_extend.tcx.generics_of(enum_variants_extend.adt_def.did()).count() == 0 {
1305+
// FIXME(estebank): we could also verify that the arguments being
1306+
// work for the `enum`, instead of just looking if it takes *any*.
1307+
err.span_suggestion_verbose(
1308+
args_span,
1309+
format!("{type_name} doesn't have generic parameters"),
1310+
"",
1311+
Applicability::MachineApplicable,
1312+
);
1313+
return;
1314+
}
1315+
let Ok(snippet) = enum_variants_extend.tcx.sess.source_map().span_to_snippet(args_span) else {
1316+
err.note(msg);
1317+
return;
1318+
};
1319+
let (qself_sugg_span, is_self) = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) =
1320+
&enum_variants_extend.qself.kind
1321+
{
1322+
// If the path segment already has type params, we want to overwrite
1323+
// them.
1324+
match &path.segments {
1325+
// `segment` is the previous to last element on the path,
1326+
// which would normally be the `enum` itself, while the last
1327+
// `_` `PathSegment` corresponds to the variant.
1328+
[.., hir::PathSegment { ident, args, res: Res::Def(DefKind::Enum, _), .. }, _] => (
1329+
// We need to include the `::` in `Type::Variant::<Args>`
1330+
// to point the span to `::<Args>`, not just `<Args>`.
1331+
ident
1332+
.span
1333+
.shrink_to_hi()
1334+
.to(args.map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
1335+
false,
1336+
),
1337+
[segment] => {
1338+
(
1339+
// We need to include the `::` in `Type::Variant::<Args>`
1340+
// to point the span to `::<Args>`, not just `<Args>`.
1341+
segment
1342+
.ident
1343+
.span
1344+
.shrink_to_hi()
1345+
.to(segment.args.map_or(segment.ident.span.shrink_to_hi(), |a| a.span_ext)),
1346+
kw::SelfUpper == segment.ident.name,
1347+
)
1348+
}
1349+
_ => {
1350+
err.note(msg);
1351+
return;
1352+
}
1353+
}
1354+
} else {
1355+
err.note(msg);
1356+
return;
1357+
};
1358+
let suggestion = vec![
1359+
if is_self {
1360+
// Account for people writing `Self::Variant::<Args>`, where
1361+
// `Self` is the enum, and suggest replacing `Self` with the
1362+
// appropriate type: `Type::<Args>::Variant`.
1363+
(enum_variants_extend.qself.span, format!("{type_name}{snippet}"))
1364+
} else {
1365+
(qself_sugg_span, snippet)
1366+
},
1367+
(args_span, String::new()),
1368+
];
1369+
err.multipart_suggestion_verbose(msg, suggestion, Applicability::MaybeIncorrect);
1370+
}

0 commit comments

Comments
 (0)