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