rustc_type_ir/relate/
combine.rs

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    /// Whether aliases should be related structurally. This is pretty much
27    /// always `No` unless you're equating in some specific locations of the
28    /// new solver. See the comments in these use-cases for more details.
29    fn structurally_relate_aliases(&self) -> StructurallyRelateAliases;
30
31    /// Register obligations that must hold in order for this relation to hold
32    fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>);
33
34    /// Register predicates that must hold in order for this relation to hold.
35    /// This uses the default `param_env` of the obligation.
36    fn register_predicates(
37        &mut self,
38        obligations: impl IntoIterator<Item: Upcast<I, I::Predicate>>,
39    );
40
41    /// Register `AliasRelate` obligation(s) that both types must be related to each other.
42    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        // Relate integral variables to other types
67        (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        // Relate floating-point variables to other types
89        (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        // We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm.
103        (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        // All other cases of inference are errors
129        (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                // During coherence, opaque types should be treated as *possibly*
135                // equal to any other type. This is an
136                // extremely heavy hammer, but can be relaxed in a forwards-compatible
137                // way later.
138                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        // All other cases of inference with other variables are errors.
185        (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    // In general, we do not check whether all types which occur during
266    // type checking are well-formed. We only check wf of user-provided types
267    // and when actually using a type, e.g. for method calls.
268    //
269    // This means that when subtyping, we may end up with unconstrained
270    // inference variables if a generalized type has bivariant parameters.
271    // A parameter may only be bivariant if it is constrained by a projection
272    // bound in a where-clause. As an example, imagine a type:
273    //
274    //     struct Foo<A, B> where A: Iterator<Item = B> {
275    //         data: A
276    //     }
277    //
278    // here, `A` will be covariant, but `B` is unconstrained. However, whatever it is,
279    // for `Foo` to be WF, it must be equal to `A::Item`.
280    //
281    // If we have an input `Foo<?A, ?B>`, then after generalization we will wind
282    // up with a type like `Foo<?C, ?D>`. When we enforce `Foo<?A, ?B> <: Foo<?C, ?D>`,
283    // we will wind up with the requirement that `?A <: ?C`, but no particular
284    // relationship between `?B` and `?D` (after all, these types may be completely
285    // different). If we do nothing else, this may mean that `?D` goes unconstrained
286    // (as in #41677). To avoid this we emit a `WellFormed` when relating types with
287    // bivariant arguments.
288    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}