]>
Commit | Line | Data |
---|---|---|
9fa01778 XL |
1 | use crate::infer::at::At; |
2 | use crate::infer::InferOk; | |
3 | use crate::infer::canonical::OriginalQueryValues; | |
0531ce1d | 4 | use std::iter::FromIterator; |
b7449926 | 5 | use syntax::source_map::Span; |
9fa01778 XL |
6 | use crate::ty::subst::Kind; |
7 | use crate::ty::{self, Ty, TyCtxt}; | |
0531ce1d XL |
8 | |
9 | impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> { | |
10 | /// Given a type `ty` of some value being dropped, computes a set | |
11 | /// of "kinds" (types, regions) that must be outlive the execution | |
12 | /// of the destructor. These basically correspond to data that the | |
13 | /// destructor might access. This is used during regionck to | |
14 | /// impose "outlives" constraints on any lifetimes referenced | |
15 | /// within. | |
16 | /// | |
17 | /// The rules here are given by the "dropck" RFCs, notably [#1238] | |
18 | /// and [#1327]. This is a fixed-point computation, where we | |
19 | /// explore all the data that will be dropped (transitively) when | |
20 | /// a value of type `ty` is dropped. For each type T that will be | |
21 | /// dropped and which has a destructor, we must assume that all | |
22 | /// the types/regions of T are live during the destructor, unless | |
23 | /// they are marked with a special attribute (`#[may_dangle]`). | |
24 | /// | |
25 | /// [#1238]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md | |
26 | /// [#1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md | |
27 | pub fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<Kind<'tcx>>> { | |
28 | debug!( | |
29 | "dropck_outlives(ty={:?}, param_env={:?})", | |
30 | ty, self.param_env, | |
31 | ); | |
32 | ||
33 | // Quick check: there are a number of cases that we know do not require | |
34 | // any destructor. | |
35 | let tcx = self.infcx.tcx; | |
36 | if trivial_dropck_outlives(tcx, ty) { | |
8faf50e0 XL |
37 | return InferOk { |
38 | value: vec![], | |
39 | obligations: vec![], | |
40 | }; | |
0531ce1d XL |
41 | } |
42 | ||
43 | let gcx = tcx.global_tcx(); | |
0bf4aa26 | 44 | let mut orig_values = OriginalQueryValues::default(); |
8faf50e0 | 45 | let c_ty = self.infcx.canonicalize_query(&self.param_env.and(ty), &mut orig_values); |
0531ce1d XL |
46 | let span = self.cause.span; |
47 | debug!("c_ty = {:?}", c_ty); | |
0731742a XL |
48 | if let Ok(result) = &gcx.dropck_outlives(c_ty) { |
49 | if result.is_proven() { | |
0bf4aa26 XL |
50 | if let Ok(InferOk { value, obligations }) = |
51 | self.infcx.instantiate_query_response_and_region_obligations( | |
0531ce1d XL |
52 | self.cause, |
53 | self.param_env, | |
54 | &orig_values, | |
0bf4aa26 XL |
55 | result) |
56 | { | |
57 | let ty = self.infcx.resolve_type_vars_if_possible(&ty); | |
58 | let kinds = value.into_kinds_reporting_overflows(tcx, span, ty); | |
59 | return InferOk { | |
60 | value: kinds, | |
61 | obligations, | |
62 | }; | |
0531ce1d XL |
63 | } |
64 | } | |
0531ce1d XL |
65 | } |
66 | ||
67 | // Errors and ambiuity in dropck occur in two cases: | |
68 | // - unresolved inference variables at the end of typeck | |
69 | // - non well-formed types where projections cannot be resolved | |
b7449926 | 70 | // Either of these should have created an error before. |
0531ce1d XL |
71 | tcx.sess |
72 | .delay_span_bug(span, "dtorck encountered internal error"); | |
0731742a XL |
73 | |
74 | InferOk { | |
0531ce1d XL |
75 | value: vec![], |
76 | obligations: vec![], | |
0731742a | 77 | } |
0531ce1d XL |
78 | } |
79 | } | |
80 | ||
8faf50e0 | 81 | #[derive(Clone, Debug, Default)] |
0531ce1d XL |
82 | pub struct DropckOutlivesResult<'tcx> { |
83 | pub kinds: Vec<Kind<'tcx>>, | |
84 | pub overflows: Vec<Ty<'tcx>>, | |
85 | } | |
86 | ||
8faf50e0 XL |
87 | impl<'tcx> DropckOutlivesResult<'tcx> { |
88 | pub fn report_overflows( | |
89 | &self, | |
90 | tcx: TyCtxt<'_, '_, 'tcx>, | |
91 | span: Span, | |
92 | ty: Ty<'tcx>, | |
93 | ) { | |
0731742a | 94 | if let Some(overflow_ty) = self.overflows.iter().next() { |
8faf50e0 XL |
95 | let mut err = struct_span_err!( |
96 | tcx.sess, | |
97 | span, | |
98 | E0320, | |
99 | "overflow while adding drop-check rules for {}", | |
100 | ty, | |
101 | ); | |
102 | err.note(&format!("overflowed on {}", overflow_ty)); | |
103 | err.emit(); | |
104 | } | |
105 | } | |
106 | ||
107 | pub fn into_kinds_reporting_overflows( | |
108 | self, | |
109 | tcx: TyCtxt<'_, '_, 'tcx>, | |
110 | span: Span, | |
111 | ty: Ty<'tcx>, | |
112 | ) -> Vec<Kind<'tcx>> { | |
113 | self.report_overflows(tcx, span, ty); | |
114 | let DropckOutlivesResult { kinds, overflows: _ } = self; | |
115 | kinds | |
116 | } | |
117 | } | |
118 | ||
0531ce1d XL |
119 | /// A set of constraints that need to be satisfied in order for |
120 | /// a type to be valid for destruction. | |
121 | #[derive(Clone, Debug)] | |
122 | pub struct DtorckConstraint<'tcx> { | |
123 | /// Types that are required to be alive in order for this | |
124 | /// type to be valid for destruction. | |
125 | pub outlives: Vec<ty::subst::Kind<'tcx>>, | |
126 | ||
127 | /// Types that could not be resolved: projections and params. | |
128 | pub dtorck_types: Vec<Ty<'tcx>>, | |
129 | ||
130 | /// If, during the computation of the dtorck constraint, we | |
131 | /// overflow, that gets recorded here. The caller is expected to | |
132 | /// report an error. | |
133 | pub overflows: Vec<Ty<'tcx>>, | |
134 | } | |
135 | ||
136 | impl<'tcx> DtorckConstraint<'tcx> { | |
137 | pub fn empty() -> DtorckConstraint<'tcx> { | |
138 | DtorckConstraint { | |
139 | outlives: vec![], | |
140 | dtorck_types: vec![], | |
141 | overflows: vec![], | |
142 | } | |
143 | } | |
144 | } | |
145 | ||
146 | impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx> { | |
147 | fn from_iter<I: IntoIterator<Item = DtorckConstraint<'tcx>>>(iter: I) -> Self { | |
148 | let mut result = Self::empty(); | |
149 | ||
0bf4aa26 | 150 | for DtorckConstraint { outlives, dtorck_types, overflows } in iter { |
0531ce1d XL |
151 | result.outlives.extend(outlives); |
152 | result.dtorck_types.extend(dtorck_types); | |
153 | result.overflows.extend(overflows); | |
154 | } | |
155 | ||
156 | result | |
157 | } | |
158 | } | |
0531ce1d XL |
159 | BraceStructTypeFoldableImpl! { |
160 | impl<'tcx> TypeFoldable<'tcx> for DropckOutlivesResult<'tcx> { | |
161 | kinds, overflows | |
162 | } | |
163 | } | |
164 | ||
165 | BraceStructLiftImpl! { | |
166 | impl<'a, 'tcx> Lift<'tcx> for DropckOutlivesResult<'a> { | |
167 | type Lifted = DropckOutlivesResult<'tcx>; | |
168 | kinds, overflows | |
169 | } | |
170 | } | |
171 | ||
172 | impl_stable_hash_for!(struct DropckOutlivesResult<'tcx> { | |
173 | kinds, overflows | |
174 | }); | |
175 | ||
0531ce1d XL |
176 | impl_stable_hash_for!(struct DtorckConstraint<'tcx> { |
177 | outlives, | |
178 | dtorck_types, | |
179 | overflows | |
180 | }); | |
181 | ||
182 | /// This returns true if the type `ty` is "trivial" for | |
183 | /// dropck-outlives -- that is, if it doesn't require any types to | |
184 | /// outlive. This is similar but not *quite* the same as the | |
185 | /// `needs_drop` test in the compiler already -- that is, for every | |
186 | /// type T for which this function return true, needs-drop would | |
9fa01778 | 187 | /// return `false`. But the reverse does not hold: in particular, |
0531ce1d XL |
188 | /// `needs_drop` returns false for `PhantomData`, but it is not |
189 | /// trivial for dropck-outlives. | |
190 | /// | |
191 | /// Note also that `needs_drop` requires a "global" type (i.e., one | |
a1dfa0c6 | 192 | /// with erased regions), but this function does not. |
8faf50e0 | 193 | pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { |
0531ce1d XL |
194 | match ty.sty { |
195 | // None of these types have a destructor and hence they do not | |
196 | // require anything in particular to outlive the dtor's | |
197 | // execution. | |
b7449926 XL |
198 | ty::Infer(ty::FreshIntTy(_)) |
199 | | ty::Infer(ty::FreshFloatTy(_)) | |
200 | | ty::Bool | |
201 | | ty::Int(_) | |
202 | | ty::Uint(_) | |
203 | | ty::Float(_) | |
204 | | ty::Never | |
205 | | ty::FnDef(..) | |
206 | | ty::FnPtr(_) | |
207 | | ty::Char | |
208 | | ty::GeneratorWitness(..) | |
209 | | ty::RawPtr(_) | |
210 | | ty::Ref(..) | |
211 | | ty::Str | |
212 | | ty::Foreign(..) | |
213 | | ty::Error => true, | |
0531ce1d XL |
214 | |
215 | // [T; N] and [T] have same properties as T. | |
b7449926 | 216 | ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty), |
0531ce1d XL |
217 | |
218 | // (T1..Tn) and closures have same properties as T1..Tn -- | |
219 | // check if *any* of those are trivial. | |
0731742a | 220 | ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)), |
b7449926 | 221 | ty::Closure(def_id, ref substs) => substs |
0531ce1d XL |
222 | .upvar_tys(def_id, tcx) |
223 | .all(|t| trivial_dropck_outlives(tcx, t)), | |
224 | ||
b7449926 XL |
225 | ty::Adt(def, _) => { |
226 | if Some(def.did) == tcx.lang_items().manually_drop() { | |
8faf50e0 | 227 | // `ManuallyDrop` never has a dtor. |
0531ce1d XL |
228 | true |
229 | } else { | |
230 | // Other types might. Moreover, PhantomData doesn't | |
231 | // have a dtor, but it is considered to own its | |
b7449926 XL |
232 | // content, so it is non-trivial. Unions can have `impl Drop`, |
233 | // and hence are non-trivial as well. | |
0531ce1d XL |
234 | false |
235 | } | |
236 | } | |
237 | ||
0bf4aa26 | 238 | // The following *might* require a destructor: needs deeper inspection. |
b7449926 XL |
239 | ty::Dynamic(..) |
240 | | ty::Projection(..) | |
241 | | ty::Param(_) | |
242 | | ty::Opaque(..) | |
a1dfa0c6 | 243 | | ty::Placeholder(..) |
b7449926 | 244 | | ty::Infer(_) |
a1dfa0c6 | 245 | | ty::Bound(..) |
b7449926 | 246 | | ty::Generator(..) => false, |
0bf4aa26 XL |
247 | |
248 | ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), | |
0531ce1d XL |
249 | } |
250 | } |