]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / traits / error_reporting / on_unimplemented.rs
CommitLineData
487cf647 1use super::{ObligationCauseCode, PredicateObligation};
2b03887a 2use crate::infer::error_reporting::TypeErrCtxt;
487cf647
FG
3use rustc_ast::{MetaItem, NestedMetaItem};
4use rustc_attr as attr;
5use rustc_data_structures::fx::FxHashMap;
6use rustc_errors::{struct_span_err, ErrorGuaranteed};
dfeec247
XL
7use rustc_hir as hir;
8use rustc_hir::def_id::DefId;
2b03887a 9use rustc_middle::ty::SubstsRef;
487cf647
FG
10use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
11use rustc_parse_format::{ParseMode, Parser, Piece, Position};
12use rustc_span::symbol::{kw, sym, Symbol};
13use rustc_span::{Span, DUMMY_SP};
cdc7bbd5 14use std::iter;
dfeec247 15
487cf647
FG
16use crate::errors::{
17 EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
18};
19
ba9703b0
XL
20use super::InferCtxtPrivExt;
21
2b03887a 22pub trait TypeErrCtxtExt<'tcx> {
ba9703b0
XL
23 /*private*/
24 fn impl_similar_to(
25 &self,
26 trait_ref: ty::PolyTraitRef<'tcx>,
27 obligation: &PredicateObligation<'tcx>,
5e7ed085 28 ) -> Option<(DefId, SubstsRef<'tcx>)>;
ba9703b0
XL
29
30 /*private*/
31 fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str>;
32
33 fn on_unimplemented_note(
34 &self,
35 trait_ref: ty::PolyTraitRef<'tcx>,
36 obligation: &PredicateObligation<'tcx>,
37 ) -> OnUnimplementedNote;
38}
39
9c376795
FG
40/// The symbols which are always allowed in a format string
41static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
42 kw::SelfUpper,
43 sym::ItemContext,
44 sym::from_method,
45 sym::from_desugaring,
46 sym::direct,
47 sym::cause,
48 sym::integral,
49 sym::integer_,
50 sym::float,
51 sym::_Self,
52 sym::crate_local,
53];
54
2b03887a 55impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
dfeec247
XL
56 fn impl_similar_to(
57 &self,
58 trait_ref: ty::PolyTraitRef<'tcx>,
59 obligation: &PredicateObligation<'tcx>,
5e7ed085 60 ) -> Option<(DefId, SubstsRef<'tcx>)> {
dfeec247
XL
61 let tcx = self.tcx;
62 let param_env = obligation.param_env;
9ffffee4 63 let trait_ref = self.instantiate_binder_with_placeholders(trait_ref);
dfeec247
XL
64 let trait_self_ty = trait_ref.self_ty();
65
66 let mut self_match_impls = vec![];
67 let mut fuzzy_match_impls = vec![];
68
69 self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
70 let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
9c376795 71 let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);
dfeec247
XL
72
73 let impl_self_ty = impl_trait_ref.self_ty();
74
9ffffee4 75 if self.can_eq(param_env, trait_self_ty, impl_self_ty) {
5e7ed085 76 self_match_impls.push((def_id, impl_substs));
dfeec247 77
cdc7bbd5
XL
78 if iter::zip(
79 trait_ref.substs.types().skip(1),
80 impl_trait_ref.substs.types().skip(1),
81 )
5099ac24 82 .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
dfeec247 83 {
5e7ed085 84 fuzzy_match_impls.push((def_id, impl_substs));
dfeec247
XL
85 }
86 }
87 });
88
5e7ed085 89 let impl_def_id_and_substs = if self_match_impls.len() == 1 {
dfeec247
XL
90 self_match_impls[0]
91 } else if fuzzy_match_impls.len() == 1 {
92 fuzzy_match_impls[0]
93 } else {
94 return None;
95 };
96
5e7ed085
FG
97 tcx.has_attr(impl_def_id_and_substs.0, sym::rustc_on_unimplemented)
98 .then_some(impl_def_id_and_substs)
dfeec247
XL
99 }
100
101 /// Used to set on_unimplemented's `ItemContext`
102 /// to be the enclosing (async) block/function/closure
103 fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
5099ac24 104 let hir = self.tcx.hir();
dfeec247
XL
105 let node = hir.find(hir_id)?;
106 match &node {
107 hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => {
108 self.describe_generator(*body_id).or_else(|| {
ba9703b0
XL
109 Some(match sig.header {
110 hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async function",
111 _ => "a function",
dfeec247
XL
112 })
113 })
114 }
115 hir::Node::TraitItem(hir::TraitItem {
ba9703b0 116 kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)),
dfeec247
XL
117 ..
118 }) => self.describe_generator(*body_id).or_else(|| Some("a trait method")),
119 hir::Node::ImplItem(hir::ImplItem {
ba9703b0 120 kind: hir::ImplItemKind::Fn(sig, body_id),
dfeec247
XL
121 ..
122 }) => self.describe_generator(*body_id).or_else(|| {
ba9703b0
XL
123 Some(match sig.header {
124 hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async method",
125 _ => "a method",
dfeec247
XL
126 })
127 }),
128 hir::Node::Expr(hir::Expr {
064997fb 129 kind: hir::ExprKind::Closure(hir::Closure { body, movability, .. }),
dfeec247 130 ..
923072b8
FG
131 }) => self.describe_generator(*body).or_else(|| {
132 Some(if movability.is_some() { "an async closure" } else { "a closure" })
dfeec247
XL
133 }),
134 hir::Node::Expr(hir::Expr { .. }) => {
9c376795 135 let parent_hid = hir.parent_id(hir_id);
ba9703b0 136 if parent_hid != hir_id { self.describe_enclosure(parent_hid) } else { None }
dfeec247
XL
137 }
138 _ => None,
139 }
140 }
141
ba9703b0 142 fn on_unimplemented_note(
dfeec247
XL
143 &self,
144 trait_ref: ty::PolyTraitRef<'tcx>,
145 obligation: &PredicateObligation<'tcx>,
146 ) -> OnUnimplementedNote {
5e7ed085
FG
147 let (def_id, substs) = self
148 .impl_similar_to(trait_ref, obligation)
149 .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs));
f035d41b 150 let trait_ref = trait_ref.skip_binder();
dfeec247 151
9ffffee4
FG
152 let body_hir = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id);
153 let mut flags =
154 vec![(sym::ItemContext, self.describe_enclosure(body_hir).map(|s| s.to_owned()))];
dfeec247 155
a2a8927a 156 match obligation.cause.code() {
dfeec247 157 ObligationCauseCode::BuiltinDerivedObligation(..)
ba9703b0
XL
158 | ObligationCauseCode::ImplDerivedObligation(..)
159 | ObligationCauseCode::DerivedObligation(..) => {}
dfeec247
XL
160 _ => {
161 // this is a "direct", user-specified, rather than derived,
162 // obligation.
163 flags.push((sym::direct, None));
164 }
165 }
166
ba9703b0 167 if let ObligationCauseCode::ItemObligation(item)
f2b60f7d
FG
168 | ObligationCauseCode::BindingObligation(item, _)
169 | ObligationCauseCode::ExprItemObligation(item, ..)
170 | ObligationCauseCode::ExprBindingObligation(item, ..) = *obligation.cause.code()
ba9703b0 171 {
dfeec247
XL
172 // FIXME: maybe also have some way of handling methods
173 // from other traits? That would require name resolution,
174 // which we might want to be some sort of hygienic.
175 //
176 // Currently I'm leaving it for what I need for `try`.
177 if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
178 let method = self.tcx.item_name(item);
179 flags.push((sym::from_method, None));
180 flags.push((sym::from_method, Some(method.to_string())));
181 }
182 }
dfeec247
XL
183
184 if let Some(k) = obligation.cause.span.desugaring_kind() {
185 flags.push((sym::from_desugaring, None));
186 flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
187 }
dfeec247 188
2b03887a
FG
189 if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
190 flags.push((sym::cause, Some("MainFunctionType".to_string())));
191 }
192
cdc7bbd5 193 // Add all types without trimmed paths.
5e7ed085 194 ty::print::with_no_trimmed_paths!({
cdc7bbd5
XL
195 let generics = self.tcx.generics_of(def_id);
196 let self_ty = trait_ref.self_ty();
197 // This is also included through the generics list as `Self`,
198 // but the parser won't allow you to use it
199 flags.push((sym::_Self, Some(self_ty.to_string())));
200 if let Some(def) = self_ty.ty_adt_def() {
201 // We also want to be able to select self's original
202 // signature with no type arguments resolved
9ffffee4
FG
203 flags.push((
204 sym::_Self,
205 Some(self.tcx.type_of(def.did()).subst_identity().to_string()),
206 ));
cdc7bbd5 207 }
dfeec247 208
cdc7bbd5
XL
209 for param in generics.params.iter() {
210 let value = match param.kind {
211 GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
5e7ed085 212 substs[param.index as usize].to_string()
cdc7bbd5
XL
213 }
214 GenericParamDefKind::Lifetime => continue,
215 };
216 let name = param.name;
217 flags.push((name, Some(value)));
17df50a5
XL
218
219 if let GenericParamDefKind::Type { .. } = param.kind {
5e7ed085 220 let param_ty = substs[param.index as usize].expect_ty();
17df50a5
XL
221 if let Some(def) = param_ty.ty_adt_def() {
222 // We also want to be able to select the parameter's
223 // original signature with no type arguments resolved
9ffffee4
FG
224 flags.push((
225 name,
226 Some(self.tcx.type_of(def.did()).subst_identity().to_string()),
227 ));
17df50a5
XL
228 }
229 }
cdc7bbd5 230 }
dfeec247 231
5e7ed085 232 if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) {
cdc7bbd5
XL
233 flags.push((sym::crate_local, None));
234 }
dfeec247 235
cdc7bbd5
XL
236 // Allow targeting all integers using `{integral}`, even if the exact type was resolved
237 if self_ty.is_integral() {
238 flags.push((sym::_Self, Some("{integral}".to_owned())));
239 }
6a06907d 240
5e7ed085
FG
241 if self_ty.is_array_slice() {
242 flags.push((sym::_Self, Some("&[]".to_owned())));
243 }
244
04454e1e
FG
245 if self_ty.is_fn() {
246 let fn_sig = self_ty.fn_sig(self.tcx);
247 let shortname = match fn_sig.unsafety() {
248 hir::Unsafety::Normal => "fn",
249 hir::Unsafety::Unsafe => "unsafe fn",
250 };
251 flags.push((sym::_Self, Some(shortname.to_owned())));
252 }
253
254 // Slices give us `[]`, `[{ty}]`
255 if let ty::Slice(aty) = self_ty.kind() {
256 flags.push((sym::_Self, Some("[]".to_string())));
257 if let Some(def) = aty.ty_adt_def() {
258 // We also want to be able to select the slice's type's original
259 // signature with no type arguments resolved
9ffffee4
FG
260 flags.push((
261 sym::_Self,
262 Some(format!("[{}]", self.tcx.type_of(def.did()).subst_identity())),
263 ));
04454e1e
FG
264 }
265 if aty.is_integral() {
266 flags.push((sym::_Self, Some("[{integral}]".to_string())));
267 }
268 }
269
270 // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
cdc7bbd5 271 if let ty::Array(aty, len) = self_ty.kind() {
04454e1e 272 flags.push((sym::_Self, Some("[]".to_string())));
9ffffee4 273 let len = len.kind().try_to_value().and_then(|v| v.try_to_target_usize(self.tcx));
04454e1e
FG
274 flags.push((sym::_Self, Some(format!("[{}; _]", aty))));
275 if let Some(n) = len {
276 flags.push((sym::_Self, Some(format!("[{}; {}]", aty, n))));
277 }
cdc7bbd5
XL
278 if let Some(def) = aty.ty_adt_def() {
279 // We also want to be able to select the array's type's original
280 // signature with no type arguments resolved
9ffffee4 281 let def_ty = self.tcx.type_of(def.did()).subst_identity();
064997fb 282 flags.push((sym::_Self, Some(format!("[{def_ty}; _]"))));
04454e1e 283 if let Some(n) = len {
064997fb 284 flags.push((sym::_Self, Some(format!("[{def_ty}; {n}]"))));
04454e1e
FG
285 }
286 }
287 if aty.is_integral() {
288 flags.push((sym::_Self, Some("[{integral}; _]".to_string())));
289 if let Some(n) = len {
290 flags.push((sym::_Self, Some(format!("[{{integral}}; {n}]"))));
291 }
cdc7bbd5 292 }
dfeec247 293 }
f2b60f7d 294 if let ty::Dynamic(traits, _, _) = self_ty.kind() {
cdc7bbd5
XL
295 for t in traits.iter() {
296 if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() {
297 flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id))))
298 }
74b04a01
XL
299 }
300 }
cdc7bbd5 301 });
dfeec247 302
5e7ed085 303 if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
a2a8927a 304 command.evaluate(self.tcx, trait_ref, &flags)
dfeec247
XL
305 } else {
306 OnUnimplementedNote::default()
307 }
308 }
309}
487cf647
FG
310
311#[derive(Clone, Debug)]
312pub struct OnUnimplementedFormatString(Symbol);
313
314#[derive(Debug)]
315pub struct OnUnimplementedDirective {
316 pub condition: Option<MetaItem>,
317 pub subcommands: Vec<OnUnimplementedDirective>,
318 pub message: Option<OnUnimplementedFormatString>,
319 pub label: Option<OnUnimplementedFormatString>,
320 pub note: Option<OnUnimplementedFormatString>,
321 pub parent_label: Option<OnUnimplementedFormatString>,
322 pub append_const_msg: Option<Option<Symbol>>,
323}
324
325/// For the `#[rustc_on_unimplemented]` attribute
326#[derive(Default)]
327pub struct OnUnimplementedNote {
328 pub message: Option<String>,
329 pub label: Option<String>,
330 pub note: Option<String>,
331 pub parent_label: Option<String>,
332 /// Append a message for `~const Trait` errors. `None` means not requested and
333 /// should fallback to a generic message, `Some(None)` suggests using the default
334 /// appended message, `Some(Some(s))` suggests use the `s` message instead of the
335 /// default one..
336 pub append_const_msg: Option<Option<Symbol>>,
337}
338
339impl<'tcx> OnUnimplementedDirective {
340 fn parse(
341 tcx: TyCtxt<'tcx>,
342 item_def_id: DefId,
343 items: &[NestedMetaItem],
344 span: Span,
345 is_root: bool,
346 ) -> Result<Self, ErrorGuaranteed> {
347 let mut errored = None;
348 let mut item_iter = items.iter();
349
350 let parse_value = |value_str| {
351 OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span).map(Some)
352 };
353
354 let condition = if is_root {
355 None
356 } else {
357 let cond = item_iter
358 .next()
359 .ok_or_else(|| tcx.sess.emit_err(EmptyOnClauseInOnUnimplemented { span }))?
360 .meta_item()
361 .ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
362 attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| {
363 if let Some(value) = cfg.value && let Err(guar) = parse_value(value) {
364 errored = Some(guar);
365 }
366 true
367 });
368 Some(cond.clone())
369 };
370
371 let mut message = None;
372 let mut label = None;
373 let mut note = None;
374 let mut parent_label = None;
375 let mut subcommands = vec![];
376 let mut append_const_msg = None;
377
378 for item in item_iter {
379 if item.has_name(sym::message) && message.is_none() {
380 if let Some(message_) = item.value_str() {
381 message = parse_value(message_)?;
382 continue;
383 }
384 } else if item.has_name(sym::label) && label.is_none() {
385 if let Some(label_) = item.value_str() {
386 label = parse_value(label_)?;
387 continue;
388 }
389 } else if item.has_name(sym::note) && note.is_none() {
390 if let Some(note_) = item.value_str() {
391 note = parse_value(note_)?;
392 continue;
393 }
394 } else if item.has_name(sym::parent_label) && parent_label.is_none() {
395 if let Some(parent_label_) = item.value_str() {
396 parent_label = parse_value(parent_label_)?;
397 continue;
398 }
399 } else if item.has_name(sym::on)
400 && is_root
401 && message.is_none()
402 && label.is_none()
403 && note.is_none()
404 {
405 if let Some(items) = item.meta_item_list() {
406 match Self::parse(tcx, item_def_id, &items, item.span(), false) {
407 Ok(subcommand) => subcommands.push(subcommand),
408 Err(reported) => errored = Some(reported),
409 };
410 continue;
411 }
412 } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() {
413 if let Some(msg) = item.value_str() {
414 append_const_msg = Some(Some(msg));
415 continue;
416 } else if item.is_word() {
417 append_const_msg = Some(None);
418 continue;
419 }
420 }
421
422 // nothing found
423 tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() });
424 }
425
426 if let Some(reported) = errored {
427 Err(reported)
428 } else {
429 Ok(OnUnimplementedDirective {
430 condition,
431 subcommands,
432 message,
433 label,
434 note,
435 parent_label,
436 append_const_msg,
437 })
438 }
439 }
440
441 pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
442 let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) else {
443 return Ok(None);
444 };
445
446 let result = if let Some(items) = attr.meta_item_list() {
447 Self::parse(tcx, item_def_id, &items, attr.span, true).map(Some)
448 } else if let Some(value) = attr.value_str() {
449 Ok(Some(OnUnimplementedDirective {
450 condition: None,
451 message: None,
452 subcommands: vec![],
453 label: Some(OnUnimplementedFormatString::try_parse(
454 tcx,
455 item_def_id,
456 value,
457 attr.span,
458 )?),
459 note: None,
460 parent_label: None,
461 append_const_msg: None,
462 }))
463 } else {
464 let reported =
465 tcx.sess.delay_span_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str");
466 return Err(reported);
467 };
468 debug!("of_item({:?}) = {:?}", item_def_id, result);
469 result
470 }
471
472 pub fn evaluate(
473 &self,
474 tcx: TyCtxt<'tcx>,
475 trait_ref: ty::TraitRef<'tcx>,
476 options: &[(Symbol, Option<String>)],
477 ) -> OnUnimplementedNote {
478 let mut message = None;
479 let mut label = None;
480 let mut note = None;
481 let mut parent_label = None;
482 let mut append_const_msg = None;
483 info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
484
485 let options_map: FxHashMap<Symbol, String> =
486 options.iter().filter_map(|(k, v)| v.clone().map(|v| (*k, v))).collect();
487
488 for command in self.subcommands.iter().chain(Some(self)).rev() {
489 if let Some(ref condition) = command.condition && !attr::eval_condition(
490 condition,
491 &tcx.sess.parse_sess,
492 Some(tcx.features()),
493 &mut |cfg| {
494 let value = cfg.value.map(|v| {
495 OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map)
496 });
497
498 options.contains(&(cfg.name, value))
499 },
500 ) {
501 debug!("evaluate: skipping {:?} due to condition", command);
502 continue;
503 }
504 debug!("evaluate: {:?} succeeded", command);
505 if let Some(ref message_) = command.message {
506 message = Some(message_.clone());
507 }
508
509 if let Some(ref label_) = command.label {
510 label = Some(label_.clone());
511 }
512
513 if let Some(ref note_) = command.note {
514 note = Some(note_.clone());
515 }
516
517 if let Some(ref parent_label_) = command.parent_label {
518 parent_label = Some(parent_label_.clone());
519 }
520
521 append_const_msg = command.append_const_msg;
522 }
523
524 OnUnimplementedNote {
525 label: label.map(|l| l.format(tcx, trait_ref, &options_map)),
526 message: message.map(|m| m.format(tcx, trait_ref, &options_map)),
527 note: note.map(|n| n.format(tcx, trait_ref, &options_map)),
528 parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
529 append_const_msg,
530 }
531 }
532}
533
534impl<'tcx> OnUnimplementedFormatString {
535 fn try_parse(
536 tcx: TyCtxt<'tcx>,
537 item_def_id: DefId,
538 from: Symbol,
539 err_sp: Span,
540 ) -> Result<Self, ErrorGuaranteed> {
541 let result = OnUnimplementedFormatString(from);
542 result.verify(tcx, item_def_id, err_sp)?;
543 Ok(result)
544 }
545
546 fn verify(
547 &self,
548 tcx: TyCtxt<'tcx>,
549 item_def_id: DefId,
550 span: Span,
551 ) -> Result<(), ErrorGuaranteed> {
552 let trait_def_id = if tcx.is_trait(item_def_id) {
553 item_def_id
554 } else {
555 tcx.trait_id_of_impl(item_def_id)
556 .expect("expected `on_unimplemented` to correspond to a trait")
557 };
558 let trait_name = tcx.item_name(trait_def_id);
559 let generics = tcx.generics_of(item_def_id);
560 let s = self.0.as_str();
561 let parser = Parser::new(s, None, None, false, ParseMode::Format);
562 let mut result = Ok(());
563 for token in parser {
564 match token {
565 Piece::String(_) => (), // Normal string, no need to check it
566 Piece::NextArgument(a) => match a.position {
567 Position::ArgumentNamed(s) => {
568 match Symbol::intern(s) {
487cf647
FG
569 // `{ThisTraitsName}` is allowed
570 s if s == trait_name => (),
9c376795 571 s if ALLOWED_FORMAT_SYMBOLS.contains(&s) => (),
487cf647 572 // So is `{A}` if A is a type parameter
9c376795
FG
573 s if generics.params.iter().any(|param| param.name == s) => (),
574 s => {
575 result = Err(struct_span_err!(
576 tcx.sess,
577 span,
578 E0230,
579 "there is no parameter `{}` on {}",
580 s,
581 if trait_def_id == item_def_id {
582 format!("trait `{}`", trait_name)
583 } else {
584 "impl".to_string()
585 }
586 )
587 .emit());
588 }
487cf647
FG
589 }
590 }
591 // `{:1}` and `{}` are not to be used
592 Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => {
593 let reported = struct_span_err!(
594 tcx.sess,
595 span,
596 E0231,
597 "only named substitution parameters are allowed"
598 )
599 .emit();
600 result = Err(reported);
601 }
602 },
603 }
604 }
605
606 result
607 }
608
609 pub fn format(
610 &self,
611 tcx: TyCtxt<'tcx>,
612 trait_ref: ty::TraitRef<'tcx>,
613 options: &FxHashMap<Symbol, String>,
614 ) -> String {
615 let name = tcx.item_name(trait_ref.def_id);
616 let trait_str = tcx.def_path_str(trait_ref.def_id);
617 let generics = tcx.generics_of(trait_ref.def_id);
618 let generic_map = generics
619 .params
620 .iter()
621 .filter_map(|param| {
622 let value = match param.kind {
623 GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
624 trait_ref.substs[param.index as usize].to_string()
625 }
626 GenericParamDefKind::Lifetime => return None,
627 };
628 let name = param.name;
629 Some((name, value))
630 })
631 .collect::<FxHashMap<Symbol, String>>();
632 let empty_string = String::new();
633
634 let s = self.0.as_str();
635 let parser = Parser::new(s, None, None, false, ParseMode::Format);
636 let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string);
637 parser
638 .map(|p| match p {
639 Piece::String(s) => s,
640 Piece::NextArgument(a) => match a.position {
641 Position::ArgumentNamed(s) => {
642 let s = Symbol::intern(s);
643 match generic_map.get(&s) {
644 Some(val) => val,
645 None if s == name => &trait_str,
646 None => {
647 if let Some(val) = options.get(&s) {
648 val
649 } else if s == sym::from_desugaring || s == sym::from_method {
650 // don't break messages using these two arguments incorrectly
651 &empty_string
652 } else if s == sym::ItemContext {
653 &item_context
654 } else if s == sym::integral {
655 "{integral}"
656 } else if s == sym::integer_ {
657 "{integer}"
658 } else if s == sym::float {
659 "{float}"
660 } else {
661 bug!(
662 "broken on_unimplemented {:?} for {:?}: \
663 no argument matching {:?}",
664 self.0,
665 trait_ref,
666 s
667 )
668 }
669 }
670 }
671 }
672 _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0),
673 },
674 })
675 .collect()
676 }
677}