|
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