Skip to main content

rustc_type_ir/relate/
combine.rs

1use std::iter;
2
3use tracing::debug;
4
5use super::{
6    ExpectedFound, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys,
7};
8use crate::error::TypeError;
9use crate::inherent::*;
10use crate::relate::VarianceDiagInfo;
11use crate::solve::Goal;
12use crate::visit::TypeVisitableExt as _;
13use crate::{self as ty, InferCtxtLike, Interner, TypingMode, Upcast};
14
15pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>:
16    TypeRelation<I>
17where
18    Infcx: InferCtxtLike<Interner = I>,
19    I: Interner,
20{
21    fn span(&self) -> I::Span;
22
23    fn param_env(&self) -> I::ParamEnv;
24
25    /// Register obligations that must hold in order for this relation to hold
26    fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>);
27
28    /// Register predicates that must hold in order for this relation to hold.
29    /// This uses the default `param_env` of the obligation.
30    fn register_predicates(
31        &mut self,
32        obligations: impl IntoIterator<Item: Upcast<I, I::Predicate>>,
33    );
34}
35
36pub fn super_combine_tys<Infcx, I, R>(
37    infcx: &Infcx,
38    relation: &mut R,
39    a: I::Ty,
40    b: I::Ty,
41) -> RelateResult<I, I::Ty>
42where
43    Infcx: InferCtxtLike<Interner = I>,
44    I: Interner,
45    R: PredicateEmittingRelation<Infcx>,
46{
47    {
    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:47",
                        "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(47u32),
                        ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("super_combine_tys::<{0}>({1:?}, {2:?})",
                                                    std::any::type_name::<R>(), a, b) as
                                            &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("super_combine_tys::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
48    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());
49    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());
50
51    match (a.kind(), b.kind()) {
52        (ty::Error(e), _) | (_, ty::Error(e)) => {
53            infcx.set_tainted_by_errors(e);
54            return Ok(Ty::new_error(infcx.cx(), e));
55        }
56
57        // Relate integral variables to other types
58        (ty::Infer(ty::IntVar(a_id)), ty::Infer(ty::IntVar(b_id))) => {
59            infcx.equate_int_vids_raw(a_id, b_id);
60            Ok(a)
61        }
62        (ty::Infer(ty::IntVar(v_id)), ty::Int(v)) => {
63            infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v));
64            Ok(b)
65        }
66        (ty::Int(v), ty::Infer(ty::IntVar(v_id))) => {
67            infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v));
68            Ok(a)
69        }
70        (ty::Infer(ty::IntVar(v_id)), ty::Uint(v)) => {
71            infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v));
72            Ok(b)
73        }
74        (ty::Uint(v), ty::Infer(ty::IntVar(v_id))) => {
75            infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v));
76            Ok(a)
77        }
78
79        // Relate floating-point variables to other types
80        (ty::Infer(ty::FloatVar(a_id)), ty::Infer(ty::FloatVar(b_id))) => {
81            infcx.equate_float_vids_raw(a_id, b_id);
82            Ok(a)
83        }
84        (ty::Infer(ty::FloatVar(v_id)), ty::Float(v)) => {
85            infcx.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v));
86            Ok(b)
87        }
88        (ty::Float(v), ty::Infer(ty::FloatVar(v_id))) => {
89            infcx.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v));
90            Ok(a)
91        }
92
93        // We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm.
94        (ty::Alias(..), ty::Infer(ty::TyVar(_))) | (ty::Infer(ty::TyVar(_)), ty::Alias(..))
95            if infcx.next_trait_solver() =>
96        {
97            {
    ::core::panicking::panic_fmt(format_args!("We do not expect to encounter `TyVar` this late in combine -- they should have been handled earlier"));
}panic!(
98                "We do not expect to encounter `TyVar` this late in combine \
99                    -- they should have been handled earlier"
100            )
101        }
102        (_, ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)))
103        | (ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)), _)
104            if infcx.next_trait_solver() =>
105        {
106            {
    ::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")
107        }
108        (ty::Alias(ty::IsRigid::No, _), _) | (_, ty::Alias(ty::IsRigid::No, _))
109            if infcx.next_trait_solver() =>
110        {
111            {
    ::core::panicking::panic_fmt(format_args!("non-rigid aliases should be handled in the caller of super_combine_tys"));
}panic!("non-rigid aliases should be handled in the caller of super_combine_tys")
112        }
113
114        // All other cases of inference are errors
115        (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Sorts(ExpectedFound::new(a, b))),
116
117        (ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }), _)
118        | (_, ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }))
119            if !infcx.next_trait_solver() =>
120        {
121            match infcx.typing_mode_raw().assert_not_erased() {
122                // During coherence, opaque types should be treated as *possibly*
123                // equal to any other type. This is an
124                // extremely heavy hammer, but can be relaxed in a forwards-compatible
125                // way later.
126                TypingMode::Coherence => {
127                    relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
128                    Ok(a)
129                }
130                TypingMode::Typeck { .. }
131                | TypingMode::Reflection
132                | TypingMode::PostTypeckUntilBorrowck { .. }
133                | TypingMode::PostBorrowck { .. }
134                | TypingMode::PostAnalysis
135                | TypingMode::Codegen => structurally_relate_tys(relation, a, b),
136            }
137        }
138
139        _ => structurally_relate_tys(relation, a, b),
140    }
141}
142
143pub fn super_combine_consts<Infcx, I, R>(
144    infcx: &Infcx,
145    relation: &mut R,
146    a: I::Const,
147    b: I::Const,
148) -> RelateResult<I, I::Const>
149where
150    Infcx: InferCtxtLike<Interner = I>,
151    I: Interner,
152    R: PredicateEmittingRelation<Infcx>,
153{
154    {
    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:154",
                        "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(154u32),
                        ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("super_combine_consts::<{0}>({1:?}, {2:?})",
                                                    std::any::type_name::<R>(), a, b) as
                                            &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("super_combine_consts::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
155    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());
156    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());
157
158    if a == b {
159        return Ok(a);
160    }
161
162    let a = infcx.shallow_resolve_const(a);
163    let b = infcx.shallow_resolve_const(b);
164
165    match (a.kind(), b.kind()) {
166        (
167            ty::ConstKind::Infer(ty::InferConst::Var(a_vid)),
168            ty::ConstKind::Infer(ty::InferConst::Var(b_vid)),
169        ) => {
170            infcx.equate_const_vids_raw(a_vid, b_vid);
171            Ok(a)
172        }
173
174        // All other cases of inference with other variables are errors.
175        (ty::ConstKind::Infer(ty::InferConst::Var(_)), ty::ConstKind::Infer(_))
176        | (ty::ConstKind::Infer(_), ty::ConstKind::Infer(ty::InferConst::Var(_))) => {
177            {
    ::core::panicking::panic_fmt(format_args!("tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {0:?} and {1:?}",
            a, b));
}panic!(
178                "tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}"
179            )
180        }
181
182        (ty::ConstKind::Alias(ty::IsRigid::No, alias), _) if infcx.next_trait_solver() => {
183            relation.register_predicates([ty::ProjectionPredicate {
184                projection_term: alias.into(),
185                term: b.into(),
186            }]);
187            Ok(b)
188        }
189        (_, ty::ConstKind::Alias(ty::IsRigid::No, alias)) if infcx.next_trait_solver() => {
190            relation.register_predicates([ty::ProjectionPredicate {
191                projection_term: alias.into(),
192                term: a.into(),
193            }]);
194            Ok(b)
195        }
196
197        (ty::ConstKind::Infer(ty::InferConst::Var(vid)), _) => {
198            infcx.instantiate_const_var(relation, true, vid, b)?;
199            Ok(b)
200        }
201
202        (_, ty::ConstKind::Infer(ty::InferConst::Var(vid))) => {
203            infcx.instantiate_const_var(relation, false, vid, a)?;
204            Ok(a)
205        }
206
207        (ty::ConstKind::Alias(ty::IsRigid::No, _), _)
208        | (_, ty::ConstKind::Alias(ty::IsRigid::No, _))
209            if infcx.cx().features().generic_const_exprs() =>
210        {
211            relation.register_predicates([ty::PredicateKind::ConstEquate(a, b)]);
212            Ok(b)
213        }
214
215        _ => structurally_relate_consts(relation, a, b),
216    }
217}
218
219pub fn combine_ty_args<Infcx, I, R>(
220    infcx: &Infcx,
221    relation: &mut R,
222    a_ty: I::Ty,
223    b_ty: I::Ty,
224    variances: I::VariancesOf,
225    a_args: I::GenericArgs,
226    b_args: I::GenericArgs,
227    mk: impl FnOnce(I::GenericArgs) -> I::Ty,
228) -> RelateResult<I, I::Ty>
229where
230    Infcx: InferCtxtLike<Interner = I>,
231    I: Interner,
232    R: PredicateEmittingRelation<Infcx>,
233{
234    let cx = infcx.cx();
235    let mut has_unconstrained_bivariant_arg = false;
236    let args = iter::zip(a_args.iter(), b_args.iter()).enumerate().map(|(i, (a, b))| {
237        let variance = variances.get(i).unwrap();
238        let variance_info = match variance {
239            ty::Invariant => {
240                VarianceDiagInfo::Invariant { ty: a_ty, param_index: i.try_into().unwrap() }
241            }
242            ty::Covariant | ty::Contravariant => VarianceDiagInfo::default(),
243            ty::Bivariant => {
244                let has_non_region_infer = |arg: I::GenericArg| {
245                    arg.has_non_region_infer()
246                        && infcx.resolve_vars_if_possible(arg).has_non_region_infer()
247                };
248                if has_non_region_infer(a) || has_non_region_infer(b) {
249                    has_unconstrained_bivariant_arg = true;
250                }
251                VarianceDiagInfo::default()
252            }
253        };
254        relation.relate_with_variance(variance, variance_info, a, b)
255    });
256    let args = cx.mk_args_from_iter(args)?;
257
258    // In general, we do not check whether all types which occur during
259    // type checking are well-formed. We only check wf of user-provided types
260    // and when actually using a type, e.g. for method calls.
261    //
262    // This means that when subtyping, we may end up with unconstrained
263    // inference variables if a generalized type has bivariant parameters.
264    // A parameter may only be bivariant if it is constrained by a projection
265    // bound in a where-clause. As an example, imagine a type:
266    //
267    //     struct Foo<A, B> where A: Iterator<Item = B> {
268    //         data: A
269    //     }
270    //
271    // here, `A` will be covariant, but `B` is unconstrained. However, whatever it is,
272    // for `Foo` to be WF, it must be equal to `A::Item`.
273    //
274    // If we have an input `Foo<?A, ?B>`, then after generalization we will wind
275    // up with a type like `Foo<?C, ?D>`. When we enforce `Foo<?A, ?B> <: Foo<?C, ?D>`,
276    // we will wind up with the requirement that `?A <: ?C`, but no particular
277    // relationship between `?B` and `?D` (after all, these types may be completely
278    // different). If we do nothing else, this may mean that `?D` goes unconstrained
279    // (as in #41677). To avoid this we emit a `WellFormed` when relating types with
280    // bivariant arguments.
281    if has_unconstrained_bivariant_arg {
282        relation.register_predicates([
283            ty::ClauseKind::WellFormed(a_ty.into()),
284            ty::ClauseKind::WellFormed(b_ty.into()),
285        ]);
286    }
287
288    if a_args == args { Ok(a_ty) } else { Ok(mk(args)) }
289}