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