rustc_infer/infer/relate/
lattice.rs1use rustc_hir::def_id::DefId;
21use rustc_middle::traits::solve::Goal;
22use rustc_middle::ty::relate::combine::{combine_ty_args, super_combine_consts, super_combine_tys};
23use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
24use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt};
25use rustc_span::Span;
26use tracing::{debug, instrument};
27
28use super::StructurallyRelateAliases;
29use super::combine::PredicateEmittingRelation;
30use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace};
31use crate::traits::{Obligation, PredicateObligations};
32
33#[derive(Clone, Copy)]
34pub(crate) enum LatticeOpKind {
35 Glb,
36 Lub,
37}
38
39impl LatticeOpKind {
40 fn invert(self) -> Self {
41 match self {
42 LatticeOpKind::Glb => LatticeOpKind::Lub,
43 LatticeOpKind::Lub => LatticeOpKind::Glb,
44 }
45 }
46}
47
48pub(crate) struct LatticeOp<'infcx, 'tcx> {
50 infcx: &'infcx InferCtxt<'tcx>,
51 trace: TypeTrace<'tcx>,
53 param_env: ty::ParamEnv<'tcx>,
54 kind: LatticeOpKind,
56 obligations: PredicateObligations<'tcx>,
57}
58
59impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> {
60 pub(crate) fn new(
61 infcx: &'infcx InferCtxt<'tcx>,
62 trace: TypeTrace<'tcx>,
63 param_env: ty::ParamEnv<'tcx>,
64 kind: LatticeOpKind,
65 ) -> LatticeOp<'infcx, 'tcx> {
66 LatticeOp { infcx, trace, param_env, kind, obligations: PredicateObligations::new() }
67 }
68
69 pub(crate) fn into_obligations(self) -> PredicateObligations<'tcx> {
70 self.obligations
71 }
72}
73
74impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, 'tcx> {
75 fn cx(&self) -> TyCtxt<'tcx> {
76 self.infcx.tcx
77 }
78
79 fn relate_ty_args(
80 &mut self,
81 a_ty: Ty<'tcx>,
82 b_ty: Ty<'tcx>,
83 def_id: DefId,
84 a_args: ty::GenericArgsRef<'tcx>,
85 b_args: ty::GenericArgsRef<'tcx>,
86 mk: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
87 ) -> RelateResult<'tcx, Ty<'tcx>> {
88 let variances = self.cx().variances_of(def_id);
89 combine_ty_args(self.infcx, self, a_ty, b_ty, variances, a_args, b_args, |args| mk(args))
90 }
91
92 fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
93 &mut self,
94 variance: ty::Variance,
95 _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
96 a: T,
97 b: T,
98 ) -> RelateResult<'tcx, T> {
99 match variance {
100 ty::Invariant => {
101 self.obligations.extend(
102 self.infcx
103 .at(&self.trace.cause, self.param_env)
104 .eq_trace(DefineOpaqueTypes::Yes, self.trace.clone(), a, b)?
105 .into_obligations(),
106 );
107 Ok(a)
108 }
109 ty::Covariant => self.relate(a, b),
110 ty::Bivariant => Ok(a),
112 ty::Contravariant => {
113 self.kind = self.kind.invert();
114 let res = self.relate(a, b);
115 self.kind = self.kind.invert();
116 res
117 }
118 }
119 }
120
121 #[instrument(skip(self), level = "trace")]
123 fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
124 if a == b {
125 return Ok(a);
126 }
127
128 let infcx = self.infcx;
129
130 let a = infcx.shallow_resolve(a);
131 let b = infcx.shallow_resolve(b);
132
133 match (a.kind(), b.kind()) {
134 (&ty::Infer(TyVar(..)), _) => {
153 let v = infcx.next_ty_var(self.trace.cause.span);
154 self.relate_bound(v, b, a)?;
155 Ok(v)
156 }
157 (_, &ty::Infer(TyVar(..))) => {
158 let v = infcx.next_ty_var(self.trace.cause.span);
159 self.relate_bound(v, a, b)?;
160 Ok(v)
161 }
162
163 (
164 &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
165 &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
166 ) if a_def_id == b_def_id => super_combine_tys(infcx, self, a, b),
167
168 (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
169 | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
170 if def_id.is_local() && !infcx.next_trait_solver() =>
171 {
172 self.register_goals(infcx.handle_opaque_type(
173 a,
174 b,
175 self.span(),
176 self.param_env(),
177 )?);
178 Ok(a)
179 }
180
181 _ => super_combine_tys(infcx, self, a, b),
182 }
183 }
184
185 #[instrument(skip(self), level = "trace")]
186 fn regions(
187 &mut self,
188 a: ty::Region<'tcx>,
189 b: ty::Region<'tcx>,
190 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
191 let origin = SubregionOrigin::Subtype(Box::new(self.trace.clone()));
192 let mut inner = self.infcx.inner.borrow_mut();
193 let mut constraints = inner.unwrap_region_constraints();
194 Ok(match self.kind {
195 LatticeOpKind::Glb => constraints.lub_regions(self.cx(), origin, a, b),
197
198 LatticeOpKind::Lub => constraints.glb_regions(self.cx(), origin, a, b),
200 })
201 }
202
203 #[instrument(skip(self), level = "trace")]
204 fn consts(
205 &mut self,
206 a: ty::Const<'tcx>,
207 b: ty::Const<'tcx>,
208 ) -> RelateResult<'tcx, ty::Const<'tcx>> {
209 super_combine_consts(self.infcx, self, a, b)
210 }
211
212 fn binders<T>(
213 &mut self,
214 a: ty::Binder<'tcx, T>,
215 b: ty::Binder<'tcx, T>,
216 ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
217 where
218 T: Relate<TyCtxt<'tcx>>,
219 {
220 if a == b {
222 return Ok(a);
223 }
224
225 debug!("binders(a={:?}, b={:?})", a, b);
226 if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
227 self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
231 Ok(a)
232 } else {
233 Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
234 }
235 }
236}
237
238impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> {
239 fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
246 let at = self.infcx.at(&self.trace.cause, self.param_env);
247 match self.kind {
248 LatticeOpKind::Glb => {
249 self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, a)?.into_obligations());
250 self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, b)?.into_obligations());
251 }
252 LatticeOpKind::Lub => {
253 self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, a, v)?.into_obligations());
254 self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, b, v)?.into_obligations());
255 }
256 }
257 Ok(())
258 }
259}
260
261impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for LatticeOp<'_, 'tcx> {
262 fn span(&self) -> Span {
263 self.trace.span()
264 }
265
266 fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
267 StructurallyRelateAliases::No
268 }
269
270 fn param_env(&self) -> ty::ParamEnv<'tcx> {
271 self.param_env
272 }
273
274 fn register_predicates(
275 &mut self,
276 preds: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
277 ) {
278 self.obligations.extend(preds.into_iter().map(|pred| {
279 Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, pred)
280 }))
281 }
282
283 fn register_goals(&mut self, goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>) {
284 self.obligations.extend(goals.into_iter().map(|goal| {
285 Obligation::new(
286 self.infcx.tcx,
287 self.trace.cause.clone(),
288 goal.param_env,
289 goal.predicate,
290 )
291 }))
292 }
293
294 fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
295 self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
296 a.into(),
297 b.into(),
298 ty::AliasRelationDirection::Equate,
300 ))]);
301 }
302}