rustc_type_ir/relate/
combine.rs

1use tracing::debug;
2
3use super::{
4    ExpectedFound, RelateResult, StructurallyRelateAliases, TypeRelation,
5    structurally_relate_consts, structurally_relate_tys,
6};
7use crate::error::TypeError;
8use crate::inherent::*;
9use crate::solve::Goal;
10use crate::visit::TypeVisitableExt as _;
11use crate::{self as ty, InferCtxtLike, Interner, TypingMode, Upcast};
12
13pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>:
14    TypeRelation<I>
15where
16    Infcx: InferCtxtLike<Interner = I>,
17    I: Interner,
18{
19    fn span(&self) -> I::Span;
20
21    fn param_env(&self) -> I::ParamEnv;
22
23    /// Whether aliases should be related structurally. This is pretty much
24    /// always `No` unless you're equating in some specific locations of the
25    /// new solver. See the comments in these use-cases for more details.
26    fn structurally_relate_aliases(&self) -> StructurallyRelateAliases;
27
28    /// Register obligations that must hold in order for this relation to hold
29    fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>);
30
31    /// Register predicates that must hold in order for this relation to hold.
32    /// This uses the default `param_env` of the obligation.
33    fn register_predicates(
34        &mut self,
35        obligations: impl IntoIterator<Item: Upcast<I, I::Predicate>>,
36    );
37
38    /// Register `AliasRelate` obligation(s) that both types must be related to each other.
39    fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty);
40}
41
42pub fn super_combine_tys<Infcx, I, R>(
43    infcx: &Infcx,
44    relation: &mut R,
45    a: I::Ty,
46    b: I::Ty,
47) -> RelateResult<I, I::Ty>
48where
49    Infcx: InferCtxtLike<Interner = I>,
50    I: Interner,
51    R: PredicateEmittingRelation<Infcx>,
52{
53    debug!("super_combine_tys::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
54    debug_assert!(!a.has_escaping_bound_vars());
55    debug_assert!(!b.has_escaping_bound_vars());
56
57    match (a.kind(), b.kind()) {
58        (ty::Error(e), _) | (_, ty::Error(e)) => {
59            infcx.set_tainted_by_errors(e);
60            return Ok(Ty::new_error(infcx.cx(), e));
61        }
62
63        // Relate integral variables to other types
64        (ty::Infer(ty::IntVar(a_id)), ty::Infer(ty::IntVar(b_id))) => {
65            infcx.equate_int_vids_raw(a_id, b_id);
66            Ok(a)
67        }
68        (ty::Infer(ty::IntVar(v_id)), ty::Int(v)) => {
69            infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v));
70            Ok(b)
71        }
72        (ty::Int(v), ty::Infer(ty::IntVar(v_id))) => {
73            infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v));
74            Ok(a)
75        }
76        (ty::Infer(ty::IntVar(v_id)), ty::Uint(v)) => {
77            infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v));
78            Ok(b)
79        }
80        (ty::Uint(v), ty::Infer(ty::IntVar(v_id))) => {
81            infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v));
82            Ok(a)
83        }
84
85        // Relate floating-point variables to other types
86        (ty::Infer(ty::FloatVar(a_id)), ty::Infer(ty::FloatVar(b_id))) => {
87            infcx.equate_float_vids_raw(a_id, b_id);
88            Ok(a)
89        }
90        (ty::Infer(ty::FloatVar(v_id)), ty::Float(v)) => {
91            infcx.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v));
92            Ok(b)
93        }
94        (ty::Float(v), ty::Infer(ty::FloatVar(v_id))) => {
95            infcx.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v));
96            Ok(a)
97        }
98
99        // We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm.
100        (ty::Alias(..), ty::Infer(ty::TyVar(_))) | (ty::Infer(ty::TyVar(_)), ty::Alias(..))
101            if infcx.next_trait_solver() =>
102        {
103            panic!(
104                "We do not expect to encounter `TyVar` this late in combine \
105                    -- they should have been handled earlier"
106            )
107        }
108        (_, ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)))
109        | (ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)), _)
110            if infcx.next_trait_solver() =>
111        {
112            panic!("We do not expect to encounter `Fresh` variables in the new solver")
113        }
114
115        (_, ty::Alias(..)) | (ty::Alias(..), _) if infcx.next_trait_solver() => {
116            match relation.structurally_relate_aliases() {
117                StructurallyRelateAliases::Yes => structurally_relate_tys(relation, a, b),
118                StructurallyRelateAliases::No => {
119                    relation.register_alias_relate_predicate(a, b);
120                    Ok(a)
121                }
122            }
123        }
124
125        // All other cases of inference are errors
126        (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Sorts(ExpectedFound::new(a, b))),
127
128        (ty::Alias(ty::Opaque, _), _) | (_, ty::Alias(ty::Opaque, _)) => {
129            assert!(!infcx.next_trait_solver());
130            match infcx.typing_mode() {
131                // During coherence, opaque types should be treated as *possibly*
132                // equal to any other type. This is an
133                // extremely heavy hammer, but can be relaxed in a forwards-compatible
134                // way later.
135                TypingMode::Coherence => {
136                    relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
137                    Ok(a)
138                }
139                TypingMode::Analysis { .. }
140                | TypingMode::PostBorrowckAnalysis { .. }
141                | TypingMode::PostAnalysis => structurally_relate_tys(relation, a, b),
142            }
143        }
144
145        _ => structurally_relate_tys(relation, a, b),
146    }
147}
148
149pub fn super_combine_consts<Infcx, I, R>(
150    infcx: &Infcx,
151    relation: &mut R,
152    a: I::Const,
153    b: I::Const,
154) -> RelateResult<I, I::Const>
155where
156    Infcx: InferCtxtLike<Interner = I>,
157    I: Interner,
158    R: PredicateEmittingRelation<Infcx>,
159{
160    debug!("super_combine_consts::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
161    debug_assert!(!a.has_escaping_bound_vars());
162    debug_assert!(!b.has_escaping_bound_vars());
163
164    if a == b {
165        return Ok(a);
166    }
167
168    let a = infcx.shallow_resolve_const(a);
169    let b = infcx.shallow_resolve_const(b);
170
171    match (a.kind(), b.kind()) {
172        (
173            ty::ConstKind::Infer(ty::InferConst::Var(a_vid)),
174            ty::ConstKind::Infer(ty::InferConst::Var(b_vid)),
175        ) => {
176            infcx.equate_const_vids_raw(a_vid, b_vid);
177            Ok(a)
178        }
179
180        // All other cases of inference with other variables are errors.
181        (ty::ConstKind::Infer(ty::InferConst::Var(_)), ty::ConstKind::Infer(_))
182        | (ty::ConstKind::Infer(_), ty::ConstKind::Infer(ty::InferConst::Var(_))) => {
183            panic!(
184                "tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}"
185            )
186        }
187
188        (ty::ConstKind::Infer(ty::InferConst::Var(vid)), _) => {
189            infcx.instantiate_const_var_raw(relation, true, vid, b)?;
190            Ok(b)
191        }
192
193        (_, ty::ConstKind::Infer(ty::InferConst::Var(vid))) => {
194            infcx.instantiate_const_var_raw(relation, false, vid, a)?;
195            Ok(a)
196        }
197
198        (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
199            if infcx.cx().features().generic_const_exprs() || infcx.next_trait_solver() =>
200        {
201            match relation.structurally_relate_aliases() {
202                StructurallyRelateAliases::No => {
203                    relation.register_predicates([if infcx.next_trait_solver() {
204                        ty::PredicateKind::AliasRelate(
205                            a.into(),
206                            b.into(),
207                            ty::AliasRelationDirection::Equate,
208                        )
209                    } else {
210                        ty::PredicateKind::ConstEquate(a, b)
211                    }]);
212
213                    Ok(b)
214                }
215                StructurallyRelateAliases::Yes => structurally_relate_consts(relation, a, b),
216            }
217        }
218        _ => structurally_relate_consts(relation, a, b),
219    }
220}