1use std::collections::{HashMap, HashSet};
2
3use rustc_hir::def::DefKind as RDefKind;
4use rustc_middle::infer::canonical::{CanonicalVarKinds, CanonicalVarValues};
5use rustc_middle::ty::relate::{
6 Relate, RelateResult, TypeRelation, relate_args_with_variances, structurally_relate_consts,
7 structurally_relate_tys,
8};
9use rustc_middle::{mir, ty};
10use rustc_span::kw;
11
12use crate::hax::prelude::*;
13
14pub fn match_canonical_var_values<'tcx>(
17 tcx: ty::TyCtxt<'tcx>,
18 var_kinds: CanonicalVarKinds<'tcx>,
19 canonical_ty: ty::Ty<'tcx>,
20 inferred_ty: ty::Ty<'tcx>,
21) -> Option<CanonicalVarValues<'tcx>> {
22 let values = var_kinds
23 .iter()
24 .map(|kind| match kind {
25 ty::CanonicalVarKind::Region(_) => Some(tcx.lifetimes.re_erased.into()),
26 _ => None,
27 })
28 .collect();
29 let mut matcher = CanonicalVarMatcher { tcx, values };
30 matcher.relate(canonical_ty, inferred_ty).ok()?;
31
32 for (index, kind) in var_kinds.iter().enumerate() {
35 if matcher.values[index].is_none()
36 && let ty::CanonicalVarKind::Ty { sub_root, .. } = kind
37 {
38 matcher.values[index] = matcher.values[sub_root.as_usize()];
39 }
40 }
41 let values = matcher.values.into_iter().collect::<Option<Vec<_>>>()?;
42 Some(CanonicalVarValues {
43 var_values: tcx.mk_args(&values),
44 })
45}
46
47struct CanonicalVarMatcher<'tcx> {
48 tcx: ty::TyCtxt<'tcx>,
49 values: Vec<Option<ty::GenericArg<'tcx>>>,
50}
51
52impl<'tcx> CanonicalVarMatcher<'tcx> {
53 fn record<T>(
54 &mut self,
55 var: ty::BoundVar,
56 value: ty::GenericArg<'tcx>,
57 result: T,
58 ) -> RelateResult<'tcx, T> {
59 let slot = &mut self.values[var.as_usize()];
60 if slot.is_some_and(|old| old != value) {
61 Err(ty::error::TypeError::Mismatch)
62 } else {
63 *slot = Some(value);
64 Ok(result)
65 }
66 }
67}
68
69impl<'tcx> TypeRelation<ty::TyCtxt<'tcx>> for CanonicalVarMatcher<'tcx> {
70 fn cx(&self) -> ty::TyCtxt<'tcx> {
71 self.tcx
72 }
73
74 fn relate_ty_args(
75 &mut self,
76 a_ty: ty::Ty<'tcx>,
77 _: ty::Ty<'tcx>,
78 _: rustc_hir::def_id::DefId,
79 a_args: ty::GenericArgsRef<'tcx>,
80 b_args: ty::GenericArgsRef<'tcx>,
81 _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> ty::Ty<'tcx>,
82 ) -> RelateResult<'tcx, ty::Ty<'tcx>> {
83 ty::relate::relate_args_invariantly(self, a_args, b_args)?;
84 Ok(a_ty)
85 }
86
87 fn relate_with_variance<T: Relate<ty::TyCtxt<'tcx>>>(
88 &mut self,
89 _: ty::Variance,
90 _: ty::VarianceDiagInfo<ty::TyCtxt<'tcx>>,
91 a: T,
92 b: T,
93 ) -> RelateResult<'tcx, T> {
94 self.relate(a, b)
95 }
96
97 fn tys(&mut self, a: ty::Ty<'tcx>, b: ty::Ty<'tcx>) -> RelateResult<'tcx, ty::Ty<'tcx>> {
98 if let ty::Bound(ty::BoundVarIndexKind::Canonical, bound) = *a.kind() {
99 self.record(bound.var, b.into(), a)
100 } else {
101 structurally_relate_tys(self, a, b)
102 }
103 }
104
105 fn regions(
106 &mut self,
107 a: ty::Region<'tcx>,
108 _: ty::Region<'tcx>,
109 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
110 Ok(a)
111 }
112
113 fn consts(
114 &mut self,
115 a: ty::Const<'tcx>,
116 b: ty::Const<'tcx>,
117 ) -> RelateResult<'tcx, ty::Const<'tcx>> {
118 if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bound) = a.kind() {
119 self.record(bound.var, b.into(), a)
120 } else {
121 structurally_relate_consts(self, a, b)
122 }
123 }
124
125 fn binders<T>(
126 &mut self,
127 a: ty::Binder<'tcx, T>,
128 b: ty::Binder<'tcx, T>,
129 ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
130 where
131 T: Relate<ty::TyCtxt<'tcx>>,
132 {
133 self.relate(a.skip_binder(), b.skip_binder())?;
134 Ok(a)
135 }
136}
137
138pub fn fn_sig_bound_region_variances<'tcx>(
142 tcx: ty::TyCtxt<'tcx>,
143 sig: ty::PolyFnSig<'tcx>,
144) -> HashMap<ty::BoundVar, ty::Variance> {
145 struct FunctionalVariances<'tcx> {
146 tcx: ty::TyCtxt<'tcx>,
147 variances: HashMap<ty::BoundVar, ty::Variance>,
148 ambient_variance: ty::Variance,
149 target_binder: ty::DebruijnIndex,
150 }
151
152 impl<'tcx> TypeRelation<ty::TyCtxt<'tcx>> for FunctionalVariances<'tcx> {
153 fn cx(&self) -> ty::TyCtxt<'tcx> {
154 self.tcx
155 }
156
157 fn relate_ty_args(
158 &mut self,
159 a_ty: ty::Ty<'tcx>,
160 _: ty::Ty<'tcx>,
161 def_id: rustc_hir::def_id::DefId,
162 a_args: ty::GenericArgsRef<'tcx>,
163 b_args: ty::GenericArgsRef<'tcx>,
164 _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> ty::Ty<'tcx>,
165 ) -> RelateResult<'tcx, ty::Ty<'tcx>> {
166 relate_args_with_variances(self, self.tcx.variances_of(def_id), a_args, b_args)?;
167 Ok(a_ty)
168 }
169
170 fn relate_with_variance<T: Relate<ty::TyCtxt<'tcx>>>(
171 &mut self,
172 variance: ty::Variance,
173 _: ty::VarianceDiagInfo<ty::TyCtxt<'tcx>>,
174 a: T,
175 b: T,
176 ) -> RelateResult<'tcx, T> {
177 let old_variance = self.ambient_variance;
178 self.ambient_variance = self.ambient_variance.xform(variance);
179 let result = self.relate(a, b);
180 self.ambient_variance = old_variance;
181 result
182 }
183
184 fn tys(&mut self, a: ty::Ty<'tcx>, b: ty::Ty<'tcx>) -> RelateResult<'tcx, ty::Ty<'tcx>> {
185 structurally_relate_tys(self, a, b)
186 }
187
188 fn regions(
189 &mut self,
190 a: ty::Region<'tcx>,
191 _: ty::Region<'tcx>,
192 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
193 if let ty::ReBound(ty::BoundVarIndexKind::Bound(binder), ty::BoundRegion { var, .. }) =
194 a.kind()
195 && binder == self.target_binder
196 {
197 self.variances
198 .entry(var)
199 .and_modify(|old| *old = unify_variances(*old, self.ambient_variance))
200 .or_insert(self.ambient_variance);
201 }
202 Ok(a)
203 }
204
205 fn consts(
206 &mut self,
207 a: ty::Const<'tcx>,
208 b: ty::Const<'tcx>,
209 ) -> RelateResult<'tcx, ty::Const<'tcx>> {
210 structurally_relate_consts(self, a, b)
211 }
212
213 fn binders<T>(
214 &mut self,
215 a: ty::Binder<'tcx, T>,
216 b: ty::Binder<'tcx, T>,
217 ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
218 where
219 T: Relate<ty::TyCtxt<'tcx>>,
220 {
221 let old_target_binder = self.target_binder;
222 self.target_binder = self.target_binder.shifted_in(1);
223 let result = self.relate(a.skip_binder(), b.skip_binder());
224 self.target_binder = old_target_binder;
225 result?;
226 Ok(a)
227 }
228 }
229
230 fn unify_variances(a: ty::Variance, b: ty::Variance) -> ty::Variance {
231 match (a, b) {
232 (ty::Bivariant, other) | (other, ty::Bivariant) => other,
233 (ty::Invariant, _) | (_, ty::Invariant) => ty::Invariant,
234 (ty::Contravariant, ty::Covariant) | (ty::Covariant, ty::Contravariant) => {
235 ty::Invariant
236 }
237 (ty::Contravariant, ty::Contravariant) => ty::Contravariant,
238 (ty::Covariant, ty::Covariant) => ty::Covariant,
239 }
240 }
241
242 let mut relation = FunctionalVariances {
243 tcx,
244 variances: HashMap::new(),
245 ambient_variance: ty::Contravariant,
249 target_binder: ty::INNERMOST,
250 };
251 relation
252 .relate(sig.skip_binder(), sig.skip_binder())
253 .expect("a signature must relate to itself");
254
255 for (index, var) in sig.bound_vars().iter().enumerate() {
257 if matches!(var, ty::BoundVariableKind::Region(_)) {
258 relation
259 .variances
260 .entry(ty::BoundVar::from_usize(index))
261 .or_insert(ty::Bivariant);
262 }
263 }
264 relation.variances
265}
266
267pub fn inst_binder<'tcx, T>(
268 tcx: ty::TyCtxt<'tcx>,
269 typing_env: ty::TypingEnv<'tcx>,
270 args: Option<ty::GenericArgsRef<'tcx>>,
271 x: ty::EarlyBinder<'tcx, T>,
272) -> T
273where
274 T: ty::TypeFoldable<ty::TyCtxt<'tcx>> + Clone,
275{
276 match args {
277 None => x.instantiate_identity().skip_normalization(),
278 Some(args) => normalize(tcx, typing_env, x.instantiate(tcx, args)),
279 }
280}
281
282pub fn substitute<'tcx, T>(
283 tcx: ty::TyCtxt<'tcx>,
284 typing_env: ty::TypingEnv<'tcx>,
285 args: Option<ty::GenericArgsRef<'tcx>>,
286 x: T,
287) -> T
288where
289 T: ty::TypeFoldable<ty::TyCtxt<'tcx>>,
290{
291 inst_binder(tcx, typing_env, args, ty::EarlyBinder::bind(tcx, x))
292}
293
294pub fn param_env_from_clauses<'tcx>(
296 tcx: ty::TyCtxt<'tcx>,
297 predicates: impl Iterator<Item = ty::Clause<'tcx>>,
298) -> ty::ParamEnv<'tcx> {
299 let cause = rustc_trait_selection::traits::ObligationCause::dummy();
300 let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(predicates));
301 rustc_trait_selection::traits::normalize_param_env_or_error(tcx, param_env, cause)
302}
303
304#[extension_traits::extension(pub trait SubstBinder)]
305impl<'tcx, T: ty::TypeFoldable<ty::TyCtxt<'tcx>>> ty::Binder<'tcx, T> {
306 fn subst(
307 self,
308 tcx: ty::TyCtxt<'tcx>,
309 generics: &[ty::GenericArg<'tcx>],
310 ) -> ty::Binder<'tcx, T> {
311 ty::EarlyBinder::bind(tcx, self)
312 .instantiate(tcx, generics)
313 .skip_normalization()
314 }
315}
316
317pub(crate) fn can_have_generics<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> bool {
319 use RDefKind::*;
320 !matches!(
321 get_def_kind(tcx, def_id),
322 ConstParam
323 | ExternCrate
324 | ForeignMod
325 | GlobalAsm
326 | LifetimeParam
327 | Macro(..)
328 | Mod
329 | TyParam
330 | Use
331 )
332}
333
334pub(crate) fn get_variant_kind<'s, S: UnderOwnerState<'s>>(
335 adt_def: &ty::AdtDef<'s>,
336 variant_index: rustc_abi::VariantIdx,
337 _s: &S,
338) -> VariantKind {
339 if adt_def.is_struct() {
340 VariantKind::Struct
341 } else if adt_def.is_union() {
342 VariantKind::Union
343 } else {
344 let index = variant_index;
345 VariantKind::Enum { index }
346 }
347}
348
349pub fn get_mod_children<'tcx>(
351 tcx: ty::TyCtxt<'tcx>,
352 def_id: RDefId,
353) -> Vec<(Option<rustc_span::Ident>, RDefId)> {
354 match def_id.as_local() {
355 Some(ldid) => match tcx.hir_node_by_def_id(ldid) {
356 rustc_hir::Node::Crate(m)
357 | rustc_hir::Node::Item(&rustc_hir::Item {
358 kind: rustc_hir::ItemKind::Mod(_, m),
359 ..
360 }) => m
361 .item_ids
362 .iter()
363 .map(|&item_id| {
364 let opt_ident = tcx.hir_item(item_id).kind.ident();
365 let def_id = item_id.owner_id.to_def_id();
366 (opt_ident, def_id)
367 })
368 .collect(),
369 node => panic!("DefKind::Module is an unexpected node: {node:?}"),
370 },
371 None => tcx
372 .module_children(def_id)
373 .iter()
374 .filter_map(|child| Some((Some(child.ident), child.res.opt_def_id()?)))
375 .collect(),
376 }
377}
378
379pub fn get_foreign_mod_children<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Vec<RDefId> {
381 match def_id.as_local() {
382 Some(ldid) => tcx
383 .hir_node_by_def_id(ldid)
384 .expect_item()
385 .expect_foreign_mod()
386 .1
387 .iter()
388 .map(|foreign_item_ref| foreign_item_ref.owner_id.to_def_id())
389 .collect(),
390 None => vec![],
391 }
392}
393
394pub fn get_method_sig<'tcx>(
416 tcx: ty::TyCtxt<'tcx>,
417 typing_env: ty::TypingEnv<'tcx>,
418 def_id: RDefId,
419 method_args: Option<ty::GenericArgsRef<'tcx>>,
420) -> ty::PolyFnSig<'tcx> {
421 let real_sig = inst_binder(tcx, typing_env, method_args, tcx.fn_sig(def_id));
422 let item = tcx.associated_item(def_id);
423 let ty::AssocContainer::TraitImpl(Ok(decl_method_id)) = item.container else {
424 return real_sig;
425 };
426 let declared_sig = tcx.fn_sig(decl_method_id);
427
428 let impl_def_id = item.container_id(tcx);
429 let method_args =
430 method_args.unwrap_or_else(|| ty::GenericArgs::identity_for_item(tcx, def_id));
431 let implemented_trait_ref = tcx
433 .impl_trait_ref(impl_def_id)
434 .instantiate(tcx, method_args);
435 let implemented_trait_ref = normalize(tcx, typing_env, implemented_trait_ref);
436 let decl_args = method_args.rebase_onto(tcx, impl_def_id, implemented_trait_ref.args);
439 let sig = declared_sig.instantiate(tcx, decl_args);
440 let sig = normalize(tcx, typing_env, sig);
441
442 if let container_named_lts = tcx
443 .generics_of(impl_def_id)
444 .own_params
445 .iter()
446 .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
447 .filter(|p| p.name != kw::UnderscoreLifetime)
448 .map(|p| p.name)
449 .collect::<HashSet<_>>()
450 && sig
451 .bound_vars()
452 .iter()
453 .map(|v| v.expect_region())
454 .filter_map(|v| v.get_name(tcx))
455 .any(|lt| container_named_lts.contains(<))
456 {
457 tcx.anonymize_bound_vars(sig)
460 } else {
461 sig
462 }
463}
464
465pub fn assoc_tys_for_trait<'tcx>(
468 tcx: ty::TyCtxt<'tcx>,
469 typing_env: ty::TypingEnv<'tcx>,
470 tref: ty::TraitRef<'tcx>,
471) -> Vec<ty::AliasTy<'tcx>> {
472 fn gather_assoc_tys<'tcx>(
473 tcx: ty::TyCtxt<'tcx>,
474 typing_env: ty::TypingEnv<'tcx>,
475 assoc_tys: &mut Vec<ty::AliasTy<'tcx>>,
476 tref: ty::TraitRef<'tcx>,
477 ) {
478 assoc_tys.extend(
479 tcx.associated_items(tref.def_id)
480 .in_definition_order()
481 .filter(|assoc| matches!(assoc.kind, ty::AssocKind::Type { .. }))
482 .filter(|assoc| {
483 tcx.generics_of(assoc.def_id).own_params.is_empty()
484 && tcx.clauses_of(assoc.def_id).clauses.is_empty()
485 })
486 .map(|assoc| {
487 let alias_ty = ty::AliasTyKind::Projection {
488 def_id: assoc.def_id,
489 };
490 ty::AliasTy::new(tcx, alias_ty, tref.args)
491 }),
492 );
493 for clause in tcx
494 .explicit_super_clauses_of(tref.def_id)
495 .map_bound(|clauses| clauses.iter().map(|(clause, _span)| *clause))
496 .iter_instantiated(tcx, tref.args)
497 {
498 if let Some(pred) = clause.as_trait_clause() {
499 let tref = erase_and_norm(tcx, typing_env, pred.map(|b| b.skip_binder().trait_ref));
500 gather_assoc_tys(tcx, typing_env, assoc_tys, tref);
501 }
502 }
503 }
504 let mut ret = vec![];
505 gather_assoc_tys(tcx, typing_env, &mut ret, tref);
506 ret
507}
508
509pub fn dyn_self_ty<'tcx>(
511 tcx: ty::TyCtxt<'tcx>,
512 typing_env: ty::TypingEnv<'tcx>,
513 tref: ty::TraitRef<'tcx>,
514) -> Option<ty::Ty<'tcx>> {
515 let re_erased = tcx.lifetimes.re_erased;
516 if !tcx.is_dyn_compatible(tref.def_id) {
517 return None;
518 }
519
520 let main_pred = ty::Binder::dummy(ty::ExistentialPredicate::Trait(
522 ty::ExistentialTraitRef::erase_self_ty(tcx, tref),
523 ));
524
525 let ty_constraints = assoc_tys_for_trait(tcx, typing_env, tref)
526 .into_iter()
527 .map(|alias_ty| {
528 let proj = ty::ProjectionPredicate {
529 projection_term: alias_ty.into(),
530 term: ty::Ty::new_alias(tcx, ty::IsRigid::No, alias_ty).into(),
531 };
532 let proj = ty::ExistentialProjection::erase_self_ty(tcx, proj);
533 ty::Binder::dummy(ty::ExistentialPredicate::Projection(proj))
534 });
535
536 let preds = {
537 let mut preds: Vec<_> = [main_pred].into_iter().chain(ty_constraints).collect();
539 preds.sort_by(|a, b| {
540 use rustc_middle::ty::ExistentialPredicateStableCmpExt;
541 a.skip_binder().stable_cmp(tcx, &b.skip_binder())
542 });
543 tcx.mk_poly_existential_predicates(&preds)
544 };
545 let ty = tcx.mk_ty_from_kind(ty::Dynamic(preds, re_erased));
546 let ty = normalize(tcx, typing_env, ty::Unnormalized::new_wip(ty));
547 Some(ty)
548}
549
550pub fn closure_once_shim<'tcx>(
551 tcx: ty::TyCtxt<'tcx>,
552 closure_ty: ty::Ty<'tcx>,
553) -> Option<mir::Body<'tcx>> {
554 let ty::Closure(def_id, args) = closure_ty.kind() else {
555 unreachable!()
556 };
557 let instance = match args.as_closure().kind() {
558 ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
559 ty::Instance::fn_once_adapter_instance(tcx, *def_id, args)
560 }
561 ty::ClosureKind::FnOnce => return None,
562 };
563 let mir = tcx.instance_mir(instance.def).clone();
564 let mir = ty::EarlyBinder::bind(tcx, mir)
565 .instantiate(tcx, instance.args)
566 .skip_normalization();
567 Some(mir)
568}
569
570pub fn drop_glue_shim<'tcx>(
571 s: &impl UnderOwnerState<'tcx>,
572 def_id: &DefId,
573 instantiate: Option<ty::GenericArgsRef<'tcx>>,
574) -> mir::Body<'tcx> {
575 let tcx = s.base().tcx;
576 let drop_glue = tcx.require_lang_item(rustc_attr_ir::LangItem::DropGlue, rustc_span::DUMMY_SP);
577 let ty = inst_binder(tcx, s.typing_env(), instantiate, def_id.type_of(s));
578 let mut body = rustc_mir_transform::build_drop_shim(tcx, drop_glue, Some(ty), s.typing_env());
579 body.phase = mir::MirPhase::Runtime(mir::RuntimePhase::Optimized);
581 body
582}