|
1 | 1 | //! Diagnostics related methods for `Ty`.
|
2 | 2 |
|
3 |
| -use crate::ty::subst::{GenericArg, GenericArgKind}; |
| 3 | +use std::ops::ControlFlow; |
| 4 | + |
4 | 5 | use crate::ty::{
|
5 |
| - ConstKind, DefIdTree, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, |
6 |
| - InferTy, ProjectionTy, Term, Ty, TyCtxt, TypeAndMut, |
| 6 | + fold::TypeFoldable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy, Ty, TyCtxt, |
| 7 | + TypeVisitor, |
7 | 8 | };
|
8 | 9 |
|
9 | 10 | use rustc_data_structures::fx::FxHashMap;
|
@@ -75,72 +76,7 @@ impl<'tcx> Ty<'tcx> {
|
75 | 76 |
|
76 | 77 | /// Whether the type can be safely suggested during error recovery.
|
77 | 78 | pub fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
|
78 |
| - fn generic_arg_is_suggestible<'tcx>(arg: GenericArg<'tcx>, tcx: TyCtxt<'tcx>) -> bool { |
79 |
| - match arg.unpack() { |
80 |
| - GenericArgKind::Type(ty) => ty.is_suggestable(tcx), |
81 |
| - GenericArgKind::Const(c) => const_is_suggestable(c.val()), |
82 |
| - _ => true, |
83 |
| - } |
84 |
| - } |
85 |
| - |
86 |
| - fn const_is_suggestable(kind: ConstKind<'_>) -> bool { |
87 |
| - match kind { |
88 |
| - ConstKind::Infer(..) |
89 |
| - | ConstKind::Bound(..) |
90 |
| - | ConstKind::Placeholder(..) |
91 |
| - | ConstKind::Error(..) => false, |
92 |
| - _ => true, |
93 |
| - } |
94 |
| - } |
95 |
| - |
96 |
| - // FIXME(compiler-errors): Some types are still not good to suggest, |
97 |
| - // specifically references with lifetimes within the function. Not |
98 |
| - //sure we have enough information to resolve whether a region is |
99 |
| - // temporary, so I'll leave this as a fixme. |
100 |
| - |
101 |
| - match self.kind() { |
102 |
| - FnDef(..) |
103 |
| - | Closure(..) |
104 |
| - | Infer(..) |
105 |
| - | Generator(..) |
106 |
| - | GeneratorWitness(..) |
107 |
| - | Bound(_, _) |
108 |
| - | Placeholder(_) |
109 |
| - | Error(_) => false, |
110 |
| - Opaque(did, substs) => { |
111 |
| - let parent = tcx.parent(*did); |
112 |
| - if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = tcx.def_kind(parent) |
113 |
| - && let Opaque(parent_did, _) = tcx.type_of(parent).kind() |
114 |
| - && parent_did == did |
115 |
| - { |
116 |
| - substs.iter().all(|a| generic_arg_is_suggestible(a, tcx)) |
117 |
| - } else { |
118 |
| - false |
119 |
| - } |
120 |
| - } |
121 |
| - Dynamic(dty, _) => dty.iter().all(|pred| match pred.skip_binder() { |
122 |
| - ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => { |
123 |
| - substs.iter().all(|a| generic_arg_is_suggestible(a, tcx)) |
124 |
| - } |
125 |
| - ExistentialPredicate::Projection(ExistentialProjection { |
126 |
| - substs, term, .. |
127 |
| - }) => { |
128 |
| - let term_is_suggestable = match term { |
129 |
| - Term::Ty(ty) => ty.is_suggestable(tcx), |
130 |
| - Term::Const(c) => const_is_suggestable(c.val()), |
131 |
| - }; |
132 |
| - term_is_suggestable && substs.iter().all(|a| generic_arg_is_suggestible(a, tcx)) |
133 |
| - } |
134 |
| - _ => true, |
135 |
| - }), |
136 |
| - Projection(ProjectionTy { substs: args, .. }) | Adt(_, args) => { |
137 |
| - args.iter().all(|a| generic_arg_is_suggestible(a, tcx)) |
138 |
| - } |
139 |
| - Tuple(args) => args.iter().all(|ty| ty.is_suggestable(tcx)), |
140 |
| - Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(tcx), |
141 |
| - Array(ty, c) => ty.is_suggestable(tcx) && const_is_suggestable(c.val()), |
142 |
| - _ => true, |
143 |
| - } |
| 79 | + self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue() |
144 | 80 | }
|
145 | 81 | }
|
146 | 82 |
|
@@ -463,3 +399,67 @@ impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
|
463 | 399 | }
|
464 | 400 | }
|
465 | 401 | }
|
| 402 | + |
| 403 | +pub struct IsSuggestableVisitor<'tcx> { |
| 404 | + tcx: TyCtxt<'tcx>, |
| 405 | +} |
| 406 | + |
| 407 | +impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { |
| 408 | + type BreakTy = (); |
| 409 | + |
| 410 | + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { |
| 411 | + match t.kind() { |
| 412 | + FnDef(..) |
| 413 | + | Closure(..) |
| 414 | + | Infer(..) |
| 415 | + | Generator(..) |
| 416 | + | GeneratorWitness(..) |
| 417 | + | Bound(_, _) |
| 418 | + | Placeholder(_) |
| 419 | + | Error(_) => { |
| 420 | + return ControlFlow::Break(()); |
| 421 | + } |
| 422 | + |
| 423 | + Opaque(did, _) => { |
| 424 | + let parent = self.tcx.parent(*did); |
| 425 | + if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent) |
| 426 | + && let Opaque(parent_did, _) = self.tcx.type_of(parent).kind() |
| 427 | + && parent_did == did |
| 428 | + { |
| 429 | + // Okay |
| 430 | + } else { |
| 431 | + return ControlFlow::Break(()); |
| 432 | + } |
| 433 | + } |
| 434 | + |
| 435 | + Dynamic(dty, _) => { |
| 436 | + for pred in *dty { |
| 437 | + match pred.skip_binder() { |
| 438 | + ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => { |
| 439 | + // Okay |
| 440 | + } |
| 441 | + _ => return ControlFlow::Break(()), |
| 442 | + } |
| 443 | + } |
| 444 | + } |
| 445 | + |
| 446 | + _ => {} |
| 447 | + } |
| 448 | + |
| 449 | + t.super_visit_with(self) |
| 450 | + } |
| 451 | + |
| 452 | + fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> { |
| 453 | + match c.val() { |
| 454 | + ConstKind::Infer(..) |
| 455 | + | ConstKind::Bound(..) |
| 456 | + | ConstKind::Placeholder(..) |
| 457 | + | ConstKind::Error(..) => { |
| 458 | + return ControlFlow::Break(()); |
| 459 | + } |
| 460 | + _ => {} |
| 461 | + } |
| 462 | + |
| 463 | + c.super_visit_with(self) |
| 464 | + } |
| 465 | +} |
0 commit comments