1 //! Diagnostics related methods for `TyS`.
3 use crate::ty
::TyKind
::*;
4 use crate::ty
::{InferTy, TyCtxt, TyS}
;
5 use rustc_data_structures
::fx
::FxHashSet
;
6 use rustc_errors
::{Applicability, DiagnosticBuilder}
;
8 use rustc_hir
::def_id
::DefId
;
9 use rustc_hir
::{QPath, TyKind, WhereBoundPredicate, WherePredicate}
;
11 impl<'tcx
> TyS
<'tcx
> {
12 /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive.
13 pub fn is_primitive_ty(&self) -> bool
{
23 | InferTy
::FloatVar(_
)
24 | InferTy
::FreshIntTy(_
)
25 | InferTy
::FreshFloatTy(_
)
30 /// Whether the type is succinctly representable as a type instead of just referred to with a
31 /// description in error messages. This is used in the main error message.
32 pub fn is_simple_ty(&self) -> bool
{
42 | InferTy
::FloatVar(_
)
43 | InferTy
::FreshIntTy(_
)
44 | InferTy
::FreshFloatTy(_
),
46 Ref(_
, x
, _
) | Array(x
, _
) | Slice(x
) => x
.peel_refs().is_simple_ty(),
47 Tuple(tys
) if tys
.is_empty() => true,
52 /// Whether the type is succinctly representable as a type instead of just referred to with a
53 /// description in error messages. This is used in the primary span label. Beyond what
54 /// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to
55 /// ADTs with no type arguments.
56 pub fn is_simple_text(&self) -> bool
{
58 Adt(_
, substs
) => substs
.non_erasable_generics().next().is_none(),
59 Ref(_
, ty
, _
) => ty
.is_simple_text(),
60 _
=> self.is_simple_ty(),
64 /// Whether the type can be safely suggested during error recovery.
65 pub fn is_suggestable(&self) -> bool
{
79 pub fn suggest_arbitrary_trait_bound(
80 generics
: &hir
::Generics
<'_
>,
81 err
: &mut DiagnosticBuilder
<'_
>,
85 let param
= generics
.params
.iter().find(|p
| p
.name
.ident().as_str() == param_name
);
86 match (param
, param_name
) {
87 (Some(_
), "Self") => return false,
90 // Suggest a where clause bound for a non-type paremeter.
91 let (action
, prefix
) = if generics
.where_clause
.predicates
.is_empty() {
92 ("introducing a", " where ")
94 ("extending the", ", ")
96 err
.span_suggestion_verbose(
97 generics
.where_clause
.tail_span_for_suggestion(),
99 "consider {} `where` bound, but there might be an alternative better way to express \
103 format
!("{}{}: {}", prefix
, param_name
, constraint
),
104 Applicability
::MaybeIncorrect
,
109 fn suggest_removing_unsized_bound(
110 generics
: &hir
::Generics
<'_
>,
111 err
: &mut DiagnosticBuilder
<'_
>,
113 param
: &hir
::GenericParam
<'_
>,
114 def_id
: Option
<DefId
>,
116 // See if there's a `?Sized` bound that can be removed to suggest that.
117 // First look at the `where` clause because we can have `where T: ?Sized`, but that
118 // `?Sized` bound is *also* included in the `GenericParam` as a bound, which breaks
119 // the spans. Hence the somewhat involved logic that follows.
120 let mut where_unsized_bounds
= FxHashSet
::default();
121 for (where_pos
, predicate
) in generics
.where_clause
.predicates
.iter().enumerate() {
123 WherePredicate
::BoundPredicate(WhereBoundPredicate
{
127 hir
::TyKind
::Path(hir
::QPath
::Resolved(
131 res
: hir
::def
::Res
::Def(hir
::def
::DefKind
::TyParam
, _
),
140 }) if segment
.ident
.as_str() == param_name
=> {
141 for (pos
, bound
) in bounds
.iter().enumerate() {
143 hir
::GenericBound
::Unsized(_
) => {}
144 hir
::GenericBound
::Trait(poly
, hir
::TraitBoundModifier
::Maybe
)
145 if poly
.trait_ref
.trait_def_id() == def_id
=> {}
151 generics
.where_clause
.predicates
.len(),
156 (1, _
, 1, _
) => generics
.where_clause
.span
,
157 // where Foo: Bar, T: ?Sized,
159 (1, _
, len
, pos
) if pos
== len
- 1 => generics
.where_clause
.predicates
164 // where T: ?Sized, Foo: Bar,
167 span
.until(generics
.where_clause
.predicates
[pos
+ 1].span())
169 // where T: ?Sized + Bar, Foo: Bar,
171 (_
, 0, _
, _
) => bound
.span().to(bounds
[1].span().shrink_to_lo()),
172 // where T: Bar + ?Sized, Foo: Bar,
174 (_
, pos
, _
, _
) => bounds
[pos
- 1].span().shrink_to_hi().to(bound
.span()),
176 where_unsized_bounds
.insert(bound
.span());
177 err
.span_suggestion_verbose(
179 "consider removing the `?Sized` bound to make the \
180 type parameter `Sized`",
182 Applicability
::MaybeIncorrect
,
189 for (pos
, bound
) in param
.bounds
.iter().enumerate() {
191 hir
::GenericBound
::Trait(poly
, hir
::TraitBoundModifier
::Maybe
)
192 if poly
.trait_ref
.trait_def_id() == def_id
193 && !where_unsized_bounds
.contains(&bound
.span()) =>
195 let sp
= match (param
.bounds
.len(), pos
) {
198 (1, _
) => param
.span
.shrink_to_hi().to(bound
.span()),
201 (_
, 0) => bound
.span().to(param
.bounds
[1].span().shrink_to_lo()),
204 (_
, pos
) => param
.bounds
[pos
- 1].span().shrink_to_hi().to(bound
.span()),
206 err
.span_suggestion_verbose(
208 "consider removing the `?Sized` bound to make the type parameter \
211 Applicability
::MaybeIncorrect
,
219 /// Suggest restricting a type param with a new bound.
220 pub fn suggest_constraining_type_param(
222 generics
: &hir
::Generics
<'_
>,
223 err
: &mut DiagnosticBuilder
<'_
>,
226 def_id
: Option
<DefId
>,
228 let param
= generics
.params
.iter().find(|p
| p
.name
.ident().as_str() == param_name
);
230 let param
= if let Some(param
) = param
{
236 const MSG_RESTRICT_BOUND_FURTHER
: &str = "consider further restricting this bound";
237 let msg_restrict_type
= format
!("consider restricting type parameter `{}`", param_name
);
238 let msg_restrict_type_further
=
239 format
!("consider further restricting type parameter `{}`", param_name
);
241 if def_id
== tcx
.lang_items().sized_trait() {
242 // Type parameters are already `Sized` by default.
243 err
.span_label(param
.span
, &format
!("this type parameter needs to be `{}`", constraint
));
244 suggest_removing_unsized_bound(generics
, err
, param_name
, param
, def_id
);
247 let mut suggest_restrict
= |span
| {
248 err
.span_suggestion_verbose(
250 MSG_RESTRICT_BOUND_FURTHER
,
251 format
!(" + {}", constraint
),
252 Applicability
::MachineApplicable
,
256 if param_name
.starts_with("impl ") {
257 // If there's an `impl Trait` used in argument position, suggest
260 // fn foo(t: impl Foo) { ... }
263 // help: consider further restricting this bound with `+ Bar`
265 // Suggestion for tools in this case is:
267 // fn foo(t: impl Foo) { ... }
270 // replace with: `impl Foo + Bar`
272 suggest_restrict(param
.span
.shrink_to_hi());
276 if generics
.where_clause
.predicates
.is_empty()
277 // Given `trait Base<T = String>: Super<T>` where `T: Copy`, suggest restricting in the
278 // `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
279 && !matches
!(param
.kind
, hir
::GenericParamKind
::Type { default: Some(_), .. }
)
281 if let Some(bounds_span
) = param
.bounds_span() {
282 // If user has provided some bounds, suggest restricting them:
284 // fn foo<T: Foo>(t: T) { ... }
287 // help: consider further restricting this bound with `+ Bar`
289 // Suggestion for tools in this case is:
291 // fn foo<T: Foo>(t: T) { ... }
294 // replace with: `T: Bar +`
295 suggest_restrict(bounds_span
.shrink_to_hi());
297 // If user hasn't provided any bounds, suggest adding a new one:
299 // fn foo<T>(t: T) { ... }
300 // - help: consider restricting this type parameter with `T: Foo`
301 err
.span_suggestion_verbose(
302 param
.span
.shrink_to_hi(),
304 format
!(": {}", constraint
),
305 Applicability
::MachineApplicable
,
311 // This part is a bit tricky, because using the `where` clause user can
312 // provide zero, one or many bounds for the same type parameter, so we
313 // have following cases to consider:
315 // 1) When the type parameter has been provided zero bounds
318 // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
319 // - help: consider restricting this type parameter with `where X: Bar`
322 // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
323 // - insert: `, X: Bar`
326 // 2) When the type parameter has been provided one bound
329 // fn foo<T>(t: T) where T: Foo { ... }
332 // help: consider further restricting this bound with `+ Bar`
335 // fn foo<T>(t: T) where T: Foo { ... }
338 // replace with: `T: Bar +`
341 // 3) When the type parameter has been provided many bounds
344 // fn foo<T>(t: T) where T: Foo, T: Bar {... }
345 // - help: consider further restricting this type parameter with `where T: Zar`
348 // fn foo<T>(t: T) where T: Foo, T: Bar {... }
349 // - insert: `, T: Zar`
351 // Additionally, there may be no `where` clause whatsoever in the case that this was
352 // reached because the generic parameter has a default:
355 // trait Foo<T=()> {... }
356 // - help: consider further restricting this type parameter with `where T: Zar`
359 // trait Foo<T=()> where T: Zar {... }
360 // - insert: `where T: Zar`
362 if matches
!(param
.kind
, hir
::GenericParamKind
::Type { default: Some(_), .. }
)
363 && generics
.where_clause
.predicates
.len() == 0
365 // Suggest a bound, but there is no existing `where` clause *and* the type param has a
366 // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
367 err
.span_suggestion_verbose(
368 generics
.where_clause
.tail_span_for_suggestion(),
369 &msg_restrict_type_further
,
370 format
!(" where {}: {}", param_name
, constraint
),
371 Applicability
::MachineApplicable
,
374 let mut param_spans
= Vec
::new();
376 for predicate
in generics
.where_clause
.predicates
{
377 if let WherePredicate
::BoundPredicate(WhereBoundPredicate
{
383 if let TyKind
::Path(QPath
::Resolved(_
, path
)) = &bounded_ty
.kind
{
384 if let Some(segment
) = path
.segments
.first() {
385 if segment
.ident
.to_string() == param_name
{
386 param_spans
.push(span
);
393 match param_spans
[..] {
394 [¶m_span
] => suggest_restrict(param_span
.shrink_to_hi()),
396 err
.span_suggestion_verbose(
397 generics
.where_clause
.tail_span_for_suggestion(),
398 &msg_restrict_type_further
,
399 format
!(", {}: {}", param_name
, constraint
),
400 Applicability
::MachineApplicable
,
410 /// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
411 pub struct TraitObjectVisitor
<'tcx
>(pub Vec
<&'tcx hir
::Ty
<'tcx
>>, pub crate::hir
::map
::Map
<'tcx
>);
413 impl<'v
> hir
::intravisit
::Visitor
<'v
> for TraitObjectVisitor
<'v
> {
414 type Map
= rustc_hir
::intravisit
::ErasedMap
<'v
>;
416 fn nested_visit_map(&mut self) -> hir
::intravisit
::NestedVisitorMap
<Self::Map
> {
417 hir
::intravisit
::NestedVisitorMap
::None
420 fn visit_ty(&mut self, ty
: &'v hir
::Ty
<'v
>) {
422 hir
::TyKind
::TraitObject(
426 hir
::LifetimeName
::ImplicitObjectLifetimeDefault
| hir
::LifetimeName
::Static
,
433 hir
::TyKind
::OpaqueDef(item_id
, _
) => {
435 let item
= self.1.item
(item_id
);
436 hir
::intravisit
::walk_item(self, item
);
440 hir
::intravisit
::walk_ty(self, ty
);