1use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree};
2use tracing::trace;
3
4use crate::ty::context::TyCtxt;
5use crate::ty::{self, Ty};
6
7pub fn fnc_typetrees<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>) -> FncTree {
11 if tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::NoTT) {
13 return FncTree { args: ::alloc::vec::Vec::new()vec![], ret: TypeTree::new() };
14 }
15
16 if !fn_ty.is_fn() {
18 return FncTree { args: ::alloc::vec::Vec::new()vec![], ret: TypeTree::new() };
19 }
20
21 let fn_sig = fn_ty.fn_sig(tcx);
23 let sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
24
25 let mut args = ::alloc::vec::Vec::new()vec![];
27 for ty in sig.inputs().iter() {
28 let type_tree = typetree_from_ty(tcx, *ty);
29 args.push(type_tree);
30 }
31
32 let ret = typetree_from_ty(tcx, sig.output());
34
35 FncTree { args, ret }
36}
37
38pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree {
41 let mut visited = Vec::new();
42 typetree_from_ty_impl_inner(tcx, ty, 0, &mut visited, false)
43}
44
45const MAX_TYPETREE_DEPTH: usize = 6;
48
49fn typetree_from_ty_impl_inner<'tcx>(
51 tcx: TyCtxt<'tcx>,
52 ty: Ty<'tcx>,
53 depth: usize,
54 visited: &mut Vec<Ty<'tcx>>,
55 is_reference_target: bool,
56) -> TypeTree {
57 if depth >= MAX_TYPETREE_DEPTH {
58 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_middle/src/ty/typetree.rs:58",
"rustc_middle::ty::typetree", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/ty/typetree.rs"),
::tracing_core::__macro_support::Option::Some(58u32),
::tracing_core::__macro_support::Option::Some("rustc_middle::ty::typetree"),
::tracing_core::field::FieldSet::new(&["message"],
::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(&format_args!("typetree depth limit {0} reached for type: {1}",
MAX_TYPETREE_DEPTH, ty) as &dyn Value))])
});
} else { ; }
};trace!("typetree depth limit {} reached for type: {}", MAX_TYPETREE_DEPTH, ty);
59 return TypeTree::new();
60 }
61
62 if visited.contains(&ty) {
63 return TypeTree::new();
64 }
65 visited.push(ty);
66
67 if ty.is_scalar() {
68 let (kind, size) = if ty.is_integral() || ty.is_char() || ty.is_bool() {
69 (Kind::Integer, ty.primitive_size(tcx).bytes_usize())
70 } else if ty.is_floating_point() {
71 match ty {
72 x if x == tcx.types.f16 => (Kind::Half, 2),
73 x if x == tcx.types.f32 => (Kind::Float, 4),
74 x if x == tcx.types.f64 => (Kind::Double, 8),
75 x if x == tcx.types.f128 => (Kind::F128, 16),
76 _ => (Kind::Integer, 0),
77 }
78 } else {
79 (Kind::Integer, 0)
80 };
81
82 let offset = if is_reference_target && !ty.is_array() { 0 } else { -1 };
85 return TypeTree(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[Type { offset, size, kind, child: TypeTree::new() }]))vec![Type { offset, size, kind, child: TypeTree::new() }]);
86 }
87
88 if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() {
89 let Some(inner_ty) = ty.builtin_deref(true) else {
90 return TypeTree::new();
91 };
92
93 let child = typetree_from_ty_impl_inner(tcx, inner_ty, depth + 1, visited, true);
94 return TypeTree(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[Type {
offset: -1,
size: tcx.data_layout.pointer_size().bytes_usize(),
kind: Kind::Pointer,
child,
}]))vec![Type {
95 offset: -1,
96 size: tcx.data_layout.pointer_size().bytes_usize(),
97 kind: Kind::Pointer,
98 child,
99 }]);
100 }
101
102 if ty.is_array() {
103 if let ty::Array(element_ty, len_const) = ty.kind() {
104 let len = len_const.try_to_target_usize(tcx).unwrap_or(0);
105 if len == 0 {
106 return TypeTree::new();
107 }
108 let element_tree =
109 typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false);
110 let mut types = Vec::new();
111 for elem_type in &element_tree.0 {
112 types.push(Type {
113 offset: -1,
114 size: elem_type.size,
115 kind: elem_type.kind,
116 child: elem_type.child.clone(),
117 });
118 }
119
120 return TypeTree(types);
121 }
122 }
123
124 if ty.is_slice() {
125 if let ty::Slice(element_ty) = ty.kind() {
126 let element_tree =
127 typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false);
128 return element_tree;
129 }
130 }
131
132 if let ty::Tuple(tuple_types) = ty.kind() {
133 if tuple_types.is_empty() {
134 return TypeTree::new();
135 }
136
137 let mut types = Vec::new();
138 let mut current_offset = 0;
139
140 for tuple_ty in tuple_types.iter() {
141 let element_tree =
142 typetree_from_ty_impl_inner(tcx, tuple_ty, depth + 1, visited, false);
143
144 let element_layout = tcx
145 .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tuple_ty))
146 .ok()
147 .map(|layout| layout.size.bytes_usize())
148 .unwrap_or(0);
149
150 for elem_type in &element_tree.0 {
151 types.push(Type {
152 offset: if elem_type.offset == -1 {
153 current_offset as isize
154 } else {
155 current_offset as isize + elem_type.offset
156 },
157 size: elem_type.size,
158 kind: elem_type.kind,
159 child: elem_type.child.clone(),
160 });
161 }
162
163 current_offset += element_layout;
164 }
165
166 return TypeTree(types);
167 }
168
169 if let ty::Adt(adt_def, args) = ty.kind() {
170 if adt_def.is_struct() {
171 let struct_layout =
172 tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty));
173 if let Ok(layout) = struct_layout {
174 let mut types = Vec::new();
175
176 for (field_idx, field_def) in adt_def.all_fields().enumerate() {
177 let field_ty = field_def.ty(tcx, args);
178 let field_tree = typetree_from_ty_impl_inner(
179 tcx,
180 field_ty.skip_norm_wip(),
181 depth + 1,
182 visited,
183 false,
184 );
185
186 let field_offset = layout.fields.offset(field_idx).bytes_usize();
187
188 for elem_type in &field_tree.0 {
189 types.push(Type {
190 offset: if elem_type.offset == -1 {
191 field_offset as isize
192 } else {
193 field_offset as isize + elem_type.offset
194 },
195 size: elem_type.size,
196 kind: elem_type.kind,
197 child: elem_type.child.clone(),
198 });
199 }
200 }
201
202 return TypeTree(types);
203 }
204 }
205 }
206
207 TypeTree::new()
208}