]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / traits / error_reporting / on_unimplemented.rs
CommitLineData
dfeec247
XL
1use super::{
2 ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation,
3};
2b03887a 4use crate::infer::error_reporting::TypeErrCtxt;
dfeec247
XL
5use rustc_hir as hir;
6use rustc_hir::def_id::DefId;
2b03887a 7use rustc_middle::ty::SubstsRef;
ba9703b0 8use rustc_middle::ty::{self, GenericParamDefKind};
dfeec247 9use rustc_span::symbol::sym;
cdc7bbd5 10use std::iter;
dfeec247 11
ba9703b0
XL
12use super::InferCtxtPrivExt;
13
2b03887a 14pub trait TypeErrCtxtExt<'tcx> {
ba9703b0
XL
15 /*private*/
16 fn impl_similar_to(
17 &self,
18 trait_ref: ty::PolyTraitRef<'tcx>,
19 obligation: &PredicateObligation<'tcx>,
5e7ed085 20 ) -> Option<(DefId, SubstsRef<'tcx>)>;
ba9703b0
XL
21
22 /*private*/
23 fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str>;
24
25 fn on_unimplemented_note(
26 &self,
27 trait_ref: ty::PolyTraitRef<'tcx>,
28 obligation: &PredicateObligation<'tcx>,
29 ) -> OnUnimplementedNote;
30}
31
2b03887a 32impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
dfeec247
XL
33 fn impl_similar_to(
34 &self,
35 trait_ref: ty::PolyTraitRef<'tcx>,
36 obligation: &PredicateObligation<'tcx>,
5e7ed085 37 ) -> Option<(DefId, SubstsRef<'tcx>)> {
dfeec247
XL
38 let tcx = self.tcx;
39 let param_env = obligation.param_env;
fc512014 40 let trait_ref = tcx.erase_late_bound_regions(trait_ref);
dfeec247
XL
41 let trait_self_ty = trait_ref.self_ty();
42
43 let mut self_match_impls = vec![];
44 let mut fuzzy_match_impls = vec![];
45
46 self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
47 let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
04454e1e 48 let impl_trait_ref = tcx.bound_impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);
dfeec247
XL
49
50 let impl_self_ty = impl_trait_ref.self_ty();
51
52 if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
5e7ed085 53 self_match_impls.push((def_id, impl_substs));
dfeec247 54
cdc7bbd5
XL
55 if iter::zip(
56 trait_ref.substs.types().skip(1),
57 impl_trait_ref.substs.types().skip(1),
58 )
5099ac24 59 .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
dfeec247 60 {
5e7ed085 61 fuzzy_match_impls.push((def_id, impl_substs));
dfeec247
XL
62 }
63 }
64 });
65
5e7ed085 66 let impl_def_id_and_substs = if self_match_impls.len() == 1 {
dfeec247
XL
67 self_match_impls[0]
68 } else if fuzzy_match_impls.len() == 1 {
69 fuzzy_match_impls[0]
70 } else {
71 return None;
72 };
73
5e7ed085
FG
74 tcx.has_attr(impl_def_id_and_substs.0, sym::rustc_on_unimplemented)
75 .then_some(impl_def_id_and_substs)
dfeec247
XL
76 }
77
78 /// Used to set on_unimplemented's `ItemContext`
79 /// to be the enclosing (async) block/function/closure
80 fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
5099ac24 81 let hir = self.tcx.hir();
dfeec247
XL
82 let node = hir.find(hir_id)?;
83 match &node {
84 hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => {
85 self.describe_generator(*body_id).or_else(|| {
ba9703b0
XL
86 Some(match sig.header {
87 hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async function",
88 _ => "a function",
dfeec247
XL
89 })
90 })
91 }
92 hir::Node::TraitItem(hir::TraitItem {
ba9703b0 93 kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)),
dfeec247
XL
94 ..
95 }) => self.describe_generator(*body_id).or_else(|| Some("a trait method")),
96 hir::Node::ImplItem(hir::ImplItem {
ba9703b0 97 kind: hir::ImplItemKind::Fn(sig, body_id),
dfeec247
XL
98 ..
99 }) => self.describe_generator(*body_id).or_else(|| {
ba9703b0
XL
100 Some(match sig.header {
101 hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async method",
102 _ => "a method",
dfeec247
XL
103 })
104 }),
105 hir::Node::Expr(hir::Expr {
064997fb 106 kind: hir::ExprKind::Closure(hir::Closure { body, movability, .. }),
dfeec247 107 ..
923072b8
FG
108 }) => self.describe_generator(*body).or_else(|| {
109 Some(if movability.is_some() { "an async closure" } else { "a closure" })
dfeec247
XL
110 }),
111 hir::Node::Expr(hir::Expr { .. }) => {
112 let parent_hid = hir.get_parent_node(hir_id);
ba9703b0 113 if parent_hid != hir_id { self.describe_enclosure(parent_hid) } else { None }
dfeec247
XL
114 }
115 _ => None,
116 }
117 }
118
ba9703b0 119 fn on_unimplemented_note(
dfeec247
XL
120 &self,
121 trait_ref: ty::PolyTraitRef<'tcx>,
122 obligation: &PredicateObligation<'tcx>,
123 ) -> OnUnimplementedNote {
5e7ed085
FG
124 let (def_id, substs) = self
125 .impl_similar_to(trait_ref, obligation)
126 .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs));
f035d41b 127 let trait_ref = trait_ref.skip_binder();
dfeec247 128
94222f64 129 let mut flags = vec![(
3dfed10e 130 sym::ItemContext,
dfeec247 131 self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()),
94222f64 132 )];
dfeec247 133
a2a8927a 134 match obligation.cause.code() {
dfeec247 135 ObligationCauseCode::BuiltinDerivedObligation(..)
ba9703b0
XL
136 | ObligationCauseCode::ImplDerivedObligation(..)
137 | ObligationCauseCode::DerivedObligation(..) => {}
dfeec247
XL
138 _ => {
139 // this is a "direct", user-specified, rather than derived,
140 // obligation.
141 flags.push((sym::direct, None));
142 }
143 }
144
ba9703b0 145 if let ObligationCauseCode::ItemObligation(item)
f2b60f7d
FG
146 | ObligationCauseCode::BindingObligation(item, _)
147 | ObligationCauseCode::ExprItemObligation(item, ..)
148 | ObligationCauseCode::ExprBindingObligation(item, ..) = *obligation.cause.code()
ba9703b0 149 {
dfeec247
XL
150 // FIXME: maybe also have some way of handling methods
151 // from other traits? That would require name resolution,
152 // which we might want to be some sort of hygienic.
153 //
154 // Currently I'm leaving it for what I need for `try`.
155 if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
156 let method = self.tcx.item_name(item);
157 flags.push((sym::from_method, None));
158 flags.push((sym::from_method, Some(method.to_string())));
159 }
160 }
dfeec247
XL
161
162 if let Some(k) = obligation.cause.span.desugaring_kind() {
163 flags.push((sym::from_desugaring, None));
164 flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
165 }
dfeec247 166
2b03887a
FG
167 if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
168 flags.push((sym::cause, Some("MainFunctionType".to_string())));
169 }
170
cdc7bbd5 171 // Add all types without trimmed paths.
5e7ed085 172 ty::print::with_no_trimmed_paths!({
cdc7bbd5
XL
173 let generics = self.tcx.generics_of(def_id);
174 let self_ty = trait_ref.self_ty();
175 // This is also included through the generics list as `Self`,
176 // but the parser won't allow you to use it
177 flags.push((sym::_Self, Some(self_ty.to_string())));
178 if let Some(def) = self_ty.ty_adt_def() {
179 // We also want to be able to select self's original
180 // signature with no type arguments resolved
5e7ed085 181 flags.push((sym::_Self, Some(self.tcx.type_of(def.did()).to_string())));
cdc7bbd5 182 }
dfeec247 183
cdc7bbd5
XL
184 for param in generics.params.iter() {
185 let value = match param.kind {
186 GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
5e7ed085 187 substs[param.index as usize].to_string()
cdc7bbd5
XL
188 }
189 GenericParamDefKind::Lifetime => continue,
190 };
191 let name = param.name;
192 flags.push((name, Some(value)));
17df50a5
XL
193
194 if let GenericParamDefKind::Type { .. } = param.kind {
5e7ed085 195 let param_ty = substs[param.index as usize].expect_ty();
17df50a5
XL
196 if let Some(def) = param_ty.ty_adt_def() {
197 // We also want to be able to select the parameter's
198 // original signature with no type arguments resolved
5e7ed085 199 flags.push((name, Some(self.tcx.type_of(def.did()).to_string())));
17df50a5
XL
200 }
201 }
cdc7bbd5 202 }
dfeec247 203
5e7ed085 204 if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) {
cdc7bbd5
XL
205 flags.push((sym::crate_local, None));
206 }
dfeec247 207
cdc7bbd5
XL
208 // Allow targeting all integers using `{integral}`, even if the exact type was resolved
209 if self_ty.is_integral() {
210 flags.push((sym::_Self, Some("{integral}".to_owned())));
211 }
6a06907d 212
5e7ed085
FG
213 if self_ty.is_array_slice() {
214 flags.push((sym::_Self, Some("&[]".to_owned())));
215 }
216
04454e1e
FG
217 if self_ty.is_fn() {
218 let fn_sig = self_ty.fn_sig(self.tcx);
219 let shortname = match fn_sig.unsafety() {
220 hir::Unsafety::Normal => "fn",
221 hir::Unsafety::Unsafe => "unsafe fn",
222 };
223 flags.push((sym::_Self, Some(shortname.to_owned())));
224 }
225
226 // Slices give us `[]`, `[{ty}]`
227 if let ty::Slice(aty) = self_ty.kind() {
228 flags.push((sym::_Self, Some("[]".to_string())));
229 if let Some(def) = aty.ty_adt_def() {
230 // We also want to be able to select the slice's type's original
231 // signature with no type arguments resolved
064997fb 232 flags.push((sym::_Self, Some(format!("[{}]", self.tcx.type_of(def.did())))));
04454e1e
FG
233 }
234 if aty.is_integral() {
235 flags.push((sym::_Self, Some("[{integral}]".to_string())));
236 }
237 }
238
239 // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
cdc7bbd5 240 if let ty::Array(aty, len) = self_ty.kind() {
04454e1e 241 flags.push((sym::_Self, Some("[]".to_string())));
923072b8 242 let len = len.kind().try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
04454e1e
FG
243 flags.push((sym::_Self, Some(format!("[{}; _]", aty))));
244 if let Some(n) = len {
245 flags.push((sym::_Self, Some(format!("[{}; {}]", aty, n))));
246 }
cdc7bbd5
XL
247 if let Some(def) = aty.ty_adt_def() {
248 // We also want to be able to select the array's type's original
249 // signature with no type arguments resolved
064997fb
FG
250 let def_ty = self.tcx.type_of(def.did());
251 flags.push((sym::_Self, Some(format!("[{def_ty}; _]"))));
04454e1e 252 if let Some(n) = len {
064997fb 253 flags.push((sym::_Self, Some(format!("[{def_ty}; {n}]"))));
04454e1e
FG
254 }
255 }
256 if aty.is_integral() {
257 flags.push((sym::_Self, Some("[{integral}; _]".to_string())));
258 if let Some(n) = len {
259 flags.push((sym::_Self, Some(format!("[{{integral}}; {n}]"))));
260 }
cdc7bbd5 261 }
dfeec247 262 }
f2b60f7d 263 if let ty::Dynamic(traits, _, _) = self_ty.kind() {
cdc7bbd5
XL
264 for t in traits.iter() {
265 if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() {
266 flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id))))
267 }
74b04a01
XL
268 }
269 }
cdc7bbd5 270 });
dfeec247 271
5e7ed085 272 if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
a2a8927a 273 command.evaluate(self.tcx, trait_ref, &flags)
dfeec247
XL
274 } else {
275 OnUnimplementedNote::default()
276 }
277 }
278}