Skip to main content

rustc_ty_utils/
sig_types.rs

1//! This module contains helpers for walking all types of
2//! a signature, while preserving spans as much as possible
3
4use rustc_hir::def::DefKind;
5use rustc_hir::def_id::LocalDefId;
6use rustc_middle::span_bug;
7use rustc_middle::ty::{self, TyCtxt, TypeVisitable, VisitorResult, try_visit};
8use rustc_span::Span;
9use tracing::{instrument, trace};
10
11pub trait SpannedTypeVisitor<'tcx> {
12    type Result: VisitorResult = ();
13    fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> Self::Result;
14}
15
16#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("walk_types",
                                    "rustc_ty_utils::sig_types", ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_ty_utils/src/sig_types.rs"),
                                    ::tracing_core::__macro_support::Option::Some(16u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_ty_utils::sig_types"),
                                    ::tracing_core::field::FieldSet::new(&["item"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&item)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: V::Result = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let kind = tcx.def_kind(item);
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("event compiler/rustc_ty_utils/src/sig_types.rs:23",
                                    "rustc_ty_utils::sig_types", ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_ty_utils/src/sig_types.rs"),
                                    ::tracing_core::__macro_support::Option::Some(23u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_ty_utils::sig_types"),
                                    ::tracing_core::field::FieldSet::new(&["kind"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::EVENT)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let enabled =
                    ::tracing::Level::TRACE <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::TRACE <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        {
                            let interest = __CALLSITE.interest();
                            !interest.is_never() &&
                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                    interest)
                        };
                if enabled {
                    (|value_set: ::tracing::field::ValueSet|
                                {
                                    let meta = __CALLSITE.metadata();
                                    ::tracing::Event::dispatch(meta, &value_set);
                                    ;
                                })({
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            let mut iter = __CALLSITE.metadata().fields().iter();
                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&debug(&kind) as
                                                        &dyn Value))])
                        });
                } else { ; }
            };
            match kind {
                DefKind::AssocFn | DefKind::Fn => {
                    let hir_sig =
                        tcx.hir_node_by_def_id(item).fn_decl().unwrap();
                    if hir_sig.output.is_suggestable_infer_ty().is_some() {
                        return V::Result::output();
                    }
                    let ty_sig = tcx.fn_sig(item).instantiate_identity();
                    match ::rustc_ast_ir::visit::VisitorResult::branch(visitor.visit(hir_sig.output.span(),
                                ty_sig.output())) {
                        core::ops::ControlFlow::Continue(()) =>
                            (),
                            #[allow(unreachable_code)]
                            core::ops::ControlFlow::Break(r) => {
                            return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
                        }
                    };
                    for (hir, ty) in
                        hir_sig.inputs.iter().zip(ty_sig.inputs().iter()) {
                        match ::rustc_ast_ir::visit::VisitorResult::branch(visitor.visit(hir.span,
                                    ty.map_bound(|x| *x))) {
                            core::ops::ControlFlow::Continue(()) =>
                                (),
                                #[allow(unreachable_code)]
                                core::ops::ControlFlow::Break(r) => {
                                return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
                            }
                        };
                    }
                    for (pred, span) in
                        tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
                        match ::rustc_ast_ir::visit::VisitorResult::branch(visitor.visit(span,
                                    pred)) {
                            core::ops::ControlFlow::Continue(()) =>
                                (),
                                #[allow(unreachable_code)]
                                core::ops::ControlFlow::Break(r) => {
                                return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
                            }
                        };
                    }
                }
                DefKind::TyAlias { .. } | DefKind::AssocTy | DefKind::Static {
                    .. } | DefKind::Const | DefKind::AssocConst |
                    DefKind::AnonConst => {
                    if let Some(ty) = tcx.hir_node_by_def_id(item).ty() {
                        if ty.is_suggestable_infer_ty() {
                            return V::Result::output();
                        }
                        match ::rustc_ast_ir::visit::VisitorResult::branch(visitor.visit(ty.span,
                                    tcx.type_of(item).instantiate_identity())) {
                            core::ops::ControlFlow::Continue(()) =>
                                (),
                                #[allow(unreachable_code)]
                                core::ops::ControlFlow::Break(r) => {
                                return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
                            }
                        };
                    }
                    for (pred, span) in
                        tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
                        match ::rustc_ast_ir::visit::VisitorResult::branch(visitor.visit(span,
                                    pred)) {
                            core::ops::ControlFlow::Continue(()) =>
                                (),
                                #[allow(unreachable_code)]
                                core::ops::ControlFlow::Break(r) => {
                                return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
                            }
                        };
                    }
                }
                DefKind::OpaqueTy => {
                    for (pred, span) in
                        tcx.explicit_item_bounds(item).iter_identity_copied() {
                        match ::rustc_ast_ir::visit::VisitorResult::branch(visitor.visit(span,
                                    pred)) {
                            core::ops::ControlFlow::Continue(()) =>
                                (),
                                #[allow(unreachable_code)]
                                core::ops::ControlFlow::Break(r) => {
                                return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
                            }
                        };
                    }
                }
                DefKind::Struct | DefKind::Union | DefKind::Enum => {
                    let span = tcx.def_ident_span(item).unwrap();
                    let ty = tcx.type_of(item).instantiate_identity();
                    match ::rustc_ast_ir::visit::VisitorResult::branch(visitor.visit(span,
                                ty)) {
                        core::ops::ControlFlow::Continue(()) =>
                            (),
                            #[allow(unreachable_code)]
                            core::ops::ControlFlow::Break(r) => {
                            return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
                        }
                    };
                    let ty::Adt(def, args) =
                        ty.kind() else {
                            ::rustc_middle::util::bug::span_bug_fmt(span,
                                format_args!("invalid type for {1:?}: {0:#?}", ty.kind(),
                                    kind))
                        };
                    for field in def.all_fields() {
                        let span = tcx.def_ident_span(field.did).unwrap();
                        let ty = field.ty(tcx, args);
                        match ::rustc_ast_ir::visit::VisitorResult::branch(visitor.visit(span,
                                    ty)) {
                            core::ops::ControlFlow::Continue(()) =>
                                (),
                                #[allow(unreachable_code)]
                                core::ops::ControlFlow::Break(r) => {
                                return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
                            }
                        };
                    }
                    for (pred, span) in
                        tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
                        match ::rustc_ast_ir::visit::VisitorResult::branch(visitor.visit(span,
                                    pred)) {
                            core::ops::ControlFlow::Continue(()) =>
                                (),
                                #[allow(unreachable_code)]
                                core::ops::ControlFlow::Break(r) => {
                                return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
                            }
                        };
                    }
                }
                DefKind::InlineConst | DefKind::Closure |
                    DefKind::SyntheticCoroutineBody => {}
                DefKind::Impl { of_trait } => {
                    if of_trait {
                        let span =
                            tcx.hir_node_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().trait_ref.path.span;
                        let args =
                            &tcx.impl_trait_ref(item).instantiate_identity().args[1..];
                        match ::rustc_ast_ir::visit::VisitorResult::branch(visitor.visit(span,
                                    args)) {
                            core::ops::ControlFlow::Continue(()) =>
                                (),
                                #[allow(unreachable_code)]
                                core::ops::ControlFlow::Break(r) => {
                                return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
                            }
                        };
                    }
                    let span =
                        match tcx.hir_node_by_def_id(item).ty() {
                            Some(ty) => ty.span,
                            _ => tcx.def_span(item),
                        };
                    match ::rustc_ast_ir::visit::VisitorResult::branch(visitor.visit(span,
                                tcx.type_of(item).instantiate_identity())) {
                        core::ops::ControlFlow::Continue(()) =>
                            (),
                            #[allow(unreachable_code)]
                            core::ops::ControlFlow::Break(r) => {
                            return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
                        }
                    };
                    for (pred, span) in
                        tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
                        match ::rustc_ast_ir::visit::VisitorResult::branch(visitor.visit(span,
                                    pred)) {
                            core::ops::ControlFlow::Continue(()) =>
                                (),
                                #[allow(unreachable_code)]
                                core::ops::ControlFlow::Break(r) => {
                                return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
                            }
                        };
                    }
                }
                DefKind::TraitAlias | DefKind::Trait => {
                    for (pred, span) in
                        tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
                        match ::rustc_ast_ir::visit::VisitorResult::branch(visitor.visit(span,
                                    pred)) {
                            core::ops::ControlFlow::Continue(()) =>
                                (),
                                #[allow(unreachable_code)]
                                core::ops::ControlFlow::Break(r) => {
                                return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
                            }
                        };
                    }
                }
                DefKind::Variant | DefKind::TyParam | DefKind::ConstParam |
                    DefKind::Ctor(_, _) | DefKind::Field |
                    DefKind::LifetimeParam => {
                    ::rustc_middle::util::bug::span_bug_fmt(tcx.def_span(item),
                        format_args!("{0:?} has not seen any uses of `walk_types` yet, ping oli-obk if you\'d like any help",
                            kind))
                }
                DefKind::ExternCrate | DefKind::ForeignMod |
                    DefKind::ForeignTy | DefKind::Macro(_) | DefKind::GlobalAsm
                    | DefKind::Mod | DefKind::Use => {}
            }
            V::Result::output()
        }
    }
}#[instrument(level = "trace", skip(tcx, visitor))]
17pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
18    tcx: TyCtxt<'tcx>,
19    item: LocalDefId,
20    visitor: &mut V,
21) -> V::Result {
22    let kind = tcx.def_kind(item);
23    trace!(?kind);
24    match kind {
25        // Walk over the signature of the function
26        DefKind::AssocFn | DefKind::Fn => {
27            let hir_sig = tcx.hir_node_by_def_id(item).fn_decl().unwrap();
28            // If the type of the item uses `_`, we're gonna error out anyway, but
29            // typeck (which type_of invokes below), will call back into opaque_types_defined_by
30            // causing a cycle. So we just bail out in this case.
31            if hir_sig.output.is_suggestable_infer_ty().is_some() {
32                return V::Result::output();
33            }
34            let ty_sig = tcx.fn_sig(item).instantiate_identity();
35            // Walk over the inputs and outputs manually in order to get good spans for them.
36            try_visit!(visitor.visit(hir_sig.output.span(), ty_sig.output()));
37            for (hir, ty) in hir_sig.inputs.iter().zip(ty_sig.inputs().iter()) {
38                try_visit!(visitor.visit(hir.span, ty.map_bound(|x| *x)));
39            }
40            for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
41                try_visit!(visitor.visit(span, pred));
42            }
43        }
44        // Walk over the type behind the alias
45        DefKind::TyAlias { .. } | DefKind::AssocTy |
46        // Walk over the type of the item
47        DefKind::Static { .. } | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
48            if let Some(ty) = tcx.hir_node_by_def_id(item).ty() {
49                // If the type of the item uses `_`, we're gonna error out anyway, but
50                // typeck (which type_of invokes below), will call back into opaque_types_defined_by
51                // causing a cycle. So we just bail out in this case.
52                if ty.is_suggestable_infer_ty() {
53                    return V::Result::output();
54                }
55                // Associated types in traits don't necessarily have a type that we can visit
56                try_visit!(visitor.visit(ty.span, tcx.type_of(item).instantiate_identity()));
57            }
58            for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
59                try_visit!(visitor.visit(span, pred));
60            }
61        }
62        DefKind::OpaqueTy => {
63            for (pred, span) in tcx.explicit_item_bounds(item).iter_identity_copied() {
64                try_visit!(visitor.visit(span, pred));
65            }
66        }
67        // Look at field types
68        DefKind::Struct | DefKind::Union | DefKind::Enum => {
69            let span = tcx.def_ident_span(item).unwrap();
70            let ty = tcx.type_of(item).instantiate_identity();
71            try_visit!(visitor.visit(span, ty));
72            let ty::Adt(def, args) = ty.kind() else {
73                span_bug!(span, "invalid type for {kind:?}: {:#?}", ty.kind())
74            };
75            for field in def.all_fields() {
76                let span = tcx.def_ident_span(field.did).unwrap();
77                let ty = field.ty(tcx, args);
78                try_visit!(visitor.visit(span, ty));
79            }
80            for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
81                try_visit!(visitor.visit(span, pred));
82            }
83        }
84        // These are not part of a public API, they can only appear as hidden types, and there
85        // the interesting parts are solely in the signature of the containing item's opaque type
86        // or dyn type.
87        DefKind::InlineConst | DefKind::Closure | DefKind::SyntheticCoroutineBody => {}
88        DefKind::Impl { of_trait } => {
89            if of_trait {
90                let span = tcx.hir_node_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().trait_ref.path.span;
91                let args = &tcx.impl_trait_ref(item).instantiate_identity().args[1..];
92                try_visit!(visitor.visit(span, args));
93            }
94            let span = match tcx.hir_node_by_def_id(item).ty() {
95                Some(ty) => ty.span,
96                _ => tcx.def_span(item),
97            };
98            try_visit!(visitor.visit(span, tcx.type_of(item).instantiate_identity()));
99            for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
100                try_visit!(visitor.visit(span, pred));
101            }
102        }
103        DefKind::TraitAlias | DefKind::Trait => {
104            for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
105                try_visit!(visitor.visit(span, pred));
106            }
107        }
108        | DefKind::Variant
109        | DefKind::TyParam
110        | DefKind::ConstParam
111        | DefKind::Ctor(_, _)
112        | DefKind::Field
113        | DefKind::LifetimeParam => {
114            span_bug!(
115                tcx.def_span(item),
116                "{kind:?} has not seen any uses of `walk_types` yet, ping oli-obk if you'd like any help"
117            )
118        }
119        // These don't have any types, but are visited during privacy checking.
120        | DefKind::ExternCrate
121        | DefKind::ForeignMod
122        | DefKind::ForeignTy
123        | DefKind::Macro(_)
124        | DefKind::GlobalAsm
125        | DefKind::Mod
126        | DefKind::Use => {}
127    }
128    V::Result::output()
129}