Skip to content

Commit

Permalink
HIR - Refactor handling of ConstGeneric to avoid needing to monomorph…
Browse files Browse the repository at this point in the history
…ise HIR/MIR
  • Loading branch information
thepowersgang committed Oct 15, 2024
1 parent 890f24e commit 502a152
Show file tree
Hide file tree
Showing 23 changed files with 298 additions and 183 deletions.
12 changes: 11 additions & 1 deletion src/hir/deserialise.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ namespace {
}
}

::HIR::ConstGeneric_Unevaluated deserialise_constgeneric_unevaluated();
::HIR::ConstGeneric deserialise_constgeneric();
EncodedLiteral deserialise_encodedliteral();

Expand Down Expand Up @@ -1375,13 +1376,22 @@ namespace {
return rv;
}

::HIR::ConstGeneric_Unevaluated HirDeserialiser::deserialise_constgeneric_unevaluated()
{
auto p_i = deserialise_pathparams();
auto p_m = deserialise_pathparams();
auto rv = ::HIR::ConstGeneric_Unevaluated(deserialise_exprptr());
rv.params_impl = std::move(p_i);
rv.params_item = std::move(p_m);
return rv;
}
::HIR::ConstGeneric HirDeserialiser::deserialise_constgeneric()
{
switch( auto tag = m_in.read_tag() )
{
#define _(x, ...) case ::HIR::ConstGeneric::TAG_##x: return ::HIR::ConstGeneric::make_##x(__VA_ARGS__);
_(Infer, {})
_(Unevaluated, std::make_shared<HIR::ExprPtr>(deserialise_exprptr()))
_(Unevaluated, std::make_unique<HIR::ConstGeneric_Unevaluated>(deserialise_constgeneric_unevaluated()))
_(Generic,
deserialise_genericref()
)
Expand Down
2 changes: 1 addition & 1 deletion src/hir/expr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@ struct ExprNode_ArraySized:
ExprNode_ArraySized(Span sp, ::HIR::ExprNodeP val, ::HIR::ExprPtr size):
ExprNode(mv$(sp)),
m_val( mv$(val) ),
m_size( HIR::ConstGeneric(std::make_shared<HIR::ExprPtr>(mv$(size))) )
m_size( HIR::ConstGeneric(std::make_unique<HIR::ConstGeneric_Unevaluated>(mv$(size))) )
{}

NODE_METHODS();
Expand Down
12 changes: 9 additions & 3 deletions src/hir/from_ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,8 +547,14 @@ ::HIR::PathParams LowerHIR_PathParams(const Span& sp, const ::AST::PathParams& s
params.m_types.push_back( LowerHIR_Type(ty) );
}
TU_ARMA(Value, iv) {
const AST::ExprNode* node = &*iv;
if( const auto* e = dynamic_cast<const AST::ExprNode_Block*>(node) ) {
if( e->m_yields_final_value && e->m_nodes.size() == 1 ) {
node = e->m_nodes.back().get();
}
}
// TODO: Explicitly handle each expected variant... or add a proper consteval expression
if( const auto* e = dynamic_cast<const AST::ExprNode_NamedValue*>(&*iv) ) {
if( const auto* e = dynamic_cast<const AST::ExprNode_NamedValue*>(node) ) {
if( e->m_path.is_trivial() ) {
const auto& b = e->m_path.m_bindings.value.binding;
ASSERT_BUG(sp, b.is_Generic(), "Trivial path not type parameter - " << e->m_path << " - " << b.tag_str());
Expand All @@ -557,7 +563,7 @@ ::HIR::PathParams LowerHIR_PathParams(const Span& sp, const ::AST::PathParams& s
break ;
}
}
params.m_values.push_back( std::make_shared<HIR::ExprPtr>(LowerHIR_ExprNode(*iv)) );
params.m_values.push_back( std::make_unique<HIR::ConstGeneric_Unevaluated>(LowerHIR_ExprNode(*iv)) );
}
TU_ARMA(AssociatedTyEqual, ty) {
if( !allow_assoc )
Expand Down Expand Up @@ -902,7 +908,7 @@ ::HIR::TypeRef LowerHIR_Type(const ::TypeRef& ty)
}
}

return ::HIR::TypeRef::new_array( mv$(inner), HIR::ConstGeneric::make_Unevaluated(std::make_shared<HIR::ExprPtr>(LowerHIR_Expr(e.size))) );
return ::HIR::TypeRef::new_array( mv$(inner), HIR::ConstGeneric::make_Unevaluated(std::make_unique<HIR::ConstGeneric_Unevaluated>(LowerHIR_Expr(e.size))) );
}
else {
return ::HIR::TypeRef::new_array( mv$(inner), HIR::ConstGeneric::make_Infer({}) );
Expand Down
128 changes: 81 additions & 47 deletions src/hir/hir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,31 +46,7 @@ namespace HIR {
}
TU_ARMA(Unevaluated, e) {
os << "Unevaluated(";
if(e->m_mir) {
for(const auto& b : e->m_mir->blocks) {
os << "bb" << (&b - e->m_mir->blocks.data()) << ":{ ";
for(const auto& s : b.statements) {
os << s << "; ";
}
os << b.terminator;
os << " }";
}
}
else {
struct NoNewline: public ::std::ostream, ::std::streambuf {
::std::ostream& inner;
NoNewline(::std::ostream& inner): ::std::ostream(this), inner(inner) {}
int overflow(int c) override {
switch(c)
{
case '\n': inner.put(' '); break;
default: inner.put(c); break;
}
return 0;
}
} inner_os(os);
HIR_DumpExpr(inner_os, *e);
}
e->fmt(os);
os << ")";
}
TU_ARMA(Generic, e) os << "Generic(" << e << ")";
Expand Down Expand Up @@ -99,48 +75,106 @@ namespace HIR {
if(auto cmp = ::ord(te.index, xe.index)) return cmp;
}
TU_ARMA(Unevaluated, te, xe) {
return te->ord(*xe);
}
TU_ARMA(Generic, te, xe) {
if(auto cmp = ::ord(te, xe)) return cmp;
}
TU_ARMA(Evaluated, te, xe) {
if(auto cmp = ::ord(EncodedLiteralSlice(*te), EncodedLiteralSlice(*xe))) return cmp;
}
}
return OrdEqual;
}

::std::ostream& operator<<(::std::ostream& os, const ConstGeneric_Unevaluated& x)
{
x.fmt(os);
return os;
}
ConstGeneric_Unevaluated::ConstGeneric_Unevaluated(HIR::ExprPtr ep)
: expr(std::make_shared<HIR::ExprPtr>(std::move(ep)))
{
}
ConstGeneric_Unevaluated ConstGeneric_Unevaluated::clone() const
{
return monomorph(Span(), MonomorphiserNop());
}
ConstGeneric_Unevaluated ConstGeneric_Unevaluated::monomorph(const Span& sp, const Monomorphiser& ms, bool allow_infer/*=true*/) const
{
ConstGeneric_Unevaluated rv;
rv.params_impl = ms.monomorph_path_params(sp, params_impl, allow_infer);
rv.params_item = ms.monomorph_path_params(sp, params_item, allow_infer);
rv.expr = this->expr;
return rv;
}
Ordering ConstGeneric_Unevaluated::ord(const ConstGeneric_Unevaluated& x) const
{
if( this->expr.get() != x.expr.get() ) {
// If only one has populated MIR, they can't be equal (sort populated MIR after)
if( !te->m_mir != !xe->m_mir ) {
return (te->m_mir ? OrdGreater : OrdLess);
if( !this->expr->m_mir != !this->expr->m_mir ) {
return (this->expr->m_mir ? OrdGreater : OrdLess);
}

// HACK: If the inner is a const param on both, sort based on that.
// - Very similar to the ordering of TypeRef::Generic
const auto* tn = dynamic_cast<const HIR::ExprNode_ConstParam*>(&**te);
const auto* xn = dynamic_cast<const HIR::ExprNode_ConstParam*>(&**xe);
const auto* tn = dynamic_cast<const HIR::ExprNode_ConstParam*>(&**this->expr);
const auto* xn = dynamic_cast<const HIR::ExprNode_ConstParam*>(&**x.expr);
if( tn && xn )
{
// Is this valid? What if they're from different scopes?
return ::ord(tn->m_binding, xn->m_binding);
}

if( te->m_mir )
// If the MIR is populated
if( this->expr->m_mir )
{
if( te.get() != xe.get() )
{
assert(xe->m_mir);
// TODO: Compare MIR
TODO(Span(), "Compare non-expanded array sizes - (w/ MIR) " << *this << " and " << x);
}
TODO(Span(), "Compare non-expanded array sizes - (w/ MIR) " << *this << " and " << x);
}
else
{
else {
// EVIL OPTION: Just compare the string representations
// - Hopefully there's no pointers printed involved.
auto v_t = FMT(*this);
auto v_t = FMT(*this->expr);
auto v_x = FMT(x);
return ::ord(v_t, v_x);
}
}
TU_ARMA(Generic, te, xe) {
if(auto cmp = ::ord(te, xe)) return cmp;
}
TU_ARMA(Evaluated, te, xe) {
if(auto cmp = ::ord(EncodedLiteralSlice(*te), EncodedLiteralSlice(*xe))) return cmp;
}
}
if(auto cmp = this->params_impl.ord(x.params_impl)) return cmp;
if(auto cmp = this->params_item.ord(x.params_item)) return cmp;
return OrdEqual;
}
void ConstGeneric_Unevaluated::fmt(::std::ostream& os) const
{
os << "{";
os << "0=" << this->params_impl;
os << "1=" << this->params_item;
os << "}";
if(expr->m_mir) {
for(const auto& b : expr->m_mir->blocks) {
os << "bb" << (&b - expr->m_mir->blocks.data()) << ":{ ";
for(const auto& s : b.statements) {
os << s << "; ";
}
os << b.terminator;
os << " }";
}
}
else {
struct NoNewline: public ::std::ostream, ::std::streambuf {
::std::ostream& inner;
NoNewline(::std::ostream& inner): ::std::ostream(this), inner(inner) {}
int overflow(int c) override {
switch(c)
{
case '\n': inner.put(' '); break;
default: inner.put(c); break;
}
return 0;
}
} inner_os(os);
HIR_DumpExpr(inner_os, *expr);
}
}

::std::ostream& operator<<(::std::ostream& os, const Struct::Repr& x) {
os << "repr(";
Expand All @@ -160,7 +194,7 @@ HIR::ConstGeneric HIR::ConstGeneric::clone() const
{
TU_MATCH_HDRA( (*this), {)
TU_ARMA(Infer, e) return e;
TU_ARMA(Unevaluated, e) return e;
TU_ARMA(Unevaluated, e) return ::std::make_unique<ConstGeneric_Unevaluated>(e->clone());
TU_ARMA(Generic, e) return e;
TU_ARMA(Evaluated, e) return EncodedLiteralPtr(e->clone());
}
Expand Down
24 changes: 23 additions & 1 deletion src/hir/path.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "expr_ptr.hpp"

struct EncodedLiteral;
class Monomorphiser;

namespace HIR {

Expand All @@ -38,13 +39,17 @@ class EncodedLiteralPtr {
EncodedLiteral* operator->() { assert(p); return p; }
const EncodedLiteral* operator->() const { assert(p); return p; }
};
struct ConstGeneric_Unevaluated;
TAGGED_UNION_EX(ConstGeneric, (), Infer, (
(Infer, struct InferData { // To be inferred
unsigned index;
// NOTE: Workaround for VS2014, which can't use initialiser lists when a default is specified
InferData(unsigned index=~0u): index(index) {}
}),
(Unevaluated, std::shared_ptr<HIR::ExprPtr>), // Unevaluated (or evaluation deferred)
// NOTE: This is a `unique_ptr` because it contains two PathParams and a shared (2*3 pointers + 2 pointers)
// The rest of the variants here are two pointers
(Unevaluated, std::unique_ptr<ConstGeneric_Unevaluated>), // Unevaluated (or evaluation deferred)
//(Unevaluated, std::shared_ptr<HIR::ExprPtr>), // Unevaluated (or evaluation deferred)
(Generic, GenericRef), // A single generic reference
(Evaluated, EncodedLiteralPtr) // A fully known literal
),
Expand Down Expand Up @@ -313,6 +318,23 @@ class Path
friend ::std::ostream& operator<<(::std::ostream& os, const Path& x);
};

struct ConstGeneric_Unevaluated {
/// Impl-level parameters to the expression
HIR::PathParams params_impl;
HIR::PathParams params_item;
/// HIR/MIR for this unevaluated parameter
std::shared_ptr<HIR::ExprPtr> expr;

ConstGeneric_Unevaluated(HIR::ExprPtr ep);
ConstGeneric_Unevaluated clone() const;
ConstGeneric_Unevaluated monomorph(const Span& sp, const Monomorphiser& ms, bool allow_infer=true) const;
Ordering ord(const ConstGeneric_Unevaluated& x) const;
void fmt(::std::ostream& os) const;

private:
ConstGeneric_Unevaluated(){}
};

} // namespace HIR

#endif
Expand Down
8 changes: 7 additions & 1 deletion src/hir/serialise.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -690,14 +690,20 @@
}
}
}
void serialise(const ::HIR::ConstGeneric_Unevaluated& v)
{
ASSERT_BUG(v.expr->span(), v.expr->m_mir, "Encountered non-translated value in ConstGeneric");
serialise_pathparams(v.params_impl);
serialise_pathparams(v.params_item);
serialise(*v.expr);
}
void serialise(const ::HIR::ConstGeneric& v)
{
m_out.write_tag(v.tag());
TU_MATCH_HDRA( (v), {)
TU_ARMA(Infer, e) {
}
TU_ARMA(Unevaluated, e) {
ASSERT_BUG(e->span(), e->m_mir, "Encountered non-translated value in ConstGeneric");
serialise(*e);
}
TU_ARMA(Generic, e)
Expand Down
2 changes: 1 addition & 1 deletion src/hir/visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ void ::HIR::Visitor::visit_constgeneric(::HIR::ConstGeneric& v)
{
if(v.is_Unevaluated())
{
this->visit_expr(*v.as_Unevaluated());
this->visit_expr(*v.as_Unevaluated()->expr);
}
}
void ::HIR::Visitor::visit_pattern(::HIR::Pattern& pat)
Expand Down
23 changes: 20 additions & 3 deletions src/hir_conv/bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ namespace {
if( params.m_values.size() == 0 && fill_infer ) {
for(const auto& val : param_defs.m_values) {
if( val.m_default ) {
// NOTE: Can't just copy, as Unevaluated may not have had its params set yet
TODO(sp, "Value generic defaults");
}
else {
Expand All @@ -307,6 +308,22 @@ namespace {
}
}
}
void visit_path_params(::HIR::PathParams& params) override
{
HIR::Visitor::visit_path_params(params);
for(auto& v : params.m_values)
{
if(auto* ve = v.opt_Unevaluated())
{
if( m_ms.m_impl_generics ) {
(*ve)->params_impl = m_ms.m_impl_generics->make_nop_params(0);
}
if( m_ms.m_item_generics ) {
(*ve)->params_item = m_ms.m_item_generics->make_nop_params(1);
}
}
}
}
void visit_params(::HIR::GenericParams& params) override
{
static Span sp;
Expand Down Expand Up @@ -593,7 +610,7 @@ namespace {
//if( !dynamic_cast<const HIR::ExprNode_Literal*>(arg_node.get()) )
// ERROR(arg_node->span(), E0000, "Argument " << idx << " must be a literal for #[rustc_legacy_const_generics] tagged function");
HIR::ExprPtr ep { std::move(arg_node) };
e->m_params.m_values.push_back( HIR::ConstGeneric( std::make_shared<HIR::ExprPtr>(std::move(ep)) ));
e->m_params.m_values.push_back( HIR::ConstGeneric( std::make_unique<HIR::ConstGeneric_Unevaluated>(std::move(ep)) ));
// - Visit to ensure that the expr state gets filled
upper_visitor.visit_constgeneric(e->m_params.m_values.back());
}
Expand Down Expand Up @@ -621,9 +638,9 @@ namespace {
void visit(::HIR::ExprNode_ArraySized& node) override
{
auto& as = node.m_size;
if( as.is_Unevaluated() && as.as_Unevaluated().is_Unevaluated() )
if( as.is_Unevaluated() )
{
upper_visitor.visit_expr(*as.as_Unevaluated().as_Unevaluated());
upper_visitor.visit_constgeneric(as.as_Unevaluated());
}
::HIR::ExprVisitorDef::visit(node);
}
Expand Down
Loading

0 comments on commit 502a152

Please sign in to comment.