diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 0100a82a9d5..2306a25592b 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -408,7 +408,6 @@ impl CFGBuilder { self.straightline(expr, pred, [e]) } - ast::ExprLogLevel | ast::ExprMac(..) | ast::ExprInlineAsm(..) | ast::ExprFnBlock(..) | diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 57b5be4e960..683ef11aff1 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -613,7 +613,6 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> { self.walk_exprs([l, r], in_out, loop_scopes); } - ast::ExprLogLevel | ast::ExprLit(..) | ast::ExprPath(..) => {} diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index fa435378ab7..38cbde70ad1 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -541,7 +541,7 @@ fn visit_expr(v: &mut LivenessVisitor, expr: &Expr, this: @IrMaps) { // otherwise, live nodes are not required: ExprIndex(..) | ExprField(..) | ExprVstore(..) | ExprVec(..) | - ExprCall(..) | ExprMethodCall(..) | ExprTup(..) | ExprLogLevel | + ExprCall(..) | ExprMethodCall(..) | ExprTup(..) | ExprBinary(..) | ExprAddrOf(..) | ExprCast(..) | ExprUnary(..) | ExprBreak(_) | ExprAgain(_) | ExprLit(_) | ExprRet(..) | ExprBlock(..) | @@ -1271,7 +1271,6 @@ impl Liveness { }) } - ExprLogLevel | ExprLit(..) => { succ } @@ -1521,7 +1520,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { // no correctness conditions related to liveness ExprCall(..) | ExprMethodCall(..) | ExprIf(..) | ExprMatch(..) | ExprWhile(..) | ExprLoop(..) | ExprIndex(..) | ExprField(..) | - ExprVstore(..) | ExprVec(..) | ExprTup(..) | ExprLogLevel | + ExprVstore(..) | ExprVec(..) | ExprTup(..) | ExprBinary(..) | ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) | ExprAgain(..) | ExprLit(_) | ExprBlock(..) | diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index c07cd2570a3..127f835d5f6 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -469,7 +469,7 @@ impl MemCategorizationContext { ast::ExprUnary(..) | ast::ExprMethodCall(..) | ast::ExprCast(..) | ast::ExprVstore(..) | ast::ExprVec(..) | ast::ExprTup(..) | ast::ExprIf(..) | - ast::ExprLogLevel | ast::ExprBinary(..) | ast::ExprWhile(..) | + ast::ExprBinary(..) | ast::ExprWhile(..) | ast::ExprBlock(..) | ast::ExprLoop(..) | ast::ExprMatch(..) | ast::ExprLit(..) | ast::ExprBreak(..) | ast::ExprMac(..) | ast::ExprAgain(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) | diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index b52ec7be631..22b3fb8ad6e 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -503,7 +503,6 @@ impl VisitContext { self.use_expr(base, Read); } - ExprLogLevel | ExprInlineAsm(..) | ExprBreak(..) | ExprAgain(..) | diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index c2f5d0806a7..a2ee57d6df1 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -32,7 +32,7 @@ use driver::session::{Session, NoDebugInfo, FullDebugInfo}; use driver::driver::OutputFilenames; use driver::driver::{CrateAnalysis, CrateTranslation}; use lib::llvm::{ModuleRef, ValueRef, BasicBlockRef}; -use lib::llvm::{llvm, True, Vector}; +use lib::llvm::{llvm, Vector}; use lib; use metadata::common::LinkMeta; use metadata::{csearch, encoder}; @@ -2404,70 +2404,6 @@ pub fn trap(bcx: &Block) { } } -pub fn decl_gc_metadata(ccx: &CrateContext, llmod_id: &str) { - if !ccx.sess.opts.gc || !ccx.uses_gc { - return; - } - - let gc_metadata_name = ~"_gc_module_metadata_" + llmod_id; - let gc_metadata = gc_metadata_name.with_c_str(|buf| { - unsafe { - llvm::LLVMAddGlobal(ccx.llmod, Type::i32().to_ref(), buf) - } - }); - unsafe { - llvm::LLVMSetGlobalConstant(gc_metadata, True); - lib::llvm::SetLinkage(gc_metadata, lib::llvm::ExternalLinkage); - - let mut module_data = ccx.module_data.borrow_mut(); - module_data.get().insert(~"_gc_module_metadata", gc_metadata); - } -} - -pub fn create_module_map(ccx: &CrateContext) -> (ValueRef, uint) { - let str_slice_type = Type::struct_([Type::i8p(), ccx.int_type], false); - let elttype = Type::struct_([str_slice_type, ccx.int_type], false); - let maptype = { - let module_data = ccx.module_data.borrow(); - Type::array(&elttype, module_data.get().len() as u64) - }; - let map = "_rust_mod_map".with_c_str(|buf| { - unsafe { - llvm::LLVMAddGlobal(ccx.llmod, maptype.to_ref(), buf) - } - }); - lib::llvm::SetLinkage(map, lib::llvm::InternalLinkage); - let mut elts: Vec = Vec::new(); - - // This is not ideal, but the borrow checker doesn't - // like the multiple borrows. At least, it doesn't - // like them on the current snapshot. (2013-06-14) - let keys = { - let mut keys = Vec::new(); - let module_data = ccx.module_data.borrow(); - for (k, _) in module_data.get().iter() { - keys.push(k.clone()); - } - keys - }; - - for key in keys.iter() { - let llstrval = C_str_slice(ccx, token::intern_and_get_ident(*key)); - let module_data = ccx.module_data.borrow(); - let val = *module_data.get().find_equiv(key).unwrap(); - let v_ptr = p2i(ccx, val); - let elt = C_struct([ - llstrval, - v_ptr - ], false); - elts.push(elt); - } - unsafe { - llvm::LLVMSetInitializer(map, C_array(elttype, elts.as_slice())); - } - return (map, keys.len()) -} - pub fn symname(name: &str, hash: &str, vers: &str) -> ~str { let path = [PathName(token::intern(name))]; link::exported_name(ast_map::Values(path.iter()).chain(None), hash, vers) @@ -2489,11 +2425,8 @@ pub fn decl_crate_map(sess: session::Session, mapmeta: LinkMeta, mapmeta.crateid.version_or_default()) }; - let slicetype = Type::struct_([int_type, int_type], false); let maptype = Type::struct_([ Type::i32(), // version - slicetype, // child modules - slicetype, // sub crate-maps int_type.ptr_to(), // event loop factory ], false); let map = sym_name.with_c_str(|buf| { @@ -2513,22 +2446,6 @@ pub fn decl_crate_map(sess: session::Session, mapmeta: LinkMeta, } pub fn fill_crate_map(ccx: @CrateContext, map: ValueRef) { - let mut subcrates: Vec = Vec::new(); - let mut i = 1; - let cstore = ccx.sess.cstore; - while cstore.have_crate_data(i) { - let cdata = cstore.get_crate_data(i); - let nm = symname(format!("_rust_crate_map_{}", cdata.name), - cstore.get_crate_hash(i).as_str(), - cstore.get_crate_id(i).version_or_default()); - let cr = nm.with_c_str(|buf| { - unsafe { - llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf) - } - }); - subcrates.push(p2i(ccx, cr)); - i += 1; - } let event_loop_factory = match ccx.tcx.lang_items.event_loop_factory() { Some(did) => unsafe { if is_local(did) { @@ -2545,26 +2462,8 @@ pub fn fill_crate_map(ccx: @CrateContext, map: ValueRef) { None => C_null(ccx.int_type.ptr_to()) }; unsafe { - let maptype = Type::array(&ccx.int_type, subcrates.len() as u64); - let vec_elements = "_crate_map_child_vectors".with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod, maptype.to_ref(), buf) - }); - lib::llvm::SetLinkage(vec_elements, lib::llvm::InternalLinkage); - - llvm::LLVMSetInitializer(vec_elements, - C_array(ccx.int_type, subcrates.as_slice())); - let (mod_map, mod_count) = create_module_map(ccx); - llvm::LLVMSetInitializer(map, C_struct( [C_i32(2), - C_struct([ - p2i(ccx, mod_map), - C_uint(ccx, mod_count) - ], false), - C_struct([ - p2i(ccx, vec_elements), - C_uint(ccx, subcrates.len()) - ], false), event_loop_factory, ], false)); } @@ -2667,7 +2566,6 @@ pub fn trans_crate(sess: session::Session, trans_mod(ccx, &krate.module); } - decl_gc_metadata(ccx, llmod_id); fill_crate_map(ccx, ccx.crate_map); // win32: wart with exporting crate_map symbol diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 517bef52a99..80dcfc90287 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -95,7 +95,6 @@ pub struct CrateContext { // Cache of closure wrappers for bare fn's. closure_bare_wrapper_cache: RefCell>, - module_data: RefCell>, lltypes: RefCell>, llsizingtypes: RefCell>, adt_reprs: RefCell>, @@ -207,7 +206,6 @@ impl CrateContext { extern_const_values: RefCell::new(DefIdMap::new()), impl_method_cache: RefCell::new(HashMap::new()), closure_bare_wrapper_cache: RefCell::new(HashMap::new()), - module_data: RefCell::new(HashMap::new()), lltypes: RefCell::new(HashMap::new()), llsizingtypes: RefCell::new(HashMap::new()), adt_reprs: RefCell::new(HashMap::new()), diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 6ade20d2913..dd6a3e61b69 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -2539,7 +2539,6 @@ fn populate_scope_map(cx: &CrateContext, scope_map.insert(exp.id, scope_stack.last().unwrap().scope_metadata); match exp.node { - ast::ExprLogLevel | ast::ExprLit(_) | ast::ExprBreak(_) | ast::ExprAgain(_) | diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index d143d674305..bf2d192d0de 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -34,8 +34,7 @@ #[allow(non_camel_case_types)]; use back::abi; -use back::link; -use lib::llvm::{ValueRef, llvm, SetLinkage, False}; +use lib::llvm::{ValueRef, llvm}; use lib; use metadata::csearch; use middle::trans::_match; @@ -74,9 +73,7 @@ use middle::trans::type_::Type; use std::vec; use std::vec_ng::Vec; use syntax::ast; -use syntax::ast_map; use syntax::codemap; -use syntax::parse::token; use syntax::print::pprust::{expr_to_str}; // Destinations @@ -455,9 +452,6 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>, // Datum output mode means this is a scalar cast: trans_imm_cast(bcx, val, expr.id) } - ast::ExprLogLevel => { - trans_log_level(bcx) - } _ => { bcx.tcx().sess.span_bug( expr.span, @@ -1671,64 +1665,6 @@ fn trans_assign_op<'a>( return result_datum.store_to(bcx, dst_datum.val); } -fn trans_log_level<'a>(bcx: &'a Block<'a>) -> DatumBlock<'a, Expr> { - let _icx = push_ctxt("trans_log_level"); - let ccx = bcx.ccx(); - - let (modpath, modname) = { - let srccrate = { - let external_srcs = ccx.external_srcs.borrow(); - match external_srcs.get().find(&bcx.fcx.id) { - Some(&src) => { - ccx.sess.cstore.get_crate_data(src.krate).name.clone() - } - None => ccx.link_meta.crateid.name.to_str(), - } - }; - bcx.tcx().map.with_path(bcx.fcx.id, |path| { - let first = ast_map::PathMod(token::intern(srccrate)); - let mut path = Some(first).move_iter().chain(path).filter(|e| { - match *e { - ast_map::PathMod(_) => true, - _ => false - } - }); - let modpath: Vec = path.collect(); - let modname = ast_map::path_to_str(ast_map::Values(modpath.iter())); - (modpath, modname) - }) - }; - - let module_data_exists; - { - let module_data = ccx.module_data.borrow(); - module_data_exists = module_data.get().contains_key(&modname); - } - - let global = if module_data_exists { - let mut module_data = ccx.module_data.borrow_mut(); - module_data.get().get_copy(&modname) - } else { - let s = link::mangle_internal_name_by_path_and_seq( - ast_map::Values(modpath.iter()).chain(None), "loglevel"); - let global; - unsafe { - global = s.with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod, Type::i32().to_ref(), buf) - }); - llvm::LLVMSetGlobalConstant(global, False); - llvm::LLVMSetInitializer(global, C_null(Type::i32())); - lib::llvm::SetLinkage(global, lib::llvm::InternalLinkage); - } - { - let mut module_data = ccx.module_data.borrow_mut(); - module_data.get().insert(modname, global); - global - } - }; - - immediate_rvalue_bcx(bcx, Load(bcx, global), ty::mk_u32()).to_expr_datumblock() -} fn auto_ref<'a>(bcx: &'a Block<'a>, datum: Datum, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c0ad18d9520..e1dddda01f7 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3391,7 +3391,6 @@ pub fn expr_kind(tcx: ctxt, ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop"), - ast::ExprLogLevel | ast::ExprLit(_) | // Note: LitStr is carved out above ast::ExprUnary(..) | ast::ExprAddrOf(..) | diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 51efcb7d1c3..b3f7adc89e8 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -2848,9 +2848,6 @@ fn check_expr_with_unifier(fcx: @FnCtxt, } fcx.write_bot(id); } - ast::ExprLogLevel => { - fcx.write_ty(id, ty::mk_u32()) - } ast::ExprParen(a) => { check_expr_with_opt_hint_and_lvalue_pref(fcx, a, expected, lvalue_pref); fcx.write_ty(id, fcx.expr_ty(a)); diff --git a/src/libstd/rt/crate_map.rs b/src/libstd/rt/crate_map.rs index ff54a80ce99..c6d5a80208b 100644 --- a/src/libstd/rt/crate_map.rs +++ b/src/libstd/rt/crate_map.rs @@ -9,13 +9,14 @@ // except according to those terms. use cast; -use cmp::TotalOrd; -use container::MutableSet; -use iter::Iterator; use option::{Some, None, Option}; use ptr::RawPtr; use rt::rtio::EventLoop; -use vec::{ImmutableVector, OwnedVector}; + +#[cfg(stage0)] use cmp::TotalOrd; +#[cfg(stage0)] use container::MutableSet; +#[cfg(stage0)] use iter::Iterator; +#[cfg(stage0)] use vec::{ImmutableVector, OwnedVector}; // Need to tell the linker on OS X to not barf on undefined symbols // and instead look them up at runtime, which we need to resolve @@ -24,17 +25,24 @@ use vec::{ImmutableVector, OwnedVector}; #[link_args = "-Wl,-U,__rust_crate_map_toplevel"] extern {} +#[cfg(stage0)] pub struct ModEntry<'a> { name: &'a str, log_level: *mut u32 } +#[cfg(stage0)] pub struct CrateMap<'a> { version: i32, entries: &'a [ModEntry<'a>], children: &'a [&'a CrateMap<'a>], event_loop_factory: Option ~EventLoop>, } +#[cfg(not(stage0))] +pub struct CrateMap<'a> { + version: i32, + event_loop_factory: Option ~EventLoop>, +} // When working on android, apparently weak symbols don't work so well for // finding the crate map, and neither does dlopen + dlsym. This is mainly a @@ -114,6 +122,7 @@ pub fn get_crate_map() -> Option<&'static CrateMap<'static>> { } } +#[cfg(stage0)] fn version(crate_map: &CrateMap) -> i32 { match crate_map.version { 2 => return 2, @@ -121,6 +130,7 @@ fn version(crate_map: &CrateMap) -> i32 { } } +#[cfg(stage0)] fn do_iter_crate_map<'a>( crate_map: &'a CrateMap<'a>, f: |&'a ModEntry<'a>|, @@ -149,87 +159,8 @@ fn do_iter_crate_map<'a>( } /// Iterates recursively over `crate_map` and all child crate maps +#[cfg(stage0)] pub fn iter_crate_map<'a>(crate_map: &'a CrateMap<'a>, f: |&'a ModEntry<'a>|) { let mut v = ~[]; do_iter_crate_map(crate_map, f, &mut v); } - -#[cfg(test)] -mod tests { - use option::None; - use rt::crate_map::{CrateMap, ModEntry, iter_crate_map}; - - #[test] - fn iter_crate_map_duplicates() { - let mut level3: u32 = 3; - - let entries = [ - ModEntry { name: "c::m1", log_level: &mut level3}, - ]; - - let child_crate = CrateMap { - version: 2, - entries: entries, - children: &[], - event_loop_factory: None, - }; - - let root_crate = CrateMap { - version: 2, - entries: &[], - children: &[&child_crate, &child_crate], - event_loop_factory: None, - }; - - let mut cnt = 0; - unsafe { - iter_crate_map(&root_crate, |entry| { - assert!(*entry.log_level == 3); - cnt += 1; - }); - assert!(cnt == 1); - } - } - - #[test] - fn iter_crate_map_follow_children() { - let mut level2: u32 = 2; - let mut level3: u32 = 3; - let child_crate2 = CrateMap { - version: 2, - entries: &[ - ModEntry { name: "c::m1", log_level: &mut level2}, - ModEntry { name: "c::m2", log_level: &mut level3}, - ], - children: &[], - event_loop_factory: None, - }; - - let child_crate1 = CrateMap { - version: 2, - entries: &[ - ModEntry { name: "t::f1", log_level: &mut 1}, - ], - children: &[&child_crate2], - event_loop_factory: None, - }; - - let root_crate = CrateMap { - version: 2, - entries: &[ - ModEntry { name: "t::f2", log_level: &mut 0}, - ], - children: &[&child_crate1], - event_loop_factory: None, - }; - - let mut cnt = 0; - unsafe { - iter_crate_map(&root_crate, |entry| { - assert!(*entry.log_level == cnt); - cnt += 1; - }); - assert!(cnt == 4); - } - } -} diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 3e600249a7d..4ef46573e23 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -529,9 +529,6 @@ pub enum Expr_ { ExprAgain(Option), ExprRet(Option<@Expr>), - /// Gets the log level for the enclosing module - ExprLogLevel, - ExprInlineAsm(InlineAsm), ExprMac(Mac), diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index b575cfaade6..997bfcc2e94 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -120,7 +120,7 @@ impl MacResult { pub fn raw_dummy_expr(sp: codemap::Span) -> @ast::Expr { @ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprLogLevel, + node: ast::ExprTup(Vec::new()), span: sp } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 0b56cd07c88..8cc74641db8 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -816,7 +816,6 @@ pub fn noop_fold_expr(e: @Expr, folder: &mut T) -> @Expr { ExprIndex(folder.fold_expr(el), folder.fold_expr(er)) } ExprPath(ref pth) => ExprPath(folder.fold_path(pth)), - ExprLogLevel => ExprLogLevel, ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|x| folder.fold_ident(x))), ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|x| folder.fold_ident(x))), ExprRet(ref e) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 040c4da6885..f52effb8c81 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -25,7 +25,7 @@ use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain}; use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox}; use ast::{ExprBreak, ExprCall, ExprCast}; use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex}; -use ast::{ExprLit, ExprLogLevel, ExprLoop, ExprMac}; +use ast::{ExprLit, ExprLoop, ExprMac}; use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc}; use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary}; use ast::{ExprVec, ExprVstore, ExprVstoreSlice}; @@ -1886,12 +1886,6 @@ impl Parser { } } hi = self.last_span.hi; - } else if self.eat_keyword(keywords::__LogLevel) { - // LOG LEVEL expression - self.expect(&token::LPAREN); - ex = ExprLogLevel; - hi = self.span.hi; - self.expect(&token::RPAREN); } else if self.eat_keyword(keywords::Return) { // RETURN expression if can_begin_expr(&self.token) { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 36c39220483..b1990476094 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1490,11 +1490,6 @@ pub fn print_expr(s: &mut State, expr: &ast::Expr) -> io::IoResult<()> { _ => () } } - ast::ExprLogLevel => { - try!(word(&mut s.s, "__log_level")); - try!(popen(s)); - try!(pclose(s)); - } ast::ExprInlineAsm(ref a) => { if a.volatile { try!(word(&mut s.s, "__volatile__ asm!")); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 538528fb148..880fce58083 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -743,7 +743,6 @@ pub fn walk_expr>(visitor: &mut V, expression: &Expr, en ExprRet(optional_expression) => { walk_expr_opt(visitor, optional_expression, env.clone()) } - ExprLogLevel => {} ExprMac(ref macro) => visitor.visit_mac(macro, env.clone()), ExprParen(subexpression) => { visitor.visit_expr(subexpression, env.clone())