1 //! Diagnostics related methods for `TyS`.
3 use crate::ty::sty::InferTy;
4 use crate::ty::TyKind::*;
5 use crate::ty::{TyCtxt, TyS};
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(_),
31 /// Whether the type is succinctly representable as a type instead of just referred to with a
32 /// description in error messages. This is used in the main error message.
33 pub fn is_simple_ty(&self) -> bool {
43 | InferTy::FloatVar(_)
44 | InferTy::FreshIntTy(_)
45 | InferTy::FreshFloatTy(_),
47 Ref(_, x, _) | Array(x, _) | Slice(x) => x.peel_refs().is_simple_ty(),
48 Tuple(tys) if tys.is_empty() => true,
53 /// Whether the type is succinctly representable as a type instead of just referred to with a
54 /// description in error messages. This is used in the primary span label. Beyond what
55 /// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to
56 /// ADTs with no type arguments.
57 pub fn is_simple_text(&self) -> bool {
59 Adt(_, substs) => substs.types().next().is_none(),
60 Ref(_, ty, _) => ty.is_simple_text(),
61 _ => self.is_simple_ty(),
65 /// Whether the type can be safely suggested during error recovery.
66 pub fn is_suggestable(&self) -> bool {
68 Opaque(..) | FnDef(..) | FnPtr(..) | Dynamic(..) | Closure(..) | Infer(..)
69 | Projection(..) => false,
75 /// Suggest restricting a type param with a new bound.
76 pub fn suggest_constraining_type_param(
78 generics: &hir::Generics<'_>,
79 err: &mut DiagnosticBuilder<'_>,
82 def_id: Option<DefId>,
84 let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
86 let param = if let Some(param) = param {
92 const MSG_RESTRICT_BOUND_FURTHER: &str = "consider further restricting this bound";
93 let msg_restrict_type = format!("consider restricting type parameter `{}`", param_name);
94 let msg_restrict_type_further =
95 format!("consider further restricting type parameter `{}`", param_name);
97 if def_id == tcx.lang_items().sized_trait() {
98 // Type parameters are already `Sized` by default.
99 err.span_label(param.span, &format!("this type parameter needs to be `{}`", constraint));
102 let mut suggest_restrict = |span| {
103 err.span_suggestion_verbose(
105 MSG_RESTRICT_BOUND_FURTHER,
106 format!(" + {}", constraint),
107 Applicability::MachineApplicable,
111 if param_name.starts_with("impl ") {
112 // If there's an `impl Trait` used in argument position, suggest
115 // fn foo(t: impl Foo) { ... }
118 // help: consider further restricting this bound with `+ Bar`
120 // Suggestion for tools in this case is:
122 // fn foo(t: impl Foo) { ... }
125 // replace with: `impl Foo + Bar`
127 suggest_restrict(param.span.shrink_to_hi());
131 if generics.where_clause.predicates.is_empty()
132 // Given `trait Base<T = String>: Super<T>` where `T: Copy`, suggest restricting in the
133 // `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
134 && !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
136 if let Some(bounds_span) = param.bounds_span() {
137 // If user has provided some bounds, suggest restricting them:
139 // fn foo<T: Foo>(t: T) { ... }
142 // help: consider further restricting this bound with `+ Bar`
144 // Suggestion for tools in this case is:
146 // fn foo<T: Foo>(t: T) { ... }
149 // replace with: `T: Bar +`
150 suggest_restrict(bounds_span.shrink_to_hi());
152 // If user hasn't provided any bounds, suggest adding a new one:
154 // fn foo<T>(t: T) { ... }
155 // - help: consider restricting this type parameter with `T: Foo`
156 err.span_suggestion_verbose(
157 param.span.shrink_to_hi(),
159 format!(": {}", constraint),
160 Applicability::MachineApplicable,
166 // This part is a bit tricky, because using the `where` clause user can
167 // provide zero, one or many bounds for the same type parameter, so we
168 // have following cases to consider:
170 // 1) When the type parameter has been provided zero bounds
173 // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
174 // - help: consider restricting this type parameter with `where X: Bar`
177 // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
178 // - insert: `, X: Bar`
181 // 2) When the type parameter has been provided one bound
184 // fn foo<T>(t: T) where T: Foo { ... }
187 // help: consider further restricting this bound with `+ Bar`
190 // fn foo<T>(t: T) where T: Foo { ... }
193 // replace with: `T: Bar +`
196 // 3) When the type parameter has been provided many bounds
199 // fn foo<T>(t: T) where T: Foo, T: Bar {... }
200 // - help: consider further restricting this type parameter with `where T: Zar`
203 // fn foo<T>(t: T) where T: Foo, T: Bar {... }
204 // - insert: `, T: Zar`
206 let mut param_spans = Vec::new();
208 for predicate in generics.where_clause.predicates {
209 if let WherePredicate::BoundPredicate(WhereBoundPredicate {
213 if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
214 if let Some(segment) = path.segments.first() {
215 if segment.ident.to_string() == param_name {
216 param_spans.push(span);
223 match ¶m_spans[..] {
224 &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()),
226 err.span_suggestion_verbose(
227 generics.where_clause.tail_span_for_suggestion(),
228 &msg_restrict_type_further,
229 format!(", {}: {}", param_name, constraint),
230 Applicability::MachineApplicable,
239 pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>);
240 impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
241 type Map = rustc_hir::intravisit::ErasedMap<'v>;
243 fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
244 hir::intravisit::NestedVisitorMap::None
247 fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
248 if let hir::TyKind::TraitObject(
251 name: hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,