rustc_trait_selection/error_reporting/traits/
on_unimplemented.rs1use std::path::PathBuf;
2
3use rustc_hir as hir;
4use rustc_hir::attrs::diagnostic::{CustomDiagnostic, FilterOptions, FormatArgs};
5use rustc_hir::def_id::LocalDefId;
6use rustc_hir::find_attr;
7use rustc_middle::ty::print::PrintTraitRefExt;
8use rustc_middle::ty::{self, GenericParamDef, GenericParamDefKind};
9use rustc_span::Symbol;
10
11use super::{ObligationCauseCode, PredicateObligation};
12use crate::error_reporting::TypeErrCtxt;
13
14impl<'tcx> TypeErrCtxt<'_, 'tcx> {
15 fn describe_enclosure(&self, def_id: LocalDefId) -> Option<&'static str> {
18 match self.tcx.hir_node_by_def_id(def_id) {
19 hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { .. }, .. }) => Some("a function"),
20 hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) => {
21 Some("a trait method")
22 }
23 hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => {
24 Some("a method")
25 }
26 hir::Node::Expr(hir::Expr {
27 kind: hir::ExprKind::Closure(hir::Closure { kind, .. }),
28 ..
29 }) => Some(self.describe_closure(*kind)),
30 _ => None,
31 }
32 }
33
34 pub fn on_unimplemented_note(
35 &self,
36 trait_pred: ty::PolyTraitPredicate<'tcx>,
37 obligation: &PredicateObligation<'tcx>,
38 long_ty_path: &mut Option<PathBuf>,
39 ) -> CustomDiagnostic {
40 if trait_pred.polarity() != ty::PredicatePolarity::Positive {
41 return CustomDiagnostic::default();
42 }
43 if self.tcx.is_trait_alias(trait_pred.def_id()) {
46 return CustomDiagnostic::default();
47 }
48 let (filter_options, format_args) =
49 self.on_unimplemented_components(trait_pred, obligation, long_ty_path, true);
50 if let Some(command) = {
{
'done:
{
for i in
::rustc_hir::attrs::HasAttrs::get_attrs(trait_pred.def_id(),
&self.tcx) {
#[allow(unused_imports)]
use ::rustc_hir::attrs::AttributeKind::*;
let i: &::rustc_hir::Attribute = i;
match i {
::rustc_hir::Attribute::Parsed(OnUnimplemented { directive,
.. }) => {
break 'done Some(directive.as_deref());
}
::rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}find_attr!(self.tcx, trait_pred.def_id(), OnUnimplemented {directive, ..} => directive.as_deref()).flatten() {
51 command.eval(
52 Some(&filter_options),
53 &format_args,
54 )
55 } else {
56 CustomDiagnostic::default()
57 }
58 }
59
60 pub(crate) fn on_unimplemented_components(
61 &self,
62 trait_pred: ty::PolyTraitPredicate<'tcx>,
63 obligation: &PredicateObligation<'tcx>,
64 long_ty_path: &mut Option<PathBuf>,
65 print_infer_ty_var: bool,
66 ) -> (FilterOptions, FormatArgs) {
67 let (def_id, args) = (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args);
68 let trait_pred = trait_pred.skip_binder();
69
70 let mut self_types = ::alloc::vec::Vec::new()vec![];
71 let mut generic_args: Vec<(Symbol, String)> = ::alloc::vec::Vec::new()vec![];
72 let mut crate_local = false;
73 let item_context = self.describe_enclosure(obligation.cause.body_def_id).unwrap_or("");
77
78 let direct = match obligation.cause.code() {
79 ObligationCauseCode::BuiltinDerived(..)
80 | ObligationCauseCode::ImplDerived(..)
81 | ObligationCauseCode::WellFormedDerived(..) => false,
82 _ => {
83 true
86 }
87 };
88
89 let from_desugaring = obligation.cause.span.desugaring_kind();
90
91 let cause = if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
92 Some("MainFunctionType".to_string())
93 } else {
94 None
95 };
96
97 {
let _guard = NoTrimmedGuard::new();
{
let _guard = NoVisibleGuard::new();
{
let generics = self.tcx.generics_of(def_id);
let self_ty = trait_pred.self_ty();
self_types.push(self_ty.to_string());
if let Some(def) = self_ty.ty_adt_def() {
self_types.push(self.tcx.type_of(def.did()).instantiate_identity().skip_norm_wip().to_string());
}
for GenericParamDef { name, kind, index, .. } in
generics.own_params.iter() {
let value =
match kind {
GenericParamDefKind::Type { .. } |
GenericParamDefKind::Const { .. } => {
args[*index as usize].to_string()
}
GenericParamDefKind::Lifetime => continue,
};
generic_args.push((*name, value));
if let GenericParamDefKind::Type { .. } = kind {
let param_ty = args[*index as usize].expect_ty();
if let Some(def) = param_ty.ty_adt_def() {
generic_args.push((*name,
self.tcx.type_of(def.did()).instantiate_identity().skip_norm_wip().to_string()));
}
}
}
if let Some(adt) = self_ty.ty_adt_def() {
if adt.did().is_local() { crate_local = true; }
self_types.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}}}", adt.descr()))
}))
}
if self_ty.is_integral() {
self_types.push("{integral}".to_owned());
}
if self_ty.is_array_slice() { self_types.push("&[]".to_owned()); }
if self_ty.is_fn() {
let fn_sig = self_ty.fn_sig(self.tcx);
let shortname =
if let ty::FnDef(def_id, _) = *self_ty.kind() &&
self.tcx.codegen_fn_attrs(def_id).safe_target_features {
"#[target_feature] fn"
} else {
match fn_sig.safety() {
hir::Safety::Safe => "fn",
hir::Safety::Unsafe => "unsafe fn",
}
};
self_types.push(shortname.to_owned());
}
if let ty::Slice(aty) = self_ty.kind() {
self_types.push("[]".to_owned());
if let Some(def) = aty.ty_adt_def() {
self_types.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("[{0}]",
self.tcx.type_of(def.did()).instantiate_identity().skip_norm_wip()))
}));
}
if aty.is_integral() {
self_types.push("[{integral}]".to_string());
}
}
if let ty::Array(aty, len) = self_ty.kind() {
self_types.push("[]".to_string());
let len = len.try_to_target_usize(self.tcx);
self_types.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("[{0}; _]", aty))
}));
if let Some(n) = len {
self_types.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("[{0}; {1}]", aty, n))
}));
}
if let Some(def) = aty.ty_adt_def() {
let def_ty =
self.tcx.type_of(def.did()).instantiate_identity().skip_norm_wip();
self_types.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("[{0}; _]", def_ty))
}));
if let Some(n) = len {
self_types.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("[{0}; {1}]", def_ty, n))
}));
}
}
if aty.is_integral() {
self_types.push("[{integral}; _]".to_string());
if let Some(n) = len {
self_types.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("[{{integral}}; {0}]", n))
}));
}
}
}
if let ty::Dynamic(traits, _) = self_ty.kind() {
for t in traits.iter() {
if let ty::ExistentialPredicate::Trait(trait_ref) =
t.skip_binder() {
self_types.push(self.tcx.def_path_str(trait_ref.def_id));
}
}
}
if let ty::Ref(_, ref_ty, rustc_ast::Mutability::Not) =
self_ty.kind() && let ty::Slice(sty) = ref_ty.kind() &&
sty.is_integral() {
self_types.push("&[{integral}]".to_owned());
}
}
}
};ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({
100 let generics = self.tcx.generics_of(def_id);
101 let self_ty = trait_pred.self_ty();
102 self_types.push(self_ty.to_string());
103 if let Some(def) = self_ty.ty_adt_def() {
104 self_types.push(
107 self.tcx.type_of(def.did()).instantiate_identity().skip_norm_wip().to_string(),
108 );
109 }
110
111 for GenericParamDef { name, kind, index, .. } in generics.own_params.iter() {
112 let value = match kind {
113 GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
114 args[*index as usize].to_string()
115 }
116 GenericParamDefKind::Lifetime => continue,
117 };
118 generic_args.push((*name, value));
119
120 if let GenericParamDefKind::Type { .. } = kind {
121 let param_ty = args[*index as usize].expect_ty();
122 if let Some(def) = param_ty.ty_adt_def() {
123 generic_args.push((
126 *name,
127 self.tcx
128 .type_of(def.did())
129 .instantiate_identity()
130 .skip_norm_wip()
131 .to_string(),
132 ));
133 }
134 }
135 }
136
137 if let Some(adt) = self_ty.ty_adt_def() {
138 if adt.did().is_local() {
139 crate_local = true;
140 }
141 self_types.push(format!("{{{}}}", adt.descr()))
142 }
143
144 if self_ty.is_integral() {
146 self_types.push("{integral}".to_owned());
147 }
148
149 if self_ty.is_array_slice() {
150 self_types.push("&[]".to_owned());
151 }
152
153 if self_ty.is_fn() {
154 let fn_sig = self_ty.fn_sig(self.tcx);
155 let shortname = if let ty::FnDef(def_id, _) = *self_ty.kind()
156 && self.tcx.codegen_fn_attrs(def_id).safe_target_features
157 {
158 "#[target_feature] fn"
159 } else {
160 match fn_sig.safety() {
161 hir::Safety::Safe => "fn",
162 hir::Safety::Unsafe => "unsafe fn",
163 }
164 };
165 self_types.push(shortname.to_owned());
166 }
167
168 if let ty::Slice(aty) = self_ty.kind() {
170 self_types.push("[]".to_owned());
171 if let Some(def) = aty.ty_adt_def() {
172 self_types.push(format!(
175 "[{}]",
176 self.tcx.type_of(def.did()).instantiate_identity().skip_norm_wip()
177 ));
178 }
179 if aty.is_integral() {
180 self_types.push("[{integral}]".to_string());
181 }
182 }
183
184 if let ty::Array(aty, len) = self_ty.kind() {
186 self_types.push("[]".to_string());
187 let len = len.try_to_target_usize(self.tcx);
188 self_types.push(format!("[{aty}; _]"));
189 if let Some(n) = len {
190 self_types.push(format!("[{aty}; {n}]"));
191 }
192 if let Some(def) = aty.ty_adt_def() {
193 let def_ty = self.tcx.type_of(def.did()).instantiate_identity().skip_norm_wip();
196 self_types.push(format!("[{def_ty}; _]"));
197 if let Some(n) = len {
198 self_types.push(format!("[{def_ty}; {n}]"));
199 }
200 }
201 if aty.is_integral() {
202 self_types.push("[{integral}; _]".to_string());
203 if let Some(n) = len {
204 self_types.push(format!("[{{integral}}; {n}]"));
205 }
206 }
207 }
208 if let ty::Dynamic(traits, _) = self_ty.kind() {
209 for t in traits.iter() {
210 if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() {
211 self_types.push(self.tcx.def_path_str(trait_ref.def_id));
212 }
213 }
214 }
215
216 if let ty::Ref(_, ref_ty, rustc_ast::Mutability::Not) = self_ty.kind()
218 && let ty::Slice(sty) = ref_ty.kind()
219 && sty.is_integral()
220 {
221 self_types.push("&[{integral}]".to_owned());
222 }
223 }));
224
225 let this = self.tcx.def_path_str(trait_pred.trait_ref.def_id);
226 let this_resolved = trait_pred.trait_ref.print_trait_sugared().to_string();
227 let this_path =
228 ty::TraitRef::identity(self.tcx, def_id).print_only_trait_path().to_string();
229
230 let filter_options =
231 FilterOptions { self_types, from_desugaring, cause, crate_local, direct, generic_args };
232
233 let generic_args = self
239 .tcx
240 .generics_of(trait_pred.trait_ref.def_id)
241 .own_params
242 .iter()
243 .filter_map(|param| {
244 let value = match param.kind {
245 GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
246 if let Some(ty) = trait_pred.trait_ref.args[param.index as usize].as_type()
247 {
248 if print_infer_ty_var == false
249 && let ty::Infer(ty::TyVar(_)) = ty.kind()
250 {
251 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}", param.name))
})format!("{}", param.name)
252 } else {
253 self.tcx.short_string(ty, long_ty_path)
254 }
255 } else {
256 trait_pred.trait_ref.args[param.index as usize].to_string()
257 }
258 }
259 GenericParamDefKind::Lifetime => return None,
260 };
261 let name = param.name;
262 Some((name, value))
263 })
264 .collect();
265
266 let format_args =
267 FormatArgs { this, this_path, this_resolved, generic_args, item_context, .. };
268 (filter_options, format_args)
269 }
270}