about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2018-02-23 20:52:05 +0000
committerDavid Wood <david@davidtw.co>2018-03-22 21:10:59 +0000
commit17b285d2036f13f4aa06871ebfa7eb92d1bd1db3 (patch)
tree45146d15c2eb50863c03515f15f03e2eaf68c38d
parentc0fdb293620c86088b6e6d655721c45595b29fbd (diff)
downloadrust-17b285d2036f13f4aa06871ebfa7eb92d1bd1db3.tar.gz
rust-17b285d2036f13f4aa06871ebfa7eb92d1bd1db3.zip
Added UserAssertTy statement.
-rw-r--r--src/librustc/ich/impls_mir.rs4
-rw-r--r--src/librustc/mir/mod.rs11
-rw-r--r--src/librustc/mir/visit.rs19
-rw-r--r--src/librustc_mir/borrow_check/mod.rs8
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs1
-rw-r--r--src/librustc_mir/build/block.rs6
-rw-r--r--src/librustc_mir/build/matches/mod.rs15
-rw-r--r--src/librustc_mir/dataflow/impls/borrows.rs1
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs1
-rw-r--r--src/librustc_mir/hair/cx/block.rs2
-rw-r--r--src/librustc_mir/hair/mod.rs7
-rw-r--r--src/librustc_mir/interpret/step.rs2
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs1
-rw-r--r--src/librustc_mir/transform/mod.rs2
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs1
-rw-r--r--src/librustc_mir/transform/remove_noop_landing_pads.rs1
-rw-r--r--src/librustc_mir/transform/rustc_peek.rs1
-rw-r--r--src/librustc_passes/mir_stats.rs1
-rw-r--r--src/librustc_trans/mir/statement.rs1
19 files changed, 79 insertions, 6 deletions
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index 1e6dadae363..ff73f135ce6 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -277,6 +277,10 @@ for mir::StatementKind<'gcx> {
                 op.hash_stable(hcx, hasher);
                 places.hash_stable(hcx, hasher);
             }
+            mir::StatementKind::UserAssertTy(ref ty, ref local) => {
+                ty.hash_stable(hcx, hasher);
+                local.hash_stable(hcx, hasher);
+            }
             mir::StatementKind::Nop => {}
             mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
                 asm.hash_stable(hcx, hasher);
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 64a1729982a..c36e401e8d6 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1253,6 +1253,15 @@ pub enum StatementKind<'tcx> {
     /// (The starting point(s) arise implicitly from borrows.)
     EndRegion(region::Scope),
 
+    /// Encodes a user's type assertion. These need to be preserved intact so that NLL can respect
+    /// them. For example:
+    ///
+    ///     let (a, b): (T, U) = y;
+    ///
+    /// Here we would insert a `UserAssertTy<(T, U)>(y)` instruction to check that the type of `y`
+    /// is the right thing.
+    UserAssertTy(Ty<'tcx>, Local),
+
     /// No-op. Useful for deleting instructions without affecting statement indices.
     Nop,
 }
@@ -1324,6 +1333,7 @@ impl<'tcx> Debug for Statement<'tcx> {
             InlineAsm { ref asm, ref outputs, ref inputs } => {
                 write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs)
             },
+            UserAssertTy(ref ty, ref local) => write!(fmt, "UserAssertTy({:?}, {:?})", ty, local),
             Nop => write!(fmt, "nop"),
         }
     }
@@ -2184,6 +2194,7 @@ EnumTypeFoldableImpl! {
         (StatementKind::InlineAsm) { asm, outputs, inputs },
         (StatementKind::Validate)(a, b),
         (StatementKind::EndRegion)(a),
+        (StatementKind::UserAssertTy)(a, b),
         (StatementKind::Nop),
     }
 }
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 650af8dc4d9..cc5d9692e7a 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -144,6 +144,13 @@ macro_rules! make_mir_visitor {
                 self.super_operand(operand, location);
             }
 
+            fn visit_user_assert_ty(&mut self,
+                                    ty: & $($mutability)* Ty<'tcx>,
+                                    local: & $($mutability)* Local,
+                                    location: Location) {
+                self.super_user_assert_ty(ty, local, location);
+            }
+
             fn visit_place(&mut self,
                             place: & $($mutability)* Place<'tcx>,
                             context: PlaceContext<'tcx>,
@@ -376,6 +383,10 @@ macro_rules! make_mir_visitor {
                             self.visit_operand(input, location);
                         }
                     }
+                    StatementKind::UserAssertTy(ref $($mutability)* ty,
+                                                ref $($mutability)* local) => {
+                        self.visit_user_assert_ty(ty, local, location);
+                    }
                     StatementKind::Nop => {}
                 }
             }
