]>
Commit | Line | Data |
---|---|---|
7453a54e | 1 | //! This pass type-checks the MIR to ensure it is not broken. |
0731742a | 2 | |
60c5eb7d | 3 | use std::rc::Rc; |
dfeec247 | 4 | use std::{fmt, iter, mem}; |
60c5eb7d | 5 | |
a1dfa0c6 | 6 | use either::Either; |
60c5eb7d | 7 | |
ba9703b0 | 8 | use rustc_data_structures::frozen::Frozen; |
60c5eb7d | 9 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
dfeec247 XL |
10 | use rustc_errors::struct_span_err; |
11 | use rustc_hir as hir; | |
f9f354fc | 12 | use rustc_hir::def_id::{DefId, LocalDefId}; |
3dfed10e | 13 | use rustc_hir::lang_items::LangItem; |
60c5eb7d | 14 | use rustc_index::vec::{Idx, IndexVec}; |
74b04a01 | 15 | use rustc_infer::infer::canonical::QueryRegionConstraints; |
74b04a01 XL |
16 | use rustc_infer::infer::outlives::env::RegionBoundPairs; |
17 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; | |
18 | use rustc_infer::infer::{ | |
5869c6ff | 19 | InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin, |
74b04a01 | 20 | }; |
ba9703b0 XL |
21 | use rustc_middle::mir::tcx::PlaceTy; |
22 | use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; | |
23 | use rustc_middle::mir::AssertKind; | |
24 | use rustc_middle::mir::*; | |
25 | use rustc_middle::ty::adjustment::PointerCast; | |
26 | use rustc_middle::ty::cast::CastTy; | |
27 | use rustc_middle::ty::fold::TypeFoldable; | |
28 | use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef, UserSubsts}; | |
29 | use rustc_middle::ty::{ | |
3dfed10e XL |
30 | self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, RegionVid, ToPredicate, Ty, |
31 | TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness, | |
ba9703b0 | 32 | }; |
dfeec247 | 33 | use rustc_span::{Span, DUMMY_SP}; |
ba9703b0 XL |
34 | use rustc_target::abi::VariantIdx; |
35 | use rustc_trait_selection::infer::InferCtxtExt as _; | |
36 | use rustc_trait_selection::opaque_types::{GenerateMemberConstraints, InferCtxtExt}; | |
37 | use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; | |
38 | use rustc_trait_selection::traits::query::type_op; | |
39 | use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; | |
40 | use rustc_trait_selection::traits::query::{Fallible, NoSolution}; | |
41 | use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations}; | |
60c5eb7d | 42 | |
f9f354fc | 43 | use crate::dataflow::impls::MaybeInitializedPlaces; |
dfeec247 | 44 | use crate::dataflow::move_paths::MoveData; |
ba9703b0 | 45 | use crate::dataflow::ResultsCursor; |
6a06907d XL |
46 | use crate::transform::{ |
47 | check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression, | |
48 | }; | |
60c5eb7d XL |
49 | |
50 | use crate::borrow_check::{ | |
51 | borrow_set::BorrowSet, | |
dfeec247 XL |
52 | constraints::{OutlivesConstraint, OutlivesConstraintSet}, |
53 | facts::AllFacts, | |
60c5eb7d | 54 | location::LocationTable, |
60c5eb7d | 55 | member_constraints::MemberConstraintSet, |
dfeec247 | 56 | nll::ToRegionVid, |
f035d41b | 57 | path_utils, |
60c5eb7d XL |
58 | region_infer::values::{ |
59 | LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements, | |
60 | }, | |
61 | region_infer::{ClosureRegionRequirementsExt, TypeTest}, | |
60c5eb7d | 62 | renumber, |
dfeec247 XL |
63 | type_check::free_region_relations::{CreateResult, UniversalRegionRelations}, |
64 | universal_regions::{DefiningTy, UniversalRegions}, | |
f035d41b | 65 | Upvar, |
60c5eb7d | 66 | }; |
3157f602 | 67 | |
ff7c6d11 XL |
68 | macro_rules! span_mirbug { |
69 | ($context:expr, $elem:expr, $($message:tt)*) => ({ | |
60c5eb7d | 70 | $crate::borrow_check::type_check::mirbug( |
ff7c6d11 XL |
71 | $context.tcx(), |
72 | $context.last_span, | |
73 | &format!( | |
74 | "broken MIR in {:?} ({:?}): {}", | |
29967ef6 | 75 | $context.body.source.def_id(), |
ff7c6d11 XL |
76 | $elem, |
77 | format_args!($($message)*), | |
78 | ), | |
79 | ) | |
80 | }) | |
81 | } | |
82 | ||
83 | macro_rules! span_mirbug_and_err { | |
84 | ($context:expr, $elem:expr, $($message:tt)*) => ({ | |
85 | { | |
86 | span_mirbug!($context, $elem, $($message)*); | |
87 | $context.error() | |
88 | } | |
89 | }) | |
90 | } | |
91 | ||
94b46f34 | 92 | mod constraint_conversion; |
8faf50e0 | 93 | pub mod free_region_relations; |
ff7c6d11 | 94 | mod input_output; |
b7449926 | 95 | crate mod liveness; |
8faf50e0 | 96 | mod relate_tys; |
ff7c6d11 | 97 | |
abe05a73 XL |
98 | /// Type checks the given `mir` in the context of the inference |
99 | /// context `infcx`. Returns any region constraints that have yet to | |
ff7c6d11 XL |
100 | /// be proven. This result is includes liveness constraints that |
101 | /// ensure that regions appearing in the types of all local variables | |
102 | /// are live at all points where that local variable may later be | |
103 | /// used. | |
abe05a73 XL |
104 | /// |
105 | /// This phase of type-check ought to be infallible -- this is because | |
106 | /// the original, HIR-based type-check succeeded. So if any errors | |
107 | /// occur here, we will get a `bug!` reported. | |
ff7c6d11 XL |
108 | /// |
109 | /// # Parameters | |
110 | /// | |
111 | /// - `infcx` -- inference context to use | |
112 | /// - `param_env` -- parameter environment to use for trait solving | |
f9f354fc XL |
113 | /// - `body` -- MIR body to type-check |
114 | /// - `promoted` -- map of promoted constants within `body` | |
f9f354fc XL |
115 | /// - `universal_regions` -- the universal regions from `body`s function signature |
116 | /// - `location_table` -- MIR location map of `body` | |
117 | /// - `borrow_set` -- information about borrows occurring in `body` | |
118 | /// - `all_facts` -- when using Polonius, this is the generated set of Polonius facts | |
ff7c6d11 | 119 | /// - `flow_inits` -- results of a maybe-init dataflow analysis |
a1dfa0c6 | 120 | /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis |
f9f354fc | 121 | /// - `elements` -- MIR region map |
74b04a01 | 122 | pub(crate) fn type_check<'mir, 'tcx>( |
dc9dc135 XL |
123 | infcx: &InferCtxt<'_, 'tcx>, |
124 | param_env: ty::ParamEnv<'tcx>, | |
f9f354fc XL |
125 | body: &Body<'tcx>, |
126 | promoted: &IndexVec<Promoted, Body<'tcx>>, | |
8faf50e0 | 127 | universal_regions: &Rc<UniversalRegions<'tcx>>, |
94b46f34 | 128 | location_table: &LocationTable, |
8faf50e0 | 129 | borrow_set: &BorrowSet<'tcx>, |
94b46f34 | 130 | all_facts: &mut Option<AllFacts>, |
74b04a01 | 131 | flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, |
ff7c6d11 | 132 | move_data: &MoveData<'tcx>, |
8faf50e0 | 133 | elements: &Rc<RegionValueElements>, |
5869c6ff | 134 | upvars: &[Upvar<'tcx>], |
b7449926 | 135 | ) -> MirTypeckResults<'tcx> { |
ff7c6d11 | 136 | let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body)); |
8faf50e0 | 137 | let mut constraints = MirTypeckRegionConstraints { |
a1dfa0c6 XL |
138 | placeholder_indices: PlaceholderIndices::default(), |
139 | placeholder_index_to_region: IndexVec::default(), | |
9fa01778 | 140 | liveness_constraints: LivenessValues::new(elements.clone()), |
dc9dc135 XL |
141 | outlives_constraints: OutlivesConstraintSet::default(), |
142 | member_constraints: MemberConstraintSet::default(), | |
0bf4aa26 | 143 | closure_bounds_mapping: Default::default(), |
8faf50e0 XL |
144 | type_tests: Vec::default(), |
145 | }; | |
146 | ||
147 | let CreateResult { | |
148 | universal_region_relations, | |
149 | region_bound_pairs, | |
150 | normalized_inputs_and_output, | |
151 | } = free_region_relations::create( | |
ff7c6d11 | 152 | infcx, |
ff7c6d11 | 153 | param_env, |
ff7c6d11 | 154 | Some(implicit_region_bound), |
8faf50e0 XL |
155 | universal_regions, |
156 | &mut constraints, | |
8faf50e0 XL |
157 | ); |
158 | ||
0bf4aa26 XL |
159 | let mut borrowck_context = BorrowCheckContext { |
160 | universal_regions, | |
161 | location_table, | |
162 | borrow_set, | |
163 | all_facts, | |
164 | constraints: &mut constraints, | |
f035d41b | 165 | upvars, |
0bf4aa26 | 166 | }; |
ff7c6d11 | 167 | |
74b04a01 | 168 | let opaque_type_values = type_check_internal( |
0bf4aa26 | 169 | infcx, |
0bf4aa26 | 170 | param_env, |
dc9dc135 | 171 | body, |
e1599b0c | 172 | promoted, |
0bf4aa26 | 173 | ®ion_bound_pairs, |
48663c56 XL |
174 | implicit_region_bound, |
175 | &mut borrowck_context, | |
176 | &universal_region_relations, | |
177 | |mut cx| { | |
dfeec247 XL |
178 | cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output); |
179 | liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table); | |
60c5eb7d XL |
180 | |
181 | translate_outlives_facts(&mut cx); | |
74b04a01 | 182 | cx.opaque_type_values |
0bf4aa26 XL |
183 | }, |
184 | ); | |
8faf50e0 | 185 | |
74b04a01 | 186 | MirTypeckResults { constraints, universal_region_relations, opaque_type_values } |
ff7c6d11 XL |
187 | } |
188 | ||
dc9dc135 XL |
189 | fn type_check_internal<'a, 'tcx, R>( |
190 | infcx: &'a InferCtxt<'a, 'tcx>, | |
dc9dc135 | 191 | param_env: ty::ParamEnv<'tcx>, |
f9f354fc XL |
192 | body: &'a Body<'tcx>, |
193 | promoted: &'a IndexVec<Promoted, Body<'tcx>>, | |
0bf4aa26 | 194 | region_bound_pairs: &'a RegionBoundPairs<'tcx>, |
48663c56 XL |
195 | implicit_region_bound: ty::Region<'tcx>, |
196 | borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, | |
197 | universal_region_relations: &'a UniversalRegionRelations<'tcx>, | |
74b04a01 | 198 | extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R, |
60c5eb7d | 199 | ) -> R { |
ff7c6d11 XL |
200 | let mut checker = TypeChecker::new( |
201 | infcx, | |
f9f354fc | 202 | body, |
ff7c6d11 XL |
203 | param_env, |
204 | region_bound_pairs, | |
205 | implicit_region_bound, | |
94b46f34 | 206 | borrowck_context, |
0bf4aa26 | 207 | universal_region_relations, |
ff7c6d11 | 208 | ); |
abe05a73 | 209 | let errors_reported = { |
f9f354fc | 210 | let mut verifier = TypeVerifier::new(&mut checker, body, promoted); |
ba9703b0 | 211 | verifier.visit_body(&body); |
abe05a73 XL |
212 | verifier.errors_reported |
213 | }; | |
214 | ||
215 | if !errors_reported { | |
216 | // if verifier failed, don't do further checks to avoid ICEs | |
dc9dc135 | 217 | checker.typeck_mir(body); |
abe05a73 XL |
218 | } |
219 | ||
74b04a01 | 220 | extra(checker) |
abe05a73 XL |
221 | } |
222 | ||
60c5eb7d XL |
223 | fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { |
224 | let cx = &mut typeck.borrowck_context; | |
0bf4aa26 | 225 | if let Some(facts) = cx.all_facts { |
60c5eb7d | 226 | let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); |
0bf4aa26 | 227 | let location_table = cx.location_table; |
dfeec247 XL |
228 | facts.outlives.extend(cx.constraints.outlives_constraints.outlives().iter().flat_map( |
229 | |constraint: &OutlivesConstraint| { | |
230 | if let Some(from_location) = constraint.locations.from_location() { | |
231 | Either::Left(iter::once(( | |
232 | constraint.sup, | |
233 | constraint.sub, | |
234 | location_table.mid_index(from_location), | |
235 | ))) | |
236 | } else { | |
237 | Either::Right( | |
238 | location_table | |
239 | .all_points() | |
240 | .map(move |location| (constraint.sup, constraint.sub, location)), | |
241 | ) | |
242 | } | |
243 | }, | |
244 | )); | |
0bf4aa26 XL |
245 | } |
246 | } | |
247 | ||
dc9dc135 | 248 | fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: &str) { |
ff7c6d11 XL |
249 | // We sometimes see MIR failures (notably predicate failures) due to |
250 | // the fact that we check rvalue sized predicates here. So use `delay_span_bug` | |
251 | // to avoid reporting bugs in those cases. | |
252 | tcx.sess.diagnostic().delay_span_bug(span, msg); | |
7453a54e SL |
253 | } |
254 | ||
255 | enum FieldAccessError { | |
abe05a73 | 256 | OutOfRange { field_count: usize }, |
7453a54e SL |
257 | } |
258 | ||
259 | /// Verifies that MIR types are sane to not crash further checks. | |
260 | /// | |
261 | /// The sanitize_XYZ methods here take an MIR object and compute its | |
262 | /// type, calling `span_mirbug` and returning an error type if there | |
263 | /// is a problem. | |
dc9dc135 XL |
264 | struct TypeVerifier<'a, 'b, 'tcx> { |
265 | cx: &'a mut TypeChecker<'b, 'tcx>, | |
266 | body: &'b Body<'tcx>, | |
f9f354fc | 267 | promoted: &'b IndexVec<Promoted, Body<'tcx>>, |
7453a54e | 268 | last_span: Span, |
abe05a73 | 269 | errors_reported: bool, |
7453a54e SL |
270 | } |
271 | ||
dc9dc135 | 272 | impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { |
7453a54e | 273 | fn visit_span(&mut self, span: &Span) { |
8faf50e0 | 274 | if !span.is_dummy() { |
7453a54e SL |
275 | self.last_span = *span; |
276 | } | |
277 | } | |
278 | ||
48663c56 | 279 | fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { |
ff7c6d11 | 280 | self.sanitize_place(place, location, context); |
7453a54e SL |
281 | } |
282 | ||
9e0c209e SL |
283 | fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { |
284 | self.super_constant(constant, location); | |
6a06907d | 285 | let ty = self.sanitize_type(constant, constant.literal.ty()); |
e74abb32 XL |
286 | |
287 | self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| { | |
288 | let live_region_vid = | |
289 | self.cx.borrowck_context.universal_regions.to_region_vid(live_region); | |
290 | self.cx | |
291 | .borrowck_context | |
292 | .constraints | |
293 | .liveness_constraints | |
294 | .add_element(live_region_vid, location); | |
295 | }); | |
b7449926 | 296 | |
0731742a | 297 | if let Some(annotation_index) = constant.user_ty { |
b7449926 | 298 | if let Err(terr) = self.cx.relate_type_and_user_type( |
6a06907d | 299 | constant.literal.ty(), |
b7449926 | 300 | ty::Variance::Invariant, |
dfeec247 | 301 | &UserTypeProjection { base: annotation_index, projs: vec![] }, |
0bf4aa26 XL |
302 | location.to_locations(), |
303 | ConstraintCategory::Boring, | |
b7449926 | 304 | ) { |
9fa01778 | 305 | let annotation = &self.cx.user_type_annotations[annotation_index]; |
b7449926 XL |
306 | span_mirbug!( |
307 | self, | |
308 | constant, | |
309 | "bad constant user type {:?} vs {:?}: {:?}", | |
0731742a | 310 | annotation, |
6a06907d | 311 | constant.literal.ty(), |
b7449926 XL |
312 | terr, |
313 | ); | |
314 | } | |
9fa01778 | 315 | } else { |
60c5eb7d | 316 | let tcx = self.tcx(); |
6a06907d XL |
317 | let maybe_uneval = match constant.literal { |
318 | ConstantKind::Ty(ct) => match ct.val { | |
319 | ty::ConstKind::Unevaluated(def, substs, promoted) => { | |
320 | Some((def, substs, promoted)) | |
321 | } | |
322 | _ => None, | |
323 | }, | |
324 | _ => None, | |
325 | }; | |
326 | if let Some((def, substs, promoted)) = maybe_uneval { | |
dfeec247 XL |
327 | if let Some(promoted) = promoted { |
328 | let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, | |
f9f354fc | 329 | promoted: &Body<'tcx>, |
dfeec247 XL |
330 | ty, |
331 | san_ty| { | |
332 | if let Err(terr) = verifier.cx.eq_types( | |
333 | san_ty, | |
334 | ty, | |
335 | location.to_locations(), | |
336 | ConstraintCategory::Boring, | |
337 | ) { | |
338 | span_mirbug!( | |
339 | verifier, | |
340 | promoted, | |
341 | "bad promoted type ({:?}: {:?}): {:?}", | |
342 | ty, | |
343 | san_ty, | |
344 | terr | |
345 | ); | |
346 | }; | |
347 | }; | |
348 | ||
349 | if !self.errors_reported { | |
f9f354fc | 350 | let promoted_body = &self.promoted[promoted]; |
dfeec247 XL |
351 | self.sanitize_promoted(promoted_body, location); |
352 | ||
353 | let promoted_ty = promoted_body.return_ty(); | |
f9f354fc | 354 | check_err(self, promoted_body, ty, promoted_ty); |
dfeec247 XL |
355 | } |
356 | } else { | |
357 | if let Err(terr) = self.cx.fully_perform_op( | |
358 | location.to_locations(), | |
359 | ConstraintCategory::Boring, | |
360 | self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( | |
6a06907d | 361 | constant.literal.ty(), |
3dfed10e | 362 | def.did, |
dfeec247 XL |
363 | UserSubsts { substs, user_self_ty: None }, |
364 | )), | |
365 | ) { | |
366 | span_mirbug!( | |
367 | self, | |
368 | constant, | |
369 | "bad constant type {:?} ({:?})", | |
370 | constant, | |
371 | terr | |
372 | ); | |
373 | } | |
9fa01778 | 374 | } |
60c5eb7d XL |
375 | } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { |
376 | let unnormalized_ty = tcx.type_of(static_def_id); | |
377 | let locations = location.to_locations(); | |
378 | let normalized_ty = self.cx.normalize(unnormalized_ty, locations); | |
6a06907d | 379 | let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty; |
60c5eb7d XL |
380 | |
381 | if let Err(terr) = self.cx.eq_types( | |
382 | normalized_ty, | |
383 | literal_ty, | |
384 | locations, | |
385 | ConstraintCategory::Boring, | |
386 | ) { | |
387 | span_mirbug!(self, constant, "bad static type {:?} ({:?})", constant, terr); | |
388 | } | |
9fa01778 | 389 | } |
dfeec247 | 390 | |
6a06907d | 391 | if let ty::FnDef(def_id, substs) = *constant.literal.ty().kind() { |
dfeec247 | 392 | let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); |
532ac7d7 XL |
393 | self.cx.normalize_and_prove_instantiated_predicates( |
394 | instantiated_predicates, | |
395 | location.to_locations(), | |
396 | ); | |
397 | } | |
b7449926 | 398 | } |
7453a54e SL |
399 | } |
400 | ||
9e0c209e SL |
401 | fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { |
402 | self.super_rvalue(rvalue, location); | |
dc9dc135 | 403 | let rval_ty = rvalue.ty(self.body, self.tcx()); |
8bb4bdeb | 404 | self.sanitize_type(rvalue, rval_ty); |
7453a54e SL |
405 | } |
406 | ||
abe05a73 XL |
407 | fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { |
408 | self.super_local_decl(local, local_decl); | |
cc61c64b | 409 | self.sanitize_type(local_decl, local_decl.ty); |
b7449926 | 410 | |
f9f354fc XL |
411 | if let Some(user_ty) = &local_decl.user_ty { |
412 | for (user_ty, span) in user_ty.projections_and_spans() { | |
413 | let ty = if !local_decl.is_nonref_binding() { | |
414 | // If we have a binding of the form `let ref x: T = ..` | |
415 | // then remove the outermost reference so we can check the | |
416 | // type annotation for the remaining type. | |
1b1a35ee | 417 | if let ty::Ref(_, rty, _) = local_decl.ty.kind() { |
f9f354fc XL |
418 | rty |
419 | } else { | |
420 | bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); | |
421 | } | |
0731742a | 422 | } else { |
f9f354fc XL |
423 | local_decl.ty |
424 | }; | |
0731742a | 425 | |
f9f354fc XL |
426 | if let Err(terr) = self.cx.relate_type_and_user_type( |
427 | ty, | |
428 | ty::Variance::Invariant, | |
429 | user_ty, | |
430 | Locations::All(*span), | |
431 | ConstraintCategory::TypeAnnotation, | |
432 | ) { | |
433 | span_mirbug!( | |
434 | self, | |
435 | local, | |
436 | "bad user type on variable {:?}: {:?} != {:?} ({:?})", | |
437 | local, | |
438 | local_decl.ty, | |
439 | local_decl.user_ty, | |
440 | terr, | |
441 | ); | |
442 | } | |
b7449926 XL |
443 | } |
444 | } | |
cc61c64b XL |
445 | } |
446 | ||
ba9703b0 | 447 | fn visit_body(&mut self, body: &Body<'tcx>) { |
dc9dc135 XL |
448 | self.sanitize_type(&"return type", body.return_ty()); |
449 | for local_decl in &body.local_decls { | |
c30ab7b3 | 450 | self.sanitize_type(local_decl, local_decl.ty); |
7453a54e SL |
451 | } |
452 | if self.errors_reported { | |
453 | return; | |
454 | } | |
dc9dc135 | 455 | self.super_body(body); |
7453a54e SL |
456 | } |
457 | } | |
458 | ||
dc9dc135 | 459 | impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { |
e1599b0c XL |
460 | fn new( |
461 | cx: &'a mut TypeChecker<'b, 'tcx>, | |
462 | body: &'b Body<'tcx>, | |
f9f354fc | 463 | promoted: &'b IndexVec<Promoted, Body<'tcx>>, |
e1599b0c | 464 | ) -> Self { |
29967ef6 | 465 | TypeVerifier { body, promoted, cx, last_span: body.span, errors_reported: false } |
7453a54e SL |
466 | } |
467 | ||
dc9dc135 | 468 | fn tcx(&self) -> TyCtxt<'tcx> { |
7453a54e SL |
469 | self.cx.infcx.tcx |
470 | } | |
471 | ||
0531ce1d | 472 | fn sanitize_type(&mut self, parent: &dyn fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> { |
a1dfa0c6 | 473 | if ty.has_escaping_bound_vars() || ty.references_error() { |
7453a54e SL |
474 | span_mirbug_and_err!(self, parent, "bad type {:?}", ty) |
475 | } else { | |
476 | ty | |
477 | } | |
478 | } | |
479 | ||
ff7c6d11 XL |
480 | /// Checks that the types internal to the `place` match up with |
481 | /// what would be expected. | |
482 | fn sanitize_place( | |
483 | &mut self, | |
484 | place: &Place<'tcx>, | |
485 | location: Location, | |
48663c56 | 486 | context: PlaceContext, |
ff7c6d11 XL |
487 | ) -> PlaceTy<'tcx> { |
488 | debug!("sanitize_place: {:?}", place); | |
dc9dc135 | 489 | |
dfeec247 | 490 | let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty); |
dc9dc135 | 491 | |
e1599b0c XL |
492 | for elem in place.projection.iter() { |
493 | if place_ty.variant_index.is_none() { | |
494 | if place_ty.ty.references_error() { | |
495 | assert!(self.errors_reported); | |
f035d41b | 496 | return PlaceTy::from_ty(self.tcx().ty_error()); |
7453a54e | 497 | } |
ff7c6d11 | 498 | } |
e1599b0c XL |
499 | place_ty = self.sanitize_projection(place_ty, elem, place, location) |
500 | } | |
2c00a5a8 | 501 | |
60c5eb7d | 502 | if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { |
dfeec247 XL |
503 | let tcx = self.tcx(); |
504 | let trait_ref = ty::TraitRef { | |
3dfed10e | 505 | def_id: tcx.require_lang_item(LangItem::Copy, Some(self.last_span)), |
dfeec247 | 506 | substs: tcx.mk_substs_trait(place_ty.ty, &[]), |
60c5eb7d XL |
507 | }; |
508 | ||
dfeec247 XL |
509 | // To have a `Copy` operand, the type `T` of the |
510 | // value must be `Copy`. Note that we prove that `T: Copy`, | |
511 | // rather than using the `is_copy_modulo_regions` | |
512 | // test. This is important because | |
513 | // `is_copy_modulo_regions` ignores the resulting region | |
514 | // obligations and assumes they pass. This can result in | |
515 | // bounds from `Copy` impls being unsoundly ignored (e.g., | |
516 | // #29149). Note that we decide to use `Copy` before knowing | |
517 | // whether the bounds fully apply: in effect, the rule is | |
518 | // that if a value of some type could implement `Copy`, then | |
519 | // it must. | |
520 | self.cx.prove_trait_ref( | |
521 | trait_ref, | |
522 | location.to_locations(), | |
523 | ConstraintCategory::CopyBound, | |
524 | ); | |
60c5eb7d XL |
525 | } |
526 | ||
e1599b0c | 527 | place_ty |
7453a54e SL |
528 | } |
529 | ||
f9f354fc | 530 | fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) { |
9fa01778 XL |
531 | // Determine the constraints from the promoted MIR by running the type |
532 | // checker on the promoted MIR, then transfer the constraints back to | |
533 | // the main MIR, changing the locations to the provided location. | |
534 | ||
f9f354fc | 535 | let parent_body = mem::replace(&mut self.body, promoted_body); |
9fa01778 | 536 | |
e74abb32 XL |
537 | // Use new sets of constraints and closure bounds so that we can |
538 | // modify their locations. | |
9fa01778 XL |
539 | let all_facts = &mut None; |
540 | let mut constraints = Default::default(); | |
541 | let mut closure_bounds = Default::default(); | |
dfeec247 XL |
542 | let mut liveness_constraints = |
543 | LivenessValues::new(Rc::new(RegionValueElements::new(&promoted_body))); | |
48663c56 | 544 | // Don't try to add borrow_region facts for the promoted MIR |
48663c56 | 545 | |
e74abb32 XL |
546 | let mut swap_constraints = |this: &mut Self| { |
547 | mem::swap(this.cx.borrowck_context.all_facts, all_facts); | |
548 | mem::swap( | |
549 | &mut this.cx.borrowck_context.constraints.outlives_constraints, | |
dfeec247 | 550 | &mut constraints, |
e74abb32 XL |
551 | ); |
552 | mem::swap( | |
553 | &mut this.cx.borrowck_context.constraints.closure_bounds_mapping, | |
dfeec247 | 554 | &mut closure_bounds, |
e74abb32 XL |
555 | ); |
556 | mem::swap( | |
557 | &mut this.cx.borrowck_context.constraints.liveness_constraints, | |
dfeec247 | 558 | &mut liveness_constraints, |
e74abb32 XL |
559 | ); |
560 | }; | |
561 | ||
562 | swap_constraints(self); | |
9fa01778 | 563 | |
ba9703b0 | 564 | self.visit_body(&promoted_body); |
9fa01778 XL |
565 | |
566 | if !self.errors_reported { | |
567 | // if verifier failed, don't do further checks to avoid ICEs | |
dc9dc135 | 568 | self.cx.typeck_mir(promoted_body); |
9fa01778 XL |
569 | } |
570 | ||
dc9dc135 | 571 | self.body = parent_body; |
9fa01778 | 572 | // Merge the outlives constraints back in, at the given location. |
e74abb32 | 573 | swap_constraints(self); |
9fa01778 | 574 | |
48663c56 | 575 | let locations = location.to_locations(); |
dc9dc135 | 576 | for constraint in constraints.outlives().iter() { |
48663c56 XL |
577 | let mut constraint = *constraint; |
578 | constraint.locations = locations; | |
f035d41b | 579 | if let ConstraintCategory::Return(_) |
e74abb32 XL |
580 | | ConstraintCategory::UseAsConst |
581 | | ConstraintCategory::UseAsStatic = constraint.category | |
48663c56 | 582 | { |
74b04a01 | 583 | // "Returning" from a promoted is an assignment to a |
48663c56 XL |
584 | // temporary from the user's point of view. |
585 | constraint.category = ConstraintCategory::Boring; | |
9fa01778 | 586 | } |
48663c56 XL |
587 | self.cx.borrowck_context.constraints.outlives_constraints.push(constraint) |
588 | } | |
e74abb32 | 589 | for live_region in liveness_constraints.rows() { |
dfeec247 XL |
590 | self.cx |
591 | .borrowck_context | |
592 | .constraints | |
593 | .liveness_constraints | |
e74abb32 XL |
594 | .add_element(live_region, location); |
595 | } | |
48663c56 XL |
596 | |
597 | if !closure_bounds.is_empty() { | |
dfeec247 XL |
598 | let combined_bounds_mapping = |
599 | closure_bounds.into_iter().flat_map(|(_, value)| value).collect(); | |
600 | let existing = self | |
601 | .cx | |
602 | .borrowck_context | |
48663c56 XL |
603 | .constraints |
604 | .closure_bounds_mapping | |
605 | .insert(location, combined_bounds_mapping); | |
dfeec247 | 606 | assert!(existing.is_none(), "Multiple promoteds/closures at the same location."); |
9fa01778 XL |
607 | } |
608 | } | |
609 | ||
abe05a73 XL |
610 | fn sanitize_projection( |
611 | &mut self, | |
ff7c6d11 | 612 | base: PlaceTy<'tcx>, |
f9f354fc | 613 | pi: PlaceElem<'tcx>, |
ff7c6d11 | 614 | place: &Place<'tcx>, |
abe05a73 | 615 | location: Location, |
ff7c6d11 XL |
616 | ) -> PlaceTy<'tcx> { |
617 | debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place); | |
7453a54e | 618 | let tcx = self.tcx(); |
532ac7d7 | 619 | let base_ty = base.ty; |
f9f354fc | 620 | match pi { |
7453a54e | 621 | ProjectionElem::Deref => { |
2c00a5a8 | 622 | let deref_ty = base_ty.builtin_deref(true); |
dfeec247 XL |
623 | PlaceTy::from_ty(deref_ty.map(|t| t.ty).unwrap_or_else(|| { |
624 | span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty) | |
625 | })) | |
7453a54e | 626 | } |
ea8adc8c | 627 | ProjectionElem::Index(i) => { |
dc9dc135 | 628 | let index_ty = Place::from(i).ty(self.body, tcx).ty; |
7453a54e | 629 | if index_ty != tcx.types.usize { |
dfeec247 | 630 | PlaceTy::from_ty(span_mirbug_and_err!(self, i, "index by non-usize {:?}", i)) |
7453a54e | 631 | } else { |
dfeec247 XL |
632 | PlaceTy::from_ty(base_ty.builtin_index().unwrap_or_else(|| { |
633 | span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty) | |
634 | })) | |
7453a54e SL |
635 | } |
636 | } | |
637 | ProjectionElem::ConstantIndex { .. } => { | |
638 | // consider verifying in-bounds | |
dfeec247 XL |
639 | PlaceTy::from_ty(base_ty.builtin_index().unwrap_or_else(|| { |
640 | span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty) | |
641 | })) | |
7453a54e | 642 | } |
dfeec247 | 643 | ProjectionElem::Subslice { from, to, from_end } => { |
1b1a35ee | 644 | PlaceTy::from_ty(match base_ty.kind() { |
60c5eb7d XL |
645 | ty::Array(inner, _) => { |
646 | assert!(!from_end, "array subslices should not use from_end"); | |
1b1a35ee | 647 | tcx.mk_array(inner, to - from) |
3157f602 | 648 | } |
60c5eb7d XL |
649 | ty::Slice(..) => { |
650 | assert!(from_end, "slice subslices should use from_end"); | |
651 | base_ty | |
dfeec247 | 652 | } |
ff7c6d11 | 653 | _ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty), |
dfeec247 XL |
654 | }) |
655 | } | |
1b1a35ee | 656 | ProjectionElem::Downcast(maybe_name, index) => match base_ty.kind() { |
532ac7d7 | 657 | ty::Adt(adt_def, _substs) if adt_def.is_enum() => { |
a1dfa0c6 | 658 | if index.as_usize() >= adt_def.variants.len() { |
dfeec247 XL |
659 | PlaceTy::from_ty(span_mirbug_and_err!( |
660 | self, | |
661 | place, | |
662 | "cast to variant #{:?} but enum only has {:?}", | |
663 | index, | |
664 | adt_def.variants.len() | |
665 | )) | |
abe05a73 | 666 | } else { |
dfeec247 | 667 | PlaceTy { ty: base_ty, variant_index: Some(index) } |
7453a54e | 668 | } |
abe05a73 | 669 | } |
48663c56 XL |
670 | // We do not need to handle generators here, because this runs |
671 | // before the generator transform stage. | |
532ac7d7 XL |
672 | _ => { |
673 | let ty = if let Some(name) = maybe_name { | |
674 | span_mirbug_and_err!( | |
675 | self, | |
676 | place, | |
677 | "can't downcast {:?} as {:?}", | |
678 | base_ty, | |
679 | name | |
680 | ) | |
681 | } else { | |
682 | span_mirbug_and_err!(self, place, "can't downcast {:?}", base_ty) | |
683 | }; | |
684 | PlaceTy::from_ty(ty) | |
dfeec247 | 685 | } |
abe05a73 | 686 | }, |
7453a54e | 687 | ProjectionElem::Field(field, fty) => { |
ff7c6d11 XL |
688 | let fty = self.sanitize_type(place, fty); |
689 | match self.field_ty(place, base, field, location) { | |
dfeec247 | 690 | Ok(ty) => { |
ba9703b0 | 691 | let ty = self.cx.normalize(ty, location); |
dfeec247 | 692 | if let Err(terr) = self.cx.eq_types( |
ff7c6d11 XL |
693 | ty, |
694 | fty, | |
dfeec247 XL |
695 | location.to_locations(), |
696 | ConstraintCategory::Boring, | |
697 | ) { | |
698 | span_mirbug!( | |
699 | self, | |
700 | place, | |
701 | "bad field access ({:?}: {:?}): {:?}", | |
702 | ty, | |
703 | fty, | |
704 | terr | |
705 | ); | |
706 | } | |
707 | } | |
abe05a73 XL |
708 | Err(FieldAccessError::OutOfRange { field_count }) => span_mirbug!( |
709 | self, | |
ff7c6d11 | 710 | place, |
abe05a73 XL |
711 | "accessed field #{} but variant only has {}", |
712 | field.index(), | |
713 | field_count | |
714 | ), | |
7453a54e | 715 | } |
532ac7d7 | 716 | PlaceTy::from_ty(fty) |
7453a54e SL |
717 | } |
718 | } | |
719 | } | |
720 | ||
721 | fn error(&mut self) -> Ty<'tcx> { | |
722 | self.errors_reported = true; | |
f035d41b | 723 | self.tcx().ty_error() |
7453a54e SL |
724 | } |
725 | ||
abe05a73 XL |
726 | fn field_ty( |
727 | &mut self, | |
0531ce1d | 728 | parent: &dyn fmt::Debug, |
ff7c6d11 | 729 | base_ty: PlaceTy<'tcx>, |
abe05a73 XL |
730 | field: Field, |
731 | location: Location, | |
732 | ) -> Result<Ty<'tcx>, FieldAccessError> { | |
7453a54e SL |
733 | let tcx = self.tcx(); |
734 | ||
735 | let (variant, substs) = match base_ty { | |
1b1a35ee | 736 | PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() { |
48663c56 XL |
737 | ty::Adt(adt_def, substs) => (&adt_def.variants[variant_index], substs), |
738 | ty::Generator(def_id, substs, _) => { | |
e74abb32 | 739 | let mut variants = substs.as_generator().state_tys(def_id, tcx); |
48663c56 XL |
740 | let mut variant = match variants.nth(variant_index.into()) { |
741 | Some(v) => v, | |
dfeec247 XL |
742 | None => bug!( |
743 | "variant_index of generator out of range: {:?}/{:?}", | |
744 | variant_index, | |
745 | substs.as_generator().state_tys(def_id, tcx).count() | |
746 | ), | |
48663c56 XL |
747 | }; |
748 | return match variant.nth(field.index()) { | |
749 | Some(ty) => Ok(ty), | |
dfeec247 XL |
750 | None => Err(FieldAccessError::OutOfRange { field_count: variant.count() }), |
751 | }; | |
532ac7d7 | 752 | } |
48663c56 | 753 | _ => bug!("can't have downcast of non-adt non-generator type"), |
dfeec247 | 754 | }, |
1b1a35ee | 755 | PlaceTy { ty, variant_index: None } => match *ty.kind() { |
dfeec247 XL |
756 | ty::Adt(adt_def, substs) if !adt_def.is_enum() => { |
757 | (&adt_def.variants[VariantIdx::new(0)], substs) | |
758 | } | |
ba9703b0 | 759 | ty::Closure(_, substs) => { |
fc512014 XL |
760 | return match substs |
761 | .as_closure() | |
762 | .tupled_upvars_ty() | |
763 | .tuple_element_ty(field.index()) | |
764 | { | |
476ff2be SL |
765 | Some(ty) => Ok(ty), |
766 | None => Err(FieldAccessError::OutOfRange { | |
ba9703b0 | 767 | field_count: substs.as_closure().upvar_tys().count(), |
abe05a73 | 768 | }), |
dfeec247 | 769 | }; |
476ff2be | 770 | } |
ba9703b0 | 771 | ty::Generator(_, substs, _) => { |
48663c56 XL |
772 | // Only prefix fields (upvars and current state) are |
773 | // accessible without a variant index. | |
ba9703b0 | 774 | return match substs.as_generator().prefix_tys().nth(field.index()) { |
ea8adc8c XL |
775 | Some(ty) => Ok(ty), |
776 | None => Err(FieldAccessError::OutOfRange { | |
ba9703b0 | 777 | field_count: substs.as_generator().prefix_tys().count(), |
abe05a73 | 778 | }), |
dfeec247 | 779 | }; |
ea8adc8c | 780 | } |
b7449926 | 781 | ty::Tuple(tys) => { |
7453a54e | 782 | return match tys.get(field.index()) { |
48663c56 | 783 | Some(&ty) => Ok(ty.expect_ty()), |
dfeec247 XL |
784 | None => Err(FieldAccessError::OutOfRange { field_count: tys.len() }), |
785 | }; | |
7453a54e | 786 | } |
abe05a73 XL |
787 | _ => { |
788 | return Ok(span_mirbug_and_err!( | |
789 | self, | |
790 | parent, | |
791 | "can't project out of {:?}", | |
792 | base_ty | |
dfeec247 | 793 | )); |
abe05a73 XL |
794 | } |
795 | }, | |
7453a54e SL |
796 | }; |
797 | ||
798 | if let Some(field) = variant.fields.get(field.index()) { | |
fc512014 | 799 | Ok(self.cx.normalize(field.ty(tcx, substs), location)) |
7453a54e | 800 | } else { |
dfeec247 | 801 | Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() }) |
7453a54e SL |
802 | } |
803 | } | |
7453a54e SL |
804 | } |
805 | ||
abe05a73 XL |
806 | /// The MIR type checker. Visits the MIR and enforces all the |
807 | /// constraints needed for it to be valid and well-typed. Along the | |
808 | /// way, it accrues region constraints -- these can later be used by | |
809 | /// NLL region checking. | |
dc9dc135 XL |
810 | struct TypeChecker<'a, 'tcx> { |
811 | infcx: &'a InferCtxt<'a, 'tcx>, | |
812 | param_env: ty::ParamEnv<'tcx>, | |
476ff2be | 813 | last_span: Span, |
dc9dc135 | 814 | body: &'a Body<'tcx>, |
9fa01778 XL |
815 | /// User type annotations are shared between the main MIR and the MIR of |
816 | /// all of the promoted items. | |
817 | user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, | |
0bf4aa26 | 818 | region_bound_pairs: &'a RegionBoundPairs<'tcx>, |
48663c56 | 819 | implicit_region_bound: ty::Region<'tcx>, |
cc61c64b | 820 | reported_errors: FxHashSet<(Ty<'tcx>, Span)>, |
48663c56 XL |
821 | borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, |
822 | universal_region_relations: &'a UniversalRegionRelations<'tcx>, | |
74b04a01 | 823 | opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>, |
94b46f34 XL |
824 | } |
825 | ||
dc9dc135 | 826 | struct BorrowCheckContext<'a, 'tcx> { |
94b46f34 XL |
827 | universal_regions: &'a UniversalRegions<'tcx>, |
828 | location_table: &'a LocationTable, | |
829 | all_facts: &'a mut Option<AllFacts>, | |
8faf50e0 XL |
830 | borrow_set: &'a BorrowSet<'tcx>, |
831 | constraints: &'a mut MirTypeckRegionConstraints<'tcx>, | |
5869c6ff | 832 | upvars: &'a [Upvar<'tcx>], |
abe05a73 XL |
833 | } |
834 | ||
b7449926 XL |
835 | crate struct MirTypeckResults<'tcx> { |
836 | crate constraints: MirTypeckRegionConstraints<'tcx>, | |
ba9703b0 | 837 | pub(in crate::borrow_check) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, |
74b04a01 | 838 | crate opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>, |
b7449926 XL |
839 | } |
840 | ||
abe05a73 XL |
841 | /// A collection of region constraints that must be satisfied for the |
842 | /// program to be considered well-typed. | |
94b46f34 | 843 | crate struct MirTypeckRegionConstraints<'tcx> { |
a1dfa0c6 XL |
844 | /// Maps from a `ty::Placeholder` to the corresponding |
845 | /// `PlaceholderIndex` bit that we will use for it. | |
846 | /// | |
847 | /// To keep everything in sync, do not insert this set | |
848 | /// directly. Instead, use the `placeholder_region` helper. | |
849 | crate placeholder_indices: PlaceholderIndices, | |
850 | ||
851 | /// Each time we add a placeholder to `placeholder_indices`, we | |
852 | /// also create a corresponding "representative" region vid for | |
853 | /// that wraps it. This vector tracks those. This way, when we | |
854 | /// convert the same `ty::RePlaceholder(p)` twice, we can map to | |
855 | /// the same underlying `RegionVid`. | |
856 | crate placeholder_index_to_region: IndexVec<PlaceholderIndex, ty::Region<'tcx>>, | |
857 | ||
abe05a73 XL |
858 | /// In general, the type-checker is not responsible for enforcing |
859 | /// liveness constraints; this job falls to the region inferencer, | |
860 | /// which performs a liveness analysis. However, in some limited | |
861 | /// cases, the MIR type-checker creates temporary regions that do | |
862 | /// not otherwise appear in the MIR -- in particular, the | |
863 | /// late-bound regions that it instantiates at call-sites -- and | |
864 | /// hence it must report on their liveness constraints. | |
8faf50e0 | 865 | crate liveness_constraints: LivenessValues<RegionVid>, |
abe05a73 | 866 | |
dc9dc135 XL |
867 | crate outlives_constraints: OutlivesConstraintSet, |
868 | ||
869 | crate member_constraints: MemberConstraintSet<'tcx, RegionVid>, | |
abe05a73 | 870 | |
0bf4aa26 XL |
871 | crate closure_bounds_mapping: |
872 | FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>, | |
873 | ||
94b46f34 | 874 | crate type_tests: Vec<TypeTest<'tcx>>, |
abe05a73 XL |
875 | } |
876 | ||
a1dfa0c6 XL |
877 | impl MirTypeckRegionConstraints<'tcx> { |
878 | fn placeholder_region( | |
879 | &mut self, | |
dc9dc135 | 880 | infcx: &InferCtxt<'_, 'tcx>, |
a1dfa0c6 XL |
881 | placeholder: ty::PlaceholderRegion, |
882 | ) -> ty::Region<'tcx> { | |
883 | let placeholder_index = self.placeholder_indices.insert(placeholder); | |
884 | match self.placeholder_index_to_region.get(placeholder_index) { | |
885 | Some(&v) => v, | |
886 | None => { | |
5869c6ff | 887 | let origin = NllRegionVariableOrigin::Placeholder(placeholder); |
a1dfa0c6 XL |
888 | let region = infcx.next_nll_region_var_in_universe(origin, placeholder.universe); |
889 | self.placeholder_index_to_region.push(region); | |
890 | region | |
891 | } | |
892 | } | |
893 | } | |
894 | } | |
895 | ||
83c7162d XL |
896 | /// The `Locations` type summarizes *where* region constraints are |
897 | /// required to hold. Normally, this is at a particular point which | |
898 | /// created the obligation, but for constraints that the user gave, we | |
899 | /// want the constraint to hold at all points. | |
8faf50e0 | 900 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] |
83c7162d XL |
901 | pub enum Locations { |
902 | /// Indicates that a type constraint should always be true. This | |
903 | /// is particularly important in the new borrowck analysis for | |
904 | /// things like the type of the return slot. Consider this | |
905 | /// example: | |
906 | /// | |
907 | /// ``` | |
908 | /// fn foo<'a>(x: &'a u32) -> &'a u32 { | |
909 | /// let y = 22; | |
910 | /// return &y; // error | |
911 | /// } | |
912 | /// ``` | |
913 | /// | |
914 | /// Here, we wind up with the signature from the return type being | |
915 | /// something like `&'1 u32` where `'1` is a universal region. But | |
916 | /// the type of the return slot `_0` is something like `&'2 u32` | |
917 | /// where `'2` is an existential region variable. The type checker | |
918 | /// requires that `&'2 u32 = &'1 u32` -- but at what point? In the | |
919 | /// older NLL analysis, we required this only at the entry point | |
920 | /// to the function. By the nature of the constraints, this wound | |
921 | /// up propagating to all points reachable from start (because | |
9fa01778 | 922 | /// `'1` -- as a universal region -- is live everywhere). In the |
83c7162d XL |
923 | /// newer analysis, though, this doesn't work: `_0` is considered |
924 | /// dead at the start (it has no usable value) and hence this type | |
925 | /// equality is basically a no-op. Then, later on, when we do `_0 | |
926 | /// = &'3 y`, that region `'3` never winds up related to the | |
927 | /// universal region `'1` and hence no error occurs. Therefore, we | |
928 | /// use Locations::All instead, which ensures that the `'1` and | |
929 | /// `'2` are equal everything. We also use this for other | |
930 | /// user-given type annotations; e.g., if the user wrote `let mut | |
931 | /// x: &'static u32 = ...`, we would ensure that all values | |
932 | /// assigned to `x` are of `'static` lifetime. | |
8faf50e0 | 933 | /// |
0bf4aa26 XL |
934 | /// The span points to the place the constraint arose. For example, |
935 | /// it points to the type in a user-given type annotation. If | |
936 | /// there's no sensible span then it's DUMMY_SP. | |
937 | All(Span), | |
938 | ||
939 | /// An outlives constraint that only has to hold at a single location, | |
940 | /// usually it represents a point where references flow from one spot to | |
941 | /// another (e.g., `x = y`) | |
942 | Single(Location), | |
83c7162d XL |
943 | } |
944 | ||
945 | impl Locations { | |
946 | pub fn from_location(&self) -> Option<Location> { | |
947 | match self { | |
0bf4aa26 XL |
948 | Locations::All(_) => None, |
949 | Locations::Single(from_location) => Some(*from_location), | |
83c7162d XL |
950 | } |
951 | } | |
952 | ||
8faf50e0 | 953 | /// Gets a span representing the location. |
dc9dc135 | 954 | pub fn span(&self, body: &Body<'_>) -> Span { |
0bf4aa26 XL |
955 | match self { |
956 | Locations::All(span) => *span, | |
dc9dc135 | 957 | Locations::Single(l) => body.source_info(*l).span, |
0bf4aa26 | 958 | } |
83c7162d | 959 | } |
7453a54e SL |
960 | } |
961 | ||
dc9dc135 | 962 | impl<'a, 'tcx> TypeChecker<'a, 'tcx> { |
abe05a73 | 963 | fn new( |
dc9dc135 XL |
964 | infcx: &'a InferCtxt<'a, 'tcx>, |
965 | body: &'a Body<'tcx>, | |
dc9dc135 | 966 | param_env: ty::ParamEnv<'tcx>, |
0bf4aa26 | 967 | region_bound_pairs: &'a RegionBoundPairs<'tcx>, |
48663c56 XL |
968 | implicit_region_bound: ty::Region<'tcx>, |
969 | borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, | |
970 | universal_region_relations: &'a UniversalRegionRelations<'tcx>, | |
abe05a73 | 971 | ) -> Self { |
0731742a | 972 | let mut checker = Self { |
3b2f2976 | 973 | infcx, |
476ff2be | 974 | last_span: DUMMY_SP, |
dc9dc135 XL |
975 | body, |
976 | user_type_annotations: &body.user_type_annotations, | |
7cac9316 | 977 | param_env, |
ff7c6d11 XL |
978 | region_bound_pairs, |
979 | implicit_region_bound, | |
94b46f34 | 980 | borrowck_context, |
0bf4aa26 XL |
981 | reported_errors: Default::default(), |
982 | universal_region_relations, | |
74b04a01 | 983 | opaque_type_values: FxHashMap::default(), |
0731742a | 984 | }; |
9fa01778 | 985 | checker.check_user_type_annotations(); |
0731742a XL |
986 | checker |
987 | } | |
988 | ||
29967ef6 XL |
989 | fn unsized_feature_enabled(&self) -> bool { |
990 | let features = self.tcx().features(); | |
991 | features.unsized_locals || features.unsized_fn_params | |
992 | } | |
993 | ||
9fa01778 XL |
994 | /// Equate the inferred type and the annotated type for user type annotations |
995 | fn check_user_type_annotations(&mut self) { | |
0731742a | 996 | debug!( |
9fa01778 | 997 | "check_user_type_annotations: user_type_annotations={:?}", |
dfeec247 | 998 | self.user_type_annotations |
0731742a | 999 | ); |
9fa01778 XL |
1000 | for user_annotation in self.user_type_annotations { |
1001 | let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; | |
dfeec247 XL |
1002 | let (annotation, _) = |
1003 | self.infcx.instantiate_canonical_with_fresh_inference_vars(span, user_ty); | |
0731742a | 1004 | match annotation { |
9fa01778 XL |
1005 | UserType::Ty(mut ty) => { |
1006 | ty = self.normalize(ty, Locations::All(span)); | |
1007 | ||
1008 | if let Err(terr) = self.eq_types( | |
1009 | ty, | |
1010 | inferred_ty, | |
1011 | Locations::All(span), | |
1012 | ConstraintCategory::BoringNoLocation, | |
1013 | ) { | |
1014 | span_mirbug!( | |
1015 | self, | |
1016 | user_annotation, | |
1017 | "bad user type ({:?} = {:?}): {:?}", | |
1018 | ty, | |
1019 | inferred_ty, | |
1020 | terr | |
1021 | ); | |
1022 | } | |
1023 | ||
1024 | self.prove_predicate( | |
5869c6ff | 1025 | ty::PredicateKind::WellFormed(inferred_ty.into()).to_predicate(self.tcx()), |
9fa01778 XL |
1026 | Locations::All(span), |
1027 | ConstraintCategory::TypeAnnotation, | |
1028 | ); | |
dfeec247 | 1029 | } |
9fa01778 XL |
1030 | UserType::TypeOf(def_id, user_substs) => { |
1031 | if let Err(terr) = self.fully_perform_op( | |
1032 | Locations::All(span), | |
1033 | ConstraintCategory::BoringNoLocation, | |
1034 | self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( | |
dfeec247 XL |
1035 | inferred_ty, |
1036 | def_id, | |
1037 | user_substs, | |
9fa01778 XL |
1038 | )), |
1039 | ) { | |
1040 | span_mirbug!( | |
1041 | self, | |
1042 | user_annotation, | |
1043 | "bad user type AscribeUserType({:?}, {:?} {:?}): {:?}", | |
1044 | inferred_ty, | |
1045 | def_id, | |
1046 | user_substs, | |
1047 | terr | |
1048 | ); | |
1049 | } | |
dfeec247 | 1050 | } |
0731742a | 1051 | } |
476ff2be SL |
1052 | } |
1053 | } | |
1054 | ||
94b46f34 XL |
1055 | /// Given some operation `op` that manipulates types, proves |
1056 | /// predicates, or otherwise uses the inference context, executes | |
1057 | /// `op` and then executes all the further obligations that `op` | |
1058 | /// returns. This will yield a set of outlives constraints amongst | |
b7449926 | 1059 | /// regions which are extracted and stored as having occurred at |
94b46f34 XL |
1060 | /// `locations`. |
1061 | /// | |
ba9703b0 | 1062 | /// **Any `rustc_infer::infer` operations that might generate region |
94b46f34 XL |
1063 | /// constraints should occur within this method so that those |
1064 | /// constraints can be properly localized!** | |
1065 | fn fully_perform_op<R>( | |
1066 | &mut self, | |
1067 | locations: Locations, | |
0bf4aa26 | 1068 | category: ConstraintCategory, |
dc9dc135 | 1069 | op: impl type_op::TypeOp<'tcx, Output = R>, |
8faf50e0 XL |
1070 | ) -> Fallible<R> { |
1071 | let (r, opt_data) = op.fully_perform(self.infcx)?; | |
1072 | ||
1073 | if let Some(data) = &opt_data { | |
0bf4aa26 | 1074 | self.push_region_constraints(locations, category, data); |
94b46f34 XL |
1075 | } |
1076 | ||
1077 | Ok(r) | |
476ff2be SL |
1078 | } |
1079 | ||
94b46f34 | 1080 | fn push_region_constraints( |
abe05a73 XL |
1081 | &mut self, |
1082 | locations: Locations, | |
0bf4aa26 | 1083 | category: ConstraintCategory, |
dc9dc135 | 1084 | data: &QueryRegionConstraints<'tcx>, |
94b46f34 | 1085 | ) { |
dfeec247 | 1086 | debug!("push_region_constraints: constraints generated at {:?} are {:#?}", locations, data); |
94b46f34 | 1087 | |
48663c56 XL |
1088 | constraint_conversion::ConstraintConversion::new( |
1089 | self.infcx, | |
1090 | self.borrowck_context.universal_regions, | |
1091 | self.region_bound_pairs, | |
1092 | Some(self.implicit_region_bound), | |
1093 | self.param_env, | |
1094 | locations, | |
1095 | category, | |
1096 | &mut self.borrowck_context.constraints, | |
dfeec247 XL |
1097 | ) |
1098 | .convert_all(data); | |
94b46f34 XL |
1099 | } |
1100 | ||
0bf4aa26 XL |
1101 | /// Convenient wrapper around `relate_tys::relate_types` -- see |
1102 | /// that fn for docs. | |
1103 | fn relate_types( | |
1104 | &mut self, | |
1105 | a: Ty<'tcx>, | |
1106 | v: ty::Variance, | |
1107 | b: Ty<'tcx>, | |
1108 | locations: Locations, | |
1109 | category: ConstraintCategory, | |
1110 | ) -> Fallible<()> { | |
1111 | relate_tys::relate_types( | |
8faf50e0 | 1112 | self.infcx, |
6a06907d | 1113 | self.param_env, |
8faf50e0 | 1114 | a, |
0bf4aa26 | 1115 | v, |
8faf50e0 | 1116 | b, |
94b46f34 | 1117 | locations, |
0bf4aa26 | 1118 | category, |
48663c56 | 1119 | Some(self.borrowck_context), |
94b46f34 | 1120 | ) |
7453a54e SL |
1121 | } |
1122 | ||
0bf4aa26 XL |
1123 | fn sub_types( |
1124 | &mut self, | |
1125 | sub: Ty<'tcx>, | |
1126 | sup: Ty<'tcx>, | |
1127 | locations: Locations, | |
1128 | category: ConstraintCategory, | |
1129 | ) -> Fallible<()> { | |
1130 | self.relate_types(sub, ty::Variance::Covariant, sup, locations, category) | |
1131 | } | |
1132 | ||
1133 | /// Try to relate `sub <: sup`; if this fails, instantiate opaque | |
1134 | /// variables in `sub` with their inferred definitions and try | |
1135 | /// again. This is used for opaque types in places (e.g., `let x: | |
1136 | /// impl Foo = ..`). | |
1137 | fn sub_types_or_anon( | |
1138 | &mut self, | |
1139 | sub: Ty<'tcx>, | |
1140 | sup: Ty<'tcx>, | |
1141 | locations: Locations, | |
1142 | category: ConstraintCategory, | |
1143 | ) -> Fallible<()> { | |
1144 | if let Err(terr) = self.sub_types(sub, sup, locations, category) { | |
1b1a35ee | 1145 | if let ty::Opaque(..) = sup.kind() { |
0bf4aa26 XL |
1146 | // When you have `let x: impl Foo = ...` in a closure, |
1147 | // the resulting inferend values are stored with the | |
1148 | // def-id of the base function. | |
f035d41b | 1149 | let parent_def_id = |
29967ef6 | 1150 | self.tcx().closure_base_def_id(self.body.source.def_id()).expect_local(); |
0bf4aa26 XL |
1151 | return self.eq_opaque_type_and_type(sub, sup, parent_def_id, locations, category); |
1152 | } else { | |
1153 | return Err(terr); | |
1154 | } | |
1155 | } | |
1156 | Ok(()) | |
1157 | } | |
1158 | ||
1159 | fn eq_types( | |
1160 | &mut self, | |
1161 | a: Ty<'tcx>, | |
1162 | b: Ty<'tcx>, | |
1163 | locations: Locations, | |
1164 | category: ConstraintCategory, | |
1165 | ) -> Fallible<()> { | |
1166 | self.relate_types(a, ty::Variance::Invariant, b, locations, category) | |
1167 | } | |
1168 | ||
b7449926 | 1169 | fn relate_type_and_user_type( |
8faf50e0 | 1170 | &mut self, |
b7449926 XL |
1171 | a: Ty<'tcx>, |
1172 | v: ty::Variance, | |
532ac7d7 | 1173 | user_ty: &UserTypeProjection, |
8faf50e0 | 1174 | locations: Locations, |
0bf4aa26 | 1175 | category: ConstraintCategory, |
8faf50e0 | 1176 | ) -> Fallible<()> { |
0bf4aa26 XL |
1177 | debug!( |
1178 | "relate_type_and_user_type(a={:?}, v={:?}, user_ty={:?}, locations={:?})", | |
1179 | a, v, user_ty, locations, | |
1180 | ); | |
1181 | ||
9fa01778 XL |
1182 | let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty; |
1183 | let mut curr_projected_ty = PlaceTy::from_ty(annotated_type); | |
13cf67c4 | 1184 | |
9fa01778 | 1185 | let tcx = self.infcx.tcx; |
0bf4aa26 | 1186 | |
9fa01778 | 1187 | for proj in &user_ty.projs { |
416331ca XL |
1188 | let projected_ty = curr_projected_ty.projection_ty_core( |
1189 | tcx, | |
1190 | self.param_env, | |
1191 | proj, | |
1192 | |this, field, &()| { | |
1193 | let ty = this.field_ty(tcx, field); | |
1194 | self.normalize(ty, locations) | |
1195 | }, | |
1196 | ); | |
9fa01778 | 1197 | curr_projected_ty = projected_ty; |
0bf4aa26 | 1198 | } |
dfeec247 XL |
1199 | debug!( |
1200 | "user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}", | |
1201 | user_ty.base, annotated_type, user_ty.projs, curr_projected_ty | |
1202 | ); | |
9fa01778 | 1203 | |
532ac7d7 | 1204 | let ty = curr_projected_ty.ty; |
9fa01778 | 1205 | self.relate_types(a, v, ty, locations, category)?; |
0bf4aa26 XL |
1206 | |
1207 | Ok(()) | |
1208 | } | |
1209 | ||
1210 | fn eq_opaque_type_and_type( | |
1211 | &mut self, | |
1212 | revealed_ty: Ty<'tcx>, | |
1213 | anon_ty: Ty<'tcx>, | |
f035d41b | 1214 | anon_owner_def_id: LocalDefId, |
0bf4aa26 XL |
1215 | locations: Locations, |
1216 | category: ConstraintCategory, | |
1217 | ) -> Fallible<()> { | |
1218 | debug!( | |
1219 | "eq_opaque_type_and_type( \ | |
1220 | revealed_ty={:?}, \ | |
1221 | anon_ty={:?})", | |
1222 | revealed_ty, anon_ty | |
1223 | ); | |
74b04a01 XL |
1224 | |
1225 | // Fast path for the common case. | |
1226 | if !anon_ty.has_opaque_types() { | |
1227 | if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) { | |
1228 | span_mirbug!( | |
1229 | self, | |
1230 | locations, | |
1231 | "eq_opaque_type_and_type: `{:?}=={:?}` failed with `{:?}`", | |
1232 | revealed_ty, | |
1233 | anon_ty, | |
1234 | terr | |
1235 | ); | |
1236 | } | |
1237 | return Ok(()); | |
1238 | } | |
1239 | ||
0bf4aa26 XL |
1240 | let infcx = self.infcx; |
1241 | let tcx = infcx.tcx; | |
1242 | let param_env = self.param_env; | |
dc9dc135 | 1243 | let body = self.body; |
3dfed10e | 1244 | let concrete_opaque_types = &tcx.typeck(anon_owner_def_id).concrete_opaque_types; |
74b04a01 XL |
1245 | let mut opaque_type_values = Vec::new(); |
1246 | ||
29967ef6 | 1247 | debug!("eq_opaque_type_and_type: mir_def_id={:?}", body.source.def_id()); |
0bf4aa26 | 1248 | let opaque_type_map = self.fully_perform_op( |
94b46f34 | 1249 | locations, |
0bf4aa26 XL |
1250 | category, |
1251 | CustomTypeOp::new( | |
1252 | |infcx| { | |
1253 | let mut obligations = ObligationAccumulator::default(); | |
1254 | ||
f035d41b | 1255 | let dummy_body_id = hir::CRATE_HIR_ID; |
0bf4aa26 XL |
1256 | let (output_ty, opaque_type_map) = |
1257 | obligations.add(infcx.instantiate_opaque_types( | |
1258 | anon_owner_def_id, | |
1259 | dummy_body_id, | |
1260 | param_env, | |
fc512014 | 1261 | anon_ty, |
dc9dc135 | 1262 | locations.span(body), |
0bf4aa26 XL |
1263 | )); |
1264 | debug!( | |
1265 | "eq_opaque_type_and_type: \ | |
1266 | instantiated output_ty={:?} \ | |
1267 | opaque_type_map={:#?} \ | |
1268 | revealed_ty={:?}", | |
1269 | output_ty, opaque_type_map, revealed_ty | |
1270 | ); | |
74b04a01 XL |
1271 | // Make sure that the inferred types are well-formed. I'm |
1272 | // not entirely sure this is needed (the HIR type check | |
1273 | // didn't do this) but it seems sensible to prevent opaque | |
1274 | // types hiding ill-formed types. | |
1275 | obligations.obligations.push(traits::Obligation::new( | |
1276 | ObligationCause::dummy(), | |
1277 | param_env, | |
5869c6ff | 1278 | ty::PredicateKind::WellFormed(revealed_ty.into()).to_predicate(infcx.tcx), |
74b04a01 | 1279 | )); |
dfeec247 XL |
1280 | obligations.add( |
1281 | infcx | |
1282 | .at(&ObligationCause::dummy(), param_env) | |
1283 | .eq(output_ty, revealed_ty)?, | |
1284 | ); | |
0bf4aa26 XL |
1285 | |
1286 | for (&opaque_def_id, opaque_decl) in &opaque_type_map { | |
fc512014 | 1287 | let resolved_ty = infcx.resolve_vars_if_possible(opaque_decl.concrete_ty); |
1b1a35ee XL |
1288 | let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() { |
1289 | *def_id == opaque_def_id | |
74b04a01 XL |
1290 | } else { |
1291 | false | |
1292 | }; | |
1293 | let opaque_defn_ty = match concrete_opaque_types.get(&opaque_def_id) { | |
1294 | None => { | |
1295 | if !concrete_is_opaque { | |
1296 | tcx.sess.delay_span_bug( | |
1297 | body.span, | |
1298 | &format!( | |
1299 | "Non-defining use of {:?} with revealed type", | |
1300 | opaque_def_id, | |
1301 | ), | |
1302 | ); | |
1303 | } | |
1304 | continue; | |
1305 | } | |
1306 | Some(opaque_defn_ty) => opaque_defn_ty, | |
1307 | }; | |
1308 | debug!("opaque_defn_ty = {:?}", opaque_defn_ty); | |
1309 | let subst_opaque_defn_ty = | |
1310 | opaque_defn_ty.concrete_type.subst(tcx, opaque_decl.substs); | |
1311 | let renumbered_opaque_defn_ty = | |
fc512014 | 1312 | renumber::renumber_regions(infcx, subst_opaque_defn_ty); |
416331ca | 1313 | |
0bf4aa26 | 1314 | debug!( |
74b04a01 XL |
1315 | "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}", |
1316 | opaque_decl.concrete_ty, resolved_ty, renumbered_opaque_defn_ty, | |
0bf4aa26 | 1317 | ); |
416331ca | 1318 | |
416331ca | 1319 | if !concrete_is_opaque { |
74b04a01 XL |
1320 | // Equate concrete_ty (an inference variable) with |
1321 | // the renumbered type from typeck. | |
dfeec247 XL |
1322 | obligations.add( |
1323 | infcx | |
1324 | .at(&ObligationCause::dummy(), param_env) | |
74b04a01 XL |
1325 | .eq(opaque_decl.concrete_ty, renumbered_opaque_defn_ty)?, |
1326 | ); | |
1327 | opaque_type_values.push(( | |
1328 | opaque_def_id, | |
1329 | ty::ResolvedOpaqueTy { | |
1330 | concrete_type: renumbered_opaque_defn_ty, | |
1331 | substs: opaque_decl.substs, | |
1332 | }, | |
1333 | )); | |
1334 | } else { | |
1335 | // We're using an opaque `impl Trait` type without | |
1336 | // 'revealing' it. For example, code like this: | |
1337 | // | |
1338 | // type Foo = impl Debug; | |
1339 | // fn foo1() -> Foo { ... } | |
1340 | // fn foo2() -> Foo { foo1() } | |
1341 | // | |
1342 | // In `foo2`, we're not revealing the type of `Foo` - we're | |
1343 | // just treating it as the opaque type. | |
1344 | // | |
1345 | // When this occurs, we do *not* want to try to equate | |
1346 | // the concrete type with the underlying defining type | |
1347 | // of the opaque type - this will always fail, since | |
1348 | // the defining type of an opaque type is always | |
1349 | // some other type (e.g. not itself) | |
1350 | // Essentially, none of the normal obligations apply here - | |
1351 | // we're just passing around some unknown opaque type, | |
1352 | // without actually looking at the underlying type it | |
1353 | // gets 'revealed' into | |
1354 | debug!( | |
1355 | "eq_opaque_type_and_type: non-defining use of {:?}", | |
1356 | opaque_def_id, | |
dfeec247 | 1357 | ); |
416331ca | 1358 | } |
0bf4aa26 XL |
1359 | } |
1360 | ||
1361 | debug!("eq_opaque_type_and_type: equated"); | |
1362 | ||
1363 | Ok(InferOk { | |
1364 | value: Some(opaque_type_map), | |
1365 | obligations: obligations.into_vec(), | |
1366 | }) | |
1367 | }, | |
1368 | || "input_output".to_string(), | |
1369 | ), | |
1370 | )?; | |
1371 | ||
74b04a01 XL |
1372 | self.opaque_type_values.extend(opaque_type_values); |
1373 | ||
48663c56 | 1374 | let universal_region_relations = self.universal_region_relations; |
0bf4aa26 XL |
1375 | |
1376 | // Finally, if we instantiated the anon types successfully, we | |
1377 | // have to solve any bounds (e.g., `-> impl Iterator` needs to | |
1378 | // prove that `T: Iterator` where `T` is the type we | |
1379 | // instantiated it with). | |
1380 | if let Some(opaque_type_map) = opaque_type_map { | |
1381 | for (opaque_def_id, opaque_decl) in opaque_type_map { | |
1382 | self.fully_perform_op( | |
1383 | locations, | |
1384 | ConstraintCategory::OpaqueType, | |
1385 | CustomTypeOp::new( | |
1386 | |_cx| { | |
1387 | infcx.constrain_opaque_type( | |
1388 | opaque_def_id, | |
1389 | &opaque_decl, | |
74b04a01 | 1390 | GenerateMemberConstraints::IfNoStaticBound, |
0bf4aa26 XL |
1391 | universal_region_relations, |
1392 | ); | |
dfeec247 | 1393 | Ok(InferOk { value: (), obligations: vec![] }) |
0bf4aa26 XL |
1394 | }, |
1395 | || "opaque_type_map".to_string(), | |
1396 | ), | |
1397 | )?; | |
1398 | } | |
1399 | } | |
1400 | Ok(()) | |
7453a54e SL |
1401 | } |
1402 | ||
dc9dc135 | 1403 | fn tcx(&self) -> TyCtxt<'tcx> { |
7453a54e SL |
1404 | self.infcx.tcx |
1405 | } | |
1406 | ||
f9f354fc | 1407 | fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) { |
7453a54e SL |
1408 | debug!("check_stmt: {:?}", stmt); |
1409 | let tcx = self.tcx(); | |
1410 | match stmt.kind { | |
dfeec247 | 1411 | StatementKind::Assign(box (ref place, ref rv)) => { |
8faf50e0 XL |
1412 | // Assignments to temporaries are not "interesting"; |
1413 | // they are not caused by the user, but rather artifacts | |
1414 | // of lowering. Assignments to other sorts of places *are* interesting | |
1415 | // though. | |
e74abb32 | 1416 | let category = match place.as_local() { |
dfeec247 XL |
1417 | Some(RETURN_PLACE) => { |
1418 | if let BorrowCheckContext { | |
1419 | universal_regions: | |
1420 | UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, | |
1421 | .. | |
1422 | } = self.borrowck_context | |
1423 | { | |
1424 | if tcx.is_static(*def_id) { | |
1425 | ConstraintCategory::UseAsStatic | |
1426 | } else { | |
1427 | ConstraintCategory::UseAsConst | |
1428 | } | |
0bf4aa26 | 1429 | } else { |
f035d41b | 1430 | ConstraintCategory::Return(ReturnConstraint::Normal) |
0bf4aa26 | 1431 | } |
dfeec247 | 1432 | } |
60c5eb7d | 1433 | Some(l) if !body.local_decls[l].is_user_variable() => { |
0bf4aa26 XL |
1434 | ConstraintCategory::Boring |
1435 | } | |
1436 | _ => ConstraintCategory::Assignment, | |
8faf50e0 XL |
1437 | }; |
1438 | ||
f9f354fc | 1439 | let place_ty = place.ty(body, tcx).ty; |
e74abb32 | 1440 | let place_ty = self.normalize(place_ty, location); |
f9f354fc | 1441 | let rv_ty = rv.ty(body, tcx); |
e74abb32 | 1442 | let rv_ty = self.normalize(rv_ty, location); |
0bf4aa26 XL |
1443 | if let Err(terr) = |
1444 | self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category) | |
1445 | { | |
abe05a73 XL |
1446 | span_mirbug!( |
1447 | self, | |
1448 | stmt, | |
1449 | "bad assignment ({:?} = {:?}): {:?}", | |
ff7c6d11 | 1450 | place_ty, |
abe05a73 XL |
1451 | rv_ty, |
1452 | terr | |
1453 | ); | |
5bcae85e | 1454 | } |
b7449926 | 1455 | |
0731742a | 1456 | if let Some(annotation_index) = self.rvalue_user_ty(rv) { |
b7449926 XL |
1457 | if let Err(terr) = self.relate_type_and_user_type( |
1458 | rv_ty, | |
1459 | ty::Variance::Invariant, | |
dfeec247 | 1460 | &UserTypeProjection { base: annotation_index, projs: vec![] }, |
0bf4aa26 XL |
1461 | location.to_locations(), |
1462 | ConstraintCategory::Boring, | |
b7449926 | 1463 | ) { |
9fa01778 | 1464 | let annotation = &self.user_type_annotations[annotation_index]; |
b7449926 XL |
1465 | span_mirbug!( |
1466 | self, | |
1467 | stmt, | |
1468 | "bad user type on rvalue ({:?} = {:?}): {:?}", | |
0731742a | 1469 | annotation, |
b7449926 XL |
1470 | rv_ty, |
1471 | terr | |
1472 | ); | |
1473 | } | |
1474 | } | |
1475 | ||
dc9dc135 | 1476 | self.check_rvalue(body, rv, location); |
29967ef6 | 1477 | if !self.unsized_feature_enabled() { |
b7449926 | 1478 | let trait_ref = ty::TraitRef { |
3dfed10e | 1479 | def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), |
b7449926 XL |
1480 | substs: tcx.mk_substs_trait(place_ty, &[]), |
1481 | }; | |
0bf4aa26 XL |
1482 | self.prove_trait_ref( |
1483 | trait_ref, | |
1484 | location.to_locations(), | |
1485 | ConstraintCategory::SizedBound, | |
1486 | ); | |
b7449926 | 1487 | } |
5bcae85e | 1488 | } |
dfeec247 | 1489 | StatementKind::SetDiscriminant { ref place, variant_index } => { |
f9f354fc | 1490 | let place_type = place.ty(body, tcx).ty; |
1b1a35ee | 1491 | let adt = match place_type.kind() { |
532ac7d7 | 1492 | ty::Adt(adt, _) if adt.is_enum() => adt, |
5bcae85e | 1493 | _ => { |
abe05a73 XL |
1494 | span_bug!( |
1495 | stmt.source_info.span, | |
1496 | "bad set discriminant ({:?} = {:?}): lhs is not an enum", | |
ff7c6d11 | 1497 | place, |
abe05a73 XL |
1498 | variant_index |
1499 | ); | |
5bcae85e SL |
1500 | } |
1501 | }; | |
a1dfa0c6 | 1502 | if variant_index.as_usize() >= adt.variants.len() { |
abe05a73 XL |
1503 | span_bug!( |
1504 | stmt.source_info.span, | |
1505 | "bad set discriminant ({:?} = {:?}): value of of range", | |
ff7c6d11 | 1506 | place, |
abe05a73 XL |
1507 | variant_index |
1508 | ); | |
5bcae85e SL |
1509 | }; |
1510 | } | |
dfeec247 | 1511 | StatementKind::AscribeUserType(box (ref place, ref projection), variance) => { |
f9f354fc | 1512 | let place_ty = place.ty(body, tcx).ty; |
0bf4aa26 XL |
1513 | if let Err(terr) = self.relate_type_and_user_type( |
1514 | place_ty, | |
1515 | variance, | |
0731742a | 1516 | projection, |
0bf4aa26 XL |
1517 | Locations::All(stmt.source_info.span), |
1518 | ConstraintCategory::TypeAnnotation, | |
1519 | ) { | |
9fa01778 | 1520 | let annotation = &self.user_type_annotations[projection.base]; |
0531ce1d XL |
1521 | span_mirbug!( |
1522 | self, | |
1523 | stmt, | |
0731742a | 1524 | "bad type assert ({:?} <: {:?} with projections {:?}): {:?}", |
b7449926 | 1525 | place_ty, |
0731742a XL |
1526 | annotation, |
1527 | projection.projs, | |
0531ce1d XL |
1528 | terr |
1529 | ); | |
1530 | } | |
1531 | } | |
6a06907d XL |
1532 | StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { |
1533 | .. | |
1534 | }) => span_bug!( | |
1535 | stmt.source_info.span, | |
1536 | "Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics", | |
1537 | ), | |
0bf4aa26 | 1538 | StatementKind::FakeRead(..) |
a1dfa0c6 XL |
1539 | | StatementKind::StorageLive(..) |
1540 | | StatementKind::StorageDead(..) | |
ba9703b0 | 1541 | | StatementKind::LlvmInlineAsm { .. } |
a1dfa0c6 | 1542 | | StatementKind::Retag { .. } |
3dfed10e | 1543 | | StatementKind::Coverage(..) |
ff7c6d11 | 1544 | | StatementKind::Nop => {} |
7453a54e SL |
1545 | } |
1546 | } | |
1547 | ||
abe05a73 XL |
1548 | fn check_terminator( |
1549 | &mut self, | |
dc9dc135 | 1550 | body: &Body<'tcx>, |
abe05a73 XL |
1551 | term: &Terminator<'tcx>, |
1552 | term_location: Location, | |
1553 | ) { | |
7453a54e SL |
1554 | debug!("check_terminator: {:?}", term); |
1555 | let tcx = self.tcx(); | |
54a0048b | 1556 | match term.kind { |
ff7c6d11 XL |
1557 | TerminatorKind::Goto { .. } |
1558 | | TerminatorKind::Resume | |
1559 | | TerminatorKind::Abort | |
1560 | | TerminatorKind::Return | |
1561 | | TerminatorKind::GeneratorDrop | |
1562 | | TerminatorKind::Unreachable | |
1563 | | TerminatorKind::Drop { .. } | |
f035d41b | 1564 | | TerminatorKind::FalseEdge { .. } |
f9f354fc XL |
1565 | | TerminatorKind::FalseUnwind { .. } |
1566 | | TerminatorKind::InlineAsm { .. } => { | |
7453a54e SL |
1567 | // no checks needed for these |
1568 | } | |
1569 | ||
f035d41b XL |
1570 | TerminatorKind::DropAndReplace { ref place, ref value, target: _, unwind: _ } => { |
1571 | let place_ty = place.ty(body, tcx).ty; | |
dc9dc135 | 1572 | let rv_ty = value.ty(body, tcx); |
abe05a73 | 1573 | |
0bf4aa26 XL |
1574 | let locations = term_location.to_locations(); |
1575 | if let Err(terr) = | |
1576 | self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment) | |
1577 | { | |
abe05a73 XL |
1578 | span_mirbug!( |
1579 | self, | |
1580 | term, | |
1581 | "bad DropAndReplace ({:?} = {:?}): {:?}", | |
ff7c6d11 | 1582 | place_ty, |
abe05a73 XL |
1583 | rv_ty, |
1584 | terr | |
1585 | ); | |
1586 | } | |
3157f602 | 1587 | } |
dfeec247 | 1588 | TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => { |
dc9dc135 | 1589 | let discr_ty = discr.ty(body, tcx); |
0bf4aa26 XL |
1590 | if let Err(terr) = self.sub_types( |
1591 | discr_ty, | |
1592 | switch_ty, | |
1593 | term_location.to_locations(), | |
1594 | ConstraintCategory::Assignment, | |
1595 | ) { | |
abe05a73 XL |
1596 | span_mirbug!( |
1597 | self, | |
1598 | term, | |
1599 | "bad SwitchInt ({:?} on {:?}): {:?}", | |
1600 | switch_ty, | |
1601 | discr_ty, | |
1602 | terr | |
1603 | ); | |
7453a54e | 1604 | } |
abe05a73 XL |
1605 | if !switch_ty.is_integral() && !switch_ty.is_char() && !switch_ty.is_bool() { |
1606 | span_mirbug!(self, term, "bad SwitchInt discr ty {:?}", switch_ty); | |
7453a54e SL |
1607 | } |
1608 | // FIXME: check the values | |
1609 | } | |
dfeec247 | 1610 | TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => { |
dc9dc135 | 1611 | let func_ty = func.ty(body, tcx); |
7453a54e | 1612 | debug!("check_terminator: call, func_ty={:?}", func_ty); |
1b1a35ee | 1613 | let sig = match func_ty.kind() { |
b7449926 | 1614 | ty::FnDef(..) | ty::FnPtr(_) => func_ty.fn_sig(tcx), |
7453a54e SL |
1615 | _ => { |
1616 | span_mirbug!(self, term, "call to non-function {:?}", func_ty); | |
1617 | return; | |
1618 | } | |
1619 | }; | |
a1dfa0c6 | 1620 | let (sig, map) = self.infcx.replace_bound_vars_with_fresh_vars( |
abe05a73 XL |
1621 | term.source_info.span, |
1622 | LateBoundRegionConversionTime::FnCall, | |
fc512014 | 1623 | sig, |
abe05a73 | 1624 | ); |
8faf50e0 | 1625 | let sig = self.normalize(sig, term_location); |
dc9dc135 | 1626 | self.check_call_dest(body, term, &sig, destination, term_location); |
abe05a73 | 1627 | |
83c7162d | 1628 | self.prove_predicates( |
5869c6ff | 1629 | sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty.into())), |
0bf4aa26 XL |
1630 | term_location.to_locations(), |
1631 | ConstraintCategory::Boring, | |
83c7162d XL |
1632 | ); |
1633 | ||
abe05a73 XL |
1634 | // The ordinary liveness rules will ensure that all |
1635 | // regions in the type of the callee are live here. We | |
1636 | // then further constrain the late-bound regions that | |
1637 | // were instantiated at the call site to be live as | |
1638 | // well. The resulting is that all the input (and | |
1639 | // output) types in the signature must be live, since | |
1640 | // all the inputs that fed into it were live. | |
1641 | for &late_bound_region in map.values() { | |
dfeec247 XL |
1642 | let region_vid = |
1643 | self.borrowck_context.universal_regions.to_region_vid(late_bound_region); | |
48663c56 XL |
1644 | self.borrowck_context |
1645 | .constraints | |
1646 | .liveness_constraints | |
1647 | .add_element(region_vid, term_location); | |
abe05a73 | 1648 | } |
7453a54e | 1649 | |
dc9dc135 | 1650 | self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call); |
7453a54e | 1651 | } |
dfeec247 | 1652 | TerminatorKind::Assert { ref cond, ref msg, .. } => { |
dc9dc135 | 1653 | let cond_ty = cond.ty(body, tcx); |
3157f602 XL |
1654 | if cond_ty != tcx.types.bool { |
1655 | span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty); | |
1656 | } | |
1657 | ||
74b04a01 | 1658 | if let AssertKind::BoundsCheck { ref len, ref index } = *msg { |
dc9dc135 | 1659 | if len.ty(body, tcx) != tcx.types.usize { |
3157f602 XL |
1660 | span_mirbug!(self, len, "bounds-check length non-usize {:?}", len) |
1661 | } | |
dc9dc135 | 1662 | if index.ty(body, tcx) != tcx.types.usize { |
3157f602 XL |
1663 | span_mirbug!(self, index, "bounds-check index non-usize {:?}", index) |
1664 | } | |
1665 | } | |
1666 | } | |
ea8adc8c | 1667 | TerminatorKind::Yield { ref value, .. } => { |
dc9dc135 | 1668 | let value_ty = value.ty(body, tcx); |
6a06907d | 1669 | match body.yield_ty() { |
ea8adc8c XL |
1670 | None => span_mirbug!(self, term, "yield in non-generator"), |
1671 | Some(ty) => { | |
0bf4aa26 XL |
1672 | if let Err(terr) = self.sub_types( |
1673 | value_ty, | |
1674 | ty, | |
1675 | term_location.to_locations(), | |
0731742a | 1676 | ConstraintCategory::Yield, |
0bf4aa26 | 1677 | ) { |
abe05a73 XL |
1678 | span_mirbug!( |
1679 | self, | |
ea8adc8c XL |
1680 | term, |
1681 | "type of yield value is {:?}, but the yield type is {:?}: {:?}", | |
1682 | value_ty, | |
1683 | ty, | |
abe05a73 XL |
1684 | terr |
1685 | ); | |
ea8adc8c XL |
1686 | } |
1687 | } | |
1688 | } | |
1689 | } | |
7453a54e SL |
1690 | } |
1691 | } | |
1692 | ||
abe05a73 XL |
1693 | fn check_call_dest( |
1694 | &mut self, | |
dc9dc135 | 1695 | body: &Body<'tcx>, |
abe05a73 XL |
1696 | term: &Terminator<'tcx>, |
1697 | sig: &ty::FnSig<'tcx>, | |
ff7c6d11 | 1698 | destination: &Option<(Place<'tcx>, BasicBlock)>, |
abe05a73 XL |
1699 | term_location: Location, |
1700 | ) { | |
7453a54e | 1701 | let tcx = self.tcx(); |
5bcae85e | 1702 | match *destination { |
8faf50e0 | 1703 | Some((ref dest, _target_block)) => { |
dc9dc135 | 1704 | let dest_ty = dest.ty(body, tcx).ty; |
e74abb32 XL |
1705 | let dest_ty = self.normalize(dest_ty, term_location); |
1706 | let category = match dest.as_local() { | |
1707 | Some(RETURN_PLACE) => { | |
48663c56 | 1708 | if let BorrowCheckContext { |
0bf4aa26 | 1709 | universal_regions: |
dfeec247 | 1710 | UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, |
0bf4aa26 | 1711 | .. |
48663c56 | 1712 | } = self.borrowck_context |
0bf4aa26 | 1713 | { |
48663c56 | 1714 | if tcx.is_static(*def_id) { |
0bf4aa26 XL |
1715 | ConstraintCategory::UseAsStatic |
1716 | } else { | |
1717 | ConstraintCategory::UseAsConst | |
1718 | } | |
1719 | } else { | |
f035d41b | 1720 | ConstraintCategory::Return(ReturnConstraint::Normal) |
0bf4aa26 XL |
1721 | } |
1722 | } | |
60c5eb7d | 1723 | Some(l) if !body.local_decls[l].is_user_variable() => { |
0bf4aa26 XL |
1724 | ConstraintCategory::Boring |
1725 | } | |
1726 | _ => ConstraintCategory::Assignment, | |
b7449926 XL |
1727 | }; |
1728 | ||
0bf4aa26 | 1729 | let locations = term_location.to_locations(); |
b7449926 | 1730 | |
0bf4aa26 XL |
1731 | if let Err(terr) = |
1732 | self.sub_types_or_anon(sig.output(), dest_ty, locations, category) | |
1733 | { | |
abe05a73 XL |
1734 | span_mirbug!( |
1735 | self, | |
1736 | term, | |
1737 | "call dest mismatch ({:?} <- {:?}): {:?}", | |
1738 | dest_ty, | |
1739 | sig.output(), | |
1740 | terr | |
1741 | ); | |
7453a54e | 1742 | } |
b7449926 | 1743 | |
29967ef6 | 1744 | // When `unsized_fn_params` and `unsized_locals` are both not enabled, |
b7449926 | 1745 | // this check is done at `check_local`. |
29967ef6 | 1746 | if self.unsized_feature_enabled() { |
b7449926 XL |
1747 | let span = term.source_info.span; |
1748 | self.ensure_place_sized(dest_ty, span); | |
1749 | } | |
abe05a73 | 1750 | } |
5bcae85e | 1751 | None => { |
6a06907d XL |
1752 | if !self |
1753 | .tcx() | |
1754 | .conservative_is_privately_uninhabited(self.param_env.and(sig.output())) | |
1755 | { | |
5bcae85e SL |
1756 | span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); |
1757 | } | |
abe05a73 | 1758 | } |
7453a54e SL |
1759 | } |
1760 | } | |
1761 | ||
abe05a73 XL |
1762 | fn check_call_inputs( |
1763 | &mut self, | |
dc9dc135 | 1764 | body: &Body<'tcx>, |
abe05a73 XL |
1765 | term: &Terminator<'tcx>, |
1766 | sig: &ty::FnSig<'tcx>, | |
1767 | args: &[Operand<'tcx>], | |
1768 | term_location: Location, | |
0bf4aa26 | 1769 | from_hir_call: bool, |
abe05a73 | 1770 | ) { |
7453a54e | 1771 | debug!("check_call_inputs({:?}, {:?})", sig, args); |
e74abb32 | 1772 | if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) { |
7453a54e SL |
1773 | span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); |
1774 | } | |
e74abb32 | 1775 | for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() { |
dc9dc135 | 1776 | let op_arg_ty = op_arg.ty(body, self.tcx()); |
ba9703b0 | 1777 | let op_arg_ty = self.normalize(op_arg_ty, term_location); |
0bf4aa26 XL |
1778 | let category = if from_hir_call { |
1779 | ConstraintCategory::CallArgument | |
1780 | } else { | |
1781 | ConstraintCategory::Boring | |
1782 | }; | |
1783 | if let Err(terr) = | |
1784 | self.sub_types(op_arg_ty, fn_arg, term_location.to_locations(), category) | |
1785 | { | |
abe05a73 XL |
1786 | span_mirbug!( |
1787 | self, | |
1788 | term, | |
1789 | "bad arg #{:?} ({:?} <- {:?}): {:?}", | |
1790 | n, | |
1791 | fn_arg, | |
1792 | op_arg_ty, | |
1793 | terr | |
1794 | ); | |
7453a54e SL |
1795 | } |
1796 | } | |
1797 | } | |
1798 | ||
dc9dc135 | 1799 | fn check_iscleanup(&mut self, body: &Body<'tcx>, block_data: &BasicBlockData<'tcx>) { |
abe05a73 XL |
1800 | let is_cleanup = block_data.is_cleanup; |
1801 | self.last_span = block_data.terminator().source_info.span; | |
1802 | match block_data.terminator().kind { | |
1803 | TerminatorKind::Goto { target } => { | |
dc9dc135 | 1804 | self.assert_iscleanup(body, block_data, target, is_cleanup) |
ea8adc8c | 1805 | } |
dfeec247 | 1806 | TerminatorKind::SwitchInt { ref targets, .. } => { |
29967ef6 | 1807 | for target in targets.all_targets() { |
dfeec247 XL |
1808 | self.assert_iscleanup(body, block_data, *target, is_cleanup); |
1809 | } | |
1810 | } | |
1811 | TerminatorKind::Resume => { | |
1812 | if !is_cleanup { | |
1813 | span_mirbug!(self, block_data, "resume on non-cleanup block!") | |
1814 | } | |
1815 | } | |
1816 | TerminatorKind::Abort => { | |
1817 | if !is_cleanup { | |
1818 | span_mirbug!(self, block_data, "abort on non-cleanup block!") | |
1819 | } | |
1820 | } | |
1821 | TerminatorKind::Return => { | |
1822 | if is_cleanup { | |
1823 | span_mirbug!(self, block_data, "return on cleanup block") | |
1824 | } | |
1825 | } | |
1826 | TerminatorKind::GeneratorDrop { .. } => { | |
1827 | if is_cleanup { | |
1828 | span_mirbug!(self, block_data, "generator_drop in cleanup block") | |
1829 | } | |
1830 | } | |
ea8adc8c XL |
1831 | TerminatorKind::Yield { resume, drop, .. } => { |
1832 | if is_cleanup { | |
abe05a73 | 1833 | span_mirbug!(self, block_data, "yield in cleanup block") |
ea8adc8c | 1834 | } |
dc9dc135 | 1835 | self.assert_iscleanup(body, block_data, resume, is_cleanup); |
ea8adc8c | 1836 | if let Some(drop) = drop { |
dc9dc135 | 1837 | self.assert_iscleanup(body, block_data, drop, is_cleanup); |
ea8adc8c XL |
1838 | } |
1839 | } | |
3157f602 | 1840 | TerminatorKind::Unreachable => {} |
ff7c6d11 XL |
1841 | TerminatorKind::Drop { target, unwind, .. } |
1842 | | TerminatorKind::DropAndReplace { target, unwind, .. } | |
dfeec247 | 1843 | | TerminatorKind::Assert { target, cleanup: unwind, .. } => { |
dc9dc135 | 1844 | self.assert_iscleanup(body, block_data, target, is_cleanup); |
3157f602 XL |
1845 | if let Some(unwind) = unwind { |
1846 | if is_cleanup { | |
abe05a73 | 1847 | span_mirbug!(self, block_data, "unwind on cleanup block") |
3157f602 | 1848 | } |
dc9dc135 | 1849 | self.assert_iscleanup(body, block_data, unwind, true); |
3157f602 XL |
1850 | } |
1851 | } | |
dfeec247 | 1852 | TerminatorKind::Call { ref destination, cleanup, .. } => { |
3157f602 | 1853 | if let &Some((_, target)) = destination { |
dc9dc135 | 1854 | self.assert_iscleanup(body, block_data, target, is_cleanup); |
3157f602 XL |
1855 | } |
1856 | if let Some(cleanup) = cleanup { | |
1857 | if is_cleanup { | |
abe05a73 | 1858 | span_mirbug!(self, block_data, "cleanup on cleanup block") |
3157f602 | 1859 | } |
dc9dc135 | 1860 | self.assert_iscleanup(body, block_data, cleanup, true); |
abe05a73 XL |
1861 | } |
1862 | } | |
f035d41b | 1863 | TerminatorKind::FalseEdge { real_target, imaginary_target } => { |
dc9dc135 XL |
1864 | self.assert_iscleanup(body, block_data, real_target, is_cleanup); |
1865 | self.assert_iscleanup(body, block_data, imaginary_target, is_cleanup); | |
3157f602 | 1866 | } |
dfeec247 | 1867 | TerminatorKind::FalseUnwind { real_target, unwind } => { |
dc9dc135 | 1868 | self.assert_iscleanup(body, block_data, real_target, is_cleanup); |
2c00a5a8 XL |
1869 | if let Some(unwind) = unwind { |
1870 | if is_cleanup { | |
dfeec247 | 1871 | span_mirbug!(self, block_data, "cleanup in cleanup block via false unwind"); |
2c00a5a8 | 1872 | } |
dc9dc135 | 1873 | self.assert_iscleanup(body, block_data, unwind, true); |
2c00a5a8 XL |
1874 | } |
1875 | } | |
5869c6ff XL |
1876 | TerminatorKind::InlineAsm { destination, .. } => { |
1877 | if let Some(target) = destination { | |
f9f354fc XL |
1878 | self.assert_iscleanup(body, block_data, target, is_cleanup); |
1879 | } | |
1880 | } | |
3157f602 XL |
1881 | } |
1882 | } | |
1883 | ||
abe05a73 XL |
1884 | fn assert_iscleanup( |
1885 | &mut self, | |
dc9dc135 | 1886 | body: &Body<'tcx>, |
0531ce1d | 1887 | ctxt: &dyn fmt::Debug, |
abe05a73 XL |
1888 | bb: BasicBlock, |
1889 | iscleanuppad: bool, | |
1890 | ) { | |
dc9dc135 | 1891 | if body[bb].is_cleanup != iscleanuppad { |
dfeec247 | 1892 | span_mirbug!(self, ctxt, "cleanuppad mismatch: {:?} should be {:?}", bb, iscleanuppad); |
3157f602 XL |
1893 | } |
1894 | } | |
1895 | ||
dc9dc135 XL |
1896 | fn check_local(&mut self, body: &Body<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) { |
1897 | match body.local_kind(local) { | |
cc61c64b XL |
1898 | LocalKind::ReturnPointer | LocalKind::Arg => { |
1899 | // return values of normal functions are required to be | |
1900 | // sized by typeck, but return values of ADT constructors are | |
1901 | // not because we don't include a `Self: Sized` bounds on them. | |
1902 | // | |
1903 | // Unbound parts of arguments were never required to be Sized | |
1904 | // - maybe we should make that a warning. | |
abe05a73 | 1905 | return; |
cc61c64b XL |
1906 | } |
1907 | LocalKind::Var | LocalKind::Temp => {} | |
1908 | } | |
1909 | ||
29967ef6 | 1910 | // When `unsized_fn_params` or `unsized_locals` is enabled, only function calls |
b7449926 | 1911 | // and nullary ops are checked in `check_call_dest`. |
29967ef6 | 1912 | if !self.unsized_feature_enabled() { |
b7449926 XL |
1913 | let span = local_decl.source_info.span; |
1914 | let ty = local_decl.ty; | |
1915 | self.ensure_place_sized(ty, span); | |
1916 | } | |
1917 | } | |
1918 | ||
1919 | fn ensure_place_sized(&mut self, ty: Ty<'tcx>, span: Span) { | |
1920 | let tcx = self.tcx(); | |
abe05a73 XL |
1921 | |
1922 | // Erase the regions from `ty` to get a global type. The | |
1923 | // `Sized` bound in no way depends on precise regions, so this | |
1924 | // shouldn't affect `is_sized`. | |
fc512014 | 1925 | let erased_ty = tcx.erase_regions(ty); |
e74abb32 | 1926 | if !erased_ty.is_sized(tcx.at(span), self.param_env) { |
cc61c64b XL |
1927 | // in current MIR construction, all non-control-flow rvalue |
1928 | // expressions evaluate through `as_temp` or `into` a return | |
1929 | // slot or local, so to find all unsized rvalues it is enough | |
1930 | // to check all temps, return slots and locals. | |
74b04a01 | 1931 | if self.reported_errors.replace((ty, span)).is_none() { |
8faf50e0 | 1932 | let mut diag = struct_span_err!( |
abe05a73 XL |
1933 | self.tcx().sess, |
1934 | span, | |
1935 | E0161, | |
1936 | "cannot move a value of type {0}: the size of {0} \ | |
1937 | cannot be statically determined", | |
1938 | ty | |
1939 | ); | |
b7449926 XL |
1940 | |
1941 | // While this is located in `nll::typeck` this error is not | |
1942 | // an NLL error, it's a required check to prevent creation | |
1943 | // of unsized rvalues in certain cases: | |
1944 | // * operand of a box expression | |
1945 | // * callee in a call expression | |
1946 | diag.emit(); | |
cc61c64b XL |
1947 | } |
1948 | } | |
1949 | } | |
1950 | ||
ff7c6d11 XL |
1951 | fn aggregate_field_ty( |
1952 | &mut self, | |
1953 | ak: &AggregateKind<'tcx>, | |
1954 | field_index: usize, | |
1955 | location: Location, | |
1956 | ) -> Result<Ty<'tcx>, FieldAccessError> { | |
1957 | let tcx = self.tcx(); | |
1958 | ||
1959 | match *ak { | |
b7449926 | 1960 | AggregateKind::Adt(def, variant_index, substs, _, active_field_index) => { |
ff7c6d11 XL |
1961 | let variant = &def.variants[variant_index]; |
1962 | let adj_field_index = active_field_index.unwrap_or(field_index); | |
1963 | if let Some(field) = variant.fields.get(adj_field_index) { | |
8faf50e0 | 1964 | Ok(self.normalize(field.ty(tcx, substs), location)) |
ff7c6d11 | 1965 | } else { |
dfeec247 | 1966 | Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() }) |
ff7c6d11 XL |
1967 | } |
1968 | } | |
ba9703b0 XL |
1969 | AggregateKind::Closure(_, substs) => { |
1970 | match substs.as_closure().upvar_tys().nth(field_index) { | |
ff7c6d11 XL |
1971 | Some(ty) => Ok(ty), |
1972 | None => Err(FieldAccessError::OutOfRange { | |
ba9703b0 | 1973 | field_count: substs.as_closure().upvar_tys().count(), |
ff7c6d11 XL |
1974 | }), |
1975 | } | |
1976 | } | |
ba9703b0 | 1977 | AggregateKind::Generator(_, substs, _) => { |
48663c56 XL |
1978 | // It doesn't make sense to look at a field beyond the prefix; |
1979 | // these require a variant index, and are not initialized in | |
1980 | // aggregate rvalues. | |
ba9703b0 | 1981 | match substs.as_generator().prefix_tys().nth(field_index) { |
48663c56 XL |
1982 | Some(ty) => Ok(ty), |
1983 | None => Err(FieldAccessError::OutOfRange { | |
ba9703b0 | 1984 | field_count: substs.as_generator().prefix_tys().count(), |
48663c56 | 1985 | }), |
ff7c6d11 XL |
1986 | } |
1987 | } | |
1988 | AggregateKind::Array(ty) => Ok(ty), | |
1989 | AggregateKind::Tuple => { | |
1990 | unreachable!("This should have been covered in check_rvalues"); | |
1991 | } | |
1992 | } | |
1993 | } | |
1994 | ||
f9f354fc | 1995 | fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { |
ff7c6d11 XL |
1996 | let tcx = self.tcx(); |
1997 | ||
1998 | match rvalue { | |
1999 | Rvalue::Aggregate(ak, ops) => { | |
60c5eb7d | 2000 | self.check_aggregate_rvalue(&body, rvalue, ak, ops, location) |
ff7c6d11 XL |
2001 | } |
2002 | ||
dfeec247 | 2003 | Rvalue::Repeat(operand, len) => { |
ba9703b0 XL |
2004 | // If the length cannot be evaluated we must assume that the length can be larger |
2005 | // than 1. | |
2006 | // If the length is larger than 1, the repeat expression will need to copy the | |
2007 | // element, so we require the `Copy` trait. | |
2008 | if len.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) { | |
fc512014 XL |
2009 | match operand { |
2010 | Operand::Copy(..) | Operand::Constant(..) => { | |
2011 | // These are always okay: direct use of a const, or a value that can evidently be copied. | |
2012 | } | |
6a06907d | 2013 | Operand::Move(place) => { |
fc512014 XL |
2014 | // Make sure that repeated elements implement `Copy`. |
2015 | let span = body.source_info(location).span; | |
2016 | let ty = operand.ty(body, tcx); | |
2017 | if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) { | |
6a06907d XL |
2018 | let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env); |
2019 | let is_const_fn = | |
2020 | is_const_fn_in_array_repeat_expression(&ccx, &place, &body); | |
2021 | ||
2022 | debug!("check_rvalue: is_const_fn={:?}", is_const_fn); | |
2023 | ||
fc512014 XL |
2024 | let def_id = body.source.def_id().expect_local(); |
2025 | self.infcx.report_selection_error( | |
2026 | &traits::Obligation::new( | |
2027 | ObligationCause::new( | |
2028 | span, | |
2029 | self.tcx().hir().local_def_id_to_hir_id(def_id), | |
6a06907d | 2030 | traits::ObligationCauseCode::RepeatVec(is_const_fn), |
3dfed10e | 2031 | ), |
fc512014 XL |
2032 | self.param_env, |
2033 | ty::Binder::bind(ty::TraitRef::new( | |
2034 | self.tcx().require_lang_item( | |
2035 | LangItem::Copy, | |
2036 | Some(self.last_span), | |
2037 | ), | |
2038 | tcx.mk_substs_trait(ty, &[]), | |
2039 | )) | |
2040 | .without_const() | |
2041 | .to_predicate(self.tcx()), | |
2042 | ), | |
2043 | &traits::SelectionError::Unimplemented, | |
2044 | false, | |
2045 | false, | |
2046 | ); | |
2047 | } | |
dfeec247 | 2048 | } |
416331ca XL |
2049 | } |
2050 | } | |
dfeec247 | 2051 | } |
ff7c6d11 XL |
2052 | |
2053 | Rvalue::NullaryOp(_, ty) => { | |
b7449926 | 2054 | // Even with unsized locals cannot box an unsized value. |
29967ef6 | 2055 | if self.unsized_feature_enabled() { |
dc9dc135 | 2056 | let span = body.source_info(location).span; |
b7449926 XL |
2057 | self.ensure_place_sized(ty, span); |
2058 | } | |
2059 | ||
ff7c6d11 | 2060 | let trait_ref = ty::TraitRef { |
3dfed10e | 2061 | def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), |
ff7c6d11 XL |
2062 | substs: tcx.mk_substs_trait(ty, &[]), |
2063 | }; | |
2064 | ||
0bf4aa26 XL |
2065 | self.prove_trait_ref( |
2066 | trait_ref, | |
2067 | location.to_locations(), | |
2068 | ConstraintCategory::SizedBound, | |
2069 | ); | |
ff7c6d11 XL |
2070 | } |
2071 | ||
0bf4aa26 XL |
2072 | Rvalue::Cast(cast_kind, op, ty) => { |
2073 | match cast_kind { | |
48663c56 | 2074 | CastKind::Pointer(PointerCast::ReifyFnPointer) => { |
f9f354fc | 2075 | let fn_sig = op.ty(body, tcx).fn_sig(tcx); |
ff7c6d11 | 2076 | |
0bf4aa26 XL |
2077 | // The type that we see in the fcx is like |
2078 | // `foo::<'a, 'b>`, where `foo` is the path to a | |
2079 | // function definition. When we extract the | |
2080 | // signature, it comes from the `fn_sig` query, | |
2081 | // and hence may contain unnormalized results. | |
2082 | let fn_sig = self.normalize(fn_sig, location); | |
ff7c6d11 | 2083 | |
0bf4aa26 | 2084 | let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig); |
ff7c6d11 | 2085 | |
0bf4aa26 | 2086 | if let Err(terr) = self.eq_types( |
ff7c6d11 XL |
2087 | ty_fn_ptr_from, |
2088 | ty, | |
0bf4aa26 XL |
2089 | location.to_locations(), |
2090 | ConstraintCategory::Cast, | |
2091 | ) { | |
2092 | span_mirbug!( | |
2093 | self, | |
2094 | rvalue, | |
2095 | "equating {:?} with {:?} yields {:?}", | |
2096 | ty_fn_ptr_from, | |
2097 | ty, | |
2098 | terr | |
2099 | ); | |
2100 | } | |
ff7c6d11 | 2101 | } |
ff7c6d11 | 2102 | |
48663c56 | 2103 | CastKind::Pointer(PointerCast::ClosureFnPointer(unsafety)) => { |
1b1a35ee | 2104 | let sig = match op.ty(body, tcx).kind() { |
ba9703b0 | 2105 | ty::Closure(_, substs) => substs.as_closure().sig(), |
0bf4aa26 XL |
2106 | _ => bug!(), |
2107 | }; | |
f9f354fc | 2108 | let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety)); |
ff7c6d11 | 2109 | |
0bf4aa26 | 2110 | if let Err(terr) = self.eq_types( |
ff7c6d11 XL |
2111 | ty_fn_ptr_from, |
2112 | ty, | |
0bf4aa26 XL |
2113 | location.to_locations(), |
2114 | ConstraintCategory::Cast, | |
2115 | ) { | |
2116 | span_mirbug!( | |
2117 | self, | |
2118 | rvalue, | |
2119 | "equating {:?} with {:?} yields {:?}", | |
2120 | ty_fn_ptr_from, | |
2121 | ty, | |
2122 | terr | |
2123 | ); | |
2124 | } | |
ff7c6d11 | 2125 | } |
ff7c6d11 | 2126 | |
48663c56 | 2127 | CastKind::Pointer(PointerCast::UnsafeFnPointer) => { |
f9f354fc | 2128 | let fn_sig = op.ty(body, tcx).fn_sig(tcx); |
ff7c6d11 | 2129 | |
0bf4aa26 XL |
2130 | // The type that we see in the fcx is like |
2131 | // `foo::<'a, 'b>`, where `foo` is the path to a | |
2132 | // function definition. When we extract the | |
2133 | // signature, it comes from the `fn_sig` query, | |
2134 | // and hence may contain unnormalized results. | |
2135 | let fn_sig = self.normalize(fn_sig, location); | |
ff7c6d11 | 2136 | |
0bf4aa26 | 2137 | let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig); |
ff7c6d11 | 2138 | |
0bf4aa26 | 2139 | if let Err(terr) = self.eq_types( |
ff7c6d11 XL |
2140 | ty_fn_ptr_from, |
2141 | ty, | |
0bf4aa26 XL |
2142 | location.to_locations(), |
2143 | ConstraintCategory::Cast, | |
2144 | ) { | |
2145 | span_mirbug!( | |
2146 | self, | |
2147 | rvalue, | |
2148 | "equating {:?} with {:?} yields {:?}", | |
2149 | ty_fn_ptr_from, | |
2150 | ty, | |
2151 | terr | |
2152 | ); | |
2153 | } | |
ff7c6d11 | 2154 | } |
ff7c6d11 | 2155 | |
48663c56 | 2156 | CastKind::Pointer(PointerCast::Unsize) => { |
0bf4aa26 XL |
2157 | let &ty = ty; |
2158 | let trait_ref = ty::TraitRef { | |
3dfed10e XL |
2159 | def_id: tcx |
2160 | .require_lang_item(LangItem::CoerceUnsized, Some(self.last_span)), | |
f9f354fc | 2161 | substs: tcx.mk_substs_trait(op.ty(body, tcx), &[ty.into()]), |
0bf4aa26 | 2162 | }; |
ff7c6d11 | 2163 | |
0bf4aa26 XL |
2164 | self.prove_trait_ref( |
2165 | trait_ref, | |
2166 | location.to_locations(), | |
2167 | ConstraintCategory::Cast, | |
2168 | ); | |
2169 | } | |
ff7c6d11 | 2170 | |
48663c56 | 2171 | CastKind::Pointer(PointerCast::MutToConstPointer) => { |
1b1a35ee | 2172 | let ty_from = match op.ty(body, tcx).kind() { |
532ac7d7 XL |
2173 | ty::RawPtr(ty::TypeAndMut { |
2174 | ty: ty_from, | |
dfeec247 | 2175 | mutbl: hir::Mutability::Mut, |
532ac7d7 XL |
2176 | }) => ty_from, |
2177 | _ => { | |
2178 | span_mirbug!( | |
2179 | self, | |
2180 | rvalue, | |
2181 | "unexpected base type for cast {:?}", | |
2182 | ty, | |
2183 | ); | |
2184 | return; | |
2185 | } | |
2186 | }; | |
1b1a35ee | 2187 | let ty_to = match ty.kind() { |
532ac7d7 XL |
2188 | ty::RawPtr(ty::TypeAndMut { |
2189 | ty: ty_to, | |
dfeec247 | 2190 | mutbl: hir::Mutability::Not, |
532ac7d7 XL |
2191 | }) => ty_to, |
2192 | _ => { | |
2193 | span_mirbug!( | |
2194 | self, | |
2195 | rvalue, | |
2196 | "unexpected target type for cast {:?}", | |
2197 | ty, | |
2198 | ); | |
2199 | return; | |
2200 | } | |
2201 | }; | |
2202 | if let Err(terr) = self.sub_types( | |
2203 | ty_from, | |
2204 | ty_to, | |
2205 | location.to_locations(), | |
2206 | ConstraintCategory::Cast, | |
2207 | ) { | |
2208 | span_mirbug!( | |
2209 | self, | |
2210 | rvalue, | |
2211 | "relating {:?} with {:?} yields {:?}", | |
2212 | ty_from, | |
2213 | ty_to, | |
2214 | terr | |
60c5eb7d | 2215 | ); |
532ac7d7 XL |
2216 | } |
2217 | } | |
2218 | ||
dfeec247 | 2219 | CastKind::Pointer(PointerCast::ArrayToPointer) => { |
f9f354fc | 2220 | let ty_from = op.ty(body, tcx); |
60c5eb7d | 2221 | |
6a06907d XL |
2222 | let opt_ty_elem_mut = match ty_from.kind() { |
2223 | ty::RawPtr(ty::TypeAndMut { mutbl: array_mut, ty: array_ty }) => { | |
2224 | match array_ty.kind() { | |
2225 | ty::Array(ty_elem, _) => Some((ty_elem, *array_mut)), | |
2226 | _ => None, | |
2227 | } | |
2228 | } | |
60c5eb7d XL |
2229 | _ => None, |
2230 | }; | |
2231 | ||
6a06907d XL |
2232 | let (ty_elem, ty_mut) = match opt_ty_elem_mut { |
2233 | Some(ty_elem_mut) => ty_elem_mut, | |
60c5eb7d XL |
2234 | None => { |
2235 | span_mirbug!( | |
2236 | self, | |
2237 | rvalue, | |
2238 | "ArrayToPointer cast from unexpected type {:?}", | |
2239 | ty_from, | |
2240 | ); | |
2241 | return; | |
2242 | } | |
2243 | }; | |
2244 | ||
6a06907d XL |
2245 | let (ty_to, ty_to_mut) = match ty.kind() { |
2246 | ty::RawPtr(ty::TypeAndMut { mutbl: ty_to_mut, ty: ty_to }) => { | |
2247 | (ty_to, *ty_to_mut) | |
2248 | } | |
60c5eb7d | 2249 | _ => { |
532ac7d7 XL |
2250 | span_mirbug!( |
2251 | self, | |
2252 | rvalue, | |
60c5eb7d | 2253 | "ArrayToPointer cast to unexpected type {:?}", |
532ac7d7 XL |
2254 | ty, |
2255 | ); | |
2256 | return; | |
532ac7d7 | 2257 | } |
60c5eb7d | 2258 | }; |
532ac7d7 | 2259 | |
6a06907d XL |
2260 | if ty_to_mut == Mutability::Mut && ty_mut == Mutability::Not { |
2261 | span_mirbug!( | |
2262 | self, | |
2263 | rvalue, | |
2264 | "ArrayToPointer cast from const {:?} to mut {:?}", | |
2265 | ty, | |
2266 | ty_to | |
2267 | ); | |
2268 | return; | |
2269 | } | |
2270 | ||
60c5eb7d XL |
2271 | if let Err(terr) = self.sub_types( |
2272 | ty_elem, | |
2273 | ty_to, | |
2274 | location.to_locations(), | |
2275 | ConstraintCategory::Cast, | |
2276 | ) { | |
2277 | span_mirbug!( | |
2278 | self, | |
2279 | rvalue, | |
2280 | "relating {:?} with {:?} yields {:?}", | |
2281 | ty_elem, | |
2282 | ty_to, | |
2283 | terr | |
2284 | ) | |
2285 | } | |
2286 | } | |
2287 | ||
2288 | CastKind::Misc => { | |
f9f354fc | 2289 | let ty_from = op.ty(body, tcx); |
60c5eb7d XL |
2290 | let cast_ty_from = CastTy::from_ty(ty_from); |
2291 | let cast_ty_to = CastTy::from_ty(ty); | |
2292 | match (cast_ty_from, cast_ty_to) { | |
60c5eb7d | 2293 | (None, _) |
ba9703b0 | 2294 | | (_, None | Some(CastTy::FnPtr)) |
60c5eb7d | 2295 | | (Some(CastTy::Float), Some(CastTy::Ptr(_))) |
ba9703b0 | 2296 | | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Float)) => { |
dfeec247 XL |
2297 | span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty,) |
2298 | } | |
ba9703b0 XL |
2299 | ( |
2300 | Some(CastTy::Int(_)), | |
2301 | Some(CastTy::Int(_) | CastTy::Float | CastTy::Ptr(_)), | |
2302 | ) | |
2303 | | (Some(CastTy::Float), Some(CastTy::Int(_) | CastTy::Float)) | |
2304 | | (Some(CastTy::Ptr(_)), Some(CastTy::Int(_) | CastTy::Ptr(_))) | |
2305 | | (Some(CastTy::FnPtr), Some(CastTy::Int(_) | CastTy::Ptr(_))) => (), | |
532ac7d7 XL |
2306 | } |
2307 | } | |
0bf4aa26 XL |
2308 | } |
2309 | } | |
ff7c6d11 | 2310 | |
8faf50e0 | 2311 | Rvalue::Ref(region, _borrow_kind, borrowed_place) => { |
60c5eb7d | 2312 | self.add_reborrow_constraint(&body, location, region, borrowed_place); |
8faf50e0 XL |
2313 | } |
2314 | ||
ba9703b0 XL |
2315 | Rvalue::BinaryOp( |
2316 | BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge, | |
6a06907d | 2317 | box (left, right), |
ba9703b0 | 2318 | ) => { |
f9f354fc | 2319 | let ty_left = left.ty(body, tcx); |
1b1a35ee | 2320 | match ty_left.kind() { |
f9f354fc XL |
2321 | // Types with regions are comparable if they have a common super-type. |
2322 | ty::RawPtr(_) | ty::FnPtr(_) => { | |
2323 | let ty_right = right.ty(body, tcx); | |
2324 | let common_ty = self.infcx.next_ty_var(TypeVariableOrigin { | |
2325 | kind: TypeVariableOriginKind::MiscVariable, | |
2326 | span: body.source_info(location).span, | |
2327 | }); | |
2328 | self.relate_types( | |
2329 | common_ty, | |
2330 | ty::Variance::Contravariant, | |
532ac7d7 | 2331 | ty_left, |
f9f354fc XL |
2332 | location.to_locations(), |
2333 | ConstraintCategory::Boring, | |
532ac7d7 | 2334 | ) |
f9f354fc XL |
2335 | .unwrap_or_else(|err| { |
2336 | bug!("Could not equate type variable with {:?}: {:?}", ty_left, err) | |
2337 | }); | |
2338 | if let Err(terr) = self.relate_types( | |
2339 | common_ty, | |
2340 | ty::Variance::Contravariant, | |
2341 | ty_right, | |
2342 | location.to_locations(), | |
2343 | ConstraintCategory::Boring, | |
2344 | ) { | |
2345 | span_mirbug!( | |
2346 | self, | |
2347 | rvalue, | |
2348 | "unexpected comparison types {:?} and {:?} yields {:?}", | |
2349 | ty_left, | |
2350 | ty_right, | |
2351 | terr | |
2352 | ) | |
2353 | } | |
532ac7d7 | 2354 | } |
f9f354fc XL |
2355 | // For types with no regions we can just check that the |
2356 | // both operands have the same type. | |
2357 | ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) | |
2358 | if ty_left == right.ty(body, tcx) => {} | |
2359 | // Other types are compared by trait methods, not by | |
2360 | // `Rvalue::BinaryOp`. | |
2361 | _ => span_mirbug!( | |
2362 | self, | |
2363 | rvalue, | |
2364 | "unexpected comparison types {:?} and {:?}", | |
2365 | ty_left, | |
2366 | right.ty(body, tcx) | |
2367 | ), | |
532ac7d7 XL |
2368 | } |
2369 | } | |
2370 | ||
dfeec247 | 2371 | Rvalue::AddressOf(..) |
f9f354fc | 2372 | | Rvalue::ThreadLocalRef(..) |
dfeec247 | 2373 | | Rvalue::Use(..) |
ff7c6d11 XL |
2374 | | Rvalue::Len(..) |
2375 | | Rvalue::BinaryOp(..) | |
2376 | | Rvalue::CheckedBinaryOp(..) | |
2377 | | Rvalue::UnaryOp(..) | |
2378 | | Rvalue::Discriminant(..) => {} | |
2379 | } | |
2380 | } | |
2381 | ||
b7449926 XL |
2382 | /// If this rvalue supports a user-given type annotation, then |
2383 | /// extract and return it. This represents the final type of the | |
2384 | /// rvalue and will be unified with the inferred type. | |
0731742a | 2385 | fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<UserTypeAnnotationIndex> { |
b7449926 XL |
2386 | match rvalue { |
2387 | Rvalue::Use(_) | |
f9f354fc | 2388 | | Rvalue::ThreadLocalRef(_) |
b7449926 XL |
2389 | | Rvalue::Repeat(..) |
2390 | | Rvalue::Ref(..) | |
dfeec247 | 2391 | | Rvalue::AddressOf(..) |
b7449926 XL |
2392 | | Rvalue::Len(..) |
2393 | | Rvalue::Cast(..) | |
2394 | | Rvalue::BinaryOp(..) | |
2395 | | Rvalue::CheckedBinaryOp(..) | |
2396 | | Rvalue::NullaryOp(..) | |
2397 | | Rvalue::UnaryOp(..) | |
2398 | | Rvalue::Discriminant(..) => None, | |
2399 | ||
2400 | Rvalue::Aggregate(aggregate, _) => match **aggregate { | |
2401 | AggregateKind::Adt(_, _, _, user_ty, _) => user_ty, | |
2402 | AggregateKind::Array(_) => None, | |
2403 | AggregateKind::Tuple => None, | |
2404 | AggregateKind::Closure(_, _) => None, | |
2405 | AggregateKind::Generator(_, _, _) => None, | |
2406 | }, | |
2407 | } | |
2408 | } | |
2409 | ||
ff7c6d11 XL |
2410 | fn check_aggregate_rvalue( |
2411 | &mut self, | |
dc9dc135 | 2412 | body: &Body<'tcx>, |
ff7c6d11 XL |
2413 | rvalue: &Rvalue<'tcx>, |
2414 | aggregate_kind: &AggregateKind<'tcx>, | |
2415 | operands: &[Operand<'tcx>], | |
2416 | location: Location, | |
2417 | ) { | |
2418 | let tcx = self.tcx(); | |
2419 | ||
2420 | self.prove_aggregate_predicates(aggregate_kind, location); | |
2421 | ||
2422 | if *aggregate_kind == AggregateKind::Tuple { | |
2423 | // tuple rvalue field type is always the type of the op. Nothing to check here. | |
2424 | return; | |
2425 | } | |
2426 | ||
2427 | for (i, operand) in operands.iter().enumerate() { | |
2428 | let field_ty = match self.aggregate_field_ty(aggregate_kind, i, location) { | |
2429 | Ok(field_ty) => field_ty, | |
2430 | Err(FieldAccessError::OutOfRange { field_count }) => { | |
2431 | span_mirbug!( | |
2432 | self, | |
2433 | rvalue, | |
2434 | "accessed field #{} but variant only has {}", | |
2435 | i, | |
2436 | field_count | |
2437 | ); | |
2438 | continue; | |
2439 | } | |
2440 | }; | |
dc9dc135 | 2441 | let operand_ty = operand.ty(body, tcx); |
ba9703b0 | 2442 | let operand_ty = self.normalize(operand_ty, location); |
8faf50e0 | 2443 | |
0bf4aa26 XL |
2444 | if let Err(terr) = self.sub_types( |
2445 | operand_ty, | |
2446 | field_ty, | |
2447 | location.to_locations(), | |
2448 | ConstraintCategory::Boring, | |
2449 | ) { | |
ff7c6d11 XL |
2450 | span_mirbug!( |
2451 | self, | |
2452 | rvalue, | |
2453 | "{:?} is not a subtype of {:?}: {:?}", | |
2454 | operand_ty, | |
2455 | field_ty, | |
2456 | terr | |
2457 | ); | |
2458 | } | |
2459 | } | |
2460 | } | |
2461 | ||
9fa01778 | 2462 | /// Adds the constraints that arise from a borrow expression `&'a P` at the location `L`. |
8faf50e0 XL |
2463 | /// |
2464 | /// # Parameters | |
2465 | /// | |
2466 | /// - `location`: the location `L` where the borrow expression occurs | |
2467 | /// - `borrow_region`: the region `'a` associated with the borrow | |
2468 | /// - `borrowed_place`: the place `P` being borrowed | |
2469 | fn add_reborrow_constraint( | |
2470 | &mut self, | |
dc9dc135 | 2471 | body: &Body<'tcx>, |
8faf50e0 XL |
2472 | location: Location, |
2473 | borrow_region: ty::Region<'tcx>, | |
2474 | borrowed_place: &Place<'tcx>, | |
2475 | ) { | |
2476 | // These constraints are only meaningful during borrowck: | |
dfeec247 XL |
2477 | let BorrowCheckContext { borrow_set, location_table, all_facts, constraints, .. } = |
2478 | self.borrowck_context; | |
8faf50e0 XL |
2479 | |
2480 | // In Polonius mode, we also push a `borrow_region` fact | |
2481 | // linking the loan to the region (in some cases, though, | |
2482 | // there is no loan associated with this borrow expression -- | |
2483 | // that occurs when we are borrowing an unsafe place, for | |
2484 | // example). | |
2485 | if let Some(all_facts) = all_facts { | |
60c5eb7d | 2486 | let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); |
3dfed10e | 2487 | if let Some(borrow_index) = borrow_set.get_index_of(&location) { |
8faf50e0 XL |
2488 | let region_vid = borrow_region.to_region_vid(); |
2489 | all_facts.borrow_region.push(( | |
2490 | region_vid, | |
3dfed10e | 2491 | borrow_index, |
8faf50e0 XL |
2492 | location_table.mid_index(location), |
2493 | )); | |
2494 | } | |
2495 | } | |
2496 | ||
2497 | // If we are reborrowing the referent of another reference, we | |
2498 | // need to add outlives relationships. In a case like `&mut | |
2499 | // *p`, where the `p` has type `&'b mut Foo`, for example, we | |
2500 | // need to ensure that `'b: 'a`. | |
2501 | ||
8faf50e0 XL |
2502 | debug!( |
2503 | "add_reborrow_constraint({:?}, {:?}, {:?})", | |
2504 | location, borrow_region, borrowed_place | |
2505 | ); | |
8faf50e0 | 2506 | |
e74abb32 | 2507 | let mut cursor = borrowed_place.projection.as_ref(); |
f035d41b XL |
2508 | let tcx = self.infcx.tcx; |
2509 | let field = path_utils::is_upvar_field_projection( | |
2510 | tcx, | |
2511 | &self.borrowck_context.upvars, | |
2512 | borrowed_place.as_ref(), | |
2513 | body, | |
2514 | ); | |
2515 | let category = if let Some(field) = field { | |
5869c6ff XL |
2516 | let var_hir_id = self.borrowck_context.upvars[field.index()].place.get_root_variable(); |
2517 | // FIXME(project-rfc-2229#8): Use Place for better diagnostics | |
2518 | ConstraintCategory::ClosureUpvar(var_hir_id) | |
f035d41b XL |
2519 | } else { |
2520 | ConstraintCategory::Boring | |
2521 | }; | |
2522 | ||
e1599b0c XL |
2523 | while let [proj_base @ .., elem] = cursor { |
2524 | cursor = proj_base; | |
2525 | ||
2526 | debug!("add_reborrow_constraint - iteration {:?}", elem); | |
2527 | ||
2528 | match elem { | |
8faf50e0 | 2529 | ProjectionElem::Deref => { |
74b04a01 | 2530 | let base_ty = Place::ty_from(borrowed_place.local, proj_base, body, tcx).ty; |
8faf50e0 XL |
2531 | |
2532 | debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); | |
1b1a35ee | 2533 | match base_ty.kind() { |
b7449926 | 2534 | ty::Ref(ref_region, _, mutbl) => { |
8faf50e0 XL |
2535 | constraints.outlives_constraints.push(OutlivesConstraint { |
2536 | sup: ref_region.to_region_vid(), | |
2537 | sub: borrow_region.to_region_vid(), | |
0bf4aa26 | 2538 | locations: location.to_locations(), |
f035d41b | 2539 | category, |
8faf50e0 XL |
2540 | }); |
2541 | ||
8faf50e0 | 2542 | match mutbl { |
dfeec247 | 2543 | hir::Mutability::Not => { |
8faf50e0 XL |
2544 | // Immutable reference. We don't need the base |
2545 | // to be valid for the entire lifetime of | |
2546 | // the borrow. | |
2547 | break; | |
2548 | } | |
dfeec247 | 2549 | hir::Mutability::Mut => { |
8faf50e0 XL |
2550 | // Mutable reference. We *do* need the base |
2551 | // to be valid, because after the base becomes | |
2552 | // invalid, someone else can use our mutable deref. | |
2553 | ||
2554 | // This is in order to make the following function | |
2555 | // illegal: | |
2556 | // ``` | |
2557 | // fn unsafe_deref<'a, 'b>(x: &'a &'b mut T) -> &'b mut T { | |
2558 | // &mut *x | |
2559 | // } | |
2560 | // ``` | |
2561 | // | |
2562 | // As otherwise you could clone `&mut T` using the | |
2563 | // following function: | |
2564 | // ``` | |
2565 | // fn bad(x: &mut T) -> (&mut T, &mut T) { | |
2566 | // let my_clone = unsafe_deref(&'a x); | |
2567 | // ENDREGION 'a; | |
2568 | // (my_clone, x) | |
2569 | // } | |
2570 | // ``` | |
2571 | } | |
2572 | } | |
2573 | } | |
b7449926 | 2574 | ty::RawPtr(..) => { |
8faf50e0 XL |
2575 | // deref of raw pointer, guaranteed to be valid |
2576 | break; | |
2577 | } | |
b7449926 | 2578 | ty::Adt(def, _) if def.is_box() => { |
8faf50e0 XL |
2579 | // deref of `Box`, need the base to be valid - propagate |
2580 | } | |
2581 | _ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place), | |
2582 | } | |
2583 | } | |
2584 | ProjectionElem::Field(..) | |
2585 | | ProjectionElem::Downcast(..) | |
2586 | | ProjectionElem::Index(..) | |
2587 | | ProjectionElem::ConstantIndex { .. } | |
2588 | | ProjectionElem::Subslice { .. } => { | |
2589 | // other field access | |
2590 | } | |
2591 | } | |
8faf50e0 XL |
2592 | } |
2593 | } | |
2594 | ||
ff7c6d11 XL |
2595 | fn prove_aggregate_predicates( |
2596 | &mut self, | |
2597 | aggregate_kind: &AggregateKind<'tcx>, | |
2598 | location: Location, | |
2599 | ) { | |
2600 | let tcx = self.tcx(); | |
2601 | ||
2602 | debug!( | |
2603 | "prove_aggregate_predicates(aggregate_kind={:?}, location={:?})", | |
0531ce1d | 2604 | aggregate_kind, location |
ff7c6d11 XL |
2605 | ); |
2606 | ||
2607 | let instantiated_predicates = match aggregate_kind { | |
b7449926 | 2608 | AggregateKind::Adt(def, _, substs, _, _) => { |
ff7c6d11 XL |
2609 | tcx.predicates_of(def.did).instantiate(tcx, substs) |
2610 | } | |
2611 | ||
2612 | // For closures, we have some **extra requirements** we | |
2613 | // | |
2614 | // have to check. In particular, in their upvars and | |
2615 | // signatures, closures often reference various regions | |
2616 | // from the surrounding function -- we call those the | |
2617 | // closure's free regions. When we borrow-check (and hence | |
2618 | // region-check) closures, we may find that the closure | |
2619 | // requires certain relationships between those free | |
2620 | // regions. However, because those free regions refer to | |
2621 | // portions of the CFG of their caller, the closure is not | |
2622 | // in a position to verify those relationships. In that | |
2623 | // case, the requirements get "propagated" to us, and so | |
2624 | // we have to solve them here where we instantiate the | |
2625 | // closure. | |
2626 | // | |
2627 | // Despite the opacity of the previous parapgrah, this is | |
2628 | // actually relatively easy to understand in terms of the | |
2629 | // desugaring. A closure gets desugared to a struct, and | |
2630 | // these extra requirements are basically like where | |
2631 | // clauses on the struct. | |
e74abb32 XL |
2632 | AggregateKind::Closure(def_id, substs) |
2633 | | AggregateKind::Generator(def_id, substs, _) => { | |
f9f354fc | 2634 | self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location) |
ff7c6d11 XL |
2635 | } |
2636 | ||
2637 | AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(), | |
2638 | }; | |
2639 | ||
8faf50e0 XL |
2640 | self.normalize_and_prove_instantiated_predicates( |
2641 | instantiated_predicates, | |
0bf4aa26 | 2642 | location.to_locations(), |
8faf50e0 | 2643 | ); |
ff7c6d11 XL |
2644 | } |
2645 | ||
0bf4aa26 XL |
2646 | fn prove_closure_bounds( |
2647 | &mut self, | |
dc9dc135 | 2648 | tcx: TyCtxt<'tcx>, |
f9f354fc | 2649 | def_id: LocalDefId, |
532ac7d7 | 2650 | substs: SubstsRef<'tcx>, |
0bf4aa26 XL |
2651 | location: Location, |
2652 | ) -> ty::InstantiatedPredicates<'tcx> { | |
74b04a01 XL |
2653 | if let Some(ref closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements |
2654 | { | |
dc9dc135 | 2655 | let closure_constraints = QueryRegionConstraints { |
f9f354fc XL |
2656 | outlives: closure_region_requirements.apply_requirements( |
2657 | tcx, | |
2658 | def_id.to_def_id(), | |
2659 | substs, | |
2660 | ), | |
dc9dc135 XL |
2661 | |
2662 | // Presently, closures never propagate member | |
2663 | // constraints to their parents -- they are enforced | |
2664 | // locally. This is largely a non-issue as member | |
2665 | // constraints only come from `-> impl Trait` and | |
2666 | // friends which don't appear (thus far...) in | |
2667 | // closures. | |
2668 | member_constraints: vec![], | |
2669 | }; | |
0bf4aa26 | 2670 | |
48663c56 | 2671 | let bounds_mapping = closure_constraints |
dc9dc135 | 2672 | .outlives |
48663c56 XL |
2673 | .iter() |
2674 | .enumerate() | |
2675 | .filter_map(|(idx, constraint)| { | |
2676 | let ty::OutlivesPredicate(k1, r2) = | |
2677 | constraint.no_bound_vars().unwrap_or_else(|| { | |
2678 | bug!("query_constraint {:?} contained bound vars", constraint,); | |
2679 | }); | |
2680 | ||
2681 | match k1.unpack() { | |
e74abb32 | 2682 | GenericArgKind::Lifetime(r1) => { |
48663c56 XL |
2683 | // constraint is r1: r2 |
2684 | let r1_vid = self.borrowck_context.universal_regions.to_region_vid(r1); | |
2685 | let r2_vid = self.borrowck_context.universal_regions.to_region_vid(r2); | |
2686 | let outlives_requirements = | |
2687 | &closure_region_requirements.outlives_requirements[idx]; | |
2688 | Some(( | |
2689 | (r1_vid, r2_vid), | |
dfeec247 | 2690 | (outlives_requirements.category, outlives_requirements.blame_span), |
48663c56 | 2691 | )) |
0bf4aa26 | 2692 | } |
e74abb32 | 2693 | GenericArgKind::Type(_) | GenericArgKind::Const(_) => None, |
48663c56 XL |
2694 | } |
2695 | }) | |
2696 | .collect(); | |
2697 | ||
dfeec247 XL |
2698 | let existing = self |
2699 | .borrowck_context | |
48663c56 XL |
2700 | .constraints |
2701 | .closure_bounds_mapping | |
2702 | .insert(location, bounds_mapping); | |
dfeec247 | 2703 | assert!(existing.is_none(), "Multiple closures at the same location."); |
0bf4aa26 XL |
2704 | |
2705 | self.push_region_constraints( | |
2706 | location.to_locations(), | |
2707 | ConstraintCategory::ClosureBounds, | |
2708 | &closure_constraints, | |
2709 | ); | |
2710 | } | |
2711 | ||
2712 | tcx.predicates_of(def_id).instantiate(tcx, substs) | |
2713 | } | |
2714 | ||
2715 | fn prove_trait_ref( | |
2716 | &mut self, | |
2717 | trait_ref: ty::TraitRef<'tcx>, | |
2718 | locations: Locations, | |
2719 | category: ConstraintCategory, | |
2720 | ) { | |
ff7c6d11 | 2721 | self.prove_predicates( |
5869c6ff | 2722 | Some(ty::PredicateKind::Trait( |
3dfed10e | 2723 | ty::TraitPredicate { trait_ref }, |
74b04a01 | 2724 | hir::Constness::NotConst, |
83c7162d | 2725 | )), |
8faf50e0 | 2726 | locations, |
0bf4aa26 | 2727 | category, |
ff7c6d11 XL |
2728 | ); |
2729 | } | |
2730 | ||
8faf50e0 XL |
2731 | fn normalize_and_prove_instantiated_predicates( |
2732 | &mut self, | |
2733 | instantiated_predicates: ty::InstantiatedPredicates<'tcx>, | |
2734 | locations: Locations, | |
2735 | ) { | |
2736 | for predicate in instantiated_predicates.predicates { | |
2737 | let predicate = self.normalize(predicate, locations); | |
0bf4aa26 | 2738 | self.prove_predicate(predicate, locations, ConstraintCategory::Boring); |
94b46f34 | 2739 | } |
8faf50e0 | 2740 | } |
94b46f34 | 2741 | |
8faf50e0 XL |
2742 | fn prove_predicates( |
2743 | &mut self, | |
f9f354fc | 2744 | predicates: impl IntoIterator<Item = impl ToPredicate<'tcx>>, |
8faf50e0 | 2745 | locations: Locations, |
0bf4aa26 | 2746 | category: ConstraintCategory, |
8faf50e0 XL |
2747 | ) { |
2748 | for predicate in predicates { | |
f9f354fc | 2749 | let predicate = predicate.to_predicate(self.tcx()); |
dfeec247 | 2750 | debug!("prove_predicates(predicate={:?}, locations={:?})", predicate, locations,); |
83c7162d | 2751 | |
0bf4aa26 | 2752 | self.prove_predicate(predicate, locations, category); |
8faf50e0 XL |
2753 | } |
2754 | } | |
2755 | ||
0bf4aa26 XL |
2756 | fn prove_predicate( |
2757 | &mut self, | |
2758 | predicate: ty::Predicate<'tcx>, | |
2759 | locations: Locations, | |
2760 | category: ConstraintCategory, | |
2761 | ) { | |
dfeec247 | 2762 | debug!("prove_predicate(predicate={:?}, location={:?})", predicate, locations,); |
94b46f34 | 2763 | |
8faf50e0 | 2764 | let param_env = self.param_env; |
94b46f34 | 2765 | self.fully_perform_op( |
8faf50e0 | 2766 | locations, |
0bf4aa26 | 2767 | category, |
8faf50e0 | 2768 | param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)), |
dfeec247 XL |
2769 | ) |
2770 | .unwrap_or_else(|NoSolution| { | |
8faf50e0 XL |
2771 | span_mirbug!(self, NoSolution, "could not prove {:?}", predicate); |
2772 | }) | |
ff7c6d11 XL |
2773 | } |
2774 | ||
f9f354fc | 2775 | fn typeck_mir(&mut self, body: &Body<'tcx>) { |
dc9dc135 XL |
2776 | self.last_span = body.span; |
2777 | debug!("run_on_mir: {:?}", body.span); | |
cc61c64b | 2778 | |
dc9dc135 | 2779 | for (local, local_decl) in body.local_decls.iter_enumerated() { |
60c5eb7d | 2780 | self.check_local(&body, local, local_decl); |
cc61c64b XL |
2781 | } |
2782 | ||
dc9dc135 | 2783 | for (block, block_data) in body.basic_blocks().iter_enumerated() { |
dfeec247 | 2784 | let mut location = Location { block, statement_index: 0 }; |
abe05a73 | 2785 | for stmt in &block_data.statements { |
8faf50e0 | 2786 | if !stmt.source_info.span.is_dummy() { |
3157f602 | 2787 | self.last_span = stmt.source_info.span; |
7453a54e | 2788 | } |
dc9dc135 | 2789 | self.check_stmt(body, stmt, location); |
abe05a73 | 2790 | location.statement_index += 1; |
7453a54e SL |
2791 | } |
2792 | ||
60c5eb7d XL |
2793 | self.check_terminator(&body, block_data.terminator(), location); |
2794 | self.check_iscleanup(&body, block_data); | |
3157f602 XL |
2795 | } |
2796 | } | |
2797 | ||
8faf50e0 | 2798 | fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T |
abe05a73 | 2799 | where |
dc9dc135 | 2800 | T: type_op::normalize::Normalizable<'tcx> + Copy + 'tcx, |
3157f602 | 2801 | { |
2c00a5a8 | 2802 | debug!("normalize(value={:?}, location={:?})", value, location); |
8faf50e0 | 2803 | let param_env = self.param_env; |
94b46f34 XL |
2804 | self.fully_perform_op( |
2805 | location.to_locations(), | |
0bf4aa26 | 2806 | ConstraintCategory::Boring, |
8faf50e0 | 2807 | param_env.and(type_op::normalize::Normalize::new(value)), |
dfeec247 XL |
2808 | ) |
2809 | .unwrap_or_else(|NoSolution| { | |
8faf50e0 XL |
2810 | span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value); |
2811 | value | |
2812 | }) | |
7453a54e SL |
2813 | } |
2814 | } | |
2815 | ||
8faf50e0 | 2816 | trait NormalizeLocation: fmt::Debug + Copy { |
83c7162d XL |
2817 | fn to_locations(self) -> Locations; |
2818 | } | |
2819 | ||
8faf50e0 | 2820 | impl NormalizeLocation for Locations { |
83c7162d XL |
2821 | fn to_locations(self) -> Locations { |
2822 | self | |
2823 | } | |
2824 | } | |
2825 | ||
8faf50e0 | 2826 | impl NormalizeLocation for Location { |
83c7162d | 2827 | fn to_locations(self) -> Locations { |
0bf4aa26 XL |
2828 | Locations::Single(self) |
2829 | } | |
2830 | } | |
2831 | ||
2832 | #[derive(Debug, Default)] | |
2833 | struct ObligationAccumulator<'tcx> { | |
2834 | obligations: PredicateObligations<'tcx>, | |
2835 | } | |
2836 | ||
2837 | impl<'tcx> ObligationAccumulator<'tcx> { | |
2838 | fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T { | |
2839 | let InferOk { value, obligations } = value; | |
2840 | self.obligations.extend(obligations); | |
2841 | value | |
2842 | } | |
2843 | ||
2844 | fn into_vec(self) -> PredicateObligations<'tcx> { | |
2845 | self.obligations | |
83c7162d XL |
2846 | } |
2847 | } |