Skip to main content

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    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_type_ir/src/relate/combine.rs:56",
                        "rustc_type_ir::relate::combine", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_type_ir/src/relate/combine.rs"),
                        ::tracing_core::__macro_support::Option::Some(56u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::relate::combine"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("super_combine_tys::<{0}>({1:?}, {2:?})",
                                                    std::any::type_name::<R>(), a, b) as &dyn Value))])
            });
    } else { ; }
};debug!("super_combine_tys::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
57    if true {
    if !!a.has_escaping_bound_vars() {
        ::core::panicking::panic("assertion failed: !a.has_escaping_bound_vars()")
    };
};debug_assert!(!a.has_escaping_bound_vars());
58    if true {
    if !!b.has_escaping_bound_vars() {
        ::core::panicking::panic("assertion failed: !b.has_escaping_bound_vars()")
    };
};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            {
    ::core::panicking::panic_fmt(format_args!("We do not expect to encounter `TyVar` this late in combine -- they should have been handled earlier"));
}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            {
    ::core::panicking::panic_fmt(format_args!("We do not expect to encounter `Fresh` variables in the new solver"));
}panic!("We do not expect to encounter `Fresh` variables in the new solver")
116        }
117
118        (ty::Alias(is_rigid_a, _), ty::Alias(is_rigid_b, _)) if infcx.next_trait_solver() => {
119            match (is_rigid_a, is_rigid_b) {
120                (ty::IsRigid::Yes, ty::IsRigid::Yes) => structurally_relate_tys(relation, a, b),
121                _ => match relation.structurally_relate_aliases() {
122                    StructurallyRelateAliases::Yes => structurally_relate_tys(relation, a, b),
123                    StructurallyRelateAliases::No => {
124                        relation.register_alias_relate_predicate(a, b);
125                        Ok(a)
126                    }
127                },
128            }
129        }
130
131        (other, ty::Alias(is_rigid, _)) | (ty::Alias(is_rigid, _), other)
132            if infcx.next_trait_solver() =>
133        {
134            if let StructurallyRelateAliases::No = relation.structurally_relate_aliases()
135                && is_rigid == ty::IsRigid::No
136            {
137                relation.register_alias_relate_predicate(a, b);
138                Ok(a)
139            } else {
140                match other {
141                    ty::Infer(infer_ty) => match infer_ty {
142                        // Normally, we shouldn't be combining an infer ty with an alias here. But
143                        // when we evaluate a `Projection(assoc_ty, expected)` goal, we normalize
144                        // the projection term and structurally equate it with the expected term. If
145                        // the normalized term is an alias type and the expected term is a ty var,
146                        // the ty var just instantiated with the alias type without combining them.
147                        // However, if the expected term is either an int var or a float var, e.g.,
148                        // when the expected term is an int literal that only can be fully inferred
149                        // after the fallback, they are passed to this function because int/float
150                        // vars can't be instantiated. As we can't structurally relate infer ty with
151                        // another type, we just error them out here instead.
152                        ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_) => {
153                            Err(TypeError::Sorts(ExpectedFound::new(a, b)))
154                        }
155
156                        ty::InferTy::TyVar(_)
157                        | ty::InferTy::FreshTy(_)
158                        | ty::InferTy::FreshIntTy(_)
159                        | ty::InferTy::FreshFloatTy(_) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
160                    },
161                    _ => structurally_relate_tys(relation, a, b),
162                }
163            }
164        }
165
166        // All other cases of inference are errors
167        (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Sorts(ExpectedFound::new(a, b))),
168
169        (ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }), _)
170        | (_, ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. })) => {
171            if !!infcx.next_trait_solver() {
    ::core::panicking::panic("assertion failed: !infcx.next_trait_solver()")
};assert!(!infcx.next_trait_solver());
172            match infcx.typing_mode_raw().assert_not_erased() {
173                // During coherence, opaque types should be treated as *possibly*
174                // equal to any other type. This is an
175                // extremely heavy hammer, but can be relaxed in a forwards-compatible
176                // way later.
177                TypingMode::Coherence => {
178                    relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
179                    Ok(a)
180                }
181                TypingMode::Typeck { .. }
182                | TypingMode::PostTypeckUntilBorrowck { .. }
183                | TypingMode::PostBorrowck { .. }
184                | TypingMode::PostAnalysis
185                | TypingMode::Codegen => structurally_relate_tys(relation, a, b),
186            }
187        }
188
189        _ => structurally_relate_tys(relation, a, b),
190    }
191}
192
193pub fn super_combine_consts<Infcx, I, R>(
194    infcx: &Infcx,
195    relation: &mut R,
196    a: I::Const,
197    b: I::Const,
198) -> RelateResult<I, I::Const>
199where
200    Infcx: InferCtxtLike<Interner = I>,
201    I: Interner,
202    R: PredicateEmittingRelation<Infcx>,
203{
204    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_type_ir/src/relate/combine.rs:204",
                        "rustc_type_ir::relate::combine", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_type_ir/src/relate/combine.rs"),
                        ::tracing_core::__macro_support::Option::Some(204u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::relate::combine"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("super_combine_consts::<{0}>({1:?}, {2:?})",
                                                    std::any::type_name::<R>(), a, b) as &dyn Value))])
            });
    } else { ; }
};debug!("super_combine_consts::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
205    if true {
    if !!a.has_escaping_bound_vars() {
        ::core::panicking::panic("assertion failed: !a.has_escaping_bound_vars()")
    };
};debug_assert!(!a.has_escaping_bound_vars());
206    if true {
    if !!b.has_escaping_bound_vars() {
        ::core::panicking::panic("assertion failed: !b.has_escaping_bound_vars()")
    };
};debug_assert!(!b.has_escaping_bound_vars());
207
208    if a == b {
209        return Ok(a);
210    }
211
212    let a = infcx.shallow_resolve_const(a);
213    let b = infcx.shallow_resolve_const(b);
214
215    match (a.kind(), b.kind()) {
216        (
217            ty::ConstKind::Infer(ty::InferConst::Var(a_vid)),
218            ty::ConstKind::Infer(ty::InferConst::Var(b_vid)),
219        ) => {
220            infcx.equate_const_vids_raw(a_vid, b_vid);
221            Ok(a)
222        }
223
224        // All other cases of inference with other variables are errors.
225        (ty::ConstKind::Infer(ty::InferConst::Var(_)), ty::ConstKind::Infer(_))
226        | (ty::ConstKind::Infer(_), ty::ConstKind::Infer(ty::InferConst::Var(_))) => {
227            {
    ::core::panicking::panic_fmt(format_args!("tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {0:?} and {1:?}",
            a, b));
}panic!(
228                "tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}"
229            )
230        }
231
232        (ty::ConstKind::Infer(ty::InferConst::Var(vid)), _) => {
233            infcx.instantiate_const_var_raw(relation, true, vid, b)?;
234            Ok(b)
235        }
236
237        (_, ty::ConstKind::Infer(ty::InferConst::Var(vid))) => {
238            infcx.instantiate_const_var_raw(relation, false, vid, a)?;
239            Ok(a)
240        }
241
242        (
243            ty::ConstKind::Unevaluated(ty::IsRigid::Yes, _),
244            ty::ConstKind::Unevaluated(ty::IsRigid::Yes, _),
245        ) if (infcx.cx().features().generic_const_exprs() || infcx.next_trait_solver()) => {
246            structurally_relate_consts(relation, a, b)
247        }
248
249        (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
250            if infcx.cx().features().generic_const_exprs() || infcx.next_trait_solver() =>
251        {
252            match relation.structurally_relate_aliases() {
253                StructurallyRelateAliases::No => {
254                    relation.register_predicates([if infcx.next_trait_solver() {
255                        ty::PredicateKind::AliasRelate(
256                            a.into(),
257                            b.into(),
258                            ty::AliasRelationDirection::Equate,
259                        )
260                    } else {
261                        ty::PredicateKind::ConstEquate(a, b)
262                    }]);
263
264                    Ok(b)
265                }
266                StructurallyRelateAliases::Yes => structurally_relate_consts(relation, a, b),
267            }
268        }
269        _ => structurally_relate_consts(relation, a, b),
270    }
271}
272
273pub fn combine_ty_args<Infcx, I, R>(
274    infcx: &Infcx,
275    relation: &mut R,
276    a_ty: I::Ty,
277    b_ty: I::Ty,
278    variances: I::VariancesOf,
279    a_args: I::GenericArgs,
280    b_args: I::GenericArgs,
281    mk: impl FnOnce(I::GenericArgs) -> I::Ty,
282) -> RelateResult<I, I::Ty>
283where
284    Infcx: InferCtxtLike<Interner = I>,
285    I: Interner,
286    R: PredicateEmittingRelation<Infcx>,
287{
288    let cx = infcx.cx();
289    let mut has_unconstrained_bivariant_arg = false;
290    let args = iter::zip(a_args.iter(), b_args.iter()).enumerate().map(|(i, (a, b))| {
291        let variance = variances.get(i).unwrap();
292        let variance_info = match variance {
293            ty::Invariant => {
294                VarianceDiagInfo::Invariant { ty: a_ty, param_index: i.try_into().unwrap() }
295            }
296            ty::Covariant | ty::Contravariant => VarianceDiagInfo::default(),
297            ty::Bivariant => {
298                let has_non_region_infer = |arg: I::GenericArg| {
299                    arg.has_non_region_infer()
300                        && infcx.resolve_vars_if_possible(arg).has_non_region_infer()
301                };
302                if has_non_region_infer(a) || has_non_region_infer(b) {
303                    has_unconstrained_bivariant_arg = true;
304                }
305                VarianceDiagInfo::default()
306            }
307        };
308        relation.relate_with_variance(variance, variance_info, a, b)
309    });
310    let args = cx.mk_args_from_iter(args)?;
311
312    // In general, we do not check whether all types which occur during
313    // type checking are well-formed. We only check wf of user-provided types
314    // and when actually using a type, e.g. for method calls.
315    //
316    // This means that when subtyping, we may end up with unconstrained
317    // inference variables if a generalized type has bivariant parameters.
318    // A parameter may only be bivariant if it is constrained by a projection
319    // bound in a where-clause. As an example, imagine a type:
320    //
321    //     struct Foo<A, B> where A: Iterator<Item = B> {
322    //         data: A
323    //     }
324    //
325    // here, `A` will be covariant, but `B` is unconstrained. However, whatever it is,
326    // for `Foo` to be WF, it must be equal to `A::Item`.
327    //
328    // If we have an input `Foo<?A, ?B>`, then after generalization we will wind
329    // up with a type like `Foo<?C, ?D>`. When we enforce `Foo<?A, ?B> <: Foo<?C, ?D>`,
330    // we will wind up with the requirement that `?A <: ?C`, but no particular
331    // relationship between `?B` and `?D` (after all, these types may be completely
332    // different). If we do nothing else, this may mean that `?D` goes unconstrained
333    // (as in #41677). To avoid this we emit a `WellFormed` when relating types with
334    // bivariant arguments.
335    if has_unconstrained_bivariant_arg {
336        relation.register_predicates([
337            ty::ClauseKind::WellFormed(a_ty.into()),
338            ty::ClauseKind::WellFormed(b_ty.into()),
339        ]);
340    }
341
342    if a_args == args { Ok(a_ty) } else { Ok(mk(args)) }
343}