From c0fdb293620c86088b6e6d655721c45595b29fbd Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 23 Feb 2018 17:28:34 +0000 Subject: [PATCH 01/17] Added initial test for #47184 --- src/test/ui/issue-47184.rs | 16 ++++++++++++++++ src/test/ui/issue-47184.stderr | 0 2 files changed, 16 insertions(+) create mode 100644 src/test/ui/issue-47184.rs create mode 100644 src/test/ui/issue-47184.stderr diff --git a/src/test/ui/issue-47184.rs b/src/test/ui/issue-47184.rs new file mode 100644 index 0000000000000..d3ffbadf23294 --- /dev/null +++ b/src/test/ui/issue-47184.rs @@ -0,0 +1,16 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(nll)] + +fn main() { + let vec: Vec<&'static String> = vec![&String::new()]; + //~^ ERROR +} diff --git a/src/test/ui/issue-47184.stderr b/src/test/ui/issue-47184.stderr new file mode 100644 index 0000000000000..e69de29bb2d1d From 17b285d2036f13f4aa06871ebfa7eb92d1bd1db3 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 23 Feb 2018 20:52:05 +0000 Subject: [PATCH 02/17] Added UserAssertTy statement. --- src/librustc/ich/impls_mir.rs | 4 ++++ src/librustc/mir/mod.rs | 11 +++++++++++ src/librustc/mir/visit.rs | 19 +++++++++++++++++++ src/librustc_mir/borrow_check/mod.rs | 8 +++++--- .../borrow_check/nll/type_check/mod.rs | 1 + src/librustc_mir/build/block.rs | 6 +++++- src/librustc_mir/build/matches/mod.rs | 15 +++++++++++++++ src/librustc_mir/dataflow/impls/borrows.rs | 1 + .../dataflow/move_paths/builder.rs | 1 + src/librustc_mir/hair/cx/block.rs | 2 ++ src/librustc_mir/hair/mod.rs | 7 +++++-- src/librustc_mir/interpret/step.rs | 2 ++ src/librustc_mir/transform/check_unsafety.rs | 1 + src/librustc_mir/transform/mod.rs | 2 ++ src/librustc_mir/transform/qualify_consts.rs | 1 + .../transform/remove_noop_landing_pads.rs | 1 + src/librustc_mir/transform/rustc_peek.rs | 1 + src/librustc_passes/mir_stats.rs | 1 + src/librustc_trans/mir/statement.rs | 1 + 19 files changed, 79 insertions(+), 6 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 1e6dadae36371..ff73f135ce643 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 64a1729982a31..c36e401e8d69b 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 650af8dc4d903..cc5d9692e7a60 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 6e1a798910dc6..305df37466d02 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 022831b5a9259..f070691a5cf8c 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 7281fb5966388..02d2522b6ba91 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 229e33dcd7862..4353eb5e4bd38 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>, 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 499ed55fad41f..fb3042014df6a 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 d6f419f6cfb41..cbf4c822769c6 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 6f6258f52f794..f049733830378 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 5f60a134fb130..138944189ff5a 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 = ... + /// let : ty = ... pattern: Pattern<'tcx>, - /// let pat = ... + /// let pat: = init ... + ty: Option>, + + /// let pat: ty = ... initializer: Option>, /// the lint level for this let-statement diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 4e1750caf26ba..f1d58ff5e884e 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 86d08dec2b9c3..02c703996643a 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 81b740c917b5e..a06571d0abddf 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 59a872a23b060..8e2f98d276966 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 cd80d25c410f1..6d365012525f6 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 76283edac7284..45e7a0d3f4c5a 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 4a4ce63cc1d4e..a4e056c6b589e 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 b5b7484940192..579b07929a2f2 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, } } From 1331cd4a8c7655875de6b94119f80f26c631925d Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 23 Feb 2018 20:54:18 +0000 Subject: [PATCH 03/17] Killing UserAssertTy in CleanupPostBorrowck pass. --- ...nd_regions.rs => cleanup_post_borrowck.rs} | 56 ++++++++++++++----- src/librustc_mir/transform/mod.rs | 7 ++- 2 files changed, 46 insertions(+), 17 deletions(-) rename src/librustc_mir/transform/{clean_end_regions.rs => cleanup_post_borrowck.rs} (61%) diff --git a/src/librustc_mir/transform/clean_end_regions.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs similarity index 61% rename from src/librustc_mir/transform/clean_end_regions.rs rename to src/librustc_mir/transform/cleanup_post_borrowck.rs index 6e8985d99d287..5fdadc32a7674 100644 --- a/src/librustc_mir/transform/clean_end_regions.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -8,16 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! This module provides one pass, `CleanEndRegions`, that reduces the -//! set of `EndRegion` statements in the MIR. +//! This module provides two passes: //! -//! The "pass" is actually implemented as two traversals (aka visits) -//! of the input MIR. The first traversal, `GatherBorrowedRegions`, -//! finds all of the regions in the MIR that are involved in a borrow. +//! - `CleanEndRegions`, that reduces the set of `EndRegion` statements +//! in the MIR. +//! - `CleanUserAssertTy`, that replaces all `UserAssertTy` statements +//! with `Nop`. +//! +//! The `CleanEndRegions` "pass" is actually implemented as two +//! traversals (aka visits) of the input MIR. The first traversal, +//! `GatherBorrowedRegions`, finds all of the regions in the MIR +//! that are involved in a borrow. //! //! The second traversal, `DeleteTrivialEndRegions`, walks over the //! MIR and removes any `EndRegion` that is applied to a region that //! was not seen in the previous pass. +//! +//! The `CleanUserAssertTy` pass runs at a distinct time from the +//! `CleanEndRegions` pass. It is important that the `CleanUserAssertTy` +//! pass runs after the MIR borrowck so that the NLL type checker can +//! perform the type assertion when it encounters the `UserAssertTy` +//! statements. use rustc_data_structures::fx::FxHashSet; @@ -27,7 +38,7 @@ use rustc::mir::visit::{MutVisitor, Visitor, TyContext}; use rustc::ty::{Ty, RegionKind, TyCtxt}; use transform::{MirPass, MirSource}; -pub struct CleanEndRegions; +pub struct CleanupPostBorrowck; struct GatherBorrowedRegions { seen_regions: FxHashSet, @@ -37,19 +48,24 @@ struct DeleteTrivialEndRegions<'a> { seen_regions: &'a FxHashSet, } -impl MirPass for CleanEndRegions { +pub struct DeleteUserAssertTy; + +impl MirPass for CleanupPostBorrowck { fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, _source: MirSource, mir: &mut Mir<'tcx>) { - if !tcx.emit_end_regions() { return; } + if tcx.emit_end_regions() { + let mut gather = GatherBorrowedRegions { + seen_regions: FxHashSet() + }; + gather.visit_mir(mir); - let mut gather = GatherBorrowedRegions { - seen_regions: FxHashSet() - }; - gather.visit_mir(mir); + let mut delete = DeleteTrivialEndRegions { seen_regions: &mut gather.seen_regions }; + delete.visit_mir(mir); + } - let mut delete = DeleteTrivialEndRegions { seen_regions: &mut gather.seen_regions }; + let mut delete = DeleteUserAssertTy; delete.visit_mir(mir); } } @@ -93,7 +109,19 @@ impl<'a, 'tcx> MutVisitor<'tcx> for DeleteTrivialEndRegions<'a> { } if delete_it { - statement.kind = StatementKind::Nop; + statement.make_nop(); + } + self.super_statement(block, statement, location); + } +} + +impl<'tcx> MutVisitor<'tcx> for DeleteUserAssertTy { + fn visit_statement(&mut self, + block: BasicBlock, + statement: &mut Statement<'tcx>, + location: Location) { + if let StatementKind::UserAssertTy(..) = statement.kind { + statement.make_nop(); } self.super_statement(block, statement, location); } diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index a06571d0abddf..427528c4f6d92 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -25,7 +25,7 @@ use syntax_pos::Span; pub mod add_validation; pub mod add_moves_for_packed_drops; -pub mod clean_end_regions; +pub mod cleanup_post_borrowck; pub mod check_unsafety; pub mod simplify_branches; pub mod simplify; @@ -192,8 +192,9 @@ fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Stea let mut mir = tcx.mir_built(def_id).steal(); run_passes![tcx, mir, def_id, 0; - // Remove all `EndRegion` statements that are not involved in borrows. - clean_end_regions::CleanEndRegions, + // Remove all `UserAssertTy` statements and all `EndRegion` statements that are not + // involved in borrows. + cleanup_post_borrowck::CleanupPostBorrowck, // What we need to do constant evaluation. simplify::SimplifyCfg::new("initial"), From 5f21aa8734d7d120ad2e09b2b3d7db6e313b3a63 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 1 Mar 2018 14:31:14 +0000 Subject: [PATCH 04/17] Added initial processing of UserAssertTy statements. --- .../borrow_check/nll/type_check/mod.rs | 17 ++++++++- .../transform/cleanup_post_borrowck.rs | 37 ++++++++++++------- src/librustc_mir/transform/mod.rs | 5 +-- 3 files changed, 41 insertions(+), 18 deletions(-) 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 f070691a5cf8c..147952d867197 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -761,12 +761,27 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); }; } + StatementKind::UserAssertTy(ref ty, ref local) => { + let local_ty = mir.local_decls()[*local].ty; + debug!("check_stmt: user_assert_ty ty={:?} local_ty={:?}", ty, local_ty); + if let Err(terr) = + self.eq_types(ty, local_ty, location.at_successor_within_block()) + { + span_mirbug!( + self, + stmt, + "bad type assert ({:?} = {:?}): {:?}", + ty, + local_ty, + terr + ); + } + } StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::InlineAsm { .. } | StatementKind::EndRegion(_) | StatementKind::Validate(..) - | StatementKind::UserAssertTy(..) | StatementKind::Nop => {} } } diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs index 5fdadc32a7674..256b1fd66e9a7 100644 --- a/src/librustc_mir/transform/cleanup_post_borrowck.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -38,7 +38,7 @@ use rustc::mir::visit::{MutVisitor, Visitor, TyContext}; use rustc::ty::{Ty, RegionKind, TyCtxt}; use transform::{MirPass, MirSource}; -pub struct CleanupPostBorrowck; +pub struct CleanEndRegions; struct GatherBorrowedRegions { seen_regions: FxHashSet, @@ -48,24 +48,19 @@ struct DeleteTrivialEndRegions<'a> { seen_regions: &'a FxHashSet, } -pub struct DeleteUserAssertTy; - -impl MirPass for CleanupPostBorrowck { +impl MirPass for CleanEndRegions { fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, _source: MirSource, mir: &mut Mir<'tcx>) { - if tcx.emit_end_regions() { - let mut gather = GatherBorrowedRegions { - seen_regions: FxHashSet() - }; - gather.visit_mir(mir); - - let mut delete = DeleteTrivialEndRegions { seen_regions: &mut gather.seen_regions }; - delete.visit_mir(mir); - } + if !tcx.emit_end_regions() { return; } - let mut delete = DeleteUserAssertTy; + let mut gather = GatherBorrowedRegions { + seen_regions: FxHashSet() + }; + gather.visit_mir(mir); + + let mut delete = DeleteTrivialEndRegions { seen_regions: &mut gather.seen_regions }; delete.visit_mir(mir); } } @@ -115,6 +110,20 @@ impl<'a, 'tcx> MutVisitor<'tcx> for DeleteTrivialEndRegions<'a> { } } +pub struct CleanUserAssertTy; + +pub struct DeleteUserAssertTy; + +impl MirPass for CleanUserAssertTy { + fn run_pass<'a, 'tcx>(&self, + _tcx: TyCtxt<'a, 'tcx, 'tcx>, + _source: MirSource, + mir: &mut Mir<'tcx>) { + let mut delete = DeleteUserAssertTy; + delete.visit_mir(mir); + } +} + impl<'tcx> MutVisitor<'tcx> for DeleteUserAssertTy { fn visit_statement(&mut self, block: BasicBlock, diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 427528c4f6d92..63ca35aa0e7b2 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -192,9 +192,8 @@ fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Stea let mut mir = tcx.mir_built(def_id).steal(); run_passes![tcx, mir, def_id, 0; - // Remove all `UserAssertTy` statements and all `EndRegion` statements that are not - // involved in borrows. - cleanup_post_borrowck::CleanupPostBorrowck, + // Remove all `EndRegion` statements that are not involved in borrows. + cleanup_post_borrowck::CleanEndRegions, // What we need to do constant evaluation. simplify::SimplifyCfg::new("initial"), From 239b3ec47346e1c5cf09135a51ff791196e7c871 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 2 Mar 2018 14:33:21 +0000 Subject: [PATCH 05/17] Changed location to at_self from at_successor. --- src/librustc_mir/borrow_check/nll/type_check/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 147952d867197..2c06c93cd9d24 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -765,7 +765,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let local_ty = mir.local_decls()[*local].ty; debug!("check_stmt: user_assert_ty ty={:?} local_ty={:?}", ty, local_ty); if let Err(terr) = - self.eq_types(ty, local_ty, location.at_successor_within_block()) + self.eq_types(ty, local_ty, location.at_self()) { span_mirbug!( self, From ee4c7ac154c8f58ff6fa07416bf74ed3aa78ae0b Mon Sep 17 00:00:00 2001 From: David Wood Date: Sat, 10 Mar 2018 23:07:13 +0000 Subject: [PATCH 06/17] Added override in renumberer for UserAssertTy. --- src/librustc_mir/borrow_check/nll/renumber.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index c54acda8a6252..5267941c8a851 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -10,7 +10,7 @@ use rustc::ty::subst::Substs; use rustc::ty::{self, ClosureSubsts, GeneratorInterior, Ty, TypeFoldable}; -use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind}; +use rustc::mir::{BasicBlock, Local, Location, Mir, Statement, StatementKind}; use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; @@ -118,6 +118,11 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { debug!("visit_closure_substs: substs={:?}", substs); } + fn visit_user_assert_ty(&mut self, _ty: &mut Ty<'tcx>, _local: &mut Local, + _location: Location) { + debug!("visit_user_assert_ty: skipping renumber"); + } + fn visit_statement( &mut self, block: BasicBlock, From c8d81b1a2ecc0f4a0301b4c990a0a6303f9a5a7c Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 13 Mar 2018 14:16:14 +0000 Subject: [PATCH 07/17] Updated test with expected error message. --- src/test/ui/issue-47184.rs | 4 ++-- src/test/ui/issue-47184.stderr | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/test/ui/issue-47184.rs b/src/test/ui/issue-47184.rs index d3ffbadf23294..0831b7e0af8e2 100644 --- a/src/test/ui/issue-47184.rs +++ b/src/test/ui/issue-47184.rs @@ -11,6 +11,6 @@ #![feature(nll)] fn main() { - let vec: Vec<&'static String> = vec![&String::new()]; - //~^ ERROR + let _vec: Vec<&'static String> = vec![&String::new()]; + //~^ ERROR borrowed value does not live long enough [E0597] } diff --git a/src/test/ui/issue-47184.stderr b/src/test/ui/issue-47184.stderr index e69de29bb2d1d..a9eb33f01e3e0 100644 --- a/src/test/ui/issue-47184.stderr +++ b/src/test/ui/issue-47184.stderr @@ -0,0 +1,14 @@ +error[E0597]: borrowed value does not live long enough + --> $DIR/issue-47184.rs:14:44 + | +LL | let _vec: Vec<&'static String> = vec![&String::new()]; + | ^^^^^^^^^^^^^ temporary value does not live long enough +LL | //~^ ERROR borrowed value does not live long enough [E0597] +LL | } + | - temporary value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From d4b9a7874bcb46cd222f114a26fd9babf59b32dd Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 13 Mar 2018 14:16:53 +0000 Subject: [PATCH 08/17] Added comment in renumberer about UserAssertTy. --- src/librustc_mir/borrow_check/nll/renumber.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index 5267941c8a851..38a14be8eb262 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -120,6 +120,9 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { fn visit_user_assert_ty(&mut self, _ty: &mut Ty<'tcx>, _local: &mut Local, _location: Location) { + // User-assert-ty statements represent types that the user added explicitly. + // We don't want to erase the regions from these types: rather, we want to + // add them as constraints at type-check time. debug!("visit_user_assert_ty: skipping renumber"); } From 5d2a60c57e00c8ced93240c5ed1039f3ddb37397 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 13 Mar 2018 14:52:23 +0000 Subject: [PATCH 09/17] No longer visiting user_assert_ty statements in constraint generation. --- src/librustc_mir/borrow_check/nll/constraint_generation.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 3a39eb5c908de..c06f77b2d8491 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -12,10 +12,10 @@ use rustc::hir; use rustc::mir::{BasicBlock, BasicBlockData, Location, Place, Mir, Rvalue}; use rustc::mir::visit::Visitor; use rustc::mir::Place::Projection; -use rustc::mir::{PlaceProjection, ProjectionElem}; +use rustc::mir::{Local, PlaceProjection, ProjectionElem}; use rustc::mir::visit::TyContext; use rustc::infer::InferCtxt; -use rustc::ty::{self, ClosureSubsts}; +use rustc::ty::{self, ClosureSubsts, Ty}; use rustc::ty::subst::Substs; use rustc::ty::fold::TypeFoldable; @@ -106,6 +106,8 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx self.super_rvalue(rvalue, location); } + + fn visit_user_assert_ty(&mut self, _ty: &Ty<'tcx>, _local: &Local, _location: Location) { } } impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { From 692a931887b23cf11ddf69191ea8d6d509a7bd10 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 15 Mar 2018 18:49:10 +0000 Subject: [PATCH 10/17] UserAssertTy can handle inference variables. This commit modifies the UserAssertTy statement to take a canonicalized type rather than a regular type so that we can handle the case where the user provided type contains a inference variable. --- src/librustc/ich/impls_mir.rs | 4 +- src/librustc/infer/canonical.rs | 29 ++++++++++---- src/librustc/mir/mod.rs | 7 ++-- src/librustc/mir/visit.rs | 13 +++---- src/librustc/ty/context.rs | 39 +++++++++++++++++++ src/librustc/ty/mod.rs | 12 ++++++ .../borrow_check/nll/constraint_generation.rs | 5 ++- src/librustc_mir/borrow_check/nll/renumber.rs | 4 +- .../borrow_check/nll/type_check/mod.rs | 8 ++-- src/librustc_mir/build/matches/mod.rs | 18 ++++++--- src/librustc_mir/hair/cx/block.rs | 2 +- src/librustc_mir/hair/mod.rs | 2 +- src/librustc_typeck/check/mod.rs | 13 ++++++- src/librustc_typeck/check/writeback.rs | 28 +++++++++++++ 14 files changed, 146 insertions(+), 38 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index ff73f135ce643..c73f171806e42 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -277,8 +277,8 @@ 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); + mir::StatementKind::UserAssertTy(ref c_ty, ref local) => { + c_ty.hash_stable(hcx, hasher); local.hash_stable(hcx, hasher); } mir::StatementKind::Nop => {} diff --git a/src/librustc/infer/canonical.rs b/src/librustc/infer/canonical.rs index 22526c7751d50..debddd708ea22 100644 --- a/src/librustc/infer/canonical.rs +++ b/src/librustc/infer/canonical.rs @@ -33,6 +33,7 @@ use infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TypeVariableOrigin}; use rustc_data_structures::indexed_vec::Idx; +use serialize::UseSpecializedDecodable; use std::fmt::Debug; use std::ops::Index; use syntax::codemap::Span; @@ -49,7 +50,7 @@ use rustc_data_structures::fx::FxHashMap; /// A "canonicalized" type `V` is one where all free inference /// variables have been rewriten to "canonical vars". These are /// numbered starting from 0 in order of first appearance. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] pub struct Canonical<'gcx, V> { pub variables: CanonicalVarInfos<'gcx>, pub value: V, @@ -57,6 +58,8 @@ pub struct Canonical<'gcx, V> { pub type CanonicalVarInfos<'gcx> = &'gcx Slice; +impl<'gcx> UseSpecializedDecodable for CanonicalVarInfos<'gcx> { } + /// A set of values corresponding to the canonical variables from some /// `Canonical`. You can give these values to /// `canonical_value.substitute` to substitute them into the canonical @@ -69,7 +72,7 @@ pub type CanonicalVarInfos<'gcx> = &'gcx Slice; /// You can also use `infcx.fresh_inference_vars_for_canonical_vars` /// to get back a `CanonicalVarValues` containing fresh inference /// variables. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] pub struct CanonicalVarValues<'tcx> { pub var_values: IndexVec>, } @@ -78,7 +81,7 @@ pub struct CanonicalVarValues<'tcx> { /// canonical value. This is sufficient information for code to create /// a copy of the canonical value in some other inference context, /// with fresh inference variables replacing the canonical values. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] pub struct CanonicalVarInfo { pub kind: CanonicalVarKind, } @@ -86,7 +89,7 @@ pub struct CanonicalVarInfo { /// Describes the "kind" of the canonical variable. This is a "kind" /// in the type-theory sense of the term -- i.e., a "meta" type system /// that analyzes type-like values. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] pub enum CanonicalVarKind { /// Some kind of type inference variable. Ty(CanonicalTyVarKind), @@ -100,7 +103,7 @@ pub enum CanonicalVarKind { /// 22.) can only be instantiated with integral/float types (e.g., /// usize or f32). In order to faithfully reproduce a type, we need to /// know what set of types a given type variable can be unified with. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] pub enum CanonicalTyVarKind { /// General type variable `?T` that can be unified with arbitrary types. General, @@ -855,11 +858,14 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'g } CloneTypeFoldableAndLiftImpls! { + ::infer::canonical::Certainty, + ::infer::canonical::CanonicalVarInfo, + ::infer::canonical::CanonicalVarKind, +} + +CloneTypeFoldableImpls! { for <'tcx> { - ::infer::canonical::Certainty, - ::infer::canonical::CanonicalVarInfo, ::infer::canonical::CanonicalVarInfos<'tcx>, - ::infer::canonical::CanonicalVarKind, } } @@ -870,6 +876,13 @@ BraceStructTypeFoldableImpl! { } where C: TypeFoldable<'tcx> } +BraceStructLiftImpl! { + impl<'a, 'tcx, T> Lift<'tcx> for Canonical<'a, T> { + type Lifted = Canonical<'tcx, T::Lifted>; + variables, value + } where T: Lift<'tcx> +} + impl<'tcx> CanonicalVarValues<'tcx> { fn iter<'a>(&'a self) -> impl Iterator> + 'a { self.var_values.iter().cloned() diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index c36e401e8d69b..9229724f0941d 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -27,7 +27,7 @@ use hir::def_id::DefId; use mir::visit::MirVisitable; use mir::interpret::{Value, PrimVal}; use ty::subst::{Subst, Substs}; -use ty::{self, AdtDef, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior}; +use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use ty::TypeAndMut; use util::ppaux; @@ -1260,7 +1260,7 @@ pub enum StatementKind<'tcx> { /// /// 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), + UserAssertTy(CanonicalTy<'tcx>, Local), /// No-op. Useful for deleting instructions without affecting statement indices. Nop, @@ -1333,7 +1333,8 @@ 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), + UserAssertTy(ref c_ty, ref local) => write!(fmt, "UserAssertTy({:?}, {:?})", + c_ty, local), Nop => write!(fmt, "nop"), } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index cc5d9692e7a60..a3fdb6f73abb0 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -10,7 +10,7 @@ use hir::def_id::DefId; use ty::subst::Substs; -use ty::{ClosureSubsts, Region, Ty, GeneratorInterior}; +use ty::{CanonicalTy, ClosureSubsts, Region, Ty, GeneratorInterior}; use mir::*; use syntax_pos::Span; @@ -145,10 +145,10 @@ macro_rules! make_mir_visitor { } fn visit_user_assert_ty(&mut self, - ty: & $($mutability)* Ty<'tcx>, + c_ty: & $($mutability)* CanonicalTy<'tcx>, local: & $($mutability)* Local, location: Location) { - self.super_user_assert_ty(ty, local, location); + self.super_user_assert_ty(c_ty, local, location); } fn visit_place(&mut self, @@ -383,9 +383,9 @@ macro_rules! make_mir_visitor { self.visit_operand(input, location); } } - StatementKind::UserAssertTy(ref $($mutability)* ty, + StatementKind::UserAssertTy(ref $($mutability)* c_ty, ref $($mutability)* local) => { - self.visit_user_assert_ty(ty, local, location); + self.visit_user_assert_ty(c_ty, local, location); } StatementKind::Nop => {} } @@ -631,10 +631,9 @@ macro_rules! make_mir_visitor { } fn super_user_assert_ty(&mut self, - ty: & $($mutability)* Ty<'tcx>, + _c_ty: & $($mutability)* CanonicalTy<'tcx>, local: & $($mutability)* Local, location: Location) { - self.visit_ty(ty, TyContext::Location(location)); self.visit_local(local, PlaceContext::Validate, location); } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index fd3465f59ebf2..573d277132296 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -48,6 +48,7 @@ use ty::layout::{LayoutDetails, TargetDataLayout}; use ty::maps; use ty::steal::Steal; use ty::BindingMode; +use ty::CanonicalTy; use util::nodemap::{NodeMap, DefIdSet, ItemLocalMap}; use util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::accumulate_vec::AccumulateVec; @@ -344,6 +345,9 @@ pub struct TypeckTables<'tcx> { /// method calls, including those of overloaded operators. type_dependent_defs: ItemLocalMap, + /// Stores the canonicalized types provided by the user. + user_provided_tys: ItemLocalMap>, + /// Stores the types for various nodes in the AST. Note that this table /// is not guaranteed to be populated until after typeck. See /// typeck::check::fn_ctxt for details. @@ -420,6 +424,7 @@ impl<'tcx> TypeckTables<'tcx> { TypeckTables { local_id_root, type_dependent_defs: ItemLocalMap(), + user_provided_tys: ItemLocalMap(), node_types: ItemLocalMap(), node_substs: ItemLocalMap(), adjustments: ItemLocalMap(), @@ -461,6 +466,20 @@ impl<'tcx> TypeckTables<'tcx> { } } + pub fn user_provided_tys(&self) -> LocalTableInContext> { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.user_provided_tys + } + } + + pub fn user_provided_tys_mut(&mut self) -> LocalTableInContextMut> { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.user_provided_tys + } + } + pub fn node_types(&self) -> LocalTableInContext> { LocalTableInContext { local_id_root: self.local_id_root, @@ -685,6 +704,7 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { let ty::TypeckTables { local_id_root, ref type_dependent_defs, + ref user_provided_tys, ref node_types, ref node_substs, ref adjustments, @@ -704,6 +724,7 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { type_dependent_defs.hash_stable(hcx, hasher); + user_provided_tys.hash_stable(hcx, hasher); node_types.hash_stable(hcx, hasher); node_substs.hash_stable(hcx, hasher); adjustments.hash_stable(hcx, hasher); @@ -1635,6 +1656,24 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice> { } } +impl<'a, 'tcx> Lift<'tcx> for &'a Slice { + type Lifted = &'tcx Slice; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + if self.len() == 0 { + return Some(Slice::empty()); + } + if tcx.interners.arena.in_arena(*self as *const _) { + return Some(unsafe { mem::transmute(*self) }); + } + // Also try in the global tcx if we're not that. + if !tcx.is_global() { + self.lift_to_tcx(tcx.global_tcx()) + } else { + None + } + } +} + pub mod tls { use super::{CtxtInterners, GlobalCtxt, TyCtxt}; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 95c5cd377d71f..68bc244971138 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -21,6 +21,7 @@ use hir::map::DefPathData; use hir::svh::Svh; use ich::Fingerprint; use ich::StableHashingContext; +use infer::canonical::{Canonical, Canonicalize}; use middle::const_val::ConstVal; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::privacy::AccessLevels; @@ -554,6 +555,17 @@ pub type Ty<'tcx> = &'tcx TyS<'tcx>; impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {} impl<'tcx> serialize::UseSpecializedDecodable for Ty<'tcx> {} +pub type CanonicalTy<'gcx> = Canonical<'gcx, Ty<'gcx>>; + +impl <'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for Ty<'tcx> { + type Canonicalized = CanonicalTy<'gcx>; + + fn intern(_gcx: TyCtxt<'_, 'gcx, 'gcx>, + value: Canonical<'gcx, Self::Lifted>) -> Self::Canonicalized { + value + } +} + /// A wrapper for slices with the additional invariant /// that the slice is interned and no other slice with /// the same contents can exist in the same context. diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index c06f77b2d8491..afaedecdf0abe 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -15,7 +15,7 @@ use rustc::mir::Place::Projection; use rustc::mir::{Local, PlaceProjection, ProjectionElem}; use rustc::mir::visit::TyContext; use rustc::infer::InferCtxt; -use rustc::ty::{self, ClosureSubsts, Ty}; +use rustc::ty::{self, CanonicalTy, ClosureSubsts}; use rustc::ty::subst::Substs; use rustc::ty::fold::TypeFoldable; @@ -107,7 +107,8 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx self.super_rvalue(rvalue, location); } - fn visit_user_assert_ty(&mut self, _ty: &Ty<'tcx>, _local: &Local, _location: Location) { } + fn visit_user_assert_ty(&mut self, _c_ty: &CanonicalTy<'tcx>, + _local: &Local, _location: Location) { } } impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index 38a14be8eb262..04c206b5c0c40 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -9,7 +9,7 @@ // except according to those terms. use rustc::ty::subst::Substs; -use rustc::ty::{self, ClosureSubsts, GeneratorInterior, Ty, TypeFoldable}; +use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorInterior, Ty, TypeFoldable}; use rustc::mir::{BasicBlock, Local, Location, Mir, Statement, StatementKind}; use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; @@ -118,7 +118,7 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { debug!("visit_closure_substs: substs={:?}", substs); } - fn visit_user_assert_ty(&mut self, _ty: &mut Ty<'tcx>, _local: &mut Local, + fn visit_user_assert_ty(&mut self, _c_ty: &mut CanonicalTy<'tcx>, _local: &mut Local, _location: Location) { // User-assert-ty statements represent types that the user added explicitly. // We don't want to erase the regions from these types: rather, we want to 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 2c06c93cd9d24..80a439b183058 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -761,12 +761,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); }; } - StatementKind::UserAssertTy(ref ty, ref local) => { + StatementKind::UserAssertTy(ref c_ty, ref local) => { let local_ty = mir.local_decls()[*local].ty; + let (ty, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars( + stmt.source_info.span, c_ty); debug!("check_stmt: user_assert_ty ty={:?} local_ty={:?}", ty, local_ty); - if let Err(terr) = - self.eq_types(ty, local_ty, location.at_self()) - { + if let Err(terr) = self.eq_types(ty, local_ty, location.at_self()) { span_mirbug!( self, stmt, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 4353eb5e4bd38..b9a6616fd076c 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -145,18 +145,24 @@ 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) { + pub fn user_assert_ty(&mut self, block: BasicBlock, hir_id: hir::HirId, + 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), - }); + + debug!("user_assert_ty: local_id={:?}", hir_id.local_id); + if let Some(c_ty) = self.hir.tables.user_provided_tys().get(hir_id) { + debug!("user_assert_ty: c_ty={:?}", c_ty); + self.cfg.push(block, Statement { + source_info, + kind: StatementKind::UserAssertTy(*c_ty, local_id), + }); + } } pub fn expr_into_pattern(&mut self, mut block: BasicBlock, - ty: Option>, + ty: Option, irrefutable_pat: Pattern<'tcx>, initializer: ExprRef<'tcx>) -> BlockAnd<()> { diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index f049733830378..14aa307f0ae1f 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -76,7 +76,7 @@ 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 ty = local.ty.clone().map(|ty| ty.hir_id); let pattern = cx.pattern_from_hir(&local.pat); result.push(StmtRef::Mirror(Box::new(Stmt { kind: StmtKind::Let { diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 138944189ff5a..fe82b8158f76d 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -97,7 +97,7 @@ pub enum StmtKind<'tcx> { pattern: Pattern<'tcx>, /// let pat: = init ... - ty: Option>, + ty: Option, /// let pat: ty = ... initializer: Option>, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 69879bbe85d6e..e2f6c965c18e9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -960,10 +960,19 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { // Add explicitly-declared locals. fn visit_local(&mut self, local: &'gcx hir::Local) { let o_ty = match local.ty { - Some(ref ty) => Some(self.fcx.to_ty(&ty)), - None => None + Some(ref ty) => { + let o_ty = self.fcx.to_ty(&ty); + + let (c_ty, _orig_values) = self.fcx.inh.infcx.canonicalize_query(&o_ty); + debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty); + self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty); + + Some(o_ty) + }, + None => None, }; self.assign(local.span, local.id, o_ty); + debug!("Local variable {:?} is assigned type {}", local.pat, self.fcx.ty_to_string( diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 862b15743c701..bbd04e0b19ae1 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -46,6 +46,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { wbcx.visit_anon_types(); wbcx.visit_cast_types(); wbcx.visit_free_region_map(); + wbcx.visit_user_provided_tys(); let used_trait_imports = mem::replace( &mut self.tables.borrow_mut().used_trait_imports, @@ -341,6 +342,33 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { self.tables.free_region_map = free_region_map; } + fn visit_user_provided_tys(&mut self) { + let fcx_tables = self.fcx.tables.borrow(); + debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); + let common_local_id_root = fcx_tables.local_id_root.unwrap(); + + for (&local_id, c_ty) in fcx_tables.user_provided_tys().iter() { + let hir_id = hir::HirId { + owner: common_local_id_root.index, + local_id, + }; + + let c_ty = if let Some(c_ty) = self.tcx().lift_to_global(c_ty) { + c_ty + } else { + span_bug!( + hir_id.to_span(&self.fcx.tcx), + "writeback: `{:?}` missing from the global type context", + c_ty + ); + }; + + self.tables + .user_provided_tys_mut() + .insert(hir_id, c_ty.clone()); + } + } + fn visit_anon_types(&mut self) { let gcx = self.tcx().global_tcx(); for (&def_id, anon_defn) in self.fcx.anon_types.borrow().iter() { From e1648bde17542a3fb13496b6b3f15a23d31062ad Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 20 Mar 2018 01:59:52 +0000 Subject: [PATCH 11/17] Switched from canonicalize_query to canonicalize_response --- src/librustc_typeck/check/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e2f6c965c18e9..10dab6afd004c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -963,7 +963,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { Some(ref ty) => { let o_ty = self.fcx.to_ty(&ty); - let (c_ty, _orig_values) = self.fcx.inh.infcx.canonicalize_query(&o_ty); + let (c_ty, _orig_values) = self.fcx.inh.infcx.canonicalize_response(&o_ty); debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty); self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty); From fc5c4daa88d2588a1eedc8caeb8ab61fc4622e8f Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 21 Mar 2018 19:47:08 +0000 Subject: [PATCH 12/17] Temporarily only adding UserAssertTy on binding patterns. --- src/librustc_mir/build/block.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 02d2522b6ba91..b2ab23024a895 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -125,11 +125,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }) })); } else { - this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| { - this.storage_live_binding(block, node, span); + // FIXME: We currently only insert `UserAssertTy` statements for patterns + // that are bindings, this is as we do not want to deconstruct the type + // being assertion to match the pattern. + if let PatternKind::Binding { var, .. } = *pattern.kind { if let Some(ty) = ty { - this.user_assert_ty(block, ty, node, span); + this.user_assert_ty(block, ty, var, span); } + } + + this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| { + this.storage_live_binding(block, node, span); this.schedule_drop_for_binding(node, span); }) } From 04aeef8d452d9dc2189bc75c3f74fd9752a3e9af Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Mar 2018 14:50:42 -0400 Subject: [PATCH 13/17] Debug logs for replace_bound_regions_with_nll_infer_vars --- src/librustc_mir/borrow_check/nll/universal_regions.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index afd338581392d..39dc29ba18b64 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -777,6 +777,11 @@ impl<'cx, 'gcx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'gcx, 'tcx> { where T: TypeFoldable<'tcx>, { + debug!( + "replace_bound_regions_with_nll_infer_vars(value={:?}, all_outlive_scope={:?})", + value, + all_outlive_scope, + ); let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| { let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion { scope: all_outlive_scope, @@ -784,6 +789,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'gcx, 'tcx> { })); let region_vid = self.next_nll_region_var(origin); indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid()); + debug!("liberated_region={:?} => {:?}", liberated_region, region_vid); region_vid }); value From 447ae7612aacb356dd3f1dd018aaa350c0493a2e Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 22 Mar 2018 22:48:39 +0000 Subject: [PATCH 14/17] Added flag to disable user type assertion. --- src/librustc/session/config.rs | 2 ++ src/librustc_mir/build/matches/mod.rs | 2 ++ src/test/run-pass/generator/yield-subtype.rs | 1 + 3 files changed, 5 insertions(+) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 0d91074e946bd..c47a351e9d39d 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1251,6 +1251,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "choose which RELRO level to use"), nll: bool = (false, parse_bool, [UNTRACKED], "run the non-lexical lifetimes MIR pass"), + disable_nll_user_type_assert: bool = (false, parse_bool, [UNTRACKED], + "disable user provided type assertion in NLL"), trans_time_graph: bool = (false, parse_bool, [UNTRACKED], "generate a graphical HTML report of time spent in trans and LLVM"), thinlto: Option = (None, parse_opt_bool, [TRACKED], diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index b9a6616fd076c..7eb52a3cdee93 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -147,6 +147,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn user_assert_ty(&mut self, block: BasicBlock, hir_id: hir::HirId, var: NodeId, span: Span) { + if self.hir.tcx().sess.opts.debugging_opts.disable_nll_user_type_assert { return; } + let local_id = self.var_indices[&var]; let source_info = self.source_info(span); diff --git a/src/test/run-pass/generator/yield-subtype.rs b/src/test/run-pass/generator/yield-subtype.rs index 7e8a0d1e2b925..c41341690441f 100644 --- a/src/test/run-pass/generator/yield-subtype.rs +++ b/src/test/run-pass/generator/yield-subtype.rs @@ -9,6 +9,7 @@ // except according to those terms. // revisions:lexical nll +//[nll]compile-flags: -Z disable-nll-user-type-assert #![cfg_attr(nll, feature(nll))] #![feature(generators)] From 03481f19eae7cf1f8475c63a0449860e3100d491 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 23 Mar 2018 10:07:18 +0000 Subject: [PATCH 15/17] Updated MIR with UserAssertTy in mir-opt tests. --- src/test/mir-opt/basic_assignment.rs | 3 +++ src/test/mir-opt/nll/reborrow-basic.rs | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs index 321c05c490356..3c236ddcf0409 100644 --- a/src/test/mir-opt/basic_assignment.rs +++ b/src/test/mir-opt/basic_assignment.rs @@ -23,6 +23,8 @@ // tend to be absent in simple code, so subtle breakage in them can // leave a quite hard-to-find trail of destruction. +// ignore-tidy-linelength + fn main() { let nodrop_x = false; let nodrop_y; @@ -46,6 +48,7 @@ fn main() { // _2 = move _3; // StorageDead(_3); // StorageLive(_4); +// UserAssertTy(Canonical { variables: Slice([]), value: std::option::Option> }, _4); // _4 = std::option::Option>::None; // StorageLive(_5); // StorageLive(_6); diff --git a/src/test/mir-opt/nll/reborrow-basic.rs b/src/test/mir-opt/nll/reborrow-basic.rs index f69c51c3562dc..92e42a73bbb6a 100644 --- a/src/test/mir-opt/nll/reborrow-basic.rs +++ b/src/test/mir-opt/nll/reborrow-basic.rs @@ -28,9 +28,9 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#7r | {bb0[6..=14]} +// | '_#7r | {bb0[4], bb0[8..=17]} // ... -// | '_#9r | {bb0[11..=14]} +// | '_#9r | {bb0[10], bb0[14..=17]} // ... // let _2: &'_#7r mut i32; // ... From 3a0162b7cb7f23236a23ef7747cc0ea5374bbb33 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 23 Mar 2018 14:04:08 +0000 Subject: [PATCH 16/17] Fixed issues with incremental tests. --- src/librustc/ty/codec.rs | 23 +++++++++++++++++++ .../incremental/hashes/let_expressions.rs | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index f98bc95356098..4e15f0711a5aa 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -17,6 +17,7 @@ // persisting to incr. comp. caches. use hir::def_id::{DefId, CrateNum}; +use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; use rustc_data_structures::fx::FxHashMap; use rustc_serialize::{Decodable, Decoder, Encoder, Encodable, opaque}; use std::hash::Hash; @@ -239,6 +240,19 @@ pub fn decode_existential_predicate_slice<'a, 'tcx, D>(decoder: &mut D) .mk_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?) } +#[inline] +pub fn decode_canonical_var_infos<'a, 'tcx, D>(decoder: &mut D) + -> Result, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + let len = decoder.read_usize()?; + let interned: Result, _> = (0..len).map(|_| Decodable::decode(decoder)) + .collect(); + Ok(decoder.tcx() + .intern_canonical_var_infos(interned?.as_slice())) +} + #[inline] pub fn decode_const<'a, 'tcx, D>(decoder: &mut D) -> Result<&'tcx ty::Const<'tcx>, D::Error> @@ -262,6 +276,7 @@ macro_rules! implement_ty_decoder { ($DecoderName:ident <$($typaram:tt),*>) => { mod __ty_decoder_impl { use super::$DecoderName; + use $crate::infer::canonical::CanonicalVarInfos; use $crate::ty; use $crate::ty::codec::*; use $crate::ty::subst::Substs; @@ -364,6 +379,14 @@ macro_rules! implement_ty_decoder { } } + impl<$($typaram),*> SpecializedDecoder> + for $DecoderName<$($typaram),*> { + fn specialized_decode(&mut self) + -> Result, Self::Error> { + decode_canonical_var_infos(self) + } + } + impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::ty::Const<'tcx>> for $DecoderName<$($typaram),*> { fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> { diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs index 851b13c705516..2f49500c3910b 100644 --- a/src/test/incremental/hashes/let_expressions.rs +++ b/src/test/incremental/hashes/let_expressions.rs @@ -49,7 +49,7 @@ pub fn add_type() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,TypeckTables")] + except="HirBody,TypeckTables,MirValidated")] #[rustc_clean(cfg="cfail3")] pub fn add_type() { let _x: u32 = 2u32; From 4161ae747740e9d61426d26da3e9f3f74fbabaca Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 23 Mar 2018 17:48:03 +0000 Subject: [PATCH 17/17] Improved comments for UserAssertTy statement. --- src/librustc/mir/mod.rs | 8 ++++++++ src/librustc/ty/context.rs | 3 ++- src/librustc_mir/build/block.rs | 6 +++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9229724f0941d..9ed4e6a8e00ae 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1260,6 +1260,14 @@ pub enum StatementKind<'tcx> { /// /// Here we would insert a `UserAssertTy<(T, U)>(y)` instruction to check that the type of `y` /// is the right thing. + /// + /// `CanonicalTy` is used to capture "inference variables" from the user's types. For example: + /// + /// let x: Vec<_> = ...; + /// let y: &u32 = ...; + /// + /// would result in `Vec` and `&'?0 u32` respectively (where `?0` is a canonicalized + /// variable). UserAssertTy(CanonicalTy<'tcx>, Local), /// No-op. Useful for deleting instructions without affecting statement indices. diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 573d277132296..55e695bb18c83 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -345,7 +345,8 @@ pub struct TypeckTables<'tcx> { /// method calls, including those of overloaded operators. type_dependent_defs: ItemLocalMap, - /// Stores the canonicalized types provided by the user. + /// Stores the canonicalized types provided by the user. See also `UserAssertTy` statement in + /// MIR. user_provided_tys: ItemLocalMap>, /// Stores the types for various nodes in the AST. Note that this table diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index b2ab23024a895..94702927d2600 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -125,9 +125,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }) })); } else { - // FIXME: We currently only insert `UserAssertTy` statements for patterns - // that are bindings, this is as we do not want to deconstruct the type - // being assertion to match the pattern. + // FIXME(#47184): We currently only insert `UserAssertTy` statements for + // patterns that are bindings, this is as we do not want to deconstruct + // the type being assertion to match the pattern. if let PatternKind::Binding { var, .. } = *pattern.kind { if let Some(ty) = ty { this.user_assert_ty(block, ty, var, span);