@@ -619,6 +630,14 @@ macro_rules! make_mir_visitor {
                 }
             }
 
+            fn super_user_assert_ty(&mut self,
+                                    ty: & $($mutability)* Ty<'tcx>,
+                                    local: & $($mutability)* Local,
+                                    location: Location) {
+                self.visit_ty(ty, TyContext::Location(location));
+                self.visit_local(local, PlaceContext::Validate, location);
+            }
+
             fn super_place(&mut self,
                             place: & $($mutability)* Place<'tcx>,
                             context: PlaceContext<'tcx>,
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 6e1a798910d..305df37466d 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -392,11 +392,13 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                 // ignored when consuming results (update to
                 // flow_state already handled).
             }
-            StatementKind::Nop | StatementKind::Validate(..) | StatementKind::StorageLive(..) => {
-                // `Nop`, `Validate`, and `StorageLive` are irrelevant
+            StatementKind::Nop |
+            StatementKind::UserAssertTy(..) |
+            StatementKind::Validate(..) |
+            StatementKind::StorageLive(..) => {
+                // `Nop`, `UserAssertTy`, `Validate`, and `StorageLive` are irrelevant
                 // to borrow check.
             }
-
             StatementKind::StorageDead(local) => {
                 self.access_place(
                     ContextKind::StorageDead.new(location),
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 022831b5a92..f070691a5cf 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -766,6 +766,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             | StatementKind::InlineAsm { .. }
             | StatementKind::EndRegion(_)
             | StatementKind::Validate(..)
+            | StatementKind::UserAssertTy(..)
             | StatementKind::Nop => {}
         }
     }
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index 7281fb59663..02d2522b6ba 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -102,6 +102,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     remainder_scope,
                     init_scope,
                     pattern,
+                    ty,
                     initializer,
                     lint_level
                 } => {
@@ -120,12 +121,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
                                 let scope = (init_scope, source_info);
                                 this.in_scope(scope, lint_level, block, |this| {
-                                    this.expr_into_pattern(block, pattern, init)
+                                    this.expr_into_pattern(block, ty, pattern, init)
                                 })
                             }));
                     } else {
                         this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
                             this.storage_live_binding(block, node, span);
+                            if let Some(ty) = ty {
+                                this.user_assert_ty(block, ty, node, span);
+                            }
                             this.schedule_drop_for_binding(node, span);
                         })
                     }
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 229e33dcd78..4353eb5e4bd 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -145,8 +145,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         end_block.unit()
     }
 
+    pub fn user_assert_ty(&mut self, block: BasicBlock, ty: Ty<'tcx>, var: NodeId, span: Span) {
+        let local_id = self.var_indices[&var];
+        let source_info = self.source_info(span);
+        self.cfg.push(block, Statement {
+            source_info,
+            kind: StatementKind::UserAssertTy(ty, local_id),
+        });
+    }
+
     pub fn expr_into_pattern(&mut self,
                              mut block: BasicBlock,
+                             ty: Option<Ty<'tcx>>,
                              irrefutable_pat: Pattern<'tcx>,
                              initializer: ExprRef<'tcx>)
                              -> BlockAnd<()> {
@@ -156,6 +166,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                    var,
                                    subpattern: None, .. } => {
                 let place = self.storage_live_binding(block, var, irrefutable_pat.span);
+
+                if let Some(ty) = ty {
+                    self.user_assert_ty(block, ty, var, irrefutable_pat.span);
+                }
+
                 unpack!(block = self.into(&place, block, initializer));
                 self.schedule_drop_for_binding(var, irrefutable_pat.span);
                 block.unit()
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index 499ed55fad4..fb3042014df 100644
--- a/src/librustc_mir/dataflow/impls/borrows.rs
+++ b/src/librustc_mir/dataflow/impls/borrows.rs
@@ -678,6 +678,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
             mir::StatementKind::SetDiscriminant { .. } |
             mir::StatementKind::StorageLive(..) |
             mir::StatementKind::Validate(..) |
+            mir::StatementKind::UserAssertTy(..) |
             mir::StatementKind::Nop => {}
 
         }
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index d6f419f6cfb..cbf4c822769 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -298,6 +298,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
             }
             StatementKind::EndRegion(_) |
             StatementKind::Validate(..) |
+            StatementKind::UserAssertTy(..) |
             StatementKind::Nop => {}
         }
     }
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index 6f6258f52f7..f0497338303 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -76,12 +76,14 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                             first_statement_index: region::FirstStatementIndex::new(index),
                         });
 
