2 ObligationCauseCode
, OnUnimplementedDirective
, OnUnimplementedNote
, PredicateObligation
,
4 use crate::infer
::InferCtxt
;
6 use rustc_hir
::def_id
::DefId
;
7 use rustc_middle
::ty
::subst
::{Subst, SubstsRef}
;
8 use rustc_middle
::ty
::{self, GenericParamDefKind}
;
9 use rustc_span
::symbol
::sym
;
12 use super::InferCtxtPrivExt
;
14 pub trait InferCtxtExt
<'tcx
> {
18 trait_ref
: ty
::PolyTraitRef
<'tcx
>,
19 obligation
: &PredicateObligation
<'tcx
>,
20 ) -> Option
<(DefId
, SubstsRef
<'tcx
>)>;
23 fn describe_enclosure(&self, hir_id
: hir
::HirId
) -> Option
<&'
static str>;
25 fn on_unimplemented_note(
27 trait_ref
: ty
::PolyTraitRef
<'tcx
>,
28 obligation
: &PredicateObligation
<'tcx
>,
29 ) -> OnUnimplementedNote
;
32 impl<'a
, 'tcx
> InferCtxtExt
<'tcx
> for InferCtxt
<'a
, 'tcx
> {
35 trait_ref
: ty
::PolyTraitRef
<'tcx
>,
36 obligation
: &PredicateObligation
<'tcx
>,
37 ) -> Option
<(DefId
, SubstsRef
<'tcx
>)> {
39 let param_env
= obligation
.param_env
;
40 let trait_ref
= tcx
.erase_late_bound_regions(trait_ref
);
41 let trait_self_ty
= trait_ref
.self_ty();
43 let mut self_match_impls
= vec
![];
44 let mut fuzzy_match_impls
= vec
![];
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
);
48 let impl_trait_ref
= tcx
.impl_trait_ref(def_id
).unwrap().subst(tcx
, impl_substs
);
50 let impl_self_ty
= impl_trait_ref
.self_ty();
52 if let Ok(..) = self.can_eq(param_env
, trait_self_ty
, impl_self_ty
) {
53 self_match_impls
.push((def_id
, impl_substs
));
56 trait_ref
.substs
.types().skip(1),
57 impl_trait_ref
.substs
.types().skip(1),
59 .all(|(u
, v
)| self.fuzzy_match_tys(u
, v
, false).is_some())
61 fuzzy_match_impls
.push((def_id
, impl_substs
));
66 let impl_def_id_and_substs
= if self_match_impls
.len() == 1 {
68 } else if fuzzy_match_impls
.len() == 1 {
74 tcx
.has_attr(impl_def_id_and_substs
.0, sym
::rustc_on_unimplemented
)
75 .then_some(impl_def_id_and_substs
)
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> {
81 let hir
= self.tcx
.hir();
82 let node
= hir
.find(hir_id
)?
;
84 hir
::Node
::Item(hir
::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }
) => {
85 self.describe_generator(*body_id
).or_else(|| {
86 Some(match sig
.header
{
87 hir
::FnHeader { asyncness: hir::IsAsync::Async, .. }
=> "an async function",
92 hir
::Node
::TraitItem(hir
::TraitItem
{
93 kind
: hir
::TraitItemKind
::Fn(_
, hir
::TraitFn
::Provided(body_id
)),
95 }) => self.describe_generator(*body_id
).or_else(|| Some("a trait method")),
96 hir
::Node
::ImplItem(hir
::ImplItem
{
97 kind
: hir
::ImplItemKind
::Fn(sig
, body_id
),
99 }) => self.describe_generator(*body_id
).or_else(|| {
100 Some(match sig
.header
{
101 hir
::FnHeader { asyncness: hir::IsAsync::Async, .. }
=> "an async method",
105 hir
::Node
::Expr(hir
::Expr
{
106 kind
: hir
::ExprKind
::Closure(_is_move
, _
, body_id
, _
, gen_movability
),
108 }) => self.describe_generator(*body_id
).or_else(|| {
109 Some(if gen_movability
.is_some() { "an async closure" }
else { "a closure" }
)
111 hir
::Node
::Expr(hir
::Expr { .. }
) => {
112 let parent_hid
= hir
.get_parent_node(hir_id
);
113 if parent_hid
!= hir_id { self.describe_enclosure(parent_hid) }
else { None }
119 fn on_unimplemented_note(
121 trait_ref
: ty
::PolyTraitRef
<'tcx
>,
122 obligation
: &PredicateObligation
<'tcx
>,
123 ) -> OnUnimplementedNote
{
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
));
127 let trait_ref
= trait_ref
.skip_binder();
129 let mut flags
= vec
![(
131 self.describe_enclosure(obligation
.cause
.body_id
).map(|s
| s
.to_owned()),
134 match obligation
.cause
.code() {
135 ObligationCauseCode
::BuiltinDerivedObligation(..)
136 | ObligationCauseCode
::ImplDerivedObligation(..)
137 | ObligationCauseCode
::DerivedObligation(..) => {}
139 // this is a "direct", user-specified, rather than derived,
141 flags
.push((sym
::direct
, None
));
145 if let ObligationCauseCode
::ItemObligation(item
)
146 | ObligationCauseCode
::BindingObligation(item
, _
) = *obligation
.cause
.code()
148 // FIXME: maybe also have some way of handling methods
149 // from other traits? That would require name resolution,
150 // which we might want to be some sort of hygienic.
152 // Currently I'm leaving it for what I need for `try`.
153 if self.tcx
.trait_of_item(item
) == Some(trait_ref
.def_id
) {
154 let method
= self.tcx
.item_name(item
);
155 flags
.push((sym
::from_method
, None
));
156 flags
.push((sym
::from_method
, Some(method
.to_string())));
160 if let Some(k
) = obligation
.cause
.span
.desugaring_kind() {
161 flags
.push((sym
::from_desugaring
, None
));
162 flags
.push((sym
::from_desugaring
, Some(format
!("{:?}", k
))));
165 // Add all types without trimmed paths.
166 ty
::print
::with_no_trimmed_paths
!({
167 let generics
= self.tcx
.generics_of(def_id
);
168 let self_ty
= trait_ref
.self_ty();
169 // This is also included through the generics list as `Self`,
170 // but the parser won't allow you to use it
171 flags
.push((sym
::_Self
, Some(self_ty
.to_string())));
172 if let Some(def
) = self_ty
.ty_adt_def() {
173 // We also want to be able to select self's original
174 // signature with no type arguments resolved
175 flags
.push((sym
::_Self
, Some(self.tcx
.type_of(def
.did()).to_string())));
178 for param
in generics
.params
.iter() {
179 let value
= match param
.kind
{
180 GenericParamDefKind
::Type { .. }
| GenericParamDefKind
::Const { .. }
=> {
181 substs
[param
.index
as usize].to_string()
183 GenericParamDefKind
::Lifetime
=> continue,
185 let name
= param
.name
;
186 flags
.push((name
, Some(value
)));
188 if let GenericParamDefKind
::Type { .. }
= param
.kind
{
189 let param_ty
= substs
[param
.index
as usize].expect_ty();
190 if let Some(def
) = param_ty
.ty_adt_def() {
191 // We also want to be able to select the parameter's
192 // original signature with no type arguments resolved
193 flags
.push((name
, Some(self.tcx
.type_of(def
.did()).to_string())));
198 if let Some(true) = self_ty
.ty_adt_def().map(|def
| def
.did().is_local()) {
199 flags
.push((sym
::crate_local
, None
));
202 // Allow targeting all integers using `{integral}`, even if the exact type was resolved
203 if self_ty
.is_integral() {
204 flags
.push((sym
::_Self
, Some("{integral}".to_owned())));
207 if self_ty
.is_array_slice() {
208 flags
.push((sym
::_Self
, Some("&[]".to_owned())));
211 if let ty
::Array(aty
, len
) = self_ty
.kind() {
212 flags
.push((sym
::_Self
, Some("[]".to_owned())));
213 flags
.push((sym
::_Self
, Some(format
!("[{}]", aty
))));
214 if let Some(def
) = aty
.ty_adt_def() {
215 // We also want to be able to select the array's type's original
216 // signature with no type arguments resolved
217 let type_string
= self.tcx
.type_of(def
.did()).to_string();
218 flags
.push((sym
::_Self
, Some(format
!("[{}]", type_string
))));
221 len
.val().try_to_value().and_then(|v
| v
.try_to_machine_usize(self.tcx
));
222 let string
= match len
{
223 Some(n
) => format
!("[{}; {}]", type_string
, n
),
224 None
=> format
!("[{}; _]", type_string
),
226 flags
.push((sym
::_Self
, Some(string
)));
229 if let ty
::Dynamic(traits
, _
) = self_ty
.kind() {
230 for t
in traits
.iter() {
231 if let ty
::ExistentialPredicate
::Trait(trait_ref
) = t
.skip_binder() {
232 flags
.push((sym
::_Self
, Some(self.tcx
.def_path_str(trait_ref
.def_id
))))
238 if let Ok(Some(command
)) = OnUnimplementedDirective
::of_item(self.tcx
, def_id
) {
239 command
.evaluate(self.tcx
, trait_ref
, &flags
)
241 OnUnimplementedNote
::default()