rustc_trait_selection/error_reporting/traits/
on_unimplemented.rs1use std::path::PathBuf;
2
3use rustc_hir as hir;
4use rustc_hir::attrs::diagnostic::{ConditionOptions, FormatArgs, OnUnimplementedNote};
5use rustc_hir::def_id::LocalDefId;
6use rustc_hir::find_attr;
7pub use rustc_hir::lints::FormatWarning;
8use rustc_middle::ty::print::PrintTraitRefExt;
9use rustc_middle::ty::{self, GenericParamDef, GenericParamDefKind};
10use rustc_span::Symbol;
11
12use super::{ObligationCauseCode, PredicateObligation};
13use crate::error_reporting::TypeErrCtxt;
14
15impl<'tcx> TypeErrCtxt<'_, 'tcx> {
16 fn describe_enclosure(&self, def_id: LocalDefId) -> Option<&'static str> {
19 match self.tcx.hir_node_by_def_id(def_id) {
20 hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { .. }, .. }) => Some("a function"),
21 hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) => {
22 Some("a trait method")
23 }
24 hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => {
25 Some("a method")
26 }
27 hir::Node::Expr(hir::Expr {
28 kind: hir::ExprKind::Closure(hir::Closure { kind, .. }),
29 ..
30 }) => Some(self.describe_closure(*kind)),
31 _ => None,
32 }
33 }
34
35 pub fn on_unimplemented_note(
36 &self,
37 trait_pred: ty::PolyTraitPredicate<'tcx>,
38 obligation: &PredicateObligation<'tcx>,
39 long_ty_path: &mut Option<PathBuf>,
40 ) -> OnUnimplementedNote {
41 if trait_pred.polarity() != ty::PredicatePolarity::Positive {
42 return OnUnimplementedNote::default();
43 }
44 let (condition_options, format_args) =
45 self.on_unimplemented_components(trait_pred, obligation, long_ty_path);
46 if let Some(command) = {
#[allow(deprecated)]
{
{
'done:
{
for i in self.tcx.get_all_attrs(trait_pred.def_id()) {
#[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() {
47 command.evaluate_directive(
48 trait_pred.skip_binder().trait_ref,
49 &condition_options,
50 &format_args,
51 )
52 } else {
53 OnUnimplementedNote::default()
54 }
55 }
56
57 pub(crate) fn on_unimplemented_components(
58 &self,
59 trait_pred: ty::PolyTraitPredicate<'tcx>,
60 obligation: &PredicateObligation<'tcx>,
61 long_ty_path: &mut Option<PathBuf>,
62 ) -> (ConditionOptions, FormatArgs) {
63 let (def_id, args) = (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args);
64 let trait_pred = trait_pred.skip_binder();
65
66 let mut self_types = ::alloc::vec::Vec::new()vec![];
67 let mut generic_args: Vec<(Symbol, String)> = ::alloc::vec::Vec::new()vec![];
68 let mut crate_local = false;
69 let item_context = self.describe_enclosure(obligation.cause.body_id).unwrap_or("");
73
74 let direct = match obligation.cause.code() {
75 ObligationCauseCode::BuiltinDerived(..)
76 | ObligationCauseCode::ImplDerived(..)
77 | ObligationCauseCode::WellFormedDerived(..) => false,
78 _ => {
79 true
82 }
83 };
84
85 let from_desugaring = obligation.cause.span.desugaring_kind();
86
87 let cause = if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
88 Some("MainFunctionType".to_string())
89 } else {
90 None
91 };
92
93 {
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().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().to_string()));
}
}
}
if let Some(true) =
self_ty.ty_adt_def().map(|def| def.did().is_local()) {
crate_local = true;
}
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()))
}));
}
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();
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!({
96 let generics = self.tcx.generics_of(def_id);
97 let self_ty = trait_pred.self_ty();
98 self_types.push(self_ty.to_string());
99 if let Some(def) = self_ty.ty_adt_def() {
100 self_types.push(self.tcx.type_of(def.did()).instantiate_identity().to_string());
103 }
104
105 for GenericParamDef { name, kind, index, .. } in generics.own_params.iter() {
106 let value = match kind {
107 GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
108 args[*index as usize].to_string()
109 }
110 GenericParamDefKind::Lifetime => continue,
111 };
112 generic_args.push((*name, value));
113
114 if let GenericParamDefKind::Type { .. } = kind {
115 let param_ty = args[*index as usize].expect_ty();
116 if let Some(def) = param_ty.ty_adt_def() {
117 generic_args.push((
120 *name,
121 self.tcx.type_of(def.did()).instantiate_identity().to_string(),
122 ));
123 }
124 }
125 }
126
127 if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) {
128 crate_local = true;
129 }
130
131 if self_ty.is_integral() {
133 self_types.push("{integral}".to_owned());
134 }
135
136 if self_ty.is_array_slice() {
137 self_types.push("&[]".to_owned());
138 }
139
140 if self_ty.is_fn() {
141 let fn_sig = self_ty.fn_sig(self.tcx);
142 let shortname = if let ty::FnDef(def_id, _) = *self_ty.kind()
143 && self.tcx.codegen_fn_attrs(def_id).safe_target_features
144 {
145 "#[target_feature] fn"
146 } else {
147 match fn_sig.safety() {
148 hir::Safety::Safe => "fn",
149 hir::Safety::Unsafe => "unsafe fn",
150 }
151 };
152 self_types.push(shortname.to_owned());
153 }
154
155 if let ty::Slice(aty) = self_ty.kind() {
157 self_types.push("[]".to_owned());
158 if let Some(def) = aty.ty_adt_def() {
159 self_types
162 .push(format!("[{}]", self.tcx.type_of(def.did()).instantiate_identity()));
163 }
164 if aty.is_integral() {
165 self_types.push("[{integral}]".to_string());
166 }
167 }
168
169 if let ty::Array(aty, len) = self_ty.kind() {
171 self_types.push("[]".to_string());
172 let len = len.try_to_target_usize(self.tcx);
173 self_types.push(format!("[{aty}; _]"));
174 if let Some(n) = len {
175 self_types.push(format!("[{aty}; {n}]"));
176 }
177 if let Some(def) = aty.ty_adt_def() {
178 let def_ty = self.tcx.type_of(def.did()).instantiate_identity();
181 self_types.push(format!("[{def_ty}; _]"));
182 if let Some(n) = len {
183 self_types.push(format!("[{def_ty}; {n}]"));
184 }
185 }
186 if aty.is_integral() {
187 self_types.push("[{integral}; _]".to_string());
188 if let Some(n) = len {
189 self_types.push(format!("[{{integral}}; {n}]"));
190 }
191 }
192 }
193 if let ty::Dynamic(traits, _) = self_ty.kind() {
194 for t in traits.iter() {
195 if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() {
196 self_types.push(self.tcx.def_path_str(trait_ref.def_id));
197 }
198 }
199 }
200
201 if let ty::Ref(_, ref_ty, rustc_ast::Mutability::Not) = self_ty.kind()
203 && let ty::Slice(sty) = ref_ty.kind()
204 && sty.is_integral()
205 {
206 self_types.push("&[{integral}]".to_owned());
207 }
208 }));
209
210 let this = self.tcx.def_path_str(trait_pred.trait_ref.def_id);
211 let trait_sugared = trait_pred.trait_ref.print_trait_sugared().to_string();
212
213 let condition_options = ConditionOptions {
214 self_types,
215 from_desugaring,
216 cause,
217 crate_local,
218 direct,
219 generic_args,
220 };
221
222 let generic_args = self
228 .tcx
229 .generics_of(trait_pred.trait_ref.def_id)
230 .own_params
231 .iter()
232 .filter_map(|param| {
233 let value = match param.kind {
234 GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
235 if let Some(ty) = trait_pred.trait_ref.args[param.index as usize].as_type()
236 {
237 self.tcx.short_string(ty, long_ty_path)
238 } else {
239 trait_pred.trait_ref.args[param.index as usize].to_string()
240 }
241 }
242 GenericParamDefKind::Lifetime => return None,
243 };
244 let name = param.name;
245 Some((name, value))
246 })
247 .collect();
248
249 let format_args = FormatArgs { this, trait_sugared, generic_args, item_context };
250 (condition_options, format_args)
251 }
252}