1 // Copyright 2017 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.
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.
11 //! This module provides two passes:
13 //! - `CleanEndRegions`, that reduces the set of `EndRegion` statements
15 //! - `CleanUserAssertTy`, that replaces all `UserAssertTy` statements
18 //! The `CleanEndRegions` "pass" is actually implemented as two
19 //! traversals (aka visits) of the input MIR. The first traversal,
20 //! `GatherBorrowedRegions`, finds all of the regions in the MIR
21 //! that are involved in a borrow.
23 //! The second traversal, `DeleteTrivialEndRegions`, walks over the
24 //! MIR and removes any `EndRegion` that is applied to a region that
25 //! was not seen in the previous pass.
27 //! The `CleanUserAssertTy` pass runs at a distinct time from the
28 //! `CleanEndRegions` pass. It is important that the `CleanUserAssertTy`
29 //! pass runs after the MIR borrowck so that the NLL type checker can
30 //! perform the type assertion when it encounters the `UserAssertTy`
33 use rustc_data_structures::fx::FxHashSet;
35 use rustc::middle::region;
36 use rustc::mir::{BasicBlock, Location, Mir, Rvalue, Statement, StatementKind};
37 use rustc::mir::visit::{MutVisitor, Visitor, TyContext};
38 use rustc::ty::{Ty, RegionKind, TyCtxt};
39 use transform::{MirPass, MirSource};
41 pub struct CleanEndRegions;
43 struct GatherBorrowedRegions {
44 seen_regions: FxHashSet<region::Scope>,
47 struct DeleteTrivialEndRegions<'a> {
48 seen_regions: &'a FxHashSet<region::Scope>,
51 impl MirPass for CleanEndRegions {
52 fn run_pass<'a, 'tcx>(&self,
53 tcx: TyCtxt<'a, 'tcx, 'tcx>,
55 mir: &mut Mir<'tcx>) {
56 if !tcx.emit_end_regions() { return; }
58 let mut gather = GatherBorrowedRegions {
59 seen_regions: FxHashSet()
61 gather.visit_mir(mir);
63 let mut delete = DeleteTrivialEndRegions { seen_regions: &mut gather.seen_regions };
64 delete.visit_mir(mir);
68 impl<'tcx> Visitor<'tcx> for GatherBorrowedRegions {
69 fn visit_rvalue(&mut self,
70 rvalue: &Rvalue<'tcx>,
72 // Gather regions that are used for borrows
73 if let Rvalue::Ref(r, _, _) = *rvalue {
74 if let RegionKind::ReScope(ce) = *r {
75 self.seen_regions.insert(ce);
78 self.super_rvalue(rvalue, location);
81 fn visit_ty(&mut self, ty: &Ty<'tcx>, _: TyContext) {
82 // Gather regions that occur in types
83 for re in ty.walk().flat_map(|t| t.regions()) {
85 RegionKind::ReScope(ce) => { self.seen_regions.insert(ce); }
93 impl<'a, 'tcx> MutVisitor<'tcx> for DeleteTrivialEndRegions<'a> {
94 fn visit_statement(&mut self,
96 statement: &mut Statement<'tcx>,
98 let mut delete_it = false;
100 if let StatementKind::EndRegion(ref region_scope) = statement.kind {
101 if !self.seen_regions.contains(region_scope) {
107 statement.make_nop();
109 self.super_statement(block, statement, location);
113 pub struct CleanUserAssertTy;
115 pub struct DeleteUserAssertTy;
117 impl MirPass for CleanUserAssertTy {
118 fn run_pass<'a, 'tcx>(&self,
119 _tcx: TyCtxt<'a, 'tcx, 'tcx>,
121 mir: &mut Mir<'tcx>) {
122 let mut delete = DeleteUserAssertTy;
123 delete.visit_mir(mir);
127 impl<'tcx> MutVisitor<'tcx> for DeleteUserAssertTy {
128 fn visit_statement(&mut self,
130 statement: &mut Statement<'tcx>,
131 location: Location) {
132 if let StatementKind::UserAssertTy(..) = statement.kind {
133 statement.make_nop();
135 self.super_statement(block, statement, location);