1 //! Diagnostics related methods for `TyS`.
3 use crate::ty
::TyKind
::*;
4 use crate::ty
::{InferTy, TyCtxt, TyS}
;
5 use rustc_errors
::{Applicability, DiagnosticBuilder}
;
7 use rustc_hir
::def_id
::DefId
;
8 use rustc_hir
::{QPath, TyKind, WhereBoundPredicate, WherePredicate}
;
10 impl<'tcx
> TyS
<'tcx
> {
11 /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive.
12 pub fn is_primitive_ty(&self) -> bool
{
22 | InferTy
::FloatVar(_
)
23 | InferTy
::FreshIntTy(_
)
24 | InferTy
::FreshFloatTy(_
)
29 /// Whether the type is succinctly representable as a type instead of just referred to with a
30 /// description in error messages. This is used in the main error message.
31 pub fn is_simple_ty(&self) -> bool
{
41 | InferTy
::FloatVar(_
)
42 | InferTy
::FreshIntTy(_
)
43 | InferTy
::FreshFloatTy(_
),
45 Ref(_
, x
, _
) | Array(x
, _
) | Slice(x
) => x
.peel_refs().is_simple_ty(),
46 Tuple(tys
) if tys
.is_empty() => true,
51 /// Whether the type is succinctly representable as a type instead of just referred to with a
52 /// description in error messages. This is used in the primary span label. Beyond what
53 /// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to
54 /// ADTs with no type arguments.
55 pub fn is_simple_text(&self) -> bool
{
57 Adt(_
, substs
) => substs
.non_erasable_generics().next().is_none(),
58 Ref(_
, ty
, _
) => ty
.is_simple_text(),
59 _
=> self.is_simple_ty(),
63 /// Whether the type can be safely suggested during error recovery.
64 pub fn is_suggestable(&self) -> bool
{
78 pub fn suggest_arbitrary_trait_bound(
79 generics
: &hir
::Generics
<'_
>,
80 err
: &mut DiagnosticBuilder
<'_
>,
84 let param
= generics
.params
.iter().find(|p
| p
.name
.ident().as_str() == param_name
);
85 match (param
, param_name
) {
86 (Some(_
), "Self") => return false,
89 // Suggest a where clause bound for a non-type paremeter.
90 let (action
, prefix
) = if generics
.where_clause
.predicates
.is_empty() {
91 ("introducing a", " where ")
93 ("extending the", ", ")
95 err
.span_suggestion_verbose(
96 generics
.where_clause
.tail_span_for_suggestion(),
98 "consider {} `where` bound, but there might be an alternative better way to express \
102 format
!("{}{}: {}", prefix
, param_name
, constraint
),
103 Applicability
::MaybeIncorrect
,
108 /// Suggest restricting a type param with a new bound.
109 pub fn suggest_constraining_type_param(
111 generics
: &hir
::Generics
<'_
>,
112 err
: &mut DiagnosticBuilder
<'_
>,
115 def_id
: Option
<DefId
>,
117 let param
= generics
.params
.iter().find(|p
| p
.name
.ident().as_str() == param_name
);
119 let param
= if let Some(param
) = param
{
125 const MSG_RESTRICT_BOUND_FURTHER
: &str = "consider further restricting this bound";
126 let msg_restrict_type
= format
!("consider restricting type parameter `{}`", param_name
);
127 let msg_restrict_type_further
=
128 format
!("consider further restricting type parameter `{}`", param_name
);
130 if def_id
== tcx
.lang_items().sized_trait() {
131 // Type parameters are already `Sized` by default.
132 err
.span_label(param
.span
, &format
!("this type parameter needs to be `{}`", constraint
));
135 let mut suggest_restrict
= |span
| {
136 err
.span_suggestion_verbose(
138 MSG_RESTRICT_BOUND_FURTHER
,
139 format
!(" + {}", constraint
),
140 Applicability
::MachineApplicable
,
144 if param_name
.starts_with("impl ") {
145 // If there's an `impl Trait` used in argument position, suggest
148 // fn foo(t: impl Foo) { ... }
151 // help: consider further restricting this bound with `+ Bar`
153 // Suggestion for tools in this case is:
155 // fn foo(t: impl Foo) { ... }
158 // replace with: `impl Foo + Bar`
160 suggest_restrict(param
.span
.shrink_to_hi());
164 if generics
.where_clause
.predicates
.is_empty()
165 // Given `trait Base<T = String>: Super<T>` where `T: Copy`, suggest restricting in the
166 // `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
167 && !matches
!(param
.kind
, hir
::GenericParamKind
::Type { default: Some(_), .. }
)
169 if let Some(bounds_span
) = param
.bounds_span() {
170 // If user has provided some bounds, suggest restricting them:
172 // fn foo<T: Foo>(t: T) { ... }
175 // help: consider further restricting this bound with `+ Bar`
177 // Suggestion for tools in this case is:
179 // fn foo<T: Foo>(t: T) { ... }
182 // replace with: `T: Bar +`
183 suggest_restrict(bounds_span
.shrink_to_hi());
185 // If user hasn't provided any bounds, suggest adding a new one:
187 // fn foo<T>(t: T) { ... }
188 // - help: consider restricting this type parameter with `T: Foo`
189 err
.span_suggestion_verbose(
190 param
.span
.shrink_to_hi(),
192 format
!(": {}", constraint
),
193 Applicability
::MachineApplicable
,
199 // This part is a bit tricky, because using the `where` clause user can
200 // provide zero, one or many bounds for the same type parameter, so we
201 // have following cases to consider:
203 // 1) When the type parameter has been provided zero bounds
206 // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
207 // - help: consider restricting this type parameter with `where X: Bar`
210 // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
211 // - insert: `, X: Bar`
214 // 2) When the type parameter has been provided one bound
217 // fn foo<T>(t: T) where T: Foo { ... }
220 // help: consider further restricting this bound with `+ Bar`
223 // fn foo<T>(t: T) where T: Foo { ... }
226 // replace with: `T: Bar +`
229 // 3) When the type parameter has been provided many bounds
232 // fn foo<T>(t: T) where T: Foo, T: Bar {... }
233 // - help: consider further restricting this type parameter with `where T: Zar`
236 // fn foo<T>(t: T) where T: Foo, T: Bar {... }
237 // - insert: `, T: Zar`
239 // Additionally, there may be no `where` clause whatsoever in the case that this was
240 // reached because the generic parameter has a default:
243 // trait Foo<T=()> {... }
244 // - help: consider further restricting this type parameter with `where T: Zar`
247 // trait Foo<T=()> where T: Zar {... }
248 // - insert: `where T: Zar`
250 if matches
!(param
.kind
, hir
::GenericParamKind
::Type { default: Some(_), .. }
)
251 && generics
.where_clause
.predicates
.len() == 0
253 // Suggest a bound, but there is no existing `where` clause *and* the type param has a
254 // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
255 err
.span_suggestion_verbose(
256 generics
.where_clause
.tail_span_for_suggestion(),
257 &msg_restrict_type_further
,
258 format
!(" where {}: {}", param_name
, constraint
),
259 Applicability
::MachineApplicable
,
262 let mut param_spans
= Vec
::new();
264 for predicate
in generics
.where_clause
.predicates
{
265 if let WherePredicate
::BoundPredicate(WhereBoundPredicate
{
271 if let TyKind
::Path(QPath
::Resolved(_
, path
)) = &bounded_ty
.kind
{
272 if let Some(segment
) = path
.segments
.first() {
273 if segment
.ident
.to_string() == param_name
{
274 param_spans
.push(span
);
281 match param_spans
[..] {
282 [¶m_span
] => suggest_restrict(param_span
.shrink_to_hi()),
284 err
.span_suggestion_verbose(
285 generics
.where_clause
.tail_span_for_suggestion(),
286 &msg_restrict_type_further
,
287 format
!(", {}: {}", param_name
, constraint
),
288 Applicability
::MachineApplicable
,
298 /// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
299 pub struct TraitObjectVisitor
<'tcx
>(pub Vec
<&'tcx hir
::Ty
<'tcx
>>, pub crate::hir
::map
::Map
<'tcx
>);
301 impl<'v
> hir
::intravisit
::Visitor
<'v
> for TraitObjectVisitor
<'v
> {
302 type Map
= rustc_hir
::intravisit
::ErasedMap
<'v
>;
304 fn nested_visit_map(&mut self) -> hir
::intravisit
::NestedVisitorMap
<Self::Map
> {
305 hir
::intravisit
::NestedVisitorMap
::None
308 fn visit_ty(&mut self, ty
: &'v hir
::Ty
<'v
>) {
310 hir
::TyKind
::TraitObject(
314 hir
::LifetimeName
::ImplicitObjectLifetimeDefault
| hir
::LifetimeName
::Static
,
321 hir
::TyKind
::OpaqueDef(item_id
, _
) => {
323 let item
= self.1.item
(item_id
);
324 hir
::intravisit
::walk_item(self, item
);
328 hir
::intravisit
::walk_ty(self, ty
);