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