1use hir_def::{
17 AdtId, GenericDefId, GenericParamId, VariantId,
18 signatures::{StructFlags, StructSignature},
19};
20use rustc_ast_ir::Mutability;
21use rustc_type_ir::{Variance, inherent::IntoKind};
22use stdx::never;
23
24use crate::{
25 db::HirDatabase,
26 generics::{Generics, generics},
27 next_solver::{
28 Const, ConstKind, ExistentialPredicate, GenericArgKind, GenericArgs, Pattern, PatternKind,
29 Region, RegionKind, StoredVariancesOf, TermKind, Ty, TyKind, VariancesOf,
30 },
31};
32
33pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> VariancesOf<'_> {
34 variances_of_query(db, def).as_ref()
35}
36
37#[salsa::tracked(
38 returns(ref),
39 cycle_fn = crate::variance::variances_of_cycle_fn,
40 cycle_initial = crate::variance::variances_of_cycle_initial,
41)]
42fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariancesOf {
43 tracing::debug!("variances_of(def={:?})", def);
44 match def {
45 GenericDefId::FunctionId(_) => (),
46 GenericDefId::AdtId(adt) => {
47 if let AdtId::StructId(id) = adt {
48 let flags = &StructSignature::of(db, id).flags;
49 let types = || crate::next_solver::default_types();
50 if flags.contains(StructFlags::IS_UNSAFE_CELL) {
51 return types().one_invariant.store();
52 } else if flags.intersects(
53 StructFlags::IS_PHANTOM_DATA | StructFlags::IS_COVARIANT_UNSAFE_CELL,
54 ) {
55 return types().one_covariant.store();
56 }
57 }
58 }
59 _ => return VariancesOf::empty().store(),
60 }
61
62 let generics = generics(db, def);
63 let count = generics.len(true);
64 if count == 0 {
65 return VariancesOf::empty().store();
66 }
67 let variances =
68 Context { generics, variances: vec![Variance::Bivariant; count].into_boxed_slice(), db }
69 .solve();
70
71 VariancesOf::new_from_slice(&variances).store()
72}
73
74pub(crate) fn variances_of_cycle_fn(
75 _db: &dyn HirDatabase,
76 _: &salsa::Cycle<'_>,
77 _last_provisional_value: &StoredVariancesOf,
78 value: StoredVariancesOf,
79 _def: GenericDefId,
80) -> StoredVariancesOf {
81 value
82}
83
84fn glb(v1: Variance, v2: Variance) -> Variance {
85 match (v1, v2) {
91 (Variance::Invariant, _) | (_, Variance::Invariant) => Variance::Invariant,
92
93 (Variance::Covariant, Variance::Contravariant) => Variance::Invariant,
94 (Variance::Contravariant, Variance::Covariant) => Variance::Invariant,
95
96 (Variance::Covariant, Variance::Covariant) => Variance::Covariant,
97
98 (Variance::Contravariant, Variance::Contravariant) => Variance::Contravariant,
99
100 (x, Variance::Bivariant) | (Variance::Bivariant, x) => x,
101 }
102}
103
104pub(crate) fn variances_of_cycle_initial(
105 db: &dyn HirDatabase,
106 _: salsa::Id,
107 def: GenericDefId,
108) -> StoredVariancesOf {
109 let generics = generics(db, def);
110 let count = generics.len(true);
111
112 VariancesOf::new_from_iter(std::iter::repeat_n(Variance::Bivariant, count)).store()
113}
114
115struct Context<'db> {
116 db: &'db dyn HirDatabase,
117 generics: Generics<'db>,
118 variances: Box<[Variance]>,
119}
120
121impl<'db> Context<'db> {
122 fn solve(mut self) -> Box<[Variance]> {
123 tracing::debug!("solve(generics={:?})", self.generics);
124 match self.generics.def() {
125 GenericDefId::AdtId(adt) => {
126 let db = self.db;
127 let mut add_constraints_from_variant = |variant| {
128 for (_, field) in db.field_types(variant).iter() {
129 self.add_constraints_from_ty(
130 field.ty().instantiate_identity().skip_norm_wip(),
131 Variance::Covariant,
132 );
133 }
134 };
135 match adt {
136 AdtId::StructId(s) => add_constraints_from_variant(VariantId::StructId(s)),
137 AdtId::UnionId(u) => add_constraints_from_variant(VariantId::UnionId(u)),
138 AdtId::EnumId(e) => {
139 e.enum_variants(db).variants.values().for_each(|&(variant, _)| {
140 add_constraints_from_variant(VariantId::EnumVariantId(variant))
141 });
142 }
143 }
144 }
145 GenericDefId::FunctionId(f) => {
146 let sig =
147 self.db.callable_item_signature(f.into()).instantiate_identity().skip_binder();
148 self.add_constraints_from_sig(sig.inputs_and_output.iter(), Variance::Covariant);
149 }
150 _ => {}
151 }
152 let mut variances = self.variances;
153
154 for (idx, param) in self.generics.iter_id(false).enumerate() {
157 if let GenericParamId::ConstParamId(_) = param {
158 variances[idx] = Variance::Invariant;
159 }
160 }
161
162 if let GenericDefId::FunctionId(_) = self.generics.def() {
164 variances
165 .iter_mut()
166 .filter(|&&mut v| v == Variance::Bivariant)
167 .for_each(|v| *v = Variance::Invariant);
168 }
169
170 variances
171 }
172
173 fn add_constraints_from_ty(&mut self, ty: Ty<'db>, variance: Variance) {
177 tracing::debug!("add_constraints_from_ty(ty={:?}, variance={:?})", ty, variance);
178 match ty.kind() {
179 TyKind::Int(_)
180 | TyKind::Uint(_)
181 | TyKind::Float(_)
182 | TyKind::Char
183 | TyKind::Bool
184 | TyKind::Never
185 | TyKind::Str
186 | TyKind::Foreign(..) => {
187 }
189 TyKind::FnDef(..)
190 | TyKind::Coroutine(..)
191 | TyKind::CoroutineClosure(..)
192 | TyKind::Closure(..) => {
193 never!("Unexpected unnameable type in variance computation: {:?}", ty);
194 }
195 TyKind::Ref(lifetime, ty, mutbl) => {
196 self.add_constraints_from_region(lifetime, variance);
197 self.add_constraints_from_mt(ty, mutbl, variance);
198 }
199 TyKind::Array(typ, len) => {
200 self.add_constraints_from_const(len);
201 self.add_constraints_from_ty(typ, variance);
202 }
203 TyKind::Slice(typ) => {
204 self.add_constraints_from_ty(typ, variance);
205 }
206 TyKind::RawPtr(ty, mutbl) => {
207 self.add_constraints_from_mt(ty, mutbl, variance);
208 }
209 TyKind::Tuple(subtys) => {
210 for subty in subtys {
211 self.add_constraints_from_ty(subty, variance);
212 }
213 }
214 TyKind::Adt(def, args) => {
215 self.add_constraints_from_args(def.def_id().into(), args, variance);
216 }
217 TyKind::Alias(alias) => {
218 self.add_constraints_from_invariant_args(alias.args);
220 }
221 TyKind::Dynamic(bounds, region) => {
222 self.add_constraints_from_region(region, variance);
224
225 for bound in bounds {
226 match bound.skip_binder() {
227 ExistentialPredicate::Trait(trait_ref) => {
228 self.add_constraints_from_invariant_args(trait_ref.args)
229 }
230 ExistentialPredicate::Projection(projection) => {
231 self.add_constraints_from_invariant_args(projection.args);
232 match projection.term.kind() {
233 TermKind::Ty(ty) => {
234 self.add_constraints_from_ty(ty, Variance::Invariant)
235 }
236 TermKind::Const(konst) => self.add_constraints_from_const(konst),
237 }
238 }
239 ExistentialPredicate::AutoTrait(_) => {}
240 }
241 }
242 }
243
244 TyKind::Param(param) => self.constrain(param.index as usize, variance),
246 TyKind::FnPtr(sig, _) => {
247 self.add_constraints_from_sig(sig.skip_binder().inputs_and_output.iter(), variance);
248 }
249 TyKind::Error(_) => {
250 }
253 TyKind::Pat(typ, pat) => {
254 self.add_constraints_from_pat(pat);
255 self.add_constraints_from_ty(typ, variance);
256 }
257 TyKind::Bound(..) => {}
258 TyKind::CoroutineWitness(..)
259 | TyKind::Placeholder(..)
260 | TyKind::Infer(..)
261 | TyKind::UnsafeBinder(..) => {
262 never!("unexpected type encountered in variance inference: {:?}", ty)
263 }
264 }
265 }
266
267 fn add_constraints_from_pat(&mut self, pat: Pattern<'db>) {
268 match pat.kind() {
269 PatternKind::Range { start, end } => {
270 self.add_constraints_from_const(start);
271 self.add_constraints_from_const(end);
272 }
273 PatternKind::NotNull => {}
274 PatternKind::Or(patterns) => {
275 for pat in patterns {
276 self.add_constraints_from_pat(pat)
277 }
278 }
279 }
280 }
281
282 fn add_constraints_from_invariant_args(&mut self, args: GenericArgs<'db>) {
283 for k in args.iter() {
284 match k.kind() {
285 GenericArgKind::Lifetime(lt) => {
286 self.add_constraints_from_region(lt, Variance::Invariant)
287 }
288 GenericArgKind::Type(ty) => self.add_constraints_from_ty(ty, Variance::Invariant),
289 GenericArgKind::Const(val) => self.add_constraints_from_const(val),
290 }
291 }
292 }
293
294 fn add_constraints_from_args(
297 &mut self,
298 def_id: GenericDefId,
299 args: GenericArgs<'db>,
300 variance: Variance,
301 ) {
302 if args.is_empty() {
303 return;
304 }
305 let variances = self.db.variances_of(def_id);
306
307 for (k, v) in args.iter().zip(variances) {
308 match k.kind() {
309 GenericArgKind::Lifetime(lt) => {
310 self.add_constraints_from_region(lt, variance.xform(v))
311 }
312 GenericArgKind::Type(ty) => self.add_constraints_from_ty(ty, variance.xform(v)),
313 GenericArgKind::Const(val) => self.add_constraints_from_const(val),
314 }
315 }
316 }
317
318 fn add_constraints_from_const(&mut self, c: Const<'db>) {
321 match c.kind() {
322 ConstKind::Unevaluated(c) => self.add_constraints_from_invariant_args(c.args),
323 _ => {}
324 }
325 }
326
327 fn add_constraints_from_sig(
330 &mut self,
331 mut sig_tys: impl DoubleEndedIterator<Item = Ty<'db>>,
332 variance: Variance,
333 ) {
334 let contra = variance.xform(Variance::Contravariant);
335 let Some(output) = sig_tys.next_back() else {
336 return never!("function signature has no return type");
337 };
338 self.add_constraints_from_ty(output, variance);
339 for input in sig_tys {
340 self.add_constraints_from_ty(input, contra);
341 }
342 }
343
344 fn add_constraints_from_region(&mut self, region: Region<'db>, variance: Variance) {
347 tracing::debug!(
348 "add_constraints_from_region(region={:?}, variance={:?})",
349 region,
350 variance
351 );
352 match region.kind() {
353 RegionKind::ReEarlyParam(param) => self.constrain(param.index as usize, variance),
354 RegionKind::ReStatic => {}
355 RegionKind::ReBound(..) => {
356 }
361 RegionKind::ReError(_) => {}
362 RegionKind::ReLateParam(..)
363 | RegionKind::RePlaceholder(..)
364 | RegionKind::ReVar(..)
365 | RegionKind::ReErased => {
366 never!(
369 "unexpected region encountered in variance \
370 inference: {:?}",
371 region
372 );
373 }
374 }
375 }
376
377 fn add_constraints_from_mt(&mut self, ty: Ty<'db>, mt: Mutability, variance: Variance) {
380 self.add_constraints_from_ty(
381 ty,
382 match mt {
383 Mutability::Mut => Variance::Invariant,
384 Mutability::Not => variance,
385 },
386 );
387 }
388
389 fn constrain(&mut self, index: usize, variance: Variance) {
390 tracing::debug!(
391 "constrain(index={:?}, variance={:?}, to={:?})",
392 index,
393 self.variances[index],
394 variance
395 );
396 self.variances[index] = glb(self.variances[index], variance);
397 }
398}