1use std::iter;
2
3use tracing::debug;
4
5use super::{
6 ExpectedFound, RelateResult, StructurallyRelateAliases, TypeRelation,
7 structurally_relate_consts, structurally_relate_tys,
8};
9use crate::error::TypeError;
10use crate::inherent::*;
11use crate::relate::VarianceDiagInfo;
12use crate::solve::Goal;
13use crate::visit::TypeVisitableExt as _;
14use crate::{self as ty, InferCtxtLike, Interner, TypingMode, Upcast};
15
16pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>:
17 TypeRelation<I>
18where
19 Infcx: InferCtxtLike<Interner = I>,
20 I: Interner,
21{
22 fn span(&self) -> I::Span;
23
24 fn param_env(&self) -> I::ParamEnv;
25
26 fn structurally_relate_aliases(&self) -> StructurallyRelateAliases;
30
31 fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>);
33
34 fn register_predicates(
37 &mut self,
38 obligations: impl IntoIterator<Item: Upcast<I, I::Predicate>>,
39 );
40
41 fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty);
43}
44
45pub fn super_combine_tys<Infcx, I, R>(
46 infcx: &Infcx,
47 relation: &mut R,
48 a: I::Ty,
49 b: I::Ty,
50) -> RelateResult<I, I::Ty>
51where
52 Infcx: InferCtxtLike<Interner = I>,
53 I: Interner,
54 R: PredicateEmittingRelation<Infcx>,
55{
56 debug!("super_combine_tys::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
57 debug_assert!(!a.has_escaping_bound_vars());
58 debug_assert!(!b.has_escaping_bound_vars());
59
60 match (a.kind(), b.kind()) {
61 (ty::Error(e), _) | (_, ty::Error(e)) => {
62 infcx.set_tainted_by_errors(e);
63 return Ok(Ty::new_error(infcx.cx(), e));
64 }
65
66 (ty::Infer(ty::IntVar(a_id)), ty::Infer(ty::IntVar(b_id))) => {
68 infcx.equate_int_vids_raw(a_id, b_id);
69 Ok(a)
70 }
71 (ty::Infer(ty::IntVar(v_id)), ty::Int(v)) => {
72 infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v));
73 Ok(b)
74 }
75 (ty::Int(v), ty::Infer(ty::IntVar(v_id))) => {
76 infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v));
77 Ok(a)
78 }
79 (ty::Infer(ty::IntVar(v_id)), ty::Uint(v)) => {
80 infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v));
81 Ok(b)
82 }
83 (ty::Uint(v), ty::Infer(ty::IntVar(v_id))) => {
84 infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v));
85 Ok(a)
86 }
87
88 (ty::Infer(ty::FloatVar(a_id)), ty::Infer(ty::FloatVar(b_id))) => {
90 infcx.equate_float_vids_raw(a_id, b_id);
91 Ok(a)
92 }
93 (ty::Infer(ty::FloatVar(v_id)), ty::Float(v)) => {
94 infcx.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v));
95 Ok(b)
96 }
97 (ty::Float(v), ty::Infer(ty::FloatVar(v_id))) => {
98 infcx.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v));
99 Ok(a)
100 }
101
102 (ty::Alias(..), ty::Infer(ty::TyVar(_))) | (ty::Infer(ty::TyVar(_)), ty::Alias(..))
104 if infcx.next_trait_solver() =>
105 {
106 panic!(
107 "We do not expect to encounter `TyVar` this late in combine \
108 -- they should have been handled earlier"
109 )
110 }
111 (_, ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)))
112 | (ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)), _)
113 if infcx.next_trait_solver() =>
114 {
115 panic!("We do not expect to encounter `Fresh` variables in the new solver")
116 }
117
118 (_, ty::Alias(..)) | (ty::Alias(..), _) if infcx.next_trait_solver() => {
119 match relation.structurally_relate_aliases() {
120 StructurallyRelateAliases::Yes => structurally_relate_tys(relation, a, b),
121 StructurallyRelateAliases::No => {
122 relation.register_alias_relate_predicate(a, b);
123 Ok(a)
124 }
125 }
126 }
127
128 (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Sorts(ExpectedFound::new(a, b))),
130
131 (ty::Alias(ty::Opaque, _), _) | (_, ty::Alias(ty::Opaque, _)) => {
132 assert!(!infcx.next_trait_solver());
133 match infcx.typing_mode() {
134 TypingMode::Coherence => {
139 relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
140 Ok(a)
141 }
142 TypingMode::Analysis { .. }
143 | TypingMode::Borrowck { .. }
144 | TypingMode::PostBorrowckAnalysis { .. }
145 | TypingMode::PostAnalysis => structurally_relate_tys(relation, a, b),
146 }
147 }
148
149 _ => structurally_relate_tys(relation, a, b),
150 }
151}
152
153pub fn super_combine_consts<Infcx, I, R>(
154 infcx: &Infcx,
155 relation: &mut R,
156 a: I::Const,
157 b: I::Const,
158) -> RelateResult<I, I::Const>
159where
160 Infcx: InferCtxtLike<Interner = I>,
161 I: Interner,
162 R: PredicateEmittingRelation<Infcx>,
163{
164 debug!("super_combine_consts::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
165 debug_assert!(!a.has_escaping_bound_vars());
166 debug_assert!(!b.has_escaping_bound_vars());
167
168 if a == b {
169 return Ok(a);
170 }
171
172 let a = infcx.shallow_resolve_const(a);
173 let b = infcx.shallow_resolve_const(b);
174
175 match (a.kind(), b.kind()) {
176 (
177 ty::ConstKind::Infer(ty::InferConst::Var(a_vid)),
178 ty::ConstKind::Infer(ty::InferConst::Var(b_vid)),
179 ) => {
180 infcx.equate_const_vids_raw(a_vid, b_vid);
181 Ok(a)
182 }
183
184 (ty::ConstKind::Infer(ty::InferConst::Var(_)), ty::ConstKind::Infer(_))
186 | (ty::ConstKind::Infer(_), ty::ConstKind::Infer(ty::InferConst::Var(_))) => {
187 panic!(
188 "tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}"
189 )
190 }
191
192 (ty::ConstKind::Infer(ty::InferConst::Var(vid)), _) => {
193 infcx.instantiate_const_var_raw(relation, true, vid, b)?;
194 Ok(b)
195 }
196
197 (_, ty::ConstKind::Infer(ty::InferConst::Var(vid))) => {
198 infcx.instantiate_const_var_raw(relation, false, vid, a)?;
199 Ok(a)
200 }
201
202 (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
203 if infcx.cx().features().generic_const_exprs() || infcx.next_trait_solver() =>
204 {
205 match relation.structurally_relate_aliases() {
206 StructurallyRelateAliases::No => {
207 relation.register_predicates([if infcx.next_trait_solver() {
208 ty::PredicateKind::AliasRelate(
209 a.into(),
210 b.into(),
211 ty::AliasRelationDirection::Equate,
212 )
213 } else {
214 ty::PredicateKind::ConstEquate(a, b)
215 }]);
216
217 Ok(b)
218 }
219 StructurallyRelateAliases::Yes => structurally_relate_consts(relation, a, b),
220 }
221 }
222 _ => structurally_relate_consts(relation, a, b),
223 }
224}
225
226pub fn combine_ty_args<Infcx, I, R>(
227 infcx: &Infcx,
228 relation: &mut R,
229 a_ty: I::Ty,
230 b_ty: I::Ty,
231 variances: I::VariancesOf,
232 a_args: I::GenericArgs,
233 b_args: I::GenericArgs,
234 mk: impl FnOnce(I::GenericArgs) -> I::Ty,
235) -> RelateResult<I, I::Ty>
236where
237 Infcx: InferCtxtLike<Interner = I>,
238 I: Interner,
239 R: PredicateEmittingRelation<Infcx>,
240{
241 let cx = infcx.cx();
242 let mut has_unconstrained_bivariant_arg = false;
243 let args = iter::zip(a_args.iter(), b_args.iter()).enumerate().map(|(i, (a, b))| {
244 let variance = variances.get(i).unwrap();
245 let variance_info = match variance {
246 ty::Invariant => {
247 VarianceDiagInfo::Invariant { ty: a_ty, param_index: i.try_into().unwrap() }
248 }
249 ty::Covariant | ty::Contravariant => VarianceDiagInfo::default(),
250 ty::Bivariant => {
251 let has_non_region_infer = |arg: I::GenericArg| {
252 arg.has_non_region_infer()
253 && infcx.resolve_vars_if_possible(arg).has_non_region_infer()
254 };
255 if has_non_region_infer(a) || has_non_region_infer(b) {
256 has_unconstrained_bivariant_arg = true;
257 }
258 VarianceDiagInfo::default()
259 }
260 };
261 relation.relate_with_variance(variance, variance_info, a, b)
262 });
263 let args = cx.mk_args_from_iter(args)?;
264
265 if has_unconstrained_bivariant_arg {
289 relation.register_predicates([
290 ty::ClauseKind::WellFormed(a_ty.into()),
291 ty::ClauseKind::WellFormed(b_ty.into()),
292 ]);
293 }
294
295 if a_args == args { Ok(a_ty) } else { Ok(mk(args)) }
296}