lean4-htt/src/library/compiler/elim_dead_let.cpp
Leonardo de Moura 7b5f283507 chore: remove Expr.localE constructor
It was used by the old frontend
2020-11-01 09:37:48 -08:00

138 lines
4.6 KiB
C++

/*
Copyright (c) 2018 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include <algorithm>
#include <unordered_set>
#include "util/name_generator.h"
#include "kernel/instantiate.h"
#include "kernel/abstract.h"
#include "kernel/for_each_fn.h"
namespace lean {
static name * g_elim_dead_let_fresh = nullptr;
class elim_dead_let_fn {
std::unordered_set<name, name_hash_fn> m_used;
name_generator m_ngen;
void mark_fvar(expr const & e) {
m_used.insert(fvar_name(e));
}
expr visit_let(expr e) {
buffer<expr> fvars;
buffer<expr> lets;
while (is_let(e)) {
expr fvar = mk_fvar(m_ngen.next());
fvars.push_back(fvar);
lets.push_back(e);
e = let_body(e);
}
e = visit(instantiate_rev(e, fvars.size(), fvars.data()));
buffer<expr> used;
buffer<std::tuple<name, expr, expr>> entries;
while (!fvars.empty()) {
expr fvar = fvars.back(); fvars.pop_back();
expr let = lets.back(); lets.pop_back();
if (m_used.find(fvar_name(fvar)) != m_used.end()) {
expr new_type = visit(instantiate_rev(let_type(let), fvars.size(), fvars.data()));
expr new_value = visit(instantiate_rev(let_value(let), fvars.size(), fvars.data()));
used.push_back(fvar);
entries.emplace_back(let_name(let), new_type, new_value);
}
}
std::reverse(used.begin(), used.end());
std::reverse(entries.begin(), entries.end());
e = abstract(e, used.size(), used.data());
unsigned i = entries.size();
while (i > 0) {
--i;
expr new_type = abstract(std::get<1>(entries[i]), i, used.data());
expr new_value = abstract(std::get<2>(entries[i]), i, used.data());
e = mk_let(std::get<0>(entries[i]), new_type, new_value, e);
}
return e;
}
expr visit_lambda(expr e) {
buffer<expr> fvars;
buffer<std::tuple<name, expr, binder_info>> entries;
while (is_lambda(e)) {
expr domain = visit(instantiate_rev(binding_domain(e), fvars.size(), fvars.data()));
expr fvar = mk_fvar(m_ngen.next());
entries.emplace_back(binding_name(e), domain, binding_info(e));
fvars.push_back(fvar);
e = binding_body(e);
}
e = visit(instantiate_rev(e, fvars.size(), fvars.data()));
e = abstract(e, fvars.size(), fvars.data());
unsigned i = entries.size();
while (i > 0) {
--i;
expr new_domain = abstract(std::get<1>(entries[i]), i, fvars.data());
e = mk_lambda(std::get<0>(entries[i]), new_domain, e, std::get<2>(entries[i]));
}
return e;
}
expr visit_app(expr const & e) {
expr fn = visit(app_fn(e));
expr arg = visit(app_arg(e));
return update_app(e, fn, arg);
}
expr visit_proj(expr const & e) {
return update_proj(e, visit(proj_expr(e)));
}
expr visit_mdata(expr const & e) {
return update_mdata(e, visit(mdata_expr(e)));
}
expr visit_pi(expr const & e) {
for_each(e, [&](expr const & e, unsigned) {
if (is_fvar(e))
mark_fvar(e);
return true;
});
return e;
}
expr visit(expr const & e) {
switch (e.kind()) {
case expr_kind::Lambda: return visit_lambda(e);
case expr_kind::Let: return visit_let(e);
case expr_kind::Proj: return visit_proj(e);
case expr_kind::App: return visit_app(e);
case expr_kind::FVar: mark_fvar(e); return e;
case expr_kind::MData: return visit_mdata(e);
case expr_kind::Pi: return visit_pi(e);
case expr_kind::Const: return e;
case expr_kind::Sort: return e;
case expr_kind::Lit: return e;
case expr_kind::BVar: return e;
case expr_kind::MVar: lean_unreachable();
}
lean_unreachable();
}
public:
elim_dead_let_fn():m_ngen(*g_elim_dead_let_fresh) {}
expr operator()(expr const & e) { return visit(e); }
};
expr elim_dead_let(expr const & e) { return elim_dead_let_fn()(e); }
void initialize_elim_dead_let() {
g_elim_dead_let_fresh = new name("_elim_dead_let_fresh");
mark_persistent(g_elim_dead_let_fresh->raw());
register_name_generator_prefix(*g_elim_dead_let_fresh);
}
void finalize_elim_dead_let() {
delete g_elim_dead_let_fresh;
}
}