]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_infer/src/infer/sub.rs
Auto merge of #98369 - jyn514:configure.py, r=Mark-Simulacrum
[rust.git] / compiler / rustc_infer / src / infer / sub.rs
1 use super::combine::{CombineFields, RelationDir};
2 use super::SubregionOrigin;
3
4 use crate::infer::combine::ConstEquateRelation;
5 use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
6 use crate::traits::Obligation;
7 use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
8 use rustc_middle::ty::visit::TypeVisitable;
9 use rustc_middle::ty::TyVar;
10 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
11 use std::mem;
12
13 /// Ensures `a` is made a subtype of `b`. Returns `a` on success.
14 pub struct Sub<'combine, 'infcx, 'tcx> {
15     fields: &'combine mut CombineFields<'infcx, 'tcx>,
16     a_is_expected: bool,
17 }
18
19 impl<'combine, 'infcx, 'tcx> Sub<'combine, 'infcx, 'tcx> {
20     pub fn new(
21         f: &'combine mut CombineFields<'infcx, 'tcx>,
22         a_is_expected: bool,
23     ) -> Sub<'combine, 'infcx, 'tcx> {
24         Sub { fields: f, a_is_expected }
25     }
26
27     fn with_expected_switched<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R {
28         self.a_is_expected = !self.a_is_expected;
29         let result = f(self);
30         self.a_is_expected = !self.a_is_expected;
31         result
32     }
33 }
34
35 impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
36     fn tag(&self) -> &'static str {
37         "Sub"
38     }
39     fn tcx(&self) -> TyCtxt<'tcx> {
40         self.fields.infcx.tcx
41     }
42
43     fn param_env(&self) -> ty::ParamEnv<'tcx> {
44         self.fields.param_env
45     }
46
47     fn a_is_expected(&self) -> bool {
48         self.a_is_expected
49     }
50
51     fn with_cause<F, R>(&mut self, cause: Cause, f: F) -> R
52     where
53         F: FnOnce(&mut Self) -> R,
54     {
55         debug!("sub with_cause={:?}", cause);
56         let old_cause = mem::replace(&mut self.fields.cause, Some(cause));
57         let r = f(self);
58         debug!("sub old_cause={:?}", old_cause);
59         self.fields.cause = old_cause;
60         r
61     }
62
63     fn relate_with_variance<T: Relate<'tcx>>(
64         &mut self,
65         variance: ty::Variance,
66         _info: ty::VarianceDiagInfo<'tcx>,
67         a: T,
68         b: T,
69     ) -> RelateResult<'tcx, T> {
70         match variance {
71             ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
72             ty::Covariant => self.relate(a, b),
73             ty::Bivariant => Ok(a),
74             ty::Contravariant => self.with_expected_switched(|this| this.relate(b, a)),
75         }
76     }
77
78     #[instrument(skip(self), level = "debug")]
79     fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
80         if a == b {
81             return Ok(a);
82         }
83
84         let infcx = self.fields.infcx;
85         let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
86         let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
87
88         match (a.kind(), b.kind()) {
89             (&ty::Infer(TyVar(_)), &ty::Infer(TyVar(_))) => {
90                 // Shouldn't have any LBR here, so we can safely put
91                 // this under a binder below without fear of accidental
92                 // capture.
93                 assert!(!a.has_escaping_bound_vars());
94                 assert!(!b.has_escaping_bound_vars());
95
96                 // can't make progress on `A <: B` if both A and B are
97                 // type variables, so record an obligation.
98                 self.fields.obligations.push(Obligation::new(
99                     self.fields.trace.cause.clone(),
100                     self.fields.param_env,
101                     ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
102                         a_is_expected: self.a_is_expected,
103                         a,
104                         b,
105                     }))
106                     .to_predicate(self.tcx()),
107                 ));
108
109                 Ok(a)
110             }
111             (&ty::Infer(TyVar(a_id)), _) => {
112                 self.fields.instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?;
113                 Ok(a)
114             }
115             (_, &ty::Infer(TyVar(b_id))) => {
116                 self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?;
117                 Ok(a)
118             }
119
120             (&ty::Error(_), _) | (_, &ty::Error(_)) => {
121                 infcx.set_tainted_by_errors();
122                 Ok(self.tcx().ty_error())
123             }
124
125             (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
126                 self.fields.infcx.super_combine_tys(self, a, b)?;
127                 Ok(a)
128             }
129             (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
130                 if self.fields.define_opaque_types && did.is_local() =>
131             {
132                 let mut generalize = |ty, ty_is_expected| {
133                     let var = infcx.next_ty_var_id_in_universe(
134                         TypeVariableOrigin {
135                             kind: TypeVariableOriginKind::MiscVariable,
136                             span: self.fields.trace.cause.span,
137                         },
138                         ty::UniverseIndex::ROOT,
139                     );
140                     self.fields.instantiate(ty, RelationDir::SubtypeOf, var, ty_is_expected)?;
141                     Ok(infcx.tcx.mk_ty_var(var))
142                 };
143                 let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) };
144                 let (a, b) = match (a.kind(), b.kind()) {
145                     (&ty::Opaque(..), _) => (a, generalize(b, true)?),
146                     (_, &ty::Opaque(..)) => (generalize(a, false)?, b),
147                     _ => unreachable!(),
148                 };
149                 self.fields.obligations.extend(
150                     infcx
151                         .handle_opaque_type(a, b, true, &self.fields.trace.cause, self.param_env())?
152                         .obligations,
153                 );
154                 Ok(a)
155             }
156
157             _ => {
158                 self.fields.infcx.super_combine_tys(self, a, b)?;
159                 Ok(a)
160             }
161         }
162     }
163
164     fn regions(
165         &mut self,
166         a: ty::Region<'tcx>,
167         b: ty::Region<'tcx>,
168     ) -> RelateResult<'tcx, ty::Region<'tcx>> {
169         debug!("{}.regions({:?}, {:?}) self.cause={:?}", self.tag(), a, b, self.fields.cause);
170
171         // FIXME -- we have more fine-grained information available
172         // from the "cause" field, we could perhaps give more tailored
173         // error messages.
174         let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
175         self.fields
176             .infcx
177             .inner
178             .borrow_mut()
179             .unwrap_region_constraints()
180             .make_subregion(origin, a, b);
181
182         Ok(a)
183     }
184
185     fn consts(
186         &mut self,
187         a: ty::Const<'tcx>,
188         b: ty::Const<'tcx>,
189     ) -> RelateResult<'tcx, ty::Const<'tcx>> {
190         self.fields.infcx.super_combine_consts(self, a, b)
191     }
192
193     fn binders<T>(
194         &mut self,
195         a: ty::Binder<'tcx, T>,
196         b: ty::Binder<'tcx, T>,
197     ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
198     where
199         T: Relate<'tcx>,
200     {
201         self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
202         Ok(a)
203     }
204 }
205
206 impl<'tcx> ConstEquateRelation<'tcx> for Sub<'_, '_, 'tcx> {
207     fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
208         self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
209     }
210 }