summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_ty_utils/src/sig_types.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_ty_utils/src/sig_types.rs')
-rw-r--r--compiler/rustc_ty_utils/src/sig_types.rs112
1 files changed, 112 insertions, 0 deletions
diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs
new file mode 100644
index 000000000..ccdc61201
--- /dev/null
+++ b/compiler/rustc_ty_utils/src/sig_types.rs
@@ -0,0 +1,112 @@
+//! This module contains helpers for walking all types of
+//! a signature, while preserving spans as much as possible
+
+use std::ops::ControlFlow;
+
+use rustc_hir::{def::DefKind, def_id::LocalDefId};
+use rustc_middle::ty::TyCtxt;
+use rustc_span::Span;
+use rustc_type_ir::visit::TypeVisitable;
+
+pub trait SpannedTypeVisitor<'tcx> {
+ type BreakTy = !;
+ fn visit(
+ &mut self,
+ span: Span,
+ value: impl TypeVisitable<TyCtxt<'tcx>>,
+ ) -> ControlFlow<Self::BreakTy>;
+}
+
+pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
+ tcx: TyCtxt<'tcx>,
+ item: LocalDefId,
+ visitor: &mut V,
+) -> ControlFlow<V::BreakTy> {
+ let kind = tcx.def_kind(item);
+ trace!(?kind);
+ match kind {
+ // Walk over the signature of the function
+ DefKind::AssocFn | DefKind::Fn => {
+ let ty_sig = tcx.fn_sig(item).instantiate_identity();
+ let hir_sig = tcx.hir().get_by_def_id(item).fn_decl().unwrap();
+ // Walk over the inputs and outputs manually in order to get good spans for them.
+ visitor.visit(hir_sig.output.span(), ty_sig.output());
+ for (hir, ty) in hir_sig.inputs.iter().zip(ty_sig.inputs().iter()) {
+ visitor.visit(hir.span, ty.map_bound(|x| *x))?;
+ }
+ for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+ visitor.visit(span, pred)?;
+ }
+ }
+ // Walk over the type behind the alias
+ DefKind::TyAlias {..} | DefKind::AssocTy |
+ // Walk over the type of the item
+ DefKind::Static(_) | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
+ let span = match tcx.hir().get_by_def_id(item).ty() {
+ Some(ty) => ty.span,
+ _ => tcx.def_span(item),
+ };
+ visitor.visit(span, tcx.type_of(item).instantiate_identity());
+ for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+ visitor.visit(span, pred)?;
+ }
+ }
+ DefKind::OpaqueTy => {
+ for (pred, span) in tcx.explicit_item_bounds(item).instantiate_identity_iter_copied() {
+ visitor.visit(span, pred)?;
+ }
+ }
+ // Look at field types
+ DefKind::Struct | DefKind::Union | DefKind::Enum => {
+ let span = tcx.def_ident_span(item).unwrap();
+ visitor.visit(span, tcx.type_of(item).instantiate_identity());
+ for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+ visitor.visit(span, pred)?;
+ }
+ }
+ // These are not part of a public API, they can only appear as hidden types, and there
+ // the interesting parts are solely in the signature of the containing item's opaque type
+ // or dyn type.
+ DefKind::InlineConst | DefKind::Closure | DefKind::Coroutine => {}
+ DefKind::Impl { of_trait } => {
+ if of_trait {
+ let span = tcx.hir().get_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().path.span;
+ let args = &tcx.impl_trait_ref(item).unwrap().instantiate_identity().args[1..];
+ visitor.visit(span, args)?;
+ }
+ let span = match tcx.hir().get_by_def_id(item).ty() {
+ Some(ty) => ty.span,
+ _ => tcx.def_span(item),
+ };
+ visitor.visit(span, tcx.type_of(item).instantiate_identity());
+ for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+ visitor.visit(span, pred)?;
+ }
+ }
+ DefKind::TraitAlias | DefKind::Trait => {
+ for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+ visitor.visit(span, pred)?;
+ }
+ }
+ | DefKind::Variant
+ | DefKind::ForeignTy
+ | DefKind::TyParam
+ | DefKind::ConstParam
+ | DefKind::Ctor(_, _)
+ | DefKind::Field
+ | DefKind::LifetimeParam => {
+ span_bug!(
+ tcx.def_span(item),
+ "{kind:?} has not seen any uses of `walk_types` yet, ping oli-obk if you'd like any help"
+ )
+ }
+ // These don't have any types.
+ | DefKind::ExternCrate
+ | DefKind::ForeignMod
+ | DefKind::Macro(_)
+ | DefKind::GlobalAsm
+ | DefKind::Mod
+ | DefKind::Use => {}
+ }
+ ControlFlow::Continue(())
+}