+                        let ty = local.ty.clone().map(|ty| cx.tables().node_id_to_type(ty.hir_id));
                         let pattern = cx.pattern_from_hir(&local.pat);
                         result.push(StmtRef::Mirror(Box::new(Stmt {
                             kind: StmtKind::Let {
                                 remainder_scope: remainder_scope,
                                 init_scope: region::Scope::Node(hir_id.local_id),
                                 pattern,
+                                ty,
                                 initializer: local.init.to_ref(),
                                 lint_level: cx.lint_level_of(local.id),
                             },
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 5f60a134fb1..138944189ff 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -93,10 +93,13 @@ pub enum StmtKind<'tcx> {
         /// lifetime of temporaries
         init_scope: region::Scope,
 
-        /// let <PAT> = ...
+        /// let <PAT>: ty = ...
         pattern: Pattern<'tcx>,
 
-        /// let pat = <INIT> ...
+        /// let pat: <TY> = init ...
+        ty: Option<Ty<'tcx>>,
+
+        /// let pat: ty = <INIT> ...
         initializer: Option<ExprRef<'tcx>>,
 
         /// the lint level for this let-statement
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 4e1750caf26..f1d58ff5e88 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -89,6 +89,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 M::end_region(self, Some(ce))?;
             }
 
+            UserAssertTy(..) => {}
+
             // Defined to do nothing. These are added by optimization passes, to avoid changing the
             // size of MIR constantly.
             Nop => {}
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 86d08dec2b9..02c70399664 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -105,6 +105,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
             StatementKind::StorageDead(..) |
             StatementKind::EndRegion(..) |
             StatementKind::Validate(..) |
+            StatementKind::UserAssertTy(..) |
             StatementKind::Nop => {
                 // safe (at least as emitted during MIR construction)
             }
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 81b740c917b..a06571d0abd 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -234,6 +234,8 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
         simplify_branches::SimplifyBranches::new("initial"),
         remove_noop_landing_pads::RemoveNoopLandingPads,
         simplify::SimplifyCfg::new("early-opt"),
+        // Remove all `UserAssertTy` statements.
+        cleanup_post_borrowck::CleanUserAssertTy,
 
         // These next passes must be executed together
         add_call_guards::CriticalCallEdges,
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 59a872a23b0..8e2f98d2769 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -1099,6 +1099,7 @@ This does not pose a problem by itself because they can't be accessed directly."
                 StatementKind::InlineAsm {..} |
                 StatementKind::EndRegion(_) |
                 StatementKind::Validate(..) |
+                StatementKind::UserAssertTy(..) |
                 StatementKind::Nop => {}
             }
         });
diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs
index cd80d25c410..6d365012525 100644
--- a/src/librustc_mir/transform/remove_noop_landing_pads.rs
+++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs
@@ -50,6 +50,7 @@ impl RemoveNoopLandingPads {
                 StatementKind::StorageLive(_) |
                 StatementKind::StorageDead(_) |
                 StatementKind::EndRegion(_) |
+                StatementKind::UserAssertTy(..) |
                 StatementKind::Nop => {
                     // These are all nops in a landing pad (there's some
                     // borrowck interaction between EndRegion and storage
diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs
index 76283edac72..45e7a0d3f4c 100644
--- a/src/librustc_mir/transform/rustc_peek.rs
+++ b/src/librustc_mir/transform/rustc_peek.rs
@@ -163,6 +163,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             mir::StatementKind::InlineAsm { .. } |
             mir::StatementKind::EndRegion(_) |
             mir::StatementKind::Validate(..) |
+            mir::StatementKind::UserAssertTy(..) |
             mir::StatementKind::Nop => continue,
             mir::StatementKind::SetDiscriminant{ .. } =>
                 span_bug!(stmt.source_info.span,
diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs
index 4a4ce63cc1d..a4e056c6b58 100644
--- a/src/librustc_passes/mir_stats.rs
+++ b/src/librustc_passes/mir_stats.rs
@@ -90,6 +90,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
             StatementKind::StorageLive(..) => "StatementKind::StorageLive",
             StatementKind::StorageDead(..) => "StatementKind::StorageDead",
             StatementKind::InlineAsm { .. } => "StatementKind::InlineAsm",
+            StatementKind::UserAssertTy(..) => "StatementKind::UserAssertTy",
             StatementKind::Nop => "StatementKind::Nop",
         }, &statement.kind);
         self.super_statement(block, statement, location);
diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs
index b5b74849401..579b07929a2 100644
--- a/src/librustc_trans/mir/statement.rs
+++ b/src/librustc_trans/mir/statement.rs
@@ -84,6 +84,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
             }
             mir::StatementKind::EndRegion(_) |
             mir::StatementKind::Validate(..) |
+            mir::StatementKind::UserAssertTy(..) |
             mir::StatementKind::Nop => bx,
         }
     }