1 //! Diagnostics related methods for `TyS`.
3 use crate::ty::subst::{GenericArg, GenericArgKind};
4 use crate::ty::TyKind::*;
6 ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy,
7 ProjectionTy, Term, TyCtxt, TyS, TypeAndMut,
10 use rustc_errors::{Applicability, DiagnosticBuilder};
12 use rustc_hir::def_id::DefId;
13 use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate};
16 impl<'tcx> TyS<'tcx> {
17 /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive.
18 pub fn is_primitive_ty(&self) -> bool {
28 | InferTy::FloatVar(_)
29 | InferTy::FreshIntTy(_)
30 | InferTy::FreshFloatTy(_)
35 /// Whether the type is succinctly representable as a type instead of just referred to with a
36 /// description in error messages. This is used in the main error message.
37 pub fn is_simple_ty(&self) -> bool {
47 | InferTy::FloatVar(_)
48 | InferTy::FreshIntTy(_)
49 | InferTy::FreshFloatTy(_),
51 Ref(_, x, _) | Array(x, _) | Slice(x) => x.peel_refs().is_simple_ty(),
52 Tuple(tys) if tys.is_empty() => true,
57 /// Whether the type is succinctly representable as a type instead of just referred to with a
58 /// description in error messages. This is used in the primary span label. Beyond what
59 /// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to
60 /// ADTs with no type arguments.
61 pub fn is_simple_text(&self) -> bool {
63 Adt(_, substs) => substs.non_erasable_generics().next().is_none(),
64 Ref(_, ty, _) => ty.is_simple_text(),
65 _ => self.is_simple_ty(),
69 /// Whether the type can be safely suggested during error recovery.
70 pub fn is_suggestable(&self) -> bool {
71 fn generic_arg_is_suggestible(arg: GenericArg<'_>) -> bool {
73 GenericArgKind::Type(ty) => ty.is_suggestable(),
74 GenericArgKind::Const(c) => const_is_suggestable(c.val),
79 fn const_is_suggestable(kind: ConstKind<'_>) -> bool {
82 | ConstKind::Bound(..)
83 | ConstKind::Placeholder(..)
84 | ConstKind::Error(..) => false,
89 // FIXME(compiler-errors): Some types are still not good to suggest,
90 // specifically references with lifetimes within the function. Not
91 //sure we have enough information to resolve whether a region is
92 // temporary, so I'll leave this as a fixme.
100 | GeneratorWitness(..)
104 Dynamic(dty, _) => dty.iter().all(|pred| match pred.skip_binder() {
105 ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => {
106 substs.iter().all(generic_arg_is_suggestible)
108 ExistentialPredicate::Projection(ExistentialProjection {
111 let term_is_suggestable = match term {
112 Term::Ty(ty) => ty.is_suggestable(),
113 Term::Const(c) => const_is_suggestable(c.val),
115 term_is_suggestable && substs.iter().all(generic_arg_is_suggestible)
119 Projection(ProjectionTy { substs: args, .. }) | Adt(_, args) | Tuple(args) => {
120 args.iter().all(generic_arg_is_suggestible)
122 Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(),
123 Array(ty, c) => ty.is_suggestable() && const_is_suggestable(c.val),
129 pub fn suggest_arbitrary_trait_bound(
130 generics: &hir::Generics<'_>,
131 err: &mut DiagnosticBuilder<'_>,
135 let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
136 match (param, param_name) {
137 (Some(_), "Self") => return false,
140 // Suggest a where clause bound for a non-type paremeter.
141 let (action, prefix) = if generics.where_clause.predicates.is_empty() {
142 ("introducing a", " where ")
144 ("extending the", ", ")
146 err.span_suggestion_verbose(
147 generics.where_clause.tail_span_for_suggestion(),
149 "consider {} `where` bound, but there might be an alternative better way to express \
153 format!("{}{}: {}", prefix, param_name, constraint),
154 Applicability::MaybeIncorrect,
159 fn suggest_removing_unsized_bound(
160 generics: &hir::Generics<'_>,
161 err: &mut DiagnosticBuilder<'_>,
163 param: &hir::GenericParam<'_>,
164 def_id: Option<DefId>,
166 // See if there's a `?Sized` bound that can be removed to suggest that.
167 // First look at the `where` clause because we can have `where T: ?Sized`,
168 // then look at params.
169 for (where_pos, predicate) in generics.where_clause.predicates.iter().enumerate() {
171 WherePredicate::BoundPredicate(WhereBoundPredicate {
175 hir::TyKind::Path(hir::QPath::Resolved(
179 res: hir::def::Res::Def(hir::def::DefKind::TyParam, _),
188 }) if segment.ident.as_str() == param_name => {
189 for (pos, bound) in bounds.iter().enumerate() {
191 hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe)
192 if poly.trait_ref.trait_def_id() == def_id => {}
198 generics.where_clause.predicates.len(),
203 (1, _, 1, _) => generics.where_clause.span,
204 // where Foo: Bar, T: ?Sized,
206 (1, _, len, pos) if pos == len - 1 => generics.where_clause.predicates
211 // where T: ?Sized, Foo: Bar,
214 span.until(generics.where_clause.predicates[pos + 1].span())
216 // where T: ?Sized + Bar, Foo: Bar,
218 (_, 0, _, _) => bound.span().to(bounds[1].span().shrink_to_lo()),
219 // where T: Bar + ?Sized, Foo: Bar,
221 (_, pos, _, _) => bounds[pos - 1].span().shrink_to_hi().to(bound.span()),
223 err.span_suggestion_verbose(
225 "consider removing the `?Sized` bound to make the \
226 type parameter `Sized`",
228 Applicability::MaybeIncorrect,
235 for (pos, bound) in param.bounds.iter().enumerate() {
237 hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe)
238 if poly.trait_ref.trait_def_id() == def_id =>
240 let sp = match (param.bounds.len(), pos) {
243 (1, _) => param.span.shrink_to_hi().to(bound.span()),
246 (_, 0) => bound.span().to(param.bounds[1].span().shrink_to_lo()),
249 (_, pos) => param.bounds[pos - 1].span().shrink_to_hi().to(bound.span()),
251 err.span_suggestion_verbose(
253 "consider removing the `?Sized` bound to make the type parameter \
256 Applicability::MaybeIncorrect,
264 /// Suggest restricting a type param with a new bound.
265 pub fn suggest_constraining_type_param(
267 generics: &hir::Generics<'_>,
268 err: &mut DiagnosticBuilder<'_>,
271 def_id: Option<DefId>,
273 let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
275 let Some(param) = param else {
279 const MSG_RESTRICT_BOUND_FURTHER: &str = "consider further restricting this bound";
280 let msg_restrict_type = format!("consider restricting type parameter `{}`", param_name);
281 let msg_restrict_type_further =
282 format!("consider further restricting type parameter `{}`", param_name);
284 if def_id == tcx.lang_items().sized_trait() {
285 // Type parameters are already `Sized` by default.
286 err.span_label(param.span, &format!("this type parameter needs to be `{}`", constraint));
287 suggest_removing_unsized_bound(generics, err, param_name, param, def_id);
290 let mut suggest_restrict = |span| {
291 err.span_suggestion_verbose(
293 MSG_RESTRICT_BOUND_FURTHER,
294 format!(" + {}", constraint),
295 Applicability::MachineApplicable,
299 if param_name.starts_with("impl ") {
300 // If there's an `impl Trait` used in argument position, suggest
303 // fn foo(t: impl Foo) { ... }
306 // help: consider further restricting this bound with `+ Bar`
308 // Suggestion for tools in this case is:
310 // fn foo(t: impl Foo) { ... }
313 // replace with: `impl Foo + Bar`
315 suggest_restrict(param.span.shrink_to_hi());
319 if generics.where_clause.predicates.is_empty()
320 // Given `trait Base<T = String>: Super<T>` where `T: Copy`, suggest restricting in the
321 // `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
322 && !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
324 if let Some(span) = param.bounds_span_for_suggestions() {
325 // If user has provided some bounds, suggest restricting them:
327 // fn foo<T: Foo>(t: T) { ... }
330 // help: consider further restricting this bound with `+ Bar`
332 // Suggestion for tools in this case is:
334 // fn foo<T: Foo>(t: T) { ... }
337 // replace with: `T: Bar +`
338 suggest_restrict(span);
340 // If user hasn't provided any bounds, suggest adding a new one:
342 // fn foo<T>(t: T) { ... }
343 // - help: consider restricting this type parameter with `T: Foo`
344 err.span_suggestion_verbose(
345 param.span.shrink_to_hi(),
347 format!(": {}", constraint),
348 Applicability::MachineApplicable,
354 // This part is a bit tricky, because using the `where` clause user can
355 // provide zero, one or many bounds for the same type parameter, so we
356 // have following cases to consider:
358 // 1) When the type parameter has been provided zero bounds
361 // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
362 // - help: consider restricting this type parameter with `where X: Bar`
365 // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
366 // - insert: `, X: Bar`
369 // 2) When the type parameter has been provided one bound
372 // fn foo<T>(t: T) where T: Foo { ... }
375 // help: consider further restricting this bound with `+ Bar`
378 // fn foo<T>(t: T) where T: Foo { ... }
381 // replace with: `T: Bar +`
384 // 3) When the type parameter has been provided many bounds
387 // fn foo<T>(t: T) where T: Foo, T: Bar {... }
388 // - help: consider further restricting this type parameter with `where T: Zar`
391 // fn foo<T>(t: T) where T: Foo, T: Bar {... }
392 // - insert: `, T: Zar`
394 // Additionally, there may be no `where` clause whatsoever in the case that this was
395 // reached because the generic parameter has a default:
398 // trait Foo<T=()> {... }
399 // - help: consider further restricting this type parameter with `where T: Zar`
402 // trait Foo<T=()> where T: Zar {... }
403 // - insert: `where T: Zar`
405 if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
406 && generics.where_clause.predicates.len() == 0
408 // Suggest a bound, but there is no existing `where` clause *and* the type param has a
409 // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
410 err.span_suggestion_verbose(
411 generics.where_clause.tail_span_for_suggestion(),
412 &msg_restrict_type_further,
413 format!(" where {}: {}", param_name, constraint),
414 Applicability::MachineApplicable,
417 let mut param_spans = Vec::new();
419 for predicate in generics.where_clause.predicates {
420 if let WherePredicate::BoundPredicate(WhereBoundPredicate {
426 if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
427 if let Some(segment) = path.segments.first() {
428 if segment.ident.to_string() == param_name {
429 param_spans.push(span);
436 match param_spans[..] {
437 [¶m_span] => suggest_restrict(param_span.shrink_to_hi()),
439 err.span_suggestion_verbose(
440 generics.where_clause.tail_span_for_suggestion(),
441 &msg_restrict_type_further,
442 format!(", {}: {}", param_name, constraint),
443 Applicability::MachineApplicable,
453 /// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
454 pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
456 impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
457 fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
459 hir::TyKind::TraitObject(
463 hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
470 hir::TyKind::OpaqueDef(item_id, _) => {
472 let item = self.1.item(item_id);
473 hir::intravisit::walk_item(self, item);
477 hir::intravisit::walk_ty(self, ty);
481 /// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
482 pub struct StaticLifetimeVisitor<'tcx>(pub Vec<Span>, pub crate::hir::map::Map<'tcx>);
484 impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
485 fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) {
486 if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static =
489 self.0.push(lt.span);