1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use fmt_macros::{Parser, Piece, Position};
13 use hir::def_id::DefId;
14 use ty::{self, TyCtxt};
15 use util::common::ErrorReported;
16 use util::nodemap::FxHashMap;
19 use syntax_pos::symbol::InternedString;
21 pub struct OnUnimplementedFormatString(InternedString);
22 pub struct OnUnimplementedInfo {
23 pub label: OnUnimplementedFormatString
26 impl<'a, 'gcx, 'tcx> OnUnimplementedInfo {
27 pub fn of_item(tcx: TyCtxt<'a, 'gcx, 'tcx>,
31 -> Result<Option<Self>, ErrorReported>
33 let attrs = tcx.get_attrs(impl_def_id);
35 let attr = if let Some(item) =
36 attrs.into_iter().find(|a| a.check_name("rustc_on_unimplemented"))
43 let span = attr.span.substitute_dummy(span);
44 if let Some(label) = attr.value_str() {
45 Ok(Some(OnUnimplementedInfo {
46 label: OnUnimplementedFormatString::try_parse(
47 tcx, trait_def_id, label.as_str(), span)?
51 tcx.sess, span, E0232,
52 "this attribute must have a value")
53 .span_label(attr.span, "attribute requires a value")
54 .note(&format!("eg `#[rustc_on_unimplemented = \"foo\"]`"))
61 impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
62 pub fn try_parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
66 -> Result<Self, ErrorReported>
68 let result = OnUnimplementedFormatString(from);
69 result.verify(tcx, trait_def_id, err_sp)?;
74 tcx: TyCtxt<'a, 'gcx, 'tcx>,
77 -> Result<(), ErrorReported>
79 let name = tcx.item_name(trait_def_id).as_str();
80 let generics = tcx.generics_of(trait_def_id);
81 let parser = Parser::new(&self.0);
82 let types = &generics.types;
83 let mut result = Ok(());
86 Piece::String(_) => (), // Normal string, no need to check it
87 Piece::NextArgument(a) => match a.position {
88 // `{Self}` is allowed
89 Position::ArgumentNamed(s) if s == "Self" => (),
90 // `{ThisTraitsName}` is allowed
91 Position::ArgumentNamed(s) if s == name => (),
92 // So is `{A}` if A is a type parameter
93 Position::ArgumentNamed(s) => match types.iter().find(|t| {
98 span_err!(tcx.sess, span, E0230,
99 "there is no type parameter \
102 result = Err(ErrorReported);
105 // `{:1}` and `{}` are not to be used
106 Position::ArgumentIs(_) => {
107 span_err!(tcx.sess, span, E0231,
108 "only named substitution \
109 parameters are allowed");
110 result = Err(ErrorReported);
120 tcx: TyCtxt<'a, 'gcx, 'tcx>,
121 trait_ref: ty::TraitRef<'tcx>)
124 let name = tcx.item_name(trait_ref.def_id).as_str();
125 let trait_str = tcx.item_path_str(trait_ref.def_id);
126 let generics = tcx.generics_of(trait_ref.def_id);
127 let generic_map = generics.types.iter().map(|param| {
128 (param.name.as_str().to_string(),
129 trait_ref.substs.type_for_def(param).to_string())
130 }).collect::<FxHashMap<String, String>>();
132 let parser = Parser::new(&self.0);
135 Piece::String(s) => s,
136 Piece::NextArgument(a) => match a.position {
137 Position::ArgumentNamed(s) => match generic_map.get(s) {
139 None if s == name => {
143 bug!("broken on_unimplemented {:?} for {:?}: \
144 no argument matching {:?}",
145 self.0, trait_ref, s)
149 bug!("broken on_unimplemented {:?} - bad \