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