1use crate::prelude::*;
2use rustc_hir::def::DefKind as RDefKind;
3use rustc_middle::{mir, ty};
4
5pub fn inst_binder<'tcx, T>(
6 tcx: ty::TyCtxt<'tcx>,
7 typing_env: ty::TypingEnv<'tcx>,
8 args: Option<ty::GenericArgsRef<'tcx>>,
9 x: ty::EarlyBinder<'tcx, T>,
10) -> T
11where
12 T: ty::TypeFoldable<ty::TyCtxt<'tcx>> + Clone,
13{
14 match args {
15 None => x.instantiate_identity(),
16 Some(args) => tcx.normalize_erasing_regions(typing_env, x.instantiate(tcx, args)),
17 }
18}
19
20pub fn substitute<'tcx, T>(
21 tcx: ty::TyCtxt<'tcx>,
22 typing_env: ty::TypingEnv<'tcx>,
23 args: Option<ty::GenericArgsRef<'tcx>>,
24 x: T,
25) -> T
26where
27 T: ty::TypeFoldable<ty::TyCtxt<'tcx>>,
28{
29 inst_binder(tcx, typing_env, args, ty::EarlyBinder::bind(x))
30}
31
32#[extension_traits::extension(pub trait SubstBinder)]
33impl<'tcx, T: ty::TypeFoldable<ty::TyCtxt<'tcx>>> ty::Binder<'tcx, T> {
34 fn subst(
35 self,
36 tcx: ty::TyCtxt<'tcx>,
37 generics: &[ty::GenericArg<'tcx>],
38 ) -> ty::Binder<'tcx, T> {
39 ty::EarlyBinder::bind(self).instantiate(tcx, generics)
40 }
41}
42
43pub(crate) fn can_have_generics<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> bool {
45 use RDefKind::*;
46 match get_def_kind(tcx, def_id) {
47 Mod | ConstParam | TyParam | LifetimeParam | Macro(..) | ExternCrate | Use | ForeignMod
48 | GlobalAsm => false,
49 _ => true,
50 }
51}
52
53#[tracing::instrument(skip(s))]
54pub(crate) fn get_variant_information<'s, S: UnderOwnerState<'s>>(
55 adt_def: &ty::AdtDef<'s>,
56 variant_index: rustc_abi::VariantIdx,
57 s: &S,
58) -> VariantInformations {
59 fn is_named<'s, I: std::iter::Iterator<Item = &'s ty::FieldDef> + Clone>(it: I) -> bool {
60 it.clone()
61 .any(|field| field.name.to_ident_string().parse::<u64>().is_err())
62 }
63 let variant_def = adt_def.variant(variant_index);
64 let variant = variant_def.def_id;
65 let constructs_type: DefId = adt_def.did().sinto(s);
66 let kind = if adt_def.is_struct() {
67 let named = is_named(adt_def.all_fields());
68 VariantKind::Struct { named }
69 } else if adt_def.is_union() {
70 VariantKind::Union
71 } else {
72 let named = is_named(variant_def.fields.iter());
73 let index = variant_index.into();
74 VariantKind::Enum { index, named }
75 };
76 VariantInformations {
77 typ: constructs_type.clone(),
78 variant: variant.sinto(s),
79 kind,
80 type_namespace: match &constructs_type.parent {
81 Some(parent) => parent.clone(),
82 None => {
83 let span = s.base().tcx.def_span(variant);
84 fatal!(
85 s[span],
86 "Type {:#?} appears to have no parent",
87 constructs_type
88 )
89 }
90 },
91 }
92}
93
94#[tracing::instrument(skip(sess))]
95pub fn translate_span(span: rustc_span::Span, sess: &rustc_session::Session) -> Span {
96 let smap: &rustc_span::source_map::SourceMap = sess.psess.source_map();
97 let filename = smap.span_to_filename(span);
98
99 let lo = smap.lookup_char_pos(span.lo());
100 let hi = smap.lookup_char_pos(span.hi());
101
102 Span {
103 lo: lo.into(),
104 hi: hi.into(),
105 filename: filename.sinto(&()),
106 rust_span_data: Some(span.data()),
107 }
108}
109
110pub trait HasParamEnv<'tcx> {
111 fn param_env(&self) -> ty::ParamEnv<'tcx>;
112 fn typing_env(&self) -> ty::TypingEnv<'tcx>;
113}
114
115impl<'tcx, S: UnderOwnerState<'tcx>> HasParamEnv<'tcx> for S {
116 fn param_env(&self) -> ty::ParamEnv<'tcx> {
117 let tcx = self.base().tcx;
118 let def_id = self.owner_id();
119 if can_have_generics(tcx, def_id) {
120 tcx.param_env(def_id)
121 } else {
122 ty::ParamEnv::empty()
123 }
124 }
125 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
126 ty::TypingEnv {
127 param_env: self.param_env(),
128 typing_mode: ty::TypingMode::PostAnalysis,
129 }
130 }
131}
132
133#[tracing::instrument(skip(s))]
134pub(crate) fn attribute_from_scope<'tcx, S: ExprState<'tcx>>(
135 s: &S,
136 scope: &rustc_middle::middle::region::Scope,
137) -> (Option<rustc_hir::hir_id::HirId>, Vec<Attribute>) {
138 let owner = s.owner_id();
139 let tcx = s.base().tcx;
140 let scope_tree = tcx.region_scope_tree(owner);
141 let hir_id = scope.hir_id(scope_tree);
142 let tcx = s.base().tcx;
143 let attributes = hir_id
144 .map(|hir_id| tcx.hir_attrs(hir_id).sinto(s))
145 .unwrap_or_default();
146 (hir_id, attributes)
147}
148
149pub fn get_closest_parent_type(
151 tcx: &ty::TyCtxt,
152 id: rustc_span::def_id::DefId,
153) -> rustc_span::def_id::DefId {
154 match tcx.def_kind(id) {
155 rustc_hir::def::DefKind::Union
156 | rustc_hir::def::DefKind::Struct
157 | rustc_hir::def::DefKind::Enum => id,
158 _ => get_closest_parent_type(tcx, tcx.parent(id)),
159 }
160}
161
162pub fn get_def_visibility<'tcx>(
165 tcx: ty::TyCtxt<'tcx>,
166 def_id: RDefId,
167 def_kind: RDefKind,
168) -> Option<bool> {
169 use RDefKind::*;
170 match def_kind {
171 AssocConst
172 | AssocFn
173 | Const
174 | Enum
175 | Field
176 | Fn
177 | ForeignTy
178 | Macro { .. }
179 | Mod
180 | Static { .. }
181 | Struct
182 | Trait
183 | TraitAlias
184 | TyAlias { .. }
185 | Union
186 | Use
187 | Variant => Some(tcx.visibility(def_id).is_public()),
188 AnonConst
190 | AssocTy
191 | Closure
192 | ConstParam
193 | Ctor { .. }
194 | ExternCrate
195 | ForeignMod
196 | GlobalAsm
197 | Impl { .. }
198 | InlineConst
199 | LifetimeParam
200 | OpaqueTy
201 | SyntheticCoroutineBody
202 | TyParam => None,
203 }
204}
205
206pub fn get_def_attrs<'tcx>(
208 tcx: ty::TyCtxt<'tcx>,
209 def_id: RDefId,
210 def_kind: RDefKind,
211) -> &'tcx [rustc_hir::Attribute] {
212 use RDefKind::*;
213 match def_kind {
214 ConstParam | LifetimeParam | TyParam | ForeignMod => &[],
216 _ => {
217 if let Some(ldid) = def_id.as_local() {
218 tcx.hir_attrs(tcx.local_def_id_to_hir_id(ldid))
219 } else {
220 tcx.attrs_for_def(def_id)
221 }
222 }
223 }
224}
225
226pub fn get_mod_children<'tcx>(
228 tcx: ty::TyCtxt<'tcx>,
229 def_id: RDefId,
230) -> Vec<(Option<rustc_span::Ident>, RDefId)> {
231 match def_id.as_local() {
232 Some(ldid) => match tcx.hir_node_by_def_id(ldid) {
233 rustc_hir::Node::Crate(m)
234 | rustc_hir::Node::Item(&rustc_hir::Item {
235 kind: rustc_hir::ItemKind::Mod(_, m),
236 ..
237 }) => m
238 .item_ids
239 .iter()
240 .map(|&item_id| {
241 let opt_ident = tcx.hir_item(item_id).kind.ident();
242 let def_id = item_id.owner_id.to_def_id();
243 (opt_ident, def_id)
244 })
245 .collect(),
246 node => panic!("DefKind::Module is an unexpected node: {node:?}"),
247 },
248 None => tcx
249 .module_children(def_id)
250 .iter()
251 .map(|child| (Some(child.ident), child.res.def_id()))
252 .collect(),
253 }
254}
255
256pub fn get_foreign_mod_children<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Vec<RDefId> {
258 match def_id.as_local() {
259 Some(ldid) => tcx
260 .hir_node_by_def_id(ldid)
261 .expect_item()
262 .expect_foreign_mod()
263 .1
264 .iter()
265 .map(|foreign_item_ref| foreign_item_ref.owner_id.to_def_id())
266 .collect(),
267 None => vec![],
268 }
269}
270
271pub fn get_method_sig<'tcx>(
293 tcx: ty::TyCtxt<'tcx>,
294 typing_env: ty::TypingEnv<'tcx>,
295 def_id: RDefId,
296 method_args: Option<ty::GenericArgsRef<'tcx>>,
297) -> ty::PolyFnSig<'tcx> {
298 let real_sig = inst_binder(tcx, typing_env, method_args, tcx.fn_sig(def_id));
299 let item = tcx.associated_item(def_id);
300 let ty::AssocContainer::TraitImpl(Ok(decl_method_id)) = item.container else {
301 return real_sig;
302 };
303 let declared_sig = tcx.fn_sig(decl_method_id);
304
305 if declared_sig.skip_binder().bound_vars().len() == real_sig.bound_vars().len() {
311 return real_sig;
312 }
313
314 let impl_def_id = item.container_id(tcx);
315 let method_args =
316 method_args.unwrap_or_else(|| ty::GenericArgs::identity_for_item(tcx, def_id));
317 let implemented_trait_ref = tcx
319 .impl_trait_ref(impl_def_id)
320 .instantiate(tcx, method_args);
321 let decl_args = method_args.rebase_onto(tcx, impl_def_id, implemented_trait_ref.args);
324 let sig = declared_sig.instantiate(tcx, decl_args);
325 let sig = tcx.anonymize_bound_vars(sig);
328 normalize(tcx, typing_env, sig)
329}
330
331pub fn assoc_tys_for_trait<'tcx>(
334 tcx: ty::TyCtxt<'tcx>,
335 typing_env: ty::TypingEnv<'tcx>,
336 tref: ty::TraitRef<'tcx>,
337) -> Vec<ty::AliasTy<'tcx>> {
338 fn gather_assoc_tys<'tcx>(
339 tcx: ty::TyCtxt<'tcx>,
340 typing_env: ty::TypingEnv<'tcx>,
341 assoc_tys: &mut Vec<ty::AliasTy<'tcx>>,
342 tref: ty::TraitRef<'tcx>,
343 ) {
344 assoc_tys.extend(
345 tcx.associated_items(tref.def_id)
346 .in_definition_order()
347 .filter(|assoc| matches!(assoc.kind, ty::AssocKind::Type { .. }))
348 .filter(|assoc| tcx.generics_of(assoc.def_id).own_params.is_empty())
349 .map(|assoc| ty::AliasTy::new(tcx, assoc.def_id, tref.args)),
350 );
351 for clause in tcx
352 .explicit_super_predicates_of(tref.def_id)
353 .map_bound(|clauses| clauses.iter().map(|(clause, _span)| *clause))
354 .iter_instantiated(tcx, tref.args)
355 {
356 if let Some(pred) = clause.as_trait_clause() {
357 let tref = erase_and_norm(tcx, typing_env, pred.skip_binder().trait_ref);
358 gather_assoc_tys(tcx, typing_env, assoc_tys, tref);
359 }
360 }
361 }
362 let mut ret = vec![];
363 gather_assoc_tys(tcx, typing_env, &mut ret, tref);
364 ret
365}
366
367pub fn dyn_self_ty<'tcx>(
369 tcx: ty::TyCtxt<'tcx>,
370 typing_env: ty::TypingEnv<'tcx>,
371 tref: ty::TraitRef<'tcx>,
372) -> Option<ty::Ty<'tcx>> {
373 let re_erased = tcx.lifetimes.re_erased;
374 if !tcx.is_dyn_compatible(tref.def_id) {
375 return None;
376 }
377
378 let main_pred = ty::Binder::dummy(ty::ExistentialPredicate::Trait(
380 ty::ExistentialTraitRef::erase_self_ty(tcx, tref),
381 ));
382
383 let ty_constraints = assoc_tys_for_trait(tcx, typing_env, tref)
384 .into_iter()
385 .map(|alias_ty| {
386 let proj = ty::ProjectionPredicate {
387 projection_term: alias_ty.into(),
388 term: ty::Ty::new_alias(tcx, ty::Projection, alias_ty).into(),
389 };
390 let proj = ty::ExistentialProjection::erase_self_ty(tcx, proj);
391 ty::Binder::dummy(ty::ExistentialPredicate::Projection(proj))
392 });
393
394 let preds = {
395 let mut preds: Vec<_> = [main_pred].into_iter().chain(ty_constraints).collect();
397 preds.sort_by(|a, b| {
398 use crate::rustc_middle::ty::ExistentialPredicateStableCmpExt;
399 a.skip_binder().stable_cmp(tcx, &b.skip_binder())
400 });
401 tcx.mk_poly_existential_predicates(&preds)
402 };
403 let ty = tcx.mk_ty_from_kind(ty::Dynamic(preds, re_erased));
404 let ty = normalize(tcx, typing_env, ty);
405 Some(ty)
406}
407
408pub fn closure_once_shim<'tcx>(
409 tcx: ty::TyCtxt<'tcx>,
410 closure_ty: ty::Ty<'tcx>,
411) -> Option<mir::Body<'tcx>> {
412 let ty::Closure(def_id, args) = closure_ty.kind() else {
413 unreachable!()
414 };
415 let instance = match args.as_closure().kind() {
416 ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
417 ty::Instance::fn_once_adapter_instance(tcx, *def_id, args)
418 }
419 ty::ClosureKind::FnOnce => return None,
420 };
421 let mir = tcx.instance_mir(instance.def).clone();
422 let mir = ty::EarlyBinder::bind(mir).instantiate(tcx, instance.args);
423 Some(mir)
424}
425
426pub fn drop_glue_shim<'tcx>(
427 tcx: ty::TyCtxt<'tcx>,
428 def_id: RDefId,
429 instantiate: Option<ty::GenericArgsRef<'tcx>>,
430) -> Option<mir::Body<'tcx>> {
431 let drop_in_place =
432 tcx.require_lang_item(rustc_hir::LangItem::DropInPlace, rustc_span::DUMMY_SP);
433 let ty = tcx.type_of(def_id);
434 let ty = match instantiate {
435 None => {
436 if !tcx.generics_of(def_id).is_empty() {
437 return None;
440 }
441 ty.instantiate_identity()
442 }
443 Some(args) => ty.instantiate(tcx, args),
444 };
445 let instance_kind = ty::InstanceKind::DropGlue(drop_in_place, Some(ty));
446 let mir = tcx.instance_mir(instance_kind).clone();
447 Some(mir)
448}