|
1 | 1 | use crate::errors::{
|
2 | 2 | self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
|
3 |
| - ParenthesizedFnTraitExpansion, |
| 3 | + ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits, |
4 | 4 | };
|
5 | 5 | use crate::fluent_generated as fluent;
|
6 | 6 | use crate::hir_ty_lowering::HirTyLowerer;
|
7 | 7 | use crate::traits::error_reporting::report_object_safety_error;
|
8 | 8 | use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
9 | 9 | use rustc_data_structures::sorted_map::SortedMap;
|
10 | 10 | use rustc_data_structures::unord::UnordMap;
|
| 11 | +use rustc_errors::MultiSpan; |
11 | 12 | use rustc_errors::{
|
12 | 13 | codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
|
13 | 14 | };
|
14 | 15 | use rustc_hir as hir;
|
| 16 | +use rustc_hir::def::{DefKind, Res}; |
15 | 17 | use rustc_hir::def_id::{DefId, LocalDefId};
|
16 | 18 | use rustc_infer::traits::FulfillmentError;
|
17 | 19 | 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}; |
19 | 23 | use rustc_session::parse::feature_err;
|
20 | 24 | 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; |
22 | 27 | 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 | +}; |
24 | 31 |
|
25 | 32 | impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
26 | 33 | /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
|
@@ -1024,15 +1031,183 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
1024 | 1031 | Ok(())
|
1025 | 1032 | }
|
1026 | 1033 | }
|
| 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 = ®ular_traits[0]; |
| 1153 | + let additional_trait = ®ular_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 | + } |
1027 | 1202 | }
|
1028 | 1203 |
|
1029 | 1204 | /// Emits an error regarding forbidden type binding associations
|
1030 | 1205 | pub fn prohibit_assoc_item_binding(
|
1031 | 1206 | tcx: TyCtxt<'_>,
|
1032 | 1207 | span: Span,
|
1033 | 1208 | segment: Option<(&hir::PathSegment<'_>, Span)>,
|
1034 |
| -) { |
1035 |
| - tcx.dcx().emit_err(AssocTypeBindingNotAllowed { |
| 1209 | +) -> ErrorGuaranteed { |
| 1210 | + return tcx.dcx().emit_err(AssocTypeBindingNotAllowed { |
1036 | 1211 | span,
|
1037 | 1212 | fn_trait_expansion: if let Some((segment, span)) = segment
|
1038 | 1213 | && segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
|
@@ -1099,3 +1274,97 @@ pub(crate) fn fn_trait_to_string(
|
1099 | 1274 | format!("{}<{}, Output={}>", trait_segment.ident, args, ret)
|
1100 | 1275 | }
|
1101 | 1276 | }
|
| 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