1use rustc_hir::def_id::DefId;
2use rustc_middle::ty::relate::{
3 self, Relate, RelateResult, TypeRelation, relate_args_with_variances,
4};
5use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
6
7use super::ConstraintDirection;
8use crate::polonius::LiveRegionVariances;
9use crate::universal_regions::UniversalRegions;
10
11pub(crate) fn record_live_region_variance<'tcx>(
13 tcx: TyCtxt<'tcx>,
14 live_region_variances: &mut LiveRegionVariances,
15 universal_regions: &UniversalRegions<'tcx>,
16 value: impl TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>,
17) {
18 let mut extractor = VarianceExtractor {
19 tcx,
20 ambient_variance: ty::Variance::Covariant,
21 directions: live_region_variances,
22 universal_regions,
23 };
24 extractor.relate(value, value).expect("Can't have a type error relating to itself");
25}
26
27struct VarianceExtractor<'a, 'tcx> {
31 tcx: TyCtxt<'tcx>,
32 ambient_variance: ty::Variance,
33 directions: &'a mut LiveRegionVariances,
34 universal_regions: &'a UniversalRegions<'tcx>,
35}
36
37impl<'tcx> VarianceExtractor<'_, 'tcx> {
38 fn record_variance(&mut self, region: ty::Region<'tcx>, variance: ty::Variance) {
39 if region.is_bound() {
49 return;
51 }
52
53 if region.is_erased() {
54 return;
61 }
62
63 let direction = match variance {
64 ty::Covariant => ConstraintDirection::Forward,
65 ty::Contravariant => ConstraintDirection::Backward,
66 ty::Invariant => ConstraintDirection::Bidirectional,
67 ty::Bivariant => {
68 return;
70 }
71 };
72
73 let region = self.universal_regions.to_region_vid(region);
74 let entry = self.directions.ensure_contains_elem(region, || None);
75 *entry = match *entry {
76 Some(existing) if existing != direction => Some(ConstraintDirection::Bidirectional),
80 _ => Some(direction),
81 };
82 }
83}
84
85impl<'tcx> TypeRelation<TyCtxt<'tcx>> for VarianceExtractor<'_, 'tcx> {
86 fn cx(&self) -> TyCtxt<'tcx> {
87 self.tcx
88 }
89
90 fn relate_ty_args(
91 &mut self,
92 a_ty: Ty<'tcx>,
93 _: Ty<'tcx>,
94 def_id: DefId,
95 a_args: ty::GenericArgsRef<'tcx>,
96 b_args: ty::GenericArgsRef<'tcx>,
97 _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
98 ) -> RelateResult<'tcx, Ty<'tcx>> {
99 let variances = self.cx().variances_of(def_id);
100 relate_args_with_variances(self, variances, a_args, b_args)?;
101 Ok(a_ty)
102 }
103
104 fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
105 &mut self,
106 variance: ty::Variance,
107 _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
108 a: T,
109 b: T,
110 ) -> RelateResult<'tcx, T> {
111 let old_ambient_variance = self.ambient_variance;
112 self.ambient_variance = self.ambient_variance.xform(variance);
113 let r = self.relate(a, b)?;
114 self.ambient_variance = old_ambient_variance;
115 Ok(r)
116 }
117
118 fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
119 {
match (&a, &b) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(a, b); relate::structurally_relate_tys(self, a, b)
121 }
122
123 fn regions(
124 &mut self,
125 a: ty::Region<'tcx>,
126 b: ty::Region<'tcx>,
127 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
128 {
match (&a, &b) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(a, b); self.record_variance(a, self.ambient_variance);
130 Ok(a)
131 }
132
133 fn consts(
134 &mut self,
135 a: ty::Const<'tcx>,
136 b: ty::Const<'tcx>,
137 ) -> RelateResult<'tcx, ty::Const<'tcx>> {
138 {
match (&a, &b) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(a, b); relate::structurally_relate_consts(self, a, b)
140 }
141
142 fn binders<T>(
143 &mut self,
144 a: ty::Binder<'tcx, T>,
145 _: ty::Binder<'tcx, T>,
146 ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
147 where
148 T: Relate<TyCtxt<'tcx>>,
149 {
150 self.relate(a.skip_binder(), a.skip_binder())?;
151 Ok(a)
152 }
153}