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 if let Some(ldid) = def_id.as_local() {
213 tcx.hir_attrs(tcx.local_def_id_to_hir_id(ldid))
214 } else {
215 match def_kind {
216 RDefKind::ConstParam | RDefKind::LifetimeParam | RDefKind::ForeignMod | RDefKind::TyParam => &[],
218 _ => tcx.attrs_for_def(def_id),
219 }
220 }
221}
222
223pub fn get_mod_children<'tcx>(
225 tcx: ty::TyCtxt<'tcx>,
226 def_id: RDefId,
227) -> Vec<(Option<rustc_span::Ident>, RDefId)> {
228 match def_id.as_local() {
229 Some(ldid) => match tcx.hir_node_by_def_id(ldid) {
230 rustc_hir::Node::Crate(m)
231 | rustc_hir::Node::Item(&rustc_hir::Item {
232 kind: rustc_hir::ItemKind::Mod(_, m),
233 ..
234 }) => m
235 .item_ids
236 .iter()
237 .map(|&item_id| {
238 let opt_ident = tcx.hir_item(item_id).kind.ident();
239 let def_id = item_id.owner_id.to_def_id();
240 (opt_ident, def_id)
241 })
242 .collect(),
243 node => panic!("DefKind::Module is an unexpected node: {node:?}"),
244 },
245 None => tcx
246 .module_children(def_id)
247 .iter()
248 .map(|child| (Some(child.ident), child.res.def_id()))
249 .collect(),
250 }
251}
252
253pub fn get_foreign_mod_children<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Vec<RDefId> {
255 match def_id.as_local() {
256 Some(ldid) => tcx
257 .hir_node_by_def_id(ldid)
258 .expect_item()
259 .expect_foreign_mod()
260 .1
261 .iter()
262 .map(|foreign_item_ref| foreign_item_ref.owner_id.to_def_id())
263 .collect(),
264 None => vec![],
265 }
266}
267
268pub fn get_method_sig<'tcx>(
290 tcx: ty::TyCtxt<'tcx>,
291 typing_env: ty::TypingEnv<'tcx>,
292 def_id: RDefId,
293 method_args: Option<ty::GenericArgsRef<'tcx>>,
294) -> ty::PolyFnSig<'tcx> {
295 let real_sig = inst_binder(tcx, typing_env, method_args, tcx.fn_sig(def_id));
296 let item = tcx.associated_item(def_id);
297 let ty::AssocContainer::TraitImpl(Ok(decl_method_id)) = item.container else {
298 return real_sig;
299 };
300 let declared_sig = tcx.fn_sig(decl_method_id);
301
302 if declared_sig.skip_binder().bound_vars().len() == real_sig.bound_vars().len() {
308 return real_sig;
309 }
310
311 let impl_def_id = item.container_id(tcx);
312 let method_args =
313 method_args.unwrap_or_else(|| ty::GenericArgs::identity_for_item(tcx, def_id));
314 let implemented_trait_ref = tcx
316 .impl_trait_ref(impl_def_id)
317 .instantiate(tcx, method_args);
318 let decl_args = method_args.rebase_onto(tcx, impl_def_id, implemented_trait_ref.args);
321 let sig = declared_sig.instantiate(tcx, decl_args);
322 let sig = tcx.anonymize_bound_vars(sig);
325 normalize(tcx, typing_env, sig)
326}
327
328pub fn assoc_tys_for_trait<'tcx>(
331 tcx: ty::TyCtxt<'tcx>,
332 typing_env: ty::TypingEnv<'tcx>,
333 tref: ty::TraitRef<'tcx>,
334) -> Vec<ty::AliasTy<'tcx>> {
335 fn gather_assoc_tys<'tcx>(
336 tcx: ty::TyCtxt<'tcx>,
337 typing_env: ty::TypingEnv<'tcx>,
338 assoc_tys: &mut Vec<ty::AliasTy<'tcx>>,
339 tref: ty::TraitRef<'tcx>,
340 ) {
341 assoc_tys.extend(
342 tcx.associated_items(tref.def_id)
343 .in_definition_order()
344 .filter(|assoc| matches!(assoc.kind, ty::AssocKind::Type { .. }))
345 .filter(|assoc| tcx.generics_of(assoc.def_id).own_params.is_empty())
346 .map(|assoc| ty::AliasTy::new(tcx, assoc.def_id, tref.args)),
347 );
348 for clause in tcx
349 .explicit_super_predicates_of(tref.def_id)
350 .map_bound(|clauses| clauses.iter().map(|(clause, _span)| *clause))
351 .iter_instantiated(tcx, tref.args)
352 {
353 if let Some(pred) = clause.as_trait_clause() {
354 let tref = erase_and_norm(tcx, typing_env, pred.skip_binder().trait_ref);
355 gather_assoc_tys(tcx, typing_env, assoc_tys, tref);
356 }
357 }
358 }
359 let mut ret = vec![];
360 gather_assoc_tys(tcx, typing_env, &mut ret, tref);
361 ret
362}
363
364pub fn dyn_self_ty<'tcx>(
366 tcx: ty::TyCtxt<'tcx>,
367 typing_env: ty::TypingEnv<'tcx>,
368 tref: ty::TraitRef<'tcx>,
369) -> Option<ty::Ty<'tcx>> {
370 let re_erased = tcx.lifetimes.re_erased;
371 if !tcx.is_dyn_compatible(tref.def_id) {
372 return None;
373 }
374
375 let main_pred = ty::Binder::dummy(ty::ExistentialPredicate::Trait(
377 ty::ExistentialTraitRef::erase_self_ty(tcx, tref),
378 ));
379
380 let ty_constraints = assoc_tys_for_trait(tcx, typing_env, tref)
381 .into_iter()
382 .map(|alias_ty| {
383 let proj = ty::ProjectionPredicate {
384 projection_term: alias_ty.into(),
385 term: ty::Ty::new_alias(tcx, ty::Projection, alias_ty).into(),
386 };
387 let proj = ty::ExistentialProjection::erase_self_ty(tcx, proj);
388 ty::Binder::dummy(ty::ExistentialPredicate::Projection(proj))
389 });
390
391 let preds = {
392 let mut preds: Vec<_> = [main_pred].into_iter().chain(ty_constraints).collect();
394 preds.sort_by(|a, b| {
395 use crate::rustc_middle::ty::ExistentialPredicateStableCmpExt;
396 a.skip_binder().stable_cmp(tcx, &b.skip_binder())
397 });
398 tcx.mk_poly_existential_predicates(&preds)
399 };
400 let ty = tcx.mk_ty_from_kind(ty::Dynamic(preds, re_erased));
401 let ty = normalize(tcx, typing_env, ty);
402 Some(ty)
403}
404
405pub fn closure_once_shim<'tcx>(
406 tcx: ty::TyCtxt<'tcx>,
407 closure_ty: ty::Ty<'tcx>,
408) -> Option<mir::Body<'tcx>> {
409 let ty::Closure(def_id, args) = closure_ty.kind() else {
410 unreachable!()
411 };
412 let instance = match args.as_closure().kind() {
413 ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
414 ty::Instance::fn_once_adapter_instance(tcx, *def_id, args)
415 }
416 ty::ClosureKind::FnOnce => return None,
417 };
418 let mir = tcx.instance_mir(instance.def).clone();
419 let mir = ty::EarlyBinder::bind(mir).instantiate(tcx, instance.args);
420 Some(mir)
421}
422
423pub fn drop_glue_shim<'tcx>(
424 tcx: ty::TyCtxt<'tcx>,
425 def_id: RDefId,
426 instantiate: Option<ty::GenericArgsRef<'tcx>>,
427) -> Option<mir::Body<'tcx>> {
428 let drop_in_place =
429 tcx.require_lang_item(rustc_hir::LangItem::DropInPlace, rustc_span::DUMMY_SP);
430 let ty = tcx.type_of(def_id);
431 let ty = match instantiate {
432 None => {
433 if !tcx.generics_of(def_id).is_empty() {
434 return None;
437 }
438 ty.instantiate_identity()
439 }
440 Some(args) => ty.instantiate(tcx, args),
441 };
442 let instance_kind = ty::InstanceKind::DropGlue(drop_in_place, Some(ty));
443 let mir = tcx.instance_mir(instance_kind).clone();
444 Some(mir)
445}