]>
Commit | Line | Data |
---|---|---|
74b04a01 XL |
1 | //! Experimental types for the trait query interface. The methods |
2 | //! defined in this module are all based on **canonicalization**, | |
3 | //! which makes a canonical query by replacing unbound inference | |
4 | //! variables and regions, so that results can be reused more broadly. | |
5 | //! The providers for the queries defined here can be found in | |
6 | //! `librustc_traits`. | |
7 | ||
8 | use crate::ich::StableHashingContext; | |
9 | use crate::infer::canonical::{Canonical, QueryResponse}; | |
10 | use crate::ty::error::TypeError; | |
11 | use crate::ty::subst::GenericArg; | |
12 | use crate::ty::{self, Ty, TyCtxt}; | |
13 | ||
14 | use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; | |
15 | use rustc_data_structures::sync::Lrc; | |
16 | use rustc_errors::struct_span_err; | |
17 | use rustc_span::source_map::Span; | |
18 | use std::iter::FromIterator; | |
19 | use std::mem; | |
20 | ||
21 | pub mod type_op { | |
22 | use crate::ty::fold::TypeFoldable; | |
23 | use crate::ty::subst::UserSubsts; | |
24 | use crate::ty::{Predicate, Ty}; | |
25 | use rustc_hir::def_id::DefId; | |
26 | use std::fmt; | |
27 | ||
28 | #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] | |
29 | pub struct AscribeUserType<'tcx> { | |
30 | pub mir_ty: Ty<'tcx>, | |
31 | pub def_id: DefId, | |
32 | pub user_substs: UserSubsts<'tcx>, | |
33 | } | |
34 | ||
35 | impl<'tcx> AscribeUserType<'tcx> { | |
36 | pub fn new(mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>) -> Self { | |
37 | Self { mir_ty, def_id, user_substs } | |
38 | } | |
39 | } | |
40 | ||
41 | #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] | |
42 | pub struct Eq<'tcx> { | |
43 | pub a: Ty<'tcx>, | |
44 | pub b: Ty<'tcx>, | |
45 | } | |
46 | ||
47 | impl<'tcx> Eq<'tcx> { | |
48 | pub fn new(a: Ty<'tcx>, b: Ty<'tcx>) -> Self { | |
49 | Self { a, b } | |
50 | } | |
51 | } | |
52 | ||
53 | #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] | |
54 | pub struct Subtype<'tcx> { | |
55 | pub sub: Ty<'tcx>, | |
56 | pub sup: Ty<'tcx>, | |
57 | } | |
58 | ||
59 | impl<'tcx> Subtype<'tcx> { | |
60 | pub fn new(sub: Ty<'tcx>, sup: Ty<'tcx>) -> Self { | |
61 | Self { sub, sup } | |
62 | } | |
63 | } | |
64 | ||
65 | #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] | |
66 | pub struct ProvePredicate<'tcx> { | |
67 | pub predicate: Predicate<'tcx>, | |
68 | } | |
69 | ||
70 | impl<'tcx> ProvePredicate<'tcx> { | |
71 | pub fn new(predicate: Predicate<'tcx>) -> Self { | |
72 | ProvePredicate { predicate } | |
73 | } | |
74 | } | |
75 | ||
76 | #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] | |
77 | pub struct Normalize<T> { | |
78 | pub value: T, | |
79 | } | |
80 | ||
81 | impl<'tcx, T> Normalize<T> | |
82 | where | |
83 | T: fmt::Debug + TypeFoldable<'tcx>, | |
84 | { | |
85 | pub fn new(value: T) -> Self { | |
86 | Self { value } | |
87 | } | |
88 | } | |
89 | } | |
90 | ||
91 | pub type CanonicalProjectionGoal<'tcx> = | |
92 | Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>; | |
93 | ||
94 | pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>; | |
95 | ||
96 | pub type CanonicalPredicateGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>; | |
97 | ||
98 | pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> = | |
99 | Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>; | |
100 | ||
101 | pub type CanonicalTypeOpEqGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Eq<'tcx>>>; | |
102 | ||
103 | pub type CanonicalTypeOpSubtypeGoal<'tcx> = | |
104 | Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Subtype<'tcx>>>; | |
105 | ||
106 | pub type CanonicalTypeOpProvePredicateGoal<'tcx> = | |
107 | Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ProvePredicate<'tcx>>>; | |
108 | ||
109 | pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = | |
110 | Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>; | |
111 | ||
112 | #[derive(Clone, Debug, HashStable)] | |
113 | pub struct NoSolution; | |
114 | ||
115 | pub type Fallible<T> = Result<T, NoSolution>; | |
116 | ||
117 | impl<'tcx> From<TypeError<'tcx>> for NoSolution { | |
118 | fn from(_: TypeError<'tcx>) -> NoSolution { | |
119 | NoSolution | |
120 | } | |
121 | } | |
122 | ||
123 | #[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)] | |
124 | pub struct DropckOutlivesResult<'tcx> { | |
125 | pub kinds: Vec<GenericArg<'tcx>>, | |
126 | pub overflows: Vec<Ty<'tcx>>, | |
127 | } | |
128 | ||
129 | impl<'tcx> DropckOutlivesResult<'tcx> { | |
130 | pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { | |
3dfed10e | 131 | if let Some(overflow_ty) = self.overflows.get(0) { |
74b04a01 XL |
132 | let mut err = struct_span_err!( |
133 | tcx.sess, | |
134 | span, | |
135 | E0320, | |
136 | "overflow while adding drop-check rules for {}", | |
137 | ty, | |
138 | ); | |
139 | err.note(&format!("overflowed on {}", overflow_ty)); | |
140 | err.emit(); | |
141 | } | |
142 | } | |
143 | ||
144 | pub fn into_kinds_reporting_overflows( | |
145 | self, | |
146 | tcx: TyCtxt<'tcx>, | |
147 | span: Span, | |
148 | ty: Ty<'tcx>, | |
149 | ) -> Vec<GenericArg<'tcx>> { | |
150 | self.report_overflows(tcx, span, ty); | |
151 | let DropckOutlivesResult { kinds, overflows: _ } = self; | |
152 | kinds | |
153 | } | |
154 | } | |
155 | ||
156 | /// A set of constraints that need to be satisfied in order for | |
157 | /// a type to be valid for destruction. | |
158 | #[derive(Clone, Debug, HashStable)] | |
159 | pub struct DtorckConstraint<'tcx> { | |
160 | /// Types that are required to be alive in order for this | |
161 | /// type to be valid for destruction. | |
162 | pub outlives: Vec<ty::subst::GenericArg<'tcx>>, | |
163 | ||
164 | /// Types that could not be resolved: projections and params. | |
165 | pub dtorck_types: Vec<Ty<'tcx>>, | |
166 | ||
167 | /// If, during the computation of the dtorck constraint, we | |
168 | /// overflow, that gets recorded here. The caller is expected to | |
169 | /// report an error. | |
170 | pub overflows: Vec<Ty<'tcx>>, | |
171 | } | |
172 | ||
173 | impl<'tcx> DtorckConstraint<'tcx> { | |
174 | pub fn empty() -> DtorckConstraint<'tcx> { | |
175 | DtorckConstraint { outlives: vec![], dtorck_types: vec![], overflows: vec![] } | |
176 | } | |
177 | } | |
178 | ||
179 | impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx> { | |
180 | fn from_iter<I: IntoIterator<Item = DtorckConstraint<'tcx>>>(iter: I) -> Self { | |
181 | let mut result = Self::empty(); | |
182 | ||
183 | for DtorckConstraint { outlives, dtorck_types, overflows } in iter { | |
184 | result.outlives.extend(outlives); | |
185 | result.dtorck_types.extend(dtorck_types); | |
186 | result.overflows.extend(overflows); | |
187 | } | |
188 | ||
189 | result | |
190 | } | |
191 | } | |
192 | ||
193 | /// This returns true if the type `ty` is "trivial" for | |
194 | /// dropck-outlives -- that is, if it doesn't require any types to | |
195 | /// outlive. This is similar but not *quite* the same as the | |
196 | /// `needs_drop` test in the compiler already -- that is, for every | |
197 | /// type T for which this function return true, needs-drop would | |
198 | /// return `false`. But the reverse does not hold: in particular, | |
199 | /// `needs_drop` returns false for `PhantomData`, but it is not | |
200 | /// trivial for dropck-outlives. | |
201 | /// | |
202 | /// Note also that `needs_drop` requires a "global" type (i.e., one | |
203 | /// with erased regions), but this function does not. | |
204 | pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { | |
205 | match ty.kind { | |
206 | // None of these types have a destructor and hence they do not | |
207 | // require anything in particular to outlive the dtor's | |
208 | // execution. | |
209 | ty::Infer(ty::FreshIntTy(_)) | |
210 | | ty::Infer(ty::FreshFloatTy(_)) | |
211 | | ty::Bool | |
212 | | ty::Int(_) | |
213 | | ty::Uint(_) | |
214 | | ty::Float(_) | |
215 | | ty::Never | |
216 | | ty::FnDef(..) | |
217 | | ty::FnPtr(_) | |
218 | | ty::Char | |
219 | | ty::GeneratorWitness(..) | |
220 | | ty::RawPtr(_) | |
221 | | ty::Ref(..) | |
222 | | ty::Str | |
223 | | ty::Foreign(..) | |
f035d41b | 224 | | ty::Error(_) => true, |
74b04a01 XL |
225 | |
226 | // [T; N] and [T] have same properties as T. | |
227 | ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty), | |
228 | ||
229 | // (T1..Tn) and closures have same properties as T1..Tn -- | |
230 | // check if *any* of those are trivial. | |
231 | ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())), | |
ba9703b0 XL |
232 | ty::Closure(_, ref substs) => { |
233 | substs.as_closure().upvar_tys().all(|t| trivial_dropck_outlives(tcx, t)) | |
74b04a01 XL |
234 | } |
235 | ||
236 | ty::Adt(def, _) => { | |
237 | if Some(def.did) == tcx.lang_items().manually_drop() { | |
238 | // `ManuallyDrop` never has a dtor. | |
239 | true | |
240 | } else { | |
241 | // Other types might. Moreover, PhantomData doesn't | |
242 | // have a dtor, but it is considered to own its | |
243 | // content, so it is non-trivial. Unions can have `impl Drop`, | |
244 | // and hence are non-trivial as well. | |
245 | false | |
246 | } | |
247 | } | |
248 | ||
249 | // The following *might* require a destructor: needs deeper inspection. | |
250 | ty::Dynamic(..) | |
251 | | ty::Projection(..) | |
252 | | ty::Param(_) | |
253 | | ty::Opaque(..) | |
254 | | ty::Placeholder(..) | |
255 | | ty::Infer(_) | |
256 | | ty::Bound(..) | |
257 | | ty::Generator(..) => false, | |
74b04a01 XL |
258 | } |
259 | } | |
260 | ||
261 | #[derive(Debug, HashStable)] | |
262 | pub struct CandidateStep<'tcx> { | |
263 | pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, | |
264 | pub autoderefs: usize, | |
265 | /// `true` if the type results from a dereference of a raw pointer. | |
266 | /// when assembling candidates, we include these steps, but not when | |
267 | /// picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods | |
268 | /// `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then | |
269 | /// `foo.by_raw_ptr()` will work and `foo.by_ref()` won't. | |
270 | pub from_unsafe_deref: bool, | |
271 | pub unsize: bool, | |
272 | } | |
273 | ||
274 | #[derive(Clone, Debug, HashStable)] | |
275 | pub struct MethodAutoderefStepsResult<'tcx> { | |
276 | /// The valid autoderef steps that could be find. | |
277 | pub steps: Lrc<Vec<CandidateStep<'tcx>>>, | |
278 | /// If Some(T), a type autoderef reported an error on. | |
279 | pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>, | |
280 | /// If `true`, `steps` has been truncated due to reaching the | |
281 | /// recursion limit. | |
282 | pub reached_recursion_limit: bool, | |
283 | } | |
284 | ||
285 | #[derive(Debug, HashStable)] | |
286 | pub struct MethodAutoderefBadTy<'tcx> { | |
287 | pub reached_raw_pointer: bool, | |
288 | pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, | |
289 | } | |
290 | ||
291 | /// Result from the `normalize_projection_ty` query. | |
292 | #[derive(Clone, Debug, HashStable, TypeFoldable, Lift)] | |
293 | pub struct NormalizationResult<'tcx> { | |
294 | /// Result of normalization. | |
295 | pub normalized_ty: Ty<'tcx>, | |
296 | } | |
297 | ||
298 | /// Outlives bounds are relationships between generic parameters, | |
299 | /// whether they both be regions (`'a: 'b`) or whether types are | |
300 | /// involved (`T: 'a`). These relationships can be extracted from the | |
301 | /// full set of predicates we understand or also from types (in which | |
302 | /// case they are called implied bounds). They are fed to the | |
303 | /// `OutlivesEnv` which in turn is supplied to the region checker and | |
304 | /// other parts of the inference system. | |
305 | #[derive(Clone, Debug, TypeFoldable, Lift)] | |
306 | pub enum OutlivesBound<'tcx> { | |
307 | RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), | |
308 | RegionSubParam(ty::Region<'tcx>, ty::ParamTy), | |
309 | RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>), | |
310 | } | |
311 | ||
312 | impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OutlivesBound<'tcx> { | |
313 | fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { | |
314 | mem::discriminant(self).hash_stable(hcx, hasher); | |
315 | match *self { | |
316 | OutlivesBound::RegionSubRegion(ref a, ref b) => { | |
317 | a.hash_stable(hcx, hasher); | |
318 | b.hash_stable(hcx, hasher); | |
319 | } | |
320 | OutlivesBound::RegionSubParam(ref a, ref b) => { | |
321 | a.hash_stable(hcx, hasher); | |
322 | b.hash_stable(hcx, hasher); | |
323 | } | |
324 | OutlivesBound::RegionSubProjection(ref a, ref b) => { | |
325 | a.hash_stable(hcx, hasher); | |
326 | b.hash_stable(hcx, hasher); | |
327 | } | |
328 | } | |
329 | } | |
330 | } |