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