Skip to content

Commit 8506b7d

Browse files
Make Ty::is_suggestable use a visitor
1 parent 99930ac commit 8506b7d

File tree

1 file changed

+69
-69
lines changed

1 file changed

+69
-69
lines changed

compiler/rustc_middle/src/ty/diagnostics.rs

+69-69
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
//! Diagnostics related methods for `Ty`.
22
3-
use crate::ty::subst::{GenericArg, GenericArgKind};
3+
use std::ops::ControlFlow;
4+
45
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,
78
};
89

910
use rustc_data_structures::fx::FxHashMap;
@@ -75,72 +76,7 @@ impl<'tcx> Ty<'tcx> {
7576

7677
/// Whether the type can be safely suggested during error recovery.
7778
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()
14480
}
14581
}
14682

@@ -463,3 +399,67 @@ impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
463399
}
464400
}
465401
}
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

Comments
 (0)