2 ObligationCauseCode
, OnUnimplementedDirective
, OnUnimplementedNote
, PredicateObligation
,
4 use crate::infer
::InferCtxt
;
6 use rustc_hir
::def_id
::DefId
;
7 use rustc_middle
::ty
::subst
::Subst
;
8 use rustc_middle
::ty
::{self, GenericParamDefKind}
;
9 use rustc_span
::symbol
::sym
;
11 use super::InferCtxtPrivExt
;
13 crate trait InferCtxtExt
<'tcx
> {
17 trait_ref
: ty
::PolyTraitRef
<'tcx
>,
18 obligation
: &PredicateObligation
<'tcx
>,
22 fn describe_enclosure(&self, hir_id
: hir
::HirId
) -> Option
<&'
static str>;
24 fn on_unimplemented_note(
26 trait_ref
: ty
::PolyTraitRef
<'tcx
>,
27 obligation
: &PredicateObligation
<'tcx
>,
28 ) -> OnUnimplementedNote
;
31 impl<'a
, 'tcx
> InferCtxtExt
<'tcx
> for InferCtxt
<'a
, 'tcx
> {
34 trait_ref
: ty
::PolyTraitRef
<'tcx
>,
35 obligation
: &PredicateObligation
<'tcx
>,
38 let param_env
= obligation
.param_env
;
39 let trait_ref
= tcx
.erase_late_bound_regions(&trait_ref
);
40 let trait_self_ty
= trait_ref
.self_ty();
42 let mut self_match_impls
= vec
![];
43 let mut fuzzy_match_impls
= vec
![];
45 self.tcx
.for_each_relevant_impl(trait_ref
.def_id
, trait_self_ty
, |def_id
| {
46 let impl_substs
= self.fresh_substs_for_item(obligation
.cause
.span
, def_id
);
47 let impl_trait_ref
= tcx
.impl_trait_ref(def_id
).unwrap().subst(tcx
, impl_substs
);
49 let impl_self_ty
= impl_trait_ref
.self_ty();
51 if let Ok(..) = self.can_eq(param_env
, trait_self_ty
, impl_self_ty
) {
52 self_match_impls
.push(def_id
);
58 .zip(impl_trait_ref
.substs
.types().skip(1))
59 .all(|(u
, v
)| self.fuzzy_match_tys(u
, v
))
61 fuzzy_match_impls
.push(def_id
);
66 let impl_def_id
= if self_match_impls
.len() == 1 {
68 } else if fuzzy_match_impls
.len() == 1 {
74 tcx
.has_attr(impl_def_id
, sym
::rustc_on_unimplemented
).then_some(impl_def_id
)
77 /// Used to set on_unimplemented's `ItemContext`
78 /// to be the enclosing (async) block/function/closure
79 fn describe_enclosure(&self, hir_id
: hir
::HirId
) -> Option
<&'
static str> {
80 let hir
= &self.tcx
.hir();
81 let node
= hir
.find(hir_id
)?
;
83 hir
::Node
::Item(hir
::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }
) => {
84 self.describe_generator(*body_id
).or_else(|| {
85 Some(match sig
.header
{
86 hir
::FnHeader { asyncness: hir::IsAsync::Async, .. }
=> "an async function",
91 hir
::Node
::TraitItem(hir
::TraitItem
{
92 kind
: hir
::TraitItemKind
::Fn(_
, hir
::TraitFn
::Provided(body_id
)),
94 }) => self.describe_generator(*body_id
).or_else(|| Some("a trait method")),
95 hir
::Node
::ImplItem(hir
::ImplItem
{
96 kind
: hir
::ImplItemKind
::Fn(sig
, body_id
),
98 }) => self.describe_generator(*body_id
).or_else(|| {
99 Some(match sig
.header
{
100 hir
::FnHeader { asyncness: hir::IsAsync::Async, .. }
=> "an async method",
104 hir
::Node
::Expr(hir
::Expr
{
105 kind
: hir
::ExprKind
::Closure(_is_move
, _
, body_id
, _
, gen_movability
),
107 }) => self.describe_generator(*body_id
).or_else(|| {
108 Some(if gen_movability
.is_some() { "an async closure" }
else { "a closure" }
)
110 hir
::Node
::Expr(hir
::Expr { .. }
) => {
111 let parent_hid
= hir
.get_parent_node(hir_id
);
112 if parent_hid
!= hir_id { self.describe_enclosure(parent_hid) }
else { None }
118 fn on_unimplemented_note(
120 trait_ref
: ty
::PolyTraitRef
<'tcx
>,
121 obligation
: &PredicateObligation
<'tcx
>,
122 ) -> OnUnimplementedNote
{
124 self.impl_similar_to(trait_ref
, obligation
).unwrap_or_else(|| trait_ref
.def_id());
125 let trait_ref
= *trait_ref
.skip_binder();
127 let mut flags
= vec
![];
130 self.describe_enclosure(obligation
.cause
.body_id
).map(|s
| s
.to_owned()),
133 match obligation
.cause
.code
{
134 ObligationCauseCode
::BuiltinDerivedObligation(..)
135 | ObligationCauseCode
::ImplDerivedObligation(..)
136 | ObligationCauseCode
::DerivedObligation(..) => {}
138 // this is a "direct", user-specified, rather than derived,
140 flags
.push((sym
::direct
, None
));
144 if let ObligationCauseCode
::ItemObligation(item
)
145 | ObligationCauseCode
::BindingObligation(item
, _
) = obligation
.cause
.code
147 // FIXME: maybe also have some way of handling methods
148 // from other traits? That would require name resolution,
149 // which we might want to be some sort of hygienic.
151 // Currently I'm leaving it for what I need for `try`.
152 if self.tcx
.trait_of_item(item
) == Some(trait_ref
.def_id
) {
153 let method
= self.tcx
.item_name(item
);
154 flags
.push((sym
::from_method
, None
));
155 flags
.push((sym
::from_method
, Some(method
.to_string())));
158 if let Some((t
, _
)) = self.get_parent_trait_ref(&obligation
.cause
.code
) {
159 flags
.push((sym
::parent_trait
, Some(t
)));
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
))));
166 let generics
= self.tcx
.generics_of(def_id
);
167 let self_ty
= trait_ref
.self_ty();
168 // This is also included through the generics list as `Self`,
169 // but the parser won't allow you to use it
170 flags
.push((sym
::_Self
, Some(self_ty
.to_string())));
171 if let Some(def
) = self_ty
.ty_adt_def() {
172 // We also want to be able to select self's original
173 // signature with no type arguments resolved
174 flags
.push((sym
::_Self
, Some(self.tcx
.type_of(def
.did
).to_string())));
177 for param
in generics
.params
.iter() {
178 let value
= match param
.kind
{
179 GenericParamDefKind
::Type { .. }
| GenericParamDefKind
::Const
=> {
180 trait_ref
.substs
[param
.index
as usize].to_string()
182 GenericParamDefKind
::Lifetime
=> continue,
184 let name
= param
.name
;
185 flags
.push((name
, Some(value
)));
188 if let Some(true) = self_ty
.ty_adt_def().map(|def
| def
.did
.is_local()) {
189 flags
.push((sym
::crate_local
, None
));
192 // Allow targeting all integers using `{integral}`, even if the exact type was resolved
193 if self_ty
.is_integral() {
194 flags
.push((sym
::_Self
, Some("{integral}".to_owned())));
197 if let ty
::Array(aty
, len
) = self_ty
.kind
{
198 flags
.push((sym
::_Self
, Some("[]".to_owned())));
199 flags
.push((sym
::_Self
, Some(format
!("[{}]", aty
))));
200 if let Some(def
) = aty
.ty_adt_def() {
201 // We also want to be able to select the array's type's original
202 // signature with no type arguments resolved
205 Some(format
!("[{}]", self.tcx
.type_of(def
.did
).to_string())),
208 if let Some(len
) = len
.try_eval_usize(tcx
, ty
::ParamEnv
::empty()) {
211 Some(format
!("[{}; {}]", self.tcx
.type_of(def
.did
).to_string(), len
)),
216 Some(format
!("[{}; _]", self.tcx
.type_of(def
.did
).to_string())),
221 if let ty
::Dynamic(traits
, _
) = self_ty
.kind
{
222 for t
in *traits
.skip_binder() {
223 if let ty
::ExistentialPredicate
::Trait(trait_ref
) = t
{
224 flags
.push((sym
::_Self
, Some(self.tcx
.def_path_str(trait_ref
.def_id
))))
229 if let Ok(Some(command
)) =
230 OnUnimplementedDirective
::of_item(self.tcx
, trait_ref
.def_id
, def_id
)
232 command
.evaluate(self.tcx
, trait_ref
, &flags
[..])
234 OnUnimplementedNote
::default()