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, Unnormalized, 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 { ; }
            };
            let mut visit_alias =
                ||
                    {
                        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().skip_norm_wip())) {
                                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.skip_norm_wip())) {
                                core::ops::ControlFlow::Continue(()) =>
                                    (),
                                    #[allow(unreachable_code)]
                                    core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
                                }
                            };
                        }
                        V::Result::output()
                    };
            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().skip_norm_wip();
                    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.skip_norm_wip())) {
                            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 => return visit_alias(),
                DefKind::InlineConst if tcx.is_type_system_inline_const(item)
                    => return visit_alias(),
                DefKind::OpaqueTy => {
                    for (pred, span) in
                        tcx.explicit_item_bounds(item).iter_identity_copied().map(Unnormalized::skip_norm_wip)
                        {
                        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().skip_norm_wip();
                    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.skip_norm_wip())) {
                            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().skip_norm_wip().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().skip_norm_wip())) {
                        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.skip_norm_wip())) {
                            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.skip_norm_wip())) {
                            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    let mut visit_alias = || {
25        if let Some(ty) = tcx.hir_node_by_def_id(item).ty() {
26            // If the type of the item uses `_`, we're gonna error out anyway, but
27            // typeck (which type_of invokes below), will call back into opaque_types_defined_by
28            // causing a cycle. So we just bail out in this case.
29            if ty.is_suggestable_infer_ty() {
30                return V::Result::output();
31            }
32            // Associated types in traits don't necessarily have a type that we can visit
33            try_visit!(
34                visitor.visit(ty.span, tcx.type_of(item).instantiate_identity().skip_norm_wip())
35            );
36        }
37        for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
38            try_visit!(visitor.visit(span, pred.skip_norm_wip()));
39        }
40        V::Result::output()
41    };
42    match kind {
43        // Walk over the signature of the function
44        DefKind::AssocFn | DefKind::Fn => {
45            let hir_sig = tcx.hir_node_by_def_id(item).fn_decl().unwrap();
46            // If the type of the item uses `_`, we're gonna error out anyway, but
47            // typeck (which type_of invokes below), will call back into opaque_types_defined_by
48            // causing a cycle. So we just bail out in this case.
49            if hir_sig.output.is_suggestable_infer_ty().is_some() {
50                return V::Result::output();
51            }
52            let ty_sig = tcx.fn_sig(item).instantiate_identity().skip_norm_wip();
53            // Walk over the inputs and outputs manually in order to get good spans for them.
54            try_visit!(visitor.visit(hir_sig.output.span(), ty_sig.output()));
55            for (hir, ty) in hir_sig.inputs.iter().zip(ty_sig.inputs().iter()) {
56                try_visit!(visitor.visit(hir.span, ty.map_bound(|x| *x)));
57            }
58            for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
59                try_visit!(visitor.visit(span, pred.skip_norm_wip()));
60            }
61        }
62        // Walk over the type behind the alias or the type of the item
63        DefKind::TyAlias { .. }
64        | DefKind::AssocTy
65        | DefKind::Static { .. }
66        | DefKind::Const { .. }
67        | DefKind::AssocConst { .. }
68        | DefKind::AnonConst => return visit_alias(),
69        DefKind::InlineConst if tcx.is_type_system_inline_const(item) => return visit_alias(),
70        DefKind::OpaqueTy => {
71            for (pred, span) in tcx
72                .explicit_item_bounds(item)
73                .iter_identity_copied()
74                .map(Unnormalized::skip_norm_wip)
75            {
76                try_visit!(visitor.visit(span, pred));
77            }
78        }
79        // Look at field types
80        DefKind::Struct | DefKind::Union | DefKind::Enum => {
81            let span = tcx.def_ident_span(item).unwrap();
82            let ty = tcx.type_of(item).instantiate_identity().skip_norm_wip();
83            try_visit!(visitor.visit(span, ty));
84            let ty::Adt(def, args) = ty.kind() else {
85                span_bug!(span, "invalid type for {kind:?}: {:#?}", ty.kind())
86            };
87            for field in def.all_fields() {
88                let span = tcx.def_ident_span(field.did).unwrap();
89                let ty = field.ty(tcx, args);
90                try_visit!(visitor.visit(span, ty));
91            }
92            for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
93                try_visit!(visitor.visit(span, pred.skip_norm_wip()));
94            }
95        }
96        // These are not part of a public API, they can only appear as hidden types, and there
97        // the interesting parts are solely in the signature of the containing item's opaque type
98        // or dyn type.
99        DefKind::InlineConst | DefKind::Closure | DefKind::SyntheticCoroutineBody => {}
100        DefKind::Impl { of_trait } => {
101            if of_trait {
102                let span = tcx
103                    .hir_node_by_def_id(item)
104                    .expect_item()
105                    .expect_impl()
106                    .of_trait
107                    .unwrap()
108                    .trait_ref
109                    .path
110                    .span;
111                let args =
112                    &tcx.impl_trait_ref(item).instantiate_identity().skip_norm_wip().args[1..];
113                try_visit!(visitor.visit(span, args));
114            }
115            let span = match tcx.hir_node_by_def_id(item).ty() {
116                Some(ty) => ty.span,
117                _ => tcx.def_span(item),
118            };
119            try_visit!(
120                visitor.visit(span, tcx.type_of(item).instantiate_identity().skip_norm_wip())
121            );
122            for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
123                try_visit!(visitor.visit(span, pred.skip_norm_wip()));
124            }
125        }
126        DefKind::TraitAlias | DefKind::Trait => {
127            for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) {
128                try_visit!(visitor.visit(span, pred.skip_norm_wip()));
129            }
130        }
131        DefKind::Variant
132        | DefKind::TyParam
133        | DefKind::ConstParam
134        | DefKind::Ctor(_, _)
135        | DefKind::Field
136        | DefKind::LifetimeParam => {
137            span_bug!(
138                tcx.def_span(item),
139                "{kind:?} has not seen any uses of `walk_types` yet, ping oli-obk if you'd like any help"
140            )
141        }
142        // These don't have any types, but are visited during privacy checking.
143        DefKind::ExternCrate
144        | DefKind::ForeignMod
145        | DefKind::ForeignTy
146        | DefKind::Macro(_)
147        | DefKind::GlobalAsm
148        | DefKind::Mod
149        | DefKind::Use => {}
150    }
151    V::Result::output()
152}