]>
Commit | Line | Data |
---|---|---|
7453a54e SL |
1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! This pass type-checks the MIR to ensure it is not broken. | |
12 | #![allow(unreachable_code)] | |
13 | ||
abe05a73 XL |
14 | use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult}; |
15 | use rustc::infer::region_constraints::RegionConstraintData; | |
16 | use rustc::traits::{self, FulfillmentContext}; | |
17 | use rustc::ty::error::TypeError; | |
54a0048b | 18 | use rustc::ty::fold::TypeFoldable; |
5bcae85e | 19 | use rustc::ty::{self, Ty, TyCtxt, TypeVariants}; |
cc61c64b | 20 | use rustc::middle::const_val::ConstVal; |
c30ab7b3 | 21 | use rustc::mir::*; |
7453a54e | 22 | use rustc::mir::tcx::LvalueTy; |
c30ab7b3 | 23 | use rustc::mir::visit::Visitor; |
7453a54e | 24 | use std::fmt; |
9e0c209e | 25 | use syntax::ast; |
3157f602 | 26 | use syntax_pos::{Span, DUMMY_SP}; |
abe05a73 | 27 | use transform::{MirPass, MirSource}; |
3157f602 | 28 | |
cc61c64b | 29 | use rustc_data_structures::fx::FxHashSet; |
3157f602 | 30 | use rustc_data_structures::indexed_vec::Idx; |
7453a54e | 31 | |
abe05a73 XL |
32 | /// Type checks the given `mir` in the context of the inference |
33 | /// context `infcx`. Returns any region constraints that have yet to | |
34 | /// be proven. | |
35 | /// | |
36 | /// This phase of type-check ought to be infallible -- this is because | |
37 | /// the original, HIR-based type-check succeeded. So if any errors | |
38 | /// occur here, we will get a `bug!` reported. | |
39 | pub fn type_check<'a, 'gcx, 'tcx>( | |
40 | infcx: &InferCtxt<'a, 'gcx, 'tcx>, | |
41 | body_id: ast::NodeId, | |
42 | param_env: ty::ParamEnv<'gcx>, | |
43 | mir: &Mir<'tcx>, | |
44 | ) -> MirTypeckRegionConstraints<'tcx> { | |
45 | let mut checker = TypeChecker::new(infcx, body_id, param_env); | |
46 | let errors_reported = { | |
47 | let mut verifier = TypeVerifier::new(&mut checker, mir); | |
48 | verifier.visit_mir(mir); | |
49 | verifier.errors_reported | |
50 | }; | |
51 | ||
52 | if !errors_reported { | |
53 | // if verifier failed, don't do further checks to avoid ICEs | |
54 | checker.typeck_mir(mir); | |
55 | } | |
56 | ||
57 | checker.constraints | |
58 | } | |
59 | ||
8bb4bdeb XL |
60 | fn mirbug(tcx: TyCtxt, span: Span, msg: &str) { |
61 | tcx.sess.diagnostic().span_bug(span, msg); | |
62 | } | |
63 | ||
7453a54e SL |
64 | macro_rules! span_mirbug { |
65 | ($context:expr, $elem:expr, $($message:tt)*) => ({ | |
8bb4bdeb | 66 | mirbug($context.tcx(), $context.last_span, |
ea8adc8c XL |
67 | &format!("broken MIR in {:?} ({:?}): {}", |
68 | $context.body_id, | |
69 | $elem, | |
70 | format_args!($($message)*))) | |
7453a54e SL |
71 | }) |
72 | } | |
73 | ||
74 | macro_rules! span_mirbug_and_err { | |
75 | ($context:expr, $elem:expr, $($message:tt)*) => ({ | |
76 | { | |
8bb4bdeb | 77 | span_mirbug!($context, $elem, $($message)*); |
7453a54e SL |
78 | $context.error() |
79 | } | |
80 | }) | |
81 | } | |
82 | ||
83 | enum FieldAccessError { | |
abe05a73 | 84 | OutOfRange { field_count: usize }, |
7453a54e SL |
85 | } |
86 | ||
87 | /// Verifies that MIR types are sane to not crash further checks. | |
88 | /// | |
89 | /// The sanitize_XYZ methods here take an MIR object and compute its | |
90 | /// type, calling `span_mirbug` and returning an error type if there | |
91 | /// is a problem. | |
abe05a73 | 92 | struct TypeVerifier<'a, 'b: 'a, 'gcx: 'b + 'tcx, 'tcx: 'b> { |
a7813a04 | 93 | cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>, |
7453a54e SL |
94 | mir: &'a Mir<'tcx>, |
95 | last_span: Span, | |
ea8adc8c | 96 | body_id: ast::NodeId, |
abe05a73 | 97 | errors_reported: bool, |
7453a54e SL |
98 | } |
99 | ||
a7813a04 | 100 | impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { |
7453a54e SL |
101 | fn visit_span(&mut self, span: &Span) { |
102 | if *span != DUMMY_SP { | |
103 | self.last_span = *span; | |
104 | } | |
105 | } | |
106 | ||
abe05a73 XL |
107 | fn visit_lvalue( |
108 | &mut self, | |
109 | lvalue: &Lvalue<'tcx>, | |
110 | _context: visit::LvalueContext, | |
111 | location: Location, | |
112 | ) { | |
9e0c209e | 113 | self.sanitize_lvalue(lvalue, location); |
7453a54e SL |
114 | } |
115 | ||
9e0c209e SL |
116 | fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { |
117 | self.super_constant(constant, location); | |
7453a54e SL |
118 | self.sanitize_type(constant, constant.ty); |
119 | } | |
120 | ||
9e0c209e SL |
121 | fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { |
122 | self.super_rvalue(rvalue, location); | |
8bb4bdeb XL |
123 | let rval_ty = rvalue.ty(self.mir, self.tcx()); |
124 | self.sanitize_type(rvalue, rval_ty); | |
7453a54e SL |
125 | } |
126 | ||
abe05a73 XL |
127 | fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { |
128 | self.super_local_decl(local, local_decl); | |
cc61c64b XL |
129 | self.sanitize_type(local_decl, local_decl.ty); |
130 | } | |
131 | ||
7453a54e | 132 | fn visit_mir(&mut self, mir: &Mir<'tcx>) { |
abe05a73 | 133 | self.sanitize_type(&"return type", mir.return_ty()); |
c30ab7b3 SL |
134 | for local_decl in &mir.local_decls { |
135 | self.sanitize_type(local_decl, local_decl.ty); | |
7453a54e SL |
136 | } |
137 | if self.errors_reported { | |
138 | return; | |
139 | } | |
140 | self.super_mir(mir); | |
141 | } | |
142 | } | |
143 | ||
a7813a04 XL |
144 | impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { |
145 | fn new(cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self { | |
7453a54e | 146 | TypeVerifier { |
3b2f2976 | 147 | mir, |
ea8adc8c XL |
148 | body_id: cx.body_id, |
149 | cx, | |
7453a54e | 150 | last_span: mir.span, |
abe05a73 | 151 | errors_reported: false, |
7453a54e SL |
152 | } |
153 | } | |
154 | ||
a7813a04 | 155 | fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { |
7453a54e SL |
156 | self.cx.infcx.tcx |
157 | } | |
158 | ||
7453a54e | 159 | fn sanitize_type(&mut self, parent: &fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> { |
abe05a73 | 160 | if ty.has_escaping_regions() || ty.references_error() { |
7453a54e SL |
161 | span_mirbug_and_err!(self, parent, "bad type {:?}", ty) |
162 | } else { | |
163 | ty | |
164 | } | |
165 | } | |
166 | ||
9e0c209e | 167 | fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> LvalueTy<'tcx> { |
7453a54e SL |
168 | debug!("sanitize_lvalue: {:?}", lvalue); |
169 | match *lvalue { | |
abe05a73 XL |
170 | Lvalue::Local(index) => LvalueTy::Ty { |
171 | ty: self.mir.local_decls[index].ty, | |
172 | }, | |
8bb4bdeb XL |
173 | Lvalue::Static(box Static { def_id, ty: sty }) => { |
174 | let sty = self.sanitize_type(lvalue, sty); | |
7cac9316 | 175 | let ty = self.tcx().type_of(def_id); |
abe05a73 XL |
176 | let ty = self.cx.normalize(&ty, location); |
177 | if let Err(terr) = self.cx | |
178 | .eq_types(self.last_span, ty, sty, location.at_self()) | |
179 | { | |
8bb4bdeb | 180 | span_mirbug!( |
abe05a73 XL |
181 | self, |
182 | lvalue, | |
183 | "bad static type ({:?}: {:?}): {:?}", | |
184 | ty, | |
185 | sty, | |
186 | terr | |
187 | ); | |
8bb4bdeb XL |
188 | } |
189 | LvalueTy::Ty { ty: sty } | |
abe05a73 | 190 | } |
7453a54e | 191 | Lvalue::Projection(ref proj) => { |
9e0c209e | 192 | let base_ty = self.sanitize_lvalue(&proj.base, location); |
7453a54e SL |
193 | if let LvalueTy::Ty { ty } = base_ty { |
194 | if ty.references_error() { | |
195 | assert!(self.errors_reported); | |
abe05a73 XL |
196 | return LvalueTy::Ty { |
197 | ty: self.tcx().types.err, | |
198 | }; | |
7453a54e SL |
199 | } |
200 | } | |
9e0c209e | 201 | self.sanitize_projection(base_ty, &proj.elem, lvalue, location) |
7453a54e SL |
202 | } |
203 | } | |
204 | } | |
205 | ||
abe05a73 XL |
206 | fn sanitize_projection( |
207 | &mut self, | |
208 | base: LvalueTy<'tcx>, | |
209 | pi: &LvalueElem<'tcx>, | |
210 | lvalue: &Lvalue<'tcx>, | |
211 | location: Location, | |
212 | ) -> LvalueTy<'tcx> { | |
7453a54e SL |
213 | debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, lvalue); |
214 | let tcx = self.tcx(); | |
215 | let base_ty = base.to_ty(tcx); | |
216 | let span = self.last_span; | |
217 | match *pi { | |
218 | ProjectionElem::Deref => { | |
219 | let deref_ty = base_ty.builtin_deref(true, ty::LvaluePreference::NoPreference); | |
220 | LvalueTy::Ty { | |
221 | ty: deref_ty.map(|t| t.ty).unwrap_or_else(|| { | |
abe05a73 XL |
222 | span_mirbug_and_err!(self, lvalue, "deref of non-pointer {:?}", base_ty) |
223 | }), | |
7453a54e SL |
224 | } |
225 | } | |
ea8adc8c XL |
226 | ProjectionElem::Index(i) => { |
227 | let index_ty = Lvalue::Local(i).ty(self.mir, tcx).to_ty(tcx); | |
7453a54e SL |
228 | if index_ty != tcx.types.usize { |
229 | LvalueTy::Ty { | |
abe05a73 | 230 | ty: span_mirbug_and_err!(self, i, "index by non-usize {:?}", i), |
7453a54e SL |
231 | } |
232 | } else { | |
233 | LvalueTy::Ty { | |
234 | ty: base_ty.builtin_index().unwrap_or_else(|| { | |
abe05a73 XL |
235 | span_mirbug_and_err!(self, lvalue, "index of non-array {:?}", base_ty) |
236 | }), | |
7453a54e SL |
237 | } |
238 | } | |
239 | } | |
240 | ProjectionElem::ConstantIndex { .. } => { | |
241 | // consider verifying in-bounds | |
242 | LvalueTy::Ty { | |
243 | ty: base_ty.builtin_index().unwrap_or_else(|| { | |
abe05a73 XL |
244 | span_mirbug_and_err!(self, lvalue, "index of non-array {:?}", base_ty) |
245 | }), | |
7453a54e SL |
246 | } |
247 | } | |
abe05a73 XL |
248 | ProjectionElem::Subslice { from, to } => LvalueTy::Ty { |
249 | ty: match base_ty.sty { | |
250 | ty::TyArray(inner, size) => { | |
251 | let size = size.val.to_const_int().unwrap().to_u64().unwrap(); | |
252 | let min_size = (from as u64) + (to as u64); | |
253 | if let Some(rest_size) = size.checked_sub(min_size) { | |
254 | tcx.mk_array(inner, rest_size) | |
255 | } else { | |
3157f602 | 256 | span_mirbug_and_err!( |
abe05a73 XL |
257 | self, |
258 | lvalue, | |
259 | "taking too-small slice of {:?}", | |
260 | base_ty | |
261 | ) | |
3157f602 XL |
262 | } |
263 | } | |
abe05a73 XL |
264 | ty::TySlice(..) => base_ty, |
265 | _ => span_mirbug_and_err!(self, lvalue, "slice of non-array {:?}", base_ty), | |
266 | }, | |
267 | }, | |
268 | ProjectionElem::Downcast(adt_def1, index) => match base_ty.sty { | |
269 | ty::TyAdt(adt_def, substs) if adt_def.is_enum() && adt_def == adt_def1 => { | |
270 | if index >= adt_def.variants.len() { | |
271 | LvalueTy::Ty { | |
272 | ty: span_mirbug_and_err!( | |
273 | self, | |
274 | lvalue, | |
275 | "cast to variant #{:?} but enum only has {:?}", | |
276 | index, | |
277 | adt_def.variants.len() | |
278 | ), | |
279 | } | |
280 | } else { | |
281 | LvalueTy::Downcast { | |
282 | adt_def, | |
283 | substs, | |
284 | variant_index: index, | |
7453a54e SL |
285 | } |
286 | } | |
abe05a73 XL |
287 | } |
288 | _ => LvalueTy::Ty { | |
289 | ty: span_mirbug_and_err!( | |
290 | self, | |
291 | lvalue, | |
292 | "can't downcast {:?} as {:?}", | |
293 | base_ty, | |
294 | adt_def1 | |
295 | ), | |
7453a54e | 296 | }, |
abe05a73 | 297 | }, |
7453a54e SL |
298 | ProjectionElem::Field(field, fty) => { |
299 | let fty = self.sanitize_type(lvalue, fty); | |
abe05a73 | 300 | match self.field_ty(lvalue, base, field, location) { |
7453a54e | 301 | Ok(ty) => { |
abe05a73 | 302 | if let Err(terr) = self.cx.eq_types(span, ty, fty, location.at_self()) { |
7453a54e | 303 | span_mirbug!( |
abe05a73 XL |
304 | self, |
305 | lvalue, | |
306 | "bad field access ({:?}: {:?}): {:?}", | |
307 | ty, | |
308 | fty, | |
309 | terr | |
310 | ); | |
7453a54e SL |
311 | } |
312 | } | |
abe05a73 XL |
313 | Err(FieldAccessError::OutOfRange { field_count }) => span_mirbug!( |
314 | self, | |
315 | lvalue, | |
316 | "accessed field #{} but variant only has {}", | |
317 | field.index(), | |
318 | field_count | |
319 | ), | |
7453a54e SL |
320 | } |
321 | LvalueTy::Ty { ty: fty } | |
322 | } | |
323 | } | |
324 | } | |
325 | ||
326 | fn error(&mut self) -> Ty<'tcx> { | |
327 | self.errors_reported = true; | |
328 | self.tcx().types.err | |
329 | } | |
330 | ||
abe05a73 XL |
331 | fn field_ty( |
332 | &mut self, | |
333 | parent: &fmt::Debug, | |
334 | base_ty: LvalueTy<'tcx>, | |
335 | field: Field, | |
336 | location: Location, | |
337 | ) -> Result<Ty<'tcx>, FieldAccessError> { | |
7453a54e SL |
338 | let tcx = self.tcx(); |
339 | ||
340 | let (variant, substs) = match base_ty { | |
abe05a73 XL |
341 | LvalueTy::Downcast { |
342 | adt_def, | |
343 | substs, | |
344 | variant_index, | |
345 | } => (&adt_def.variants[variant_index], substs), | |
7453a54e | 346 | LvalueTy::Ty { ty } => match ty.sty { |
9e0c209e | 347 | ty::TyAdt(adt_def, substs) if adt_def.is_univariant() => { |
abe05a73 XL |
348 | (&adt_def.variants[0], substs) |
349 | } | |
476ff2be SL |
350 | ty::TyClosure(def_id, substs) => { |
351 | return match substs.upvar_tys(def_id, tcx).nth(field.index()) { | |
352 | Some(ty) => Ok(ty), | |
353 | None => Err(FieldAccessError::OutOfRange { | |
abe05a73 XL |
354 | field_count: substs.upvar_tys(def_id, tcx).count(), |
355 | }), | |
476ff2be SL |
356 | } |
357 | } | |
ea8adc8c XL |
358 | ty::TyGenerator(def_id, substs, _) => { |
359 | // Try upvars first. `field_tys` requires final optimized MIR. | |
360 | if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field.index()) { | |
361 | return Ok(ty); | |
362 | } | |
363 | ||
364 | return match substs.field_tys(def_id, tcx).nth(field.index()) { | |
365 | Some(ty) => Ok(ty), | |
366 | None => Err(FieldAccessError::OutOfRange { | |
abe05a73 XL |
367 | field_count: substs.field_tys(def_id, tcx).count() + 1, |
368 | }), | |
369 | }; | |
ea8adc8c | 370 | } |
8bb4bdeb | 371 | ty::TyTuple(tys, _) => { |
7453a54e SL |
372 | return match tys.get(field.index()) { |
373 | Some(&ty) => Ok(ty), | |
374 | None => Err(FieldAccessError::OutOfRange { | |
abe05a73 XL |
375 | field_count: tys.len(), |
376 | }), | |
7453a54e SL |
377 | } |
378 | } | |
abe05a73 XL |
379 | _ => { |
380 | return Ok(span_mirbug_and_err!( | |
381 | self, | |
382 | parent, | |
383 | "can't project out of {:?}", | |
384 | base_ty | |
385 | )) | |
386 | } | |
387 | }, | |
7453a54e SL |
388 | }; |
389 | ||
390 | if let Some(field) = variant.fields.get(field.index()) { | |
abe05a73 | 391 | Ok(self.cx.normalize(&field.ty(tcx, substs), location)) |
7453a54e | 392 | } else { |
abe05a73 XL |
393 | Err(FieldAccessError::OutOfRange { |
394 | field_count: variant.fields.len(), | |
395 | }) | |
7453a54e SL |
396 | } |
397 | } | |
7453a54e SL |
398 | } |
399 | ||
abe05a73 XL |
400 | /// The MIR type checker. Visits the MIR and enforces all the |
401 | /// constraints needed for it to be valid and well-typed. Along the | |
402 | /// way, it accrues region constraints -- these can later be used by | |
403 | /// NLL region checking. | |
404 | pub struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { | |
a7813a04 | 405 | infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, |
7cac9316 | 406 | param_env: ty::ParamEnv<'gcx>, |
476ff2be SL |
407 | last_span: Span, |
408 | body_id: ast::NodeId, | |
cc61c64b | 409 | reported_errors: FxHashSet<(Ty<'tcx>, Span)>, |
abe05a73 XL |
410 | constraints: MirTypeckRegionConstraints<'tcx>, |
411 | } | |
412 | ||
413 | /// A collection of region constraints that must be satisfied for the | |
414 | /// program to be considered well-typed. | |
415 | #[derive(Default)] | |
416 | pub struct MirTypeckRegionConstraints<'tcx> { | |
417 | /// In general, the type-checker is not responsible for enforcing | |
418 | /// liveness constraints; this job falls to the region inferencer, | |
419 | /// which performs a liveness analysis. However, in some limited | |
420 | /// cases, the MIR type-checker creates temporary regions that do | |
421 | /// not otherwise appear in the MIR -- in particular, the | |
422 | /// late-bound regions that it instantiates at call-sites -- and | |
423 | /// hence it must report on their liveness constraints. | |
424 | pub liveness_set: Vec<(ty::Region<'tcx>, Location)>, | |
425 | ||
426 | /// During the course of type-checking, we will accumulate region | |
427 | /// constraints due to performing subtyping operations or solving | |
428 | /// traits. These are accumulated into this vector for later use. | |
429 | pub outlives_sets: Vec<OutlivesSet<'tcx>>, | |
430 | } | |
431 | ||
432 | /// Outlives relationships between regions and types created at a | |
433 | /// particular point within the control-flow graph. | |
434 | pub struct OutlivesSet<'tcx> { | |
435 | /// The locations associated with these constraints. | |
436 | pub locations: Locations, | |
437 | ||
438 | /// Constraints generated. In terms of the NLL RFC, when you have | |
439 | /// a constraint `R1: R2 @ P`, the data in there specifies things | |
440 | /// like `R1: R2`. | |
441 | pub data: RegionConstraintData<'tcx>, | |
442 | } | |
443 | ||
444 | #[derive(Copy, Clone, Debug)] | |
445 | pub struct Locations { | |
446 | /// The location in the MIR that generated these constraints. | |
447 | /// This is intended for error reporting and diagnosis; the | |
448 | /// constraints may *take effect* at a distinct spot. | |
449 | pub from_location: Location, | |
450 | ||
451 | /// The constraints must be met at this location. In terms of the | |
452 | /// NLL RFC, when you have a constraint `R1: R2 @ P`, this field | |
453 | /// is the `P` value. | |
454 | pub at_location: Location, | |
7453a54e SL |
455 | } |
456 | ||
a7813a04 | 457 | impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { |
abe05a73 XL |
458 | fn new( |
459 | infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, | |
460 | body_id: ast::NodeId, | |
461 | param_env: ty::ParamEnv<'gcx>, | |
462 | ) -> Self { | |
7453a54e | 463 | TypeChecker { |
3b2f2976 | 464 | infcx, |
476ff2be | 465 | last_span: DUMMY_SP, |
7cac9316 XL |
466 | body_id, |
467 | param_env, | |
cc61c64b | 468 | reported_errors: FxHashSet(), |
abe05a73 | 469 | constraints: MirTypeckRegionConstraints::default(), |
476ff2be SL |
470 | } |
471 | } | |
472 | ||
473 | fn misc(&self, span: Span) -> traits::ObligationCause<'tcx> { | |
474 | traits::ObligationCause::misc(span, self.body_id) | |
475 | } | |
476 | ||
abe05a73 XL |
477 | fn fully_perform_op<OP, R>( |
478 | &mut self, | |
479 | locations: Locations, | |
480 | op: OP, | |
481 | ) -> Result<R, TypeError<'tcx>> | |
482 | where | |
483 | OP: FnOnce(&mut Self) -> InferResult<'tcx, R>, | |
484 | { | |
485 | let mut fulfill_cx = FulfillmentContext::new(); | |
486 | let InferOk { value, obligations } = self.infcx.commit_if_ok(|_| op(self))?; | |
487 | fulfill_cx.register_predicate_obligations(self.infcx, obligations); | |
488 | if let Err(e) = fulfill_cx.select_all_or_error(self.infcx) { | |
489 | span_mirbug!(self, "", "errors selecting obligation: {:?}", e); | |
490 | } | |
491 | ||
492 | let data = self.infcx.take_and_reset_region_constraints(); | |
493 | if !data.is_empty() { | |
494 | self.constraints | |
495 | .outlives_sets | |
496 | .push(OutlivesSet { locations, data }); | |
7453a54e | 497 | } |
abe05a73 XL |
498 | |
499 | Ok(value) | |
7453a54e SL |
500 | } |
501 | ||
abe05a73 XL |
502 | fn sub_types( |
503 | &mut self, | |
504 | sub: Ty<'tcx>, | |
505 | sup: Ty<'tcx>, | |
506 | locations: Locations, | |
507 | ) -> UnitResult<'tcx> { | |
508 | self.fully_perform_op(locations, |this| { | |
509 | this.infcx | |
510 | .at(&this.misc(this.last_span), this.param_env) | |
511 | .sup(sup, sub) | |
512 | }) | |
7453a54e SL |
513 | } |
514 | ||
abe05a73 XL |
515 | fn eq_types( |
516 | &mut self, | |
517 | _span: Span, | |
518 | a: Ty<'tcx>, | |
519 | b: Ty<'tcx>, | |
520 | locations: Locations, | |
521 | ) -> UnitResult<'tcx> { | |
522 | self.fully_perform_op(locations, |this| { | |
523 | this.infcx | |
524 | .at(&this.misc(this.last_span), this.param_env) | |
525 | .eq(b, a) | |
526 | }) | |
7453a54e SL |
527 | } |
528 | ||
a7813a04 | 529 | fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { |
7453a54e SL |
530 | self.infcx.tcx |
531 | } | |
532 | ||
abe05a73 | 533 | fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Location) { |
7453a54e SL |
534 | debug!("check_stmt: {:?}", stmt); |
535 | let tcx = self.tcx(); | |
536 | match stmt.kind { | |
537 | StatementKind::Assign(ref lv, ref rv) => { | |
5bcae85e SL |
538 | let lv_ty = lv.ty(mir, tcx).to_ty(tcx); |
539 | let rv_ty = rv.ty(mir, tcx); | |
abe05a73 XL |
540 | if let Err(terr) = |
541 | self.sub_types(rv_ty, lv_ty, location.at_successor_within_block()) | |
542 | { | |
543 | span_mirbug!( | |
544 | self, | |
545 | stmt, | |
546 | "bad assignment ({:?} = {:?}): {:?}", | |
547 | lv_ty, | |
548 | rv_ty, | |
549 | terr | |
550 | ); | |
5bcae85e SL |
551 | } |
552 | } | |
abe05a73 XL |
553 | StatementKind::SetDiscriminant { |
554 | ref lvalue, | |
555 | variant_index, | |
556 | } => { | |
5bcae85e SL |
557 | let lvalue_type = lvalue.ty(mir, tcx).to_ty(tcx); |
558 | let adt = match lvalue_type.sty { | |
9e0c209e | 559 | TypeVariants::TyAdt(adt, _) if adt.is_enum() => adt, |
5bcae85e | 560 | _ => { |
abe05a73 XL |
561 | span_bug!( |
562 | stmt.source_info.span, | |
563 | "bad set discriminant ({:?} = {:?}): lhs is not an enum", | |
564 | lvalue, | |
565 | variant_index | |
566 | ); | |
5bcae85e SL |
567 | } |
568 | }; | |
569 | if variant_index >= adt.variants.len() { | |
abe05a73 XL |
570 | span_bug!( |
571 | stmt.source_info.span, | |
572 | "bad set discriminant ({:?} = {:?}): value of of range", | |
573 | lvalue, | |
574 | variant_index | |
575 | ); | |
5bcae85e SL |
576 | }; |
577 | } | |
ea8adc8c XL |
578 | StatementKind::StorageLive(_) | |
579 | StatementKind::StorageDead(_) | | |
8bb4bdeb | 580 | StatementKind::InlineAsm { .. } | |
041b39d2 | 581 | StatementKind::EndRegion(_) | |
3b2f2976 | 582 | StatementKind::Validate(..) | |
9e0c209e | 583 | StatementKind::Nop => {} |
7453a54e SL |
584 | } |
585 | } | |
586 | ||
abe05a73 XL |
587 | fn check_terminator( |
588 | &mut self, | |
589 | mir: &Mir<'tcx>, | |
590 | term: &Terminator<'tcx>, | |
591 | term_location: Location, | |
592 | ) { | |
7453a54e SL |
593 | debug!("check_terminator: {:?}", term); |
594 | let tcx = self.tcx(); | |
54a0048b SL |
595 | match term.kind { |
596 | TerminatorKind::Goto { .. } | | |
597 | TerminatorKind::Resume | | |
598 | TerminatorKind::Return | | |
ea8adc8c | 599 | TerminatorKind::GeneratorDrop | |
3157f602 | 600 | TerminatorKind::Unreachable | |
abe05a73 XL |
601 | TerminatorKind::Drop { .. } | |
602 | TerminatorKind::FalseEdges { .. } => { | |
7453a54e SL |
603 | // no checks needed for these |
604 | } | |
605 | ||
3157f602 XL |
606 | TerminatorKind::DropAndReplace { |
607 | ref location, | |
608 | ref value, | |
abe05a73 XL |
609 | target, |
610 | unwind, | |
3157f602 | 611 | } => { |
5bcae85e SL |
612 | let lv_ty = location.ty(mir, tcx).to_ty(tcx); |
613 | let rv_ty = value.ty(mir, tcx); | |
abe05a73 XL |
614 | |
615 | let locations = Locations { | |
616 | from_location: term_location, | |
617 | at_location: target.start_location(), | |
618 | }; | |
619 | if let Err(terr) = self.sub_types(rv_ty, lv_ty, locations) { | |
620 | span_mirbug!( | |
621 | self, | |
622 | term, | |
623 | "bad DropAndReplace ({:?} = {:?}): {:?}", | |
624 | lv_ty, | |
625 | rv_ty, | |
626 | terr | |
627 | ); | |
628 | } | |
629 | ||
630 | // Subtle: this assignment occurs at the start of | |
631 | // *both* blocks, so we need to ensure that it holds | |
632 | // at both locations. | |
633 | if let Some(unwind) = unwind { | |
634 | let locations = Locations { | |
635 | from_location: term_location, | |
636 | at_location: unwind.start_location(), | |
637 | }; | |
638 | if let Err(terr) = self.sub_types(rv_ty, lv_ty, locations) { | |
639 | span_mirbug!( | |
640 | self, | |
641 | term, | |
642 | "bad DropAndReplace ({:?} = {:?}): {:?}", | |
643 | lv_ty, | |
644 | rv_ty, | |
645 | terr | |
646 | ); | |
647 | } | |
3157f602 XL |
648 | } |
649 | } | |
abe05a73 XL |
650 | TerminatorKind::SwitchInt { |
651 | ref discr, | |
652 | switch_ty, | |
653 | .. | |
654 | } => { | |
8bb4bdeb | 655 | let discr_ty = discr.ty(mir, tcx); |
abe05a73 XL |
656 | if let Err(terr) = self.sub_types(discr_ty, switch_ty, term_location.at_self()) { |
657 | span_mirbug!( | |
658 | self, | |
659 | term, | |
660 | "bad SwitchInt ({:?} on {:?}): {:?}", | |
661 | switch_ty, | |
662 | discr_ty, | |
663 | terr | |
664 | ); | |
7453a54e | 665 | } |
abe05a73 XL |
666 | if !switch_ty.is_integral() && !switch_ty.is_char() && !switch_ty.is_bool() { |
667 | span_mirbug!(self, term, "bad SwitchInt discr ty {:?}", switch_ty); | |
7453a54e SL |
668 | } |
669 | // FIXME: check the values | |
670 | } | |
abe05a73 XL |
671 | TerminatorKind::Call { |
672 | ref func, | |
673 | ref args, | |
674 | ref destination, | |
675 | .. | |
676 | } => { | |
5bcae85e | 677 | let func_ty = func.ty(mir, tcx); |
7453a54e | 678 | debug!("check_terminator: call, func_ty={:?}", func_ty); |
8bb4bdeb | 679 | let sig = match func_ty.sty { |
041b39d2 | 680 | ty::TyFnDef(..) | ty::TyFnPtr(_) => func_ty.fn_sig(tcx), |
7453a54e SL |
681 | _ => { |
682 | span_mirbug!(self, term, "call to non-function {:?}", func_ty); | |
683 | return; | |
684 | } | |
685 | }; | |
abe05a73 XL |
686 | let (sig, map) = self.infcx.replace_late_bound_regions_with_fresh_var( |
687 | term.source_info.span, | |
688 | LateBoundRegionConversionTime::FnCall, | |
689 | &sig, | |
690 | ); | |
691 | let sig = self.normalize(&sig, term_location); | |
692 | self.check_call_dest(mir, term, &sig, destination, term_location); | |
693 | ||
694 | // The ordinary liveness rules will ensure that all | |
695 | // regions in the type of the callee are live here. We | |
696 | // then further constrain the late-bound regions that | |
697 | // were instantiated at the call site to be live as | |
698 | // well. The resulting is that all the input (and | |
699 | // output) types in the signature must be live, since | |
700 | // all the inputs that fed into it were live. | |
701 | for &late_bound_region in map.values() { | |
702 | self.constraints | |
703 | .liveness_set | |
704 | .push((late_bound_region, term_location)); | |
705 | } | |
7453a54e SL |
706 | |
707 | if self.is_box_free(func) { | |
abe05a73 | 708 | self.check_box_free_inputs(mir, term, &sig, args, term_location); |
7453a54e | 709 | } else { |
abe05a73 | 710 | self.check_call_inputs(mir, term, &sig, args, term_location); |
7453a54e SL |
711 | } |
712 | } | |
abe05a73 XL |
713 | TerminatorKind::Assert { |
714 | ref cond, ref msg, .. | |
715 | } => { | |
5bcae85e | 716 | let cond_ty = cond.ty(mir, tcx); |
3157f602 XL |
717 | if cond_ty != tcx.types.bool { |
718 | span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty); | |
719 | } | |
720 | ||
721 | if let AssertMessage::BoundsCheck { ref len, ref index } = *msg { | |
5bcae85e | 722 | if len.ty(mir, tcx) != tcx.types.usize { |
3157f602 XL |
723 | span_mirbug!(self, len, "bounds-check length non-usize {:?}", len) |
724 | } | |
5bcae85e | 725 | if index.ty(mir, tcx) != tcx.types.usize { |
3157f602 XL |
726 | span_mirbug!(self, index, "bounds-check index non-usize {:?}", index) |
727 | } | |
728 | } | |
729 | } | |
ea8adc8c XL |
730 | TerminatorKind::Yield { ref value, .. } => { |
731 | let value_ty = value.ty(mir, tcx); | |
732 | match mir.yield_ty { | |
733 | None => span_mirbug!(self, term, "yield in non-generator"), | |
734 | Some(ty) => { | |
abe05a73 XL |
735 | if let Err(terr) = self.sub_types(value_ty, ty, term_location.at_self()) { |
736 | span_mirbug!( | |
737 | self, | |
ea8adc8c XL |
738 | term, |
739 | "type of yield value is {:?}, but the yield type is {:?}: {:?}", | |
740 | value_ty, | |
741 | ty, | |
abe05a73 XL |
742 | terr |
743 | ); | |
ea8adc8c XL |
744 | } |
745 | } | |
746 | } | |
747 | } | |
7453a54e SL |
748 | } |
749 | } | |
750 | ||
abe05a73 XL |
751 | fn check_call_dest( |
752 | &mut self, | |
753 | mir: &Mir<'tcx>, | |
754 | term: &Terminator<'tcx>, | |
755 | sig: &ty::FnSig<'tcx>, | |
756 | destination: &Option<(Lvalue<'tcx>, BasicBlock)>, | |
757 | term_location: Location, | |
758 | ) { | |
7453a54e | 759 | let tcx = self.tcx(); |
5bcae85e | 760 | match *destination { |
abe05a73 | 761 | Some((ref dest, target_block)) => { |
5bcae85e | 762 | let dest_ty = dest.ty(mir, tcx).to_ty(tcx); |
abe05a73 XL |
763 | let locations = Locations { |
764 | from_location: term_location, | |
765 | at_location: target_block.start_location(), | |
766 | }; | |
767 | if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations) { | |
768 | span_mirbug!( | |
769 | self, | |
770 | term, | |
771 | "call dest mismatch ({:?} <- {:?}): {:?}", | |
772 | dest_ty, | |
773 | sig.output(), | |
774 | terr | |
775 | ); | |
7453a54e | 776 | } |
abe05a73 | 777 | } |
5bcae85e SL |
778 | None => { |
779 | // FIXME(canndrew): This is_never should probably be an is_uninhabited | |
476ff2be | 780 | if !sig.output().is_never() { |
5bcae85e SL |
781 | span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); |
782 | } | |
abe05a73 | 783 | } |
7453a54e SL |
784 | } |
785 | } | |
786 | ||
abe05a73 XL |
787 | fn check_call_inputs( |
788 | &mut self, | |
789 | mir: &Mir<'tcx>, | |
790 | term: &Terminator<'tcx>, | |
791 | sig: &ty::FnSig<'tcx>, | |
792 | args: &[Operand<'tcx>], | |
793 | term_location: Location, | |
794 | ) { | |
7453a54e | 795 | debug!("check_call_inputs({:?}, {:?})", sig, args); |
abe05a73 | 796 | if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.variadic) { |
7453a54e SL |
797 | span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); |
798 | } | |
476ff2be | 799 | for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() { |
5bcae85e | 800 | let op_arg_ty = op_arg.ty(mir, self.tcx()); |
abe05a73 XL |
801 | if let Err(terr) = self.sub_types(op_arg_ty, fn_arg, term_location.at_self()) { |
802 | span_mirbug!( | |
803 | self, | |
804 | term, | |
805 | "bad arg #{:?} ({:?} <- {:?}): {:?}", | |
806 | n, | |
807 | fn_arg, | |
808 | op_arg_ty, | |
809 | terr | |
810 | ); | |
7453a54e SL |
811 | } |
812 | } | |
813 | } | |
814 | ||
815 | fn is_box_free(&self, operand: &Operand<'tcx>) -> bool { | |
816 | match operand { | |
cc61c64b | 817 | &Operand::Constant(box Constant { |
abe05a73 XL |
818 | literal: |
819 | Literal::Value { | |
820 | value: | |
821 | &ty::Const { | |
822 | val: ConstVal::Function(def_id, _), | |
823 | .. | |
824 | }, | |
825 | .. | |
826 | }, | |
827 | .. | |
828 | }) => Some(def_id) == self.tcx().lang_items().box_free_fn(), | |
7453a54e SL |
829 | _ => false, |
830 | } | |
831 | } | |
832 | ||
abe05a73 XL |
833 | fn check_box_free_inputs( |
834 | &mut self, | |
835 | mir: &Mir<'tcx>, | |
836 | term: &Terminator<'tcx>, | |
837 | sig: &ty::FnSig<'tcx>, | |
838 | args: &[Operand<'tcx>], | |
839 | term_location: Location, | |
840 | ) { | |
7453a54e SL |
841 | debug!("check_box_free_inputs"); |
842 | ||
843 | // box_free takes a Box as a pointer. Allow for that. | |
844 | ||
476ff2be | 845 | if sig.inputs().len() != 1 { |
7453a54e SL |
846 | span_mirbug!(self, term, "box_free should take 1 argument"); |
847 | return; | |
848 | } | |
849 | ||
476ff2be | 850 | let pointee_ty = match sig.inputs()[0].sty { |
7453a54e SL |
851 | ty::TyRawPtr(mt) => mt.ty, |
852 | _ => { | |
853 | span_mirbug!(self, term, "box_free should take a raw ptr"); | |
854 | return; | |
855 | } | |
856 | }; | |
857 | ||
858 | if args.len() != 1 { | |
859 | span_mirbug!(self, term, "box_free called with wrong # of args"); | |
860 | return; | |
861 | } | |
862 | ||
32a655c1 SL |
863 | let ty = args[0].ty(mir, self.tcx()); |
864 | let arg_ty = match ty.sty { | |
7453a54e | 865 | ty::TyRawPtr(mt) => mt.ty, |
32a655c1 | 866 | ty::TyAdt(def, _) if def.is_box() => ty.boxed_ty(), |
7453a54e SL |
867 | _ => { |
868 | span_mirbug!(self, term, "box_free called with bad arg ty"); | |
869 | return; | |
870 | } | |
871 | }; | |
872 | ||
abe05a73 XL |
873 | if let Err(terr) = self.sub_types(arg_ty, pointee_ty, term_location.at_self()) { |
874 | span_mirbug!( | |
875 | self, | |
876 | term, | |
877 | "bad box_free arg ({:?} <- {:?}): {:?}", | |
878 | pointee_ty, | |
879 | arg_ty, | |
880 | terr | |
881 | ); | |
7453a54e SL |
882 | } |
883 | } | |
884 | ||
abe05a73 XL |
885 | fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block_data: &BasicBlockData<'tcx>) { |
886 | let is_cleanup = block_data.is_cleanup; | |
887 | self.last_span = block_data.terminator().source_info.span; | |
888 | match block_data.terminator().kind { | |
889 | TerminatorKind::Goto { target } => { | |
890 | self.assert_iscleanup(mir, block_data, target, is_cleanup) | |
ea8adc8c | 891 | } |
abe05a73 XL |
892 | TerminatorKind::SwitchInt { ref targets, .. } => for target in targets { |
893 | self.assert_iscleanup(mir, block_data, *target, is_cleanup); | |
894 | }, | |
895 | TerminatorKind::Resume => if !is_cleanup { | |
896 | span_mirbug!(self, block_data, "resume on non-cleanup block!") | |
897 | }, | |
898 | TerminatorKind::Return => if is_cleanup { | |
899 | span_mirbug!(self, block_data, "return on cleanup block") | |
900 | }, | |
901 | TerminatorKind::GeneratorDrop { .. } => if is_cleanup { | |
902 | span_mirbug!(self, block_data, "generator_drop in cleanup block") | |
903 | }, | |
ea8adc8c XL |
904 | TerminatorKind::Yield { resume, drop, .. } => { |
905 | if is_cleanup { | |
abe05a73 | 906 | span_mirbug!(self, block_data, "yield in cleanup block") |
ea8adc8c | 907 | } |
abe05a73 | 908 | self.assert_iscleanup(mir, block_data, resume, is_cleanup); |
ea8adc8c | 909 | if let Some(drop) = drop { |
abe05a73 | 910 | self.assert_iscleanup(mir, block_data, drop, is_cleanup); |
ea8adc8c XL |
911 | } |
912 | } | |
3157f602 XL |
913 | TerminatorKind::Unreachable => {} |
914 | TerminatorKind::Drop { target, unwind, .. } | | |
915 | TerminatorKind::DropAndReplace { target, unwind, .. } | | |
abe05a73 XL |
916 | TerminatorKind::Assert { |
917 | target, | |
918 | cleanup: unwind, | |
919 | .. | |
920 | } => { | |
921 | self.assert_iscleanup(mir, block_data, target, is_cleanup); | |
3157f602 XL |
922 | if let Some(unwind) = unwind { |
923 | if is_cleanup { | |
abe05a73 | 924 | span_mirbug!(self, block_data, "unwind on cleanup block") |
3157f602 | 925 | } |
abe05a73 | 926 | self.assert_iscleanup(mir, block_data, unwind, true); |
3157f602 XL |
927 | } |
928 | } | |
abe05a73 XL |
929 | TerminatorKind::Call { |
930 | ref destination, | |
931 | cleanup, | |
932 | .. | |
933 | } => { | |
3157f602 | 934 | if let &Some((_, target)) = destination { |
abe05a73 | 935 | self.assert_iscleanup(mir, block_data, target, is_cleanup); |
3157f602 XL |
936 | } |
937 | if let Some(cleanup) = cleanup { | |
938 | if is_cleanup { | |
abe05a73 | 939 | span_mirbug!(self, block_data, "cleanup on cleanup block") |
3157f602 | 940 | } |
abe05a73 XL |
941 | self.assert_iscleanup(mir, block_data, cleanup, true); |
942 | } | |
943 | } | |
944 | TerminatorKind::FalseEdges { | |
945 | real_target, | |
946 | ref imaginary_targets, | |
947 | } => { | |
948 | self.assert_iscleanup(mir, block_data, real_target, is_cleanup); | |
949 | for target in imaginary_targets { | |
950 | self.assert_iscleanup(mir, block_data, *target, is_cleanup); | |
3157f602 XL |
951 | } |
952 | } | |
953 | } | |
954 | } | |
955 | ||
abe05a73 XL |
956 | fn assert_iscleanup( |
957 | &mut self, | |
958 | mir: &Mir<'tcx>, | |
959 | ctxt: &fmt::Debug, | |
960 | bb: BasicBlock, | |
961 | iscleanuppad: bool, | |
962 | ) { | |
3157f602 | 963 | if mir[bb].is_cleanup != iscleanuppad { |
abe05a73 XL |
964 | span_mirbug!( |
965 | self, | |
966 | ctxt, | |
967 | "cleanuppad mismatch: {:?} should be {:?}", | |
968 | bb, | |
969 | iscleanuppad | |
970 | ); | |
3157f602 XL |
971 | } |
972 | } | |
973 | ||
abe05a73 | 974 | fn check_local(&mut self, mir: &Mir<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) { |
cc61c64b XL |
975 | match mir.local_kind(local) { |
976 | LocalKind::ReturnPointer | LocalKind::Arg => { | |
977 | // return values of normal functions are required to be | |
978 | // sized by typeck, but return values of ADT constructors are | |
979 | // not because we don't include a `Self: Sized` bounds on them. | |
980 | // | |
981 | // Unbound parts of arguments were never required to be Sized | |
982 | // - maybe we should make that a warning. | |
abe05a73 | 983 | return; |
cc61c64b XL |
984 | } |
985 | LocalKind::Var | LocalKind::Temp => {} | |
986 | } | |
987 | ||
988 | let span = local_decl.source_info.span; | |
989 | let ty = local_decl.ty; | |
abe05a73 XL |
990 | |
991 | // Erase the regions from `ty` to get a global type. The | |
992 | // `Sized` bound in no way depends on precise regions, so this | |
993 | // shouldn't affect `is_sized`. | |
994 | let gcx = self.tcx().global_tcx(); | |
995 | let erased_ty = gcx.lift(&self.tcx().erase_regions(&ty)).unwrap(); | |
996 | if !erased_ty.is_sized(gcx, self.param_env, span) { | |
cc61c64b XL |
997 | // in current MIR construction, all non-control-flow rvalue |
998 | // expressions evaluate through `as_temp` or `into` a return | |
999 | // slot or local, so to find all unsized rvalues it is enough | |
1000 | // to check all temps, return slots and locals. | |
1001 | if let None = self.reported_errors.replace((ty, span)) { | |
abe05a73 XL |
1002 | span_err!( |
1003 | self.tcx().sess, | |
1004 | span, | |
1005 | E0161, | |
1006 | "cannot move a value of type {0}: the size of {0} \ | |
1007 | cannot be statically determined", | |
1008 | ty | |
1009 | ); | |
cc61c64b XL |
1010 | } |
1011 | } | |
1012 | } | |
1013 | ||
abe05a73 | 1014 | fn typeck_mir(&mut self, mir: &Mir<'tcx>) { |
7453a54e SL |
1015 | self.last_span = mir.span; |
1016 | debug!("run_on_mir: {:?}", mir.span); | |
cc61c64b XL |
1017 | |
1018 | for (local, local_decl) in mir.local_decls.iter_enumerated() { | |
1019 | self.check_local(mir, local, local_decl); | |
1020 | } | |
1021 | ||
abe05a73 XL |
1022 | for (block, block_data) in mir.basic_blocks().iter_enumerated() { |
1023 | let mut location = Location { | |
1024 | block, | |
1025 | statement_index: 0, | |
1026 | }; | |
1027 | for stmt in &block_data.statements { | |
3157f602 XL |
1028 | if stmt.source_info.span != DUMMY_SP { |
1029 | self.last_span = stmt.source_info.span; | |
7453a54e | 1030 | } |
abe05a73 XL |
1031 | self.check_stmt(mir, stmt, location); |
1032 | location.statement_index += 1; | |
7453a54e SL |
1033 | } |
1034 | ||
abe05a73 XL |
1035 | self.check_terminator(mir, block_data.terminator(), location); |
1036 | self.check_iscleanup(mir, block_data); | |
3157f602 XL |
1037 | } |
1038 | } | |
1039 | ||
abe05a73 XL |
1040 | fn normalize<T>(&mut self, value: &T, location: Location) -> T |
1041 | where | |
1042 | T: fmt::Debug + TypeFoldable<'tcx>, | |
3157f602 | 1043 | { |
abe05a73 XL |
1044 | self.fully_perform_op(location.at_self(), |this| { |
1045 | let mut selcx = traits::SelectionContext::new(this.infcx); | |
1046 | let cause = traits::ObligationCause::misc(this.last_span, ast::CRATE_NODE_ID); | |
1047 | let traits::Normalized { value, obligations } = | |
1048 | traits::normalize(&mut selcx, this.param_env, cause, value); | |
1049 | Ok(InferOk { value, obligations }) | |
1050 | }).unwrap() | |
7453a54e SL |
1051 | } |
1052 | } | |
1053 | ||
1054 | pub struct TypeckMir; | |
1055 | ||
7cac9316 | 1056 | impl MirPass for TypeckMir { |
abe05a73 XL |
1057 | fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) { |
1058 | let def_id = src.def_id; | |
1059 | let id = tcx.hir.as_local_node_id(def_id).unwrap(); | |
7cac9316 | 1060 | debug!("run_pass: {:?}", def_id); |
c30ab7b3 | 1061 | |
54a0048b | 1062 | if tcx.sess.err_count() > 0 { |
7453a54e SL |
1063 | // compiling a broken program can obviously result in a |
1064 | // broken MIR, so try not to report duplicate errors. | |
1065 | return; | |
1066 | } | |
7cac9316 | 1067 | let param_env = tcx.param_env(def_id); |
041b39d2 | 1068 | tcx.infer_ctxt().enter(|infcx| { |
abe05a73 XL |
1069 | let _region_constraint_sets = type_check(&infcx, id, param_env, mir); |
1070 | ||
1071 | // For verification purposes, we just ignore the resulting | |
1072 | // region constraint sets. Not our problem. =) | |
a7813a04 | 1073 | }); |
7453a54e SL |
1074 | } |
1075 | } | |
abe05a73 XL |
1076 | |
1077 | trait AtLocation { | |
1078 | /// Creates a `Locations` where `self` is both the from-location | |
1079 | /// and the at-location. This means that any required region | |
1080 | /// relationships must hold upon entering the statement/terminator | |
1081 | /// indicated by `self`. This is typically used when processing | |
1082 | /// "inputs" to the given location. | |
1083 | fn at_self(self) -> Locations; | |
1084 | ||
1085 | /// Creates a `Locations` where `self` is the from-location and | |
1086 | /// its successor within the block is the at-location. This means | |
1087 | /// that any required region relationships must hold only upon | |
1088 | /// **exiting** the statement/terminator indicated by `self`. This | |
1089 | /// is for example used when you have a `lv = rv` statement: it | |
1090 | /// indicates that the `typeof(rv) <: typeof(lv)` as of the | |
1091 | /// **next** statement. | |
1092 | fn at_successor_within_block(self) -> Locations; | |
1093 | } | |
1094 | ||
1095 | impl AtLocation for Location { | |
1096 | fn at_self(self) -> Locations { | |
1097 | Locations { | |
1098 | from_location: self, | |
1099 | at_location: self, | |
1100 | } | |
1101 | } | |
1102 | ||
1103 | fn at_successor_within_block(self) -> Locations { | |
1104 | Locations { | |
1105 | from_location: self, | |
1106 | at_location: self.successor_within_block(), | |
1107 | } | |
1108 | } | |
1109 | } |