From 21205f4f9e61469b55a853cf6be478cd6bc7a073 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 30 Sep 2015 16:17:37 +1300 Subject: [PATCH] Cache ids between lowering runs So that lowering is reproducible --- src/librustc/session/mod.rs | 4 ++ src/librustc_driver/driver.rs | 9 ++-- src/librustc_driver/pretty.rs | 3 +- src/librustc_front/lowering.rs | 83 ++++++++++++++++++++++++----- src/librustc_trans/save/dump_csv.rs | 2 +- src/librustc_trans/save/mod.rs | 8 +-- src/libsyntax/ast.rs | 1 + 7 files changed, 86 insertions(+), 24 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 1eb90580b48..0a1df25f115 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -318,6 +318,10 @@ impl NodeIdAssigner for Session { fn next_node_id(&self) -> NodeId { self.reserve_node_ids(1) } + + fn peek_node_id(&self) -> NodeId { + self.next_node_id.get().checked_add(1).unwrap() + } } fn split_msg_into_multilines(msg: &str) -> Option { diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 6f989811ed2..3db484ef930 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -112,8 +112,7 @@ pub fn compile_input(sess: Session, let expanded_crate = assign_node_ids(&sess, expanded_crate); // Lower ast -> hir. - let foo = &42; - let lcx = LoweringContext::new(foo, &sess, &expanded_crate); + let lcx = LoweringContext::new(&sess, &expanded_crate); let mut hir_forest = time(sess.time_passes(), "lowering ast -> hir", || hir_map::Forest::new(lower_crate(&lcx, &expanded_crate))); @@ -282,7 +281,7 @@ pub struct CompileState<'a, 'ast: 'a, 'tcx: 'a> { pub ast_map: Option<&'a hir_map::Map<'ast>>, pub analysis: Option<&'a ty::CrateAnalysis>, pub tcx: Option<&'a ty::ctxt<'tcx>>, - pub lcx: Option<&'a LoweringContext<'a, 'tcx>>, + pub lcx: Option<&'a LoweringContext<'a>>, pub trans: Option<&'a trans::CrateTranslation>, } @@ -340,7 +339,7 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { krate: &'a ast::Crate, hir_crate: &'a hir::Crate, crate_name: &'a str, - lcx: &'a LoweringContext<'a, 'tcx>) + lcx: &'a LoweringContext<'a>) -> CompileState<'a, 'ast, 'tcx> { CompileState { crate_name: Some(crate_name), @@ -359,7 +358,7 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { hir_crate: &'a hir::Crate, analysis: &'a ty::CrateAnalysis, tcx: &'a ty::ctxt<'tcx>, - lcx: &'a LoweringContext<'a, 'tcx>) + lcx: &'a LoweringContext<'a>) -> CompileState<'a, 'ast, 'tcx> { CompileState { analysis: Some(analysis), diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 09a1d6f6851..73961c8d757 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -670,8 +670,7 @@ pub fn pretty_print_input(sess: Session, // There is some twisted, god-forsaken tangle of lifetimes here which makes // the ordering of stuff super-finicky. let mut hir_forest; - let foo = &42; - let lcx = LoweringContext::new(foo, &sess, &krate); + let lcx = LoweringContext::new(&sess, &krate); let arenas = ty::CtxtArenas::new(); let ast_map = if compute_ast_map { hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate)); diff --git a/src/librustc_front/lowering.rs b/src/librustc_front/lowering.rs index 2b63e0615ee..27ae39acbf4 100644 --- a/src/librustc_front/lowering.rs +++ b/src/librustc_front/lowering.rs @@ -12,6 +12,8 @@ use hir; +use std::collections::HashMap; + use syntax::ast::*; use syntax::ptr::P; use syntax::codemap::{respan, Spanned, Span}; @@ -19,15 +21,17 @@ use syntax::owned_slice::OwnedSlice; use syntax::parse::token::{self, str_to_ident}; use syntax::std_inject; -pub struct LoweringContext<'a, 'hir> { - // TODO - foo: &'hir i32, - id_assigner: &'a NodeIdAssigner, +use std::cell::{Cell, RefCell}; + +pub struct LoweringContext<'a> { crate_root: Option<&'static str>, + id_cache: RefCell>, + id_assigner: &'a NodeIdAssigner, + cached_id: Cell, } -impl<'a, 'hir> LoweringContext<'a, 'hir> { - pub fn new(foo: &'hir i32, id_assigner: &'a NodeIdAssigner, c: &Crate) -> LoweringContext<'a, 'hir> { +impl<'a, 'hir> LoweringContext<'a> { + pub fn new(id_assigner: &'a NodeIdAssigner, c: &Crate) -> LoweringContext<'a> { let crate_root = if std_inject::no_core(c) { None } else if std_inject::no_std(c) { @@ -37,14 +41,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; LoweringContext { - foo: foo, - id_assigner: id_assigner, crate_root: crate_root, + id_cache: RefCell::new(HashMap::new()), + id_assigner: id_assigner, + cached_id: Cell::new(0), } } fn next_id(&self) -> NodeId { - self.id_assigner.next_node_id() + let cached = self.cached_id.get(); + if cached == 0 { + return self.id_assigner.next_node_id() + } + + self.cached_id.set(cached + 1); + cached } } @@ -745,6 +756,49 @@ pub fn lower_pat(_lctx: &LoweringContext, p: &Pat) -> P { }) } +// RAII utility for setting and unsetting the cached id. +struct CachedIdSetter<'a> { + reset: bool, + lctx: &'a LoweringContext<'a>, +} + +impl<'a> CachedIdSetter<'a> { + fn new(lctx: &'a LoweringContext, expr_id: NodeId) -> CachedIdSetter<'a> { + let id_cache: &mut HashMap<_, _> = &mut lctx.id_cache.borrow_mut(); + + if id_cache.contains_key(&expr_id) { + let cached_id = lctx.cached_id.get(); + if cached_id == 0 { + // We're entering a node where we need to track ids, but are not + // yet tracking. + lctx.cached_id.set(id_cache[&expr_id]); + } else { + // We're already tracking - check that the tracked id is the same + // as the expected id. + assert!(cached_id == id_cache[&expr_id], "id mismatch"); + } + } else { + id_cache.insert(expr_id, lctx.id_assigner.peek_node_id()); + } + + CachedIdSetter { + // Only reset the id if it was previously 0, i.e., was not cached. + // If it was cached, we are in a nested node, but our id count will + // still count towards the parent's count. + reset: lctx.cached_id.get() == 0, + lctx: lctx, + } + } +} + +impl<'a> Drop for CachedIdSetter<'a> { + fn drop(&mut self) { + if self.reset { + self.lctx.cached_id.set(0); + } + } +} + pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { P(hir::Expr { id: e.id, @@ -780,9 +834,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); // InPlace::finalize(place) // }) - - // TODO - println!("{}", lctx.foo); + let _old_cached = CachedIdSetter::new(lctx, e.id); let placer_expr = lower_expr(lctx, placer); let value_expr = lower_expr(lctx, value_expr); @@ -903,6 +955,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // might be `if let`. ExprIf(ref cond, ref blk, ref else_opt) => { let else_opt = else_opt.as_ref().map(|els| match els.node { + let _old_cached = CachedIdSetter::new(lctx, e.id); ExprIfLet(..) => { // wrap the if-let expr in a block let span = els.span; @@ -1019,6 +1072,8 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // [_ if => ,] // _ => [ | ()] // } + + let _old_cached = CachedIdSetter::new(lctx, e.id); // ` => ` let pat_arm = { @@ -1098,6 +1153,8 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // } // } + let _old_cached = CachedIdSetter::new(lctx, e.id); + // ` => ` let pat_arm = { let body_expr = expr_block(lctx, lower_block(lctx, body)); @@ -1141,6 +1198,8 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // result // } + let _old_cached = CachedIdSetter::new(lctx, e.id); + // expand let head = lower_expr(lctx, head); diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index 256774756b8..09825f1f919 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -76,7 +76,7 @@ pub struct DumpCsvVisitor<'l, 'tcx: 'l> { impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { pub fn new(tcx: &'l ty::ctxt<'tcx>, - lcx: &'l LoweringContext<'l, 'tcx>, + lcx: &'l LoweringContext<'l>, analysis: &'l ty::CrateAnalysis, output_file: Box) -> DumpCsvVisitor<'l, 'tcx> { diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 5e26322ebda..72f665f63bf 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -38,7 +38,7 @@ mod dump_csv; pub struct SaveContext<'l, 'tcx: 'l> { tcx: &'l ty::ctxt<'tcx>, - lcx: &'l lowering::LoweringContext<'l, 'tcx>, + lcx: &'l lowering::LoweringContext<'l>, span_utils: SpanUtils<'l>, } @@ -178,14 +178,14 @@ pub struct MethodCallData { impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn new(tcx: &'l ty::ctxt<'tcx>, - lcx: &'l lowering::LoweringContext<'l, 'tcx>) + lcx: &'l lowering::LoweringContext<'l>) -> SaveContext<'l, 'tcx> { let span_utils = SpanUtils::new(&tcx.sess); SaveContext::from_span_utils(tcx, lcx, span_utils) } pub fn from_span_utils(tcx: &'l ty::ctxt<'tcx>, - lcx: &'l lowering::LoweringContext<'l, 'tcx>, + lcx: &'l lowering::LoweringContext<'l>, span_utils: SpanUtils<'l>) -> SaveContext<'l, 'tcx> { SaveContext { @@ -711,7 +711,7 @@ impl<'v> Visitor<'v> for PathCollector { } pub fn process_crate<'l, 'tcx>(tcx: &'l ty::ctxt<'tcx>, - lcx: &'l lowering::LoweringContext<'l, 'tcx>, + lcx: &'l lowering::LoweringContext<'l>, krate: &ast::Crate, analysis: &ty::CrateAnalysis, odir: Option<&Path>) { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index bf43b87b267..02cd648b6d8 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -377,6 +377,7 @@ pub const DUMMY_NODE_ID: NodeId = !0; pub trait NodeIdAssigner { fn next_node_id(&self) -> NodeId; + fn peek_node_id(&self) -> NodeId; } /// The AST represents all type param bounds as types.