diff options
author | John Hodge <tpg@mutabah.net> | 2016-05-27 13:47:04 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-05-27 13:47:04 +0800 |
commit | 99b04898383e9d66c97e8f89504420263ba96c0b (patch) | |
tree | feeaa3370bd644c4889e5030415474846d27f1af | |
parent | 46b2f9450a438a597492e0015b735e625ee0cd3a (diff) | |
download | mrust-99b04898383e9d66c97e8f89504420263ba96c0b.tar.gz |
HIR Conv - Constant evaluation pass running (fully?)
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/hir/hir.cpp | 102 | ||||
-rw-r--r-- | src/hir/hir.hpp | 6 | ||||
-rw-r--r-- | src/hir/visitor.cpp | 26 | ||||
-rw-r--r-- | src/hir/visitor.hpp | 8 | ||||
-rw-r--r-- | src/hir_conv/constant_evaluation.cpp | 302 | ||||
-rw-r--r-- | src/hir_conv/expand_type.cpp | 2 | ||||
-rw-r--r-- | src/hir_conv/main_bindings.hpp | 1 | ||||
-rw-r--r-- | src/hir_conv/resolve_ufcs.cpp | 217 | ||||
-rw-r--r-- | src/main.cpp | 3 |
10 files changed, 629 insertions, 40 deletions
@@ -46,7 +46,7 @@ OBJ += hir/hir.o OBJ += hir/crate_ptr.o hir/type_ptr.o hir/expr_ptr.o OBJ += hir/type.o hir/path.o hir/expr.o OBJ += hir/visitor.o -OBJ += hir_conv/expand_type.o hir_conv/constant_evaluation.o +OBJ += hir_conv/expand_type.o hir_conv/constant_evaluation.o hir_conv/resolve_ufcs.o OBJ += dump_as_rust.o PCHS := ast/ast.hpp diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index 5b9401f5..bc1fecd5 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -28,3 +28,105 @@ namespace HIR { return os; } } + +namespace { + bool matches_type_int(const ::HIR::GenericParams& params, const ::HIR::TypeRef& left, const ::HIR::TypeRef& right) + { + assert(! left.m_data.is_Infer() ); + if( right.m_data.is_Infer() ) { + return false; + } + + if( left.m_data.is_Generic() ) { + // True? + return true; + } + + if( left.m_data.tag() != right.m_data.tag() ) { + return false; + } + TU_MATCH(::HIR::TypeRef::Data, (left.m_data, right.m_data), (le, re), + (Infer, assert(!"infer");), + (Diverge, return true; ), + (Primitive, return le == re;), + (Path, + if( le.m_data.tag() != re.m_data.tag() ) + return false; + TU_MATCH_DEF(::HIR::Path::Data, (le.m_data, re.m_data), (ple, pre), + ( + return false; + ), + (Generic, + if( ple.m_path.m_crate_name != pre.m_path.m_crate_name ) + return false; + if( ple.m_path.m_components.size() != pre.m_path.m_components.size() ) + return false; + for(unsigned int i = 0; i < ple.m_path.m_components.size(); i ++ ) + { + if( ple.m_path.m_components[i] != pre.m_path.m_components[i] ) + return false; + } + + if( ple.m_params.m_types.size() > 0 || pre.m_params.m_types.size() > 0 ) { + TODO(Span(), "Match paths " << ple << " and " << pre); + } + return true; + ) + ) + ), + (Generic, + throw ""; + ), + (TraitObject, + DEBUG("TODO: Compare " << left << " and " << right); + return false; + ), + (Array, + if( ! matches_type_int(params, *le.inner, *re.inner) ) + return false; + if( le.size_val != re.size_val ) + return false; + return true; + ), + (Slice, + return matches_type_int(params, *le.inner, *re.inner); + ), + (Tuple, + if( le.size() != re.size() ) + return false; + for( unsigned int i = 0; i < le.size(); i ++ ) + if( !matches_type_int(params, le[i], re[i]) ) + return false; + return true; + ), + (Borrow, + if( le.type != re.type ) + return false; + return matches_type_int(params, *le.inner, *re.inner); + ), + (Pointer, + if( le.is_mut != re.is_mut ) + return false; + return matches_type_int(params, *le.inner, *re.inner); + ), + (Function, + DEBUG("TODO: Compare " << left << " and " << right); + return false; + ) + ) + return false; + } +} + +bool ::HIR::TraitImpl::matches_type(const ::HIR::TypeRef& type) const +{ + return matches_type_int(m_params, m_type, type); +} +bool ::HIR::TypeImpl::matches_type(const ::HIR::TypeRef& type) const +{ + return matches_type_int(m_params, m_type, type); +} +bool ::HIR::MarkerImpl::matches_type(const ::HIR::TypeRef& type) const +{ + return matches_type_int(m_params, m_type, type); +} diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index 2887fd13..ef565c4e 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -199,6 +199,8 @@ public: ::HIR::TypeRef m_type; ::std::map< ::std::string, ::HIR::Function> m_methods; + + bool matches_type(const ::HIR::TypeRef& tr) const; }; class TraitImpl @@ -211,6 +213,8 @@ public: ::std::map< ::std::string, ::HIR::Function> m_methods; ::std::map< ::std::string, ::HIR::ExprPtr> m_constants; ::std::map< ::std::string, ::HIR::TypeRef> m_types; + + bool matches_type(const ::HIR::TypeRef& tr) const; }; class MarkerImpl @@ -220,6 +224,8 @@ public: ::HIR::PathParams m_trait_args; bool is_positive; ::HIR::TypeRef m_type; + + bool matches_type(const ::HIR::TypeRef& tr) const; }; class Crate diff --git a/src/hir/visitor.cpp b/src/hir/visitor.cpp index 9a38aa20..13fdd0f2 100644 --- a/src/hir/visitor.cpp +++ b/src/hir/visitor.cpp @@ -114,7 +114,7 @@ void ::HIR::Visitor::visit_trait(::HIR::Trait& item) { this->visit_params(item.m_params); for(auto& par : item.m_parent_traits) { - this->visit_generic_path(par); + this->visit_generic_path(par, ::HIR::Visitor::PathContext::TYPE); } for(auto& i : item.m_types) { this->visit_params(i.second.m_params); @@ -214,7 +214,7 @@ void ::HIR::Visitor::visit_params(::HIR::GenericParams& params) ), (TraitBound, this->visit_type(e.type); - this->visit_generic_path(e.trait.m_path); + this->visit_generic_path(e.trait.m_path, ::HIR::Visitor::PathContext::TYPE); ), (TraitUnbound, this->visit_type(e.type); @@ -241,13 +241,13 @@ void ::HIR::Visitor::visit_type(::HIR::TypeRef& ty) (Primitive, ), (Path, - this->visit_path(e); + this->visit_path(e, ::HIR::Visitor::PathContext::TYPE); ), (Generic, ), (TraitObject, for(auto& trait : e.m_traits) { - this->visit_generic_path(trait); + this->visit_generic_path(trait, ::HIR::Visitor::PathContext::TYPE); } ), (Array, @@ -292,12 +292,12 @@ void ::HIR::Visitor::visit_pattern(::HIR::Pattern& pat) this->visit_pattern(sp); ), (StructTuple, - this->visit_generic_path(e.path); + this->visit_generic_path(e.path, ::HIR::Visitor::PathContext::TYPE); for(auto& sp : e.sub_patterns) this->visit_pattern(sp); ), (Struct, - this->visit_generic_path(e.path); + this->visit_generic_path(e.path, ::HIR::Visitor::PathContext::TYPE); for(auto& sp : e.sub_patterns) this->visit_pattern(sp.second); ), @@ -310,12 +310,12 @@ void ::HIR::Visitor::visit_pattern(::HIR::Pattern& pat) this->visit_pattern_val(e.end); ), (EnumTuple, - this->visit_generic_path(e.path); + this->visit_generic_path(e.path, ::HIR::Visitor::PathContext::TYPE); for(auto& sp : e.sub_patterns) this->visit_pattern(sp); ), (EnumStruct, - this->visit_generic_path(e.path); + this->visit_generic_path(e.path, ::HIR::Visitor::PathContext::TYPE); for(auto& sp : e.sub_patterns) this->visit_pattern(sp.second); ), @@ -339,15 +339,15 @@ void ::HIR::Visitor::visit_pattern_val(::HIR::Pattern::Value& val) (String, ), (Named, - this->visit_path(e); + this->visit_path(e, ::HIR::Visitor::PathContext::VALUE); ) ) } -void ::HIR::Visitor::visit_path(::HIR::Path& p) +void ::HIR::Visitor::visit_path(::HIR::Path& p, ::HIR::Visitor::PathContext pc) { TU_MATCH(::HIR::Path::Data, (p.m_data), (e), (Generic, - this->visit_generic_path(e); + this->visit_generic_path(e, pc); ), (UfcsInherent, this->visit_type(*e.type); @@ -355,7 +355,7 @@ void ::HIR::Visitor::visit_path(::HIR::Path& p) ), (UfcsKnown, this->visit_type(*e.type); - this->visit_generic_path(e.trait); + this->visit_generic_path(e.trait, ::HIR::Visitor::PathContext::TYPE); this->visit_path_params(e.params); ), (UfcsUnknown, @@ -371,7 +371,7 @@ void ::HIR::Visitor::visit_path_params(::HIR::PathParams& p) this->visit_type(ty); } } -void ::HIR::Visitor::visit_generic_path(::HIR::GenericPath& p) +void ::HIR::Visitor::visit_generic_path(::HIR::GenericPath& p, ::HIR::Visitor::PathContext /*pc*/) { this->visit_path_params(p.m_params); } diff --git a/src/hir/visitor.hpp b/src/hir/visitor.hpp index 814dac67..7e8bcf63 100644 --- a/src/hir/visitor.hpp +++ b/src/hir/visitor.hpp @@ -35,9 +35,13 @@ public: virtual void visit_pattern_val(::HIR::Pattern::Value& val); virtual void visit_type(::HIR::TypeRef& tr); - virtual void visit_path(::HIR::Path& p); + enum class PathContext { + TYPE, + VALUE, + }; + virtual void visit_path(::HIR::Path& p, PathContext ); virtual void visit_path_params(::HIR::PathParams& p); - virtual void visit_generic_path(::HIR::GenericPath& p); + virtual void visit_generic_path(::HIR::GenericPath& p, PathContext ); virtual void visit_expr(::HIR::ExprPtr& exp); }; diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 2544f85c..e64dd289 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -1,33 +1,176 @@ /* * Evaluate constants + * + * HACK - Should be replaced with a reentrant typeck/mir pass */ #include "main_bindings.hpp" #include <hir/hir.hpp> #include <hir/expr.hpp> #include <hir/visitor.hpp> - +#include <algorithm> namespace { - ::HIR::Function& get_function(const Span& sp, const ::HIR::Crate& crate, const ::HIR::Path& path) + ::HIR::Literal clone_literal(const ::HIR::Literal& v) + { + TU_MATCH(::HIR::Literal, (v), (e), + (Invalid, + return ::HIR::Literal(); + ), + (List, + ::std::vector< ::HIR::Literal> vals; + for(const auto& val : e) { + vals.push_back( clone_literal(val) ); + } + return ::HIR::Literal( mv$(vals) ); + ), + (Integer, + return ::HIR::Literal(e); + ), + (Float, + return ::HIR::Literal(e); + ), + (String, + return ::HIR::Literal(e); + ) + ) + throw ""; + } + + enum class EntType { + Function, + Constant, + Struct, + }; + const void* get_ent_simplepath(const Span& sp, const ::HIR::Crate& crate, const ::HIR::SimplePath& path, EntType et) + { + if( path.m_crate_name != "" ) + TODO(sp, "get_ent_simplepath in crate"); + + const ::HIR::Module* mod = &crate.m_root_module; + for( unsigned int i = 0; i < path.m_components.size() - 1; i ++ ) + { + const auto& pc = path.m_components[i]; + auto it = mod->m_mod_items.find( pc ); + if( it == mod->m_mod_items.end() ) { + BUG(sp, "Couldn't find component " << i << " of " << path); + } + TU_MATCH_DEF( ::HIR::TypeItem, (it->second->ent), (e2), + ( + BUG(sp, "Node " << i << " of path " << path << " wasn't a module"); + ), + (Module, + mod = &e2; + ) + ) + } + + switch( et ) + { + case EntType::Function: { + auto it = mod->m_value_items.find( path.m_components.back() ); + if( it == mod->m_value_items.end() ) { + return nullptr; + } + + TU_IFLET( ::HIR::ValueItem, it->second->ent, Function, e, + return &e; + ) + else { + BUG(sp, "Path " << path << " didn't point to a functon"); + } + } break; + case EntType::Constant: { + auto it = mod->m_value_items.find( path.m_components.back() ); + if( it == mod->m_value_items.end() ) { + return nullptr; + } + + TU_IFLET( ::HIR::ValueItem, it->second->ent, Constant, e, + return &e; + ) + else { + BUG(sp, "Path " << path << " didn't point to a functon"); + } + } break; + case EntType::Struct: { + auto it = mod->m_mod_items.find( path.m_components.back() ); + if( it == mod->m_mod_items.end() ) { + return nullptr; + } + + TU_IFLET( ::HIR::TypeItem, it->second->ent, Struct, e, + return &e; + ) + else { + BUG(sp, "Path " << path << " didn't point to a struct"); + } + } break; + } + throw ""; + } + const void* get_ent_fullpath(const Span& sp, const ::HIR::Crate& crate, const ::HIR::Path& path, EntType et) { TU_MATCH(::HIR::Path::Data, (path.m_data), (e), (Generic, - TODO(sp, "get_function(path = " << path << ")"); + return get_ent_simplepath(sp, crate, e.m_path, et); ), (UfcsInherent, // Easy (ish) - TODO(sp, "get_function(path = " << path << ")"); + for( const auto& impl : crate.m_type_impls ) + { + if( ! impl.matches_type(*e.type) ) { + continue ; + } + switch( et ) + { + case EntType::Function: { + auto fit = impl.m_methods.find(e.item); + if( fit == impl.m_methods.end() ) + continue ; + return &fit->second; + } break; + case EntType::Struct: + break; + case EntType::Constant: + break; + } + } + return nullptr; ), (UfcsKnown, - TODO(sp, "get_function(path = " << path << ")"); + TODO(sp, "get_ent_fullpath(path = " << path << ")"); ), (UfcsUnknown, // TODO - Since this isn't known, can it be searched properly? - TODO(sp, "get_function(path = " << path << ")"); + TODO(sp, "get_ent_fullpath(path = " << path << ")"); ) ) throw ""; } + const ::HIR::Function& get_function(const Span& sp, const ::HIR::Crate& crate, const ::HIR::Path& path) + { + auto* rv_p = reinterpret_cast<const ::HIR::Function*>( get_ent_fullpath(sp, crate, path, EntType::Function) ); + if( !rv_p ) { + TODO(sp, "get_function(path = " << path << ")"); + } + return *rv_p; + } + const ::HIR::Struct& get_struct(const Span& sp, const ::HIR::Crate& crate, const ::HIR::SimplePath& path) + { + auto rv_p = reinterpret_cast<const ::HIR::Struct*>( get_ent_simplepath(sp, crate, path, EntType::Struct) ); + if( !rv_p ) { + BUG(sp, "Could not find struct name in " << path); + } + return *rv_p; + } + const ::HIR::Constant& get_constant(const Span& sp, const ::HIR::Crate& crate, const ::HIR::Path& path) + { + auto rv_p = reinterpret_cast<const ::HIR::Constant*>( get_ent_fullpath(sp, crate, path, EntType::Constant) ); + if( !rv_p ) { + BUG(sp, "Could not find constant in " << path); + } + return *rv_p; + } ::HIR::Literal evaluate_constant(const ::HIR::Crate& crate, const ::HIR::ExprNode& expr) { @@ -35,6 +178,7 @@ namespace { public ::HIR::ExprVisitor { const ::HIR::Crate& m_crate; + ::std::vector< ::std::pair< ::std::string, ::HIR::Literal > > m_values; ::HIR::Literal m_rv; @@ -47,7 +191,8 @@ namespace { } void visit(::HIR::ExprNode_Block& node) override { - TODO(node.span(), "ExprNode_Block"); + for(const auto& e : node.m_nodes) + e->visit(*this); } void visit(::HIR::ExprNode_Return& node) override { TODO(node.span(), "ExprNode_Return"); @@ -169,10 +314,33 @@ namespace { } } void visit(::HIR::ExprNode_UniOp& node) override { - TODO(node.span(), "ExprNode_UniOp"); + node.m_value->visit(*this); + auto val = mv$(m_rv); + + switch(node.m_op) + { + case ::HIR::ExprNode_UniOp::Op::Ref: + case ::HIR::ExprNode_UniOp::Op::RefMut: + TODO(node.span(), "&/&mut in constant"); + break; + case ::HIR::ExprNode_UniOp::Op::Invert: + TU_MATCH_DEF(::HIR::Literal, (val), (e), + ( throw ""; ), + (Integer, m_rv = ::HIR::Literal(~e); ), + (Float, ERROR(node.span(), E0000, "not operator on float in constant"); ) + ) + case ::HIR::ExprNode_UniOp::Op::Negate: + TU_MATCH_DEF(::HIR::Literal, (val), (e), + ( throw ""; ), + (Integer, m_rv = ::HIR::Literal(-e); ), + (Float, m_rv = ::HIR::Literal(-e); ) + ) + } } void visit(::HIR::ExprNode_Cast& node) override { - TODO(node.span(), "ExprNode_Cast"); + node.m_value->visit(*this); + //auto val = mv$(m_rv); + //DEBUG("ExprNode_Cast - val = " << val << " as " << node.m_type); } void visit(::HIR::ExprNode_Index& node) override { badnode(node); @@ -182,17 +350,35 @@ namespace { } void visit(::HIR::ExprNode_CallPath& node) override { - ::std::vector<HIR::Literal> arg_vals; - for(const auto& arg : node.m_args) { - arg->visit(*this); - arg_vals.push_back( mv$(m_rv) ); + auto& fcn = get_function(node.span(), m_crate, node.m_path); + // TODO: Set m_const during parse + //if( ! fcn.m_const ) { + // ERROR(node.span(), E0000, "Calling non-const function in const context - " << node.m_path); + //} + if( fcn.m_args.size() != node.m_args.size() ) { + ERROR(node.span(), E0000, "Incorrect argument count for " << node.m_path); + } + for(unsigned int i = 0; i < fcn.m_args.size(); i ++ ) + { + const auto& pattern = fcn.m_args[i].first; + node.m_args[i]->visit(*this); + auto arg_val = mv$(m_rv); + TU_IFLET(::HIR::Pattern::Data, pattern.m_data, Any, e, + m_values.push_back( ::std::make_pair(pattern.m_binding.m_name, mv$(arg_val)) ); + ) + else { + ERROR(node.span(), E0000, "Constant functions can't have destructuring pattern argments"); + } } - auto& fcn = get_function(node.span(), m_crate, node.m_path); - if( ! fcn.m_const ) { - ERROR(node.span(), E0000, "Calling non-const function in const context"); + const_cast<HIR::ExprNode&>(*fcn.m_code).visit( *this ); + assert( ! m_rv.is_Invalid() ); + //TODO(node.span(), "exec const fn - " << node.m_path); + + for(unsigned int i = 0; i < fcn.m_args.size(); i ++ ) + { + m_values.pop_back(); } - TODO(node.span(), "exec const fn - " << node.m_path); } void visit(::HIR::ExprNode_CallValue& node) override { badnode(node); @@ -226,20 +412,85 @@ namespace { ) } void visit(::HIR::ExprNode_PathValue& node) override { - TODO(node.span(), "ExprNode_PathValue"); + const auto& c = get_constant(node.span(), m_crate, node.m_path); + if( c.m_value_res.is_Invalid() ) { + const_cast<HIR::ExprNode&>(*c.m_value).visit(*this); + } + else { + m_rv = clone_literal(c.m_value_res); + } } void visit(::HIR::ExprNode_Variable& node) override { - TODO(node.span(), "ExprNode_Variable"); + for(auto it = m_values.rbegin(); it != m_values.rend(); ++it) + { + if( it->first == node.m_name) { + TU_MATCH_DEF(::HIR::Literal, (it->second), (e), + ( + m_rv = mv$(it->second); + ), + (Integer, + m_rv = ::HIR::Literal(e); + ), + (Float, + m_rv = ::HIR::Literal(e); + ) + ) + return; + } + } + ERROR(node.span(), E0000, "Couldn't find variable " << node.m_name); } void visit(::HIR::ExprNode_StructLiteral& node) override { - TODO(node.span(), "ExprNode_StructLiteral"); + const auto& str = get_struct(node.span(), m_crate, node.m_path.m_path); + const auto& fields = str.m_data.as_Named(); + + ::std::vector< ::HIR::Literal> vals; + if( node.m_base_value ) { + node.m_base_value->visit(*this); + auto base_val = mv$(m_rv); + if( !base_val.is_List() || base_val.as_List().size() != fields.size() ) { + BUG(node.span(), "Struct literal base value had an incorrect field count"); + } + vals = mv$(base_val.as_List()); + } + else { + vals.resize( fields.size() ); + } + for( const auto& val_set : node.m_values ) { + unsigned int idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& v) { return v.first == val_set.first; } ) - fields.begin(); + if( idx == fields.size() ) { + ERROR(node.span(), E0000, "Field name " << val_set.first << " isn't a member of " << node.m_path); + } + val_set.second->visit(*this); + vals[idx] = mv$(m_rv); + } + for( unsigned int i = 0; i < vals.size(); i ++ ) { + const auto& val = vals[i]; + if( val.is_Invalid() ) { + ERROR(node.span(), E0000, "Field " << fields[i].first << " wasn't set"); + } + } + + m_rv = ::HIR::Literal::make_List(mv$(vals)); } void visit(::HIR::ExprNode_Tuple& node) override { - TODO(node.span(), "ExprNode_Tuple"); + ::std::vector< ::HIR::Literal> vals; + for(const auto& vn : node.m_vals ) { + vn->visit(*this); + assert( !m_rv.is_Invalid() ); + vals.push_back( mv$(m_rv) ); + } + m_rv = ::HIR::Literal::make_List(mv$(vals)); } void visit(::HIR::ExprNode_ArrayList& node) override { - TODO(node.span(), "ExprNode_ArrayList"); + ::std::vector< ::HIR::Literal> vals; + for(const auto& vn : node.m_vals ) { + vn->visit(*this); + assert( !m_rv.is_Invalid() ); + vals.push_back( mv$(m_rv) ); + } + m_rv = ::HIR::Literal::make_List(mv$(vals)); } void visit(::HIR::ExprNode_ArraySized& node) override { TODO(node.span(), "ExprNode_ArraySized"); @@ -288,7 +539,12 @@ namespace { void visit_constant(::HIR::Constant& item) override { item.m_value_res = evaluate_constant(m_crate, *item.m_value); - DEBUG("constant = " << item.m_value_res); + DEBUG("constant: " << item.m_type << " = " << item.m_value_res); + } + void visit_static(::HIR::Static& item) override + { + item.m_value_res = evaluate_constant(m_crate, *item.m_value); + DEBUG("static: " << item.m_type << " = " << item.m_value_res); } void visit_expr(::HIR::ExprPtr& expr) override { diff --git a/src/hir_conv/expand_type.cpp b/src/hir_conv/expand_type.cpp index 7e47b3a3..6112e67d 100644 --- a/src/hir_conv/expand_type.cpp +++ b/src/hir_conv/expand_type.cpp @@ -103,7 +103,7 @@ public: void visit(::HIR::ExprNode_CallPath& node) override { - upper_visitor.visit_path(node.m_path); + upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::VALUE); ::HIR::ExprVisitorDef::visit(node); } void visit(::HIR::ExprNode_CallMethod& node) override diff --git a/src/hir_conv/main_bindings.hpp b/src/hir_conv/main_bindings.hpp index 286b7d9d..fc288975 100644 --- a/src/hir_conv/main_bindings.hpp +++ b/src/hir_conv/main_bindings.hpp @@ -6,5 +6,6 @@ namespace HIR { class Crate; }; +extern void ConvertHIR_ResolveUFCS(::HIR::Crate& crate); extern void ConvertHIR_ExpandAliases(::HIR::Crate& crate); extern void ConvertHIR_ConstantEvaluate(::HIR::Crate& hir_crate); diff --git a/src/hir_conv/resolve_ufcs.cpp b/src/hir_conv/resolve_ufcs.cpp new file mode 100644 index 00000000..6e61e8c4 --- /dev/null +++ b/src/hir_conv/resolve_ufcs.cpp @@ -0,0 +1,217 @@ +/* + * Resolve unkown UFCS traits into inherent or trait + * + * HACK - Will likely be replaced with a proper typeck pass + */ +#include "main_bindings.hpp" +#include <hir/hir.hpp> +#include <hir/expr.hpp> +#include <hir/visitor.hpp> + +namespace { + class Visitor: + public ::HIR::Visitor + { + const ::HIR::Crate& m_crate; + + ::std::vector< ::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > > m_traits; + + public: + Visitor(const ::HIR::Crate& crate): + m_crate(crate) + {} + + void visit_module(::HIR::Module& mod) override + { + for( const auto& trait_path : mod.m_traits ) + m_traits.push_back( ::std::make_pair( &trait_path, &this->find_trait(trait_path) ) ); + ::HIR::Visitor::visit_module(mod); + for(unsigned int i = 0; i < mod.m_traits.size(); i ++ ) + m_traits.pop_back(); + } + + + void visit_expr(::HIR::ExprPtr& expr) override + { + struct ExprVisitor: + public ::HIR::ExprVisitorDef + { + Visitor& upper_visitor; + + ExprVisitor(Visitor& uv): + upper_visitor(uv) + {} + + void visit(::HIR::ExprNode_Let& node) override + { + upper_visitor.visit_type(node.m_type); + ::HIR::ExprVisitorDef::visit(node); + } + void visit(::HIR::ExprNode_Cast& node) override + { + upper_visitor.visit_type(node.m_type); + ::HIR::ExprVisitorDef::visit(node); + } + + void visit(::HIR::ExprNode_CallPath& node) override + { + upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::VALUE); + ::HIR::ExprVisitorDef::visit(node); + } + void visit(::HIR::ExprNode_CallMethod& node) override + { + upper_visitor.visit_path_params(node.m_params); + ::HIR::ExprVisitorDef::visit(node); + } + + void visit(::HIR::ExprNode_Closure& node) override + { + upper_visitor.visit_type(node.m_return); + for(auto& arg : node.m_args) { + upper_visitor.visit_pattern(arg.first); + upper_visitor.visit_type(arg.second); + } + ::HIR::ExprVisitorDef::visit(node); + } + + void visit(::HIR::ExprNode_Block& node) override + { + for( const auto& trait_path : node.m_traits ) + upper_visitor.m_traits.push_back( ::std::make_pair( &trait_path, &upper_visitor.find_trait(trait_path) ) ); + ::HIR::ExprVisitorDef::visit(node); + for(unsigned int i = 0; i < node.m_traits.size(); i ++ ) + upper_visitor.m_traits.pop_back(); + } + }; + + if( &*expr != nullptr ) + { + ExprVisitor v { *this }; + (*expr).visit(v); + } + } + + void visit_path(::HIR::Path& p, ::HIR::Visitor::PathContext pc) override + { + TU_IFLET(::HIR::Path::Data, p.m_data, UfcsUnknown, e, + DEBUG("UfcsUnknown - p=" << p); + // 1. Search all impls of in-scope traits for this method on this type + for( const auto& trait_info : m_traits ) + { + const auto& trait_path = *trait_info.first; + const auto& trait = *trait_info.second; + + switch( pc ) + { + case ::HIR::Visitor::PathContext::VALUE: { + auto it1 = trait.m_values.find( e.item ); + if( it1 == trait.m_values.end() ) { + continue ; + } + // Found it, just keep going (don't care about details here) + } break; + case ::HIR::Visitor::PathContext::TYPE: { + auto it1 = trait.m_types.find( e.item ); + if( it1 == trait.m_types.end() ) { + continue ; + } + // Found it, just keep going (don't care about details here) + } break; + } + + auto trait_impl_it = m_crate.m_trait_impls.equal_range( trait_path ); + if( trait_impl_it.first == trait_impl_it.second ) { + continue ; + } + for( auto it = trait_impl_it.first; it != trait_impl_it.second; it ++ ) + { + const auto& impl = it->second; + if( !impl.matches_type(*e.type) ) { + continue ; + } + + auto new_data = ::HIR::Path::Data::make_UfcsKnown({ mv$(e.type), ::HIR::GenericPath(trait_path), mv$(e.item), mv$(e.params)} ); + p.m_data = mv$(new_data); + DEBUG("- Resolved, replace with " << p); + return ; + } + } + + // 2. No trait matched, search for inherent impl + for( const auto& impl : m_crate.m_type_impls ) + { + if( !impl.matches_type(*e.type) ) { + continue ; + } + DEBUG("- matched impl " << *e.type); + // TODO: Search for item + switch( pc ) + { + case ::HIR::Visitor::PathContext::VALUE: { + auto it1 = impl.m_methods.find( e.item ); + if( it1 == impl.m_methods.end() ) { + continue ; + } + // Found it, just keep going (don't care about details here) + } break; + case ::HIR::Visitor::PathContext::TYPE: { + continue ; + // Found it, just keep going (don't care about details here) + } break; + } + + auto new_data = ::HIR::Path::Data::make_UfcsInherent({ mv$(e.type), mv$(e.item), mv$(e.params)} ); + p.m_data = mv$(new_data); + DEBUG("- Resolved, replace with " << p); + return ; + } + + // Couldn't find it + DEBUG("Failed to find impl with '" << e.item << "' for " << *e.type); + ) + } + + + const ::HIR::Trait& find_trait(const ::HIR::SimplePath& path) const + { + if( path.m_crate_name != "" ) + TODO(Span(), "find_trait in crate"); + + const ::HIR::Module* mod = &m_crate.m_root_module; + for( unsigned int i = 0; i < path.m_components.size() - 1; i ++ ) + { + const auto& pc = path.m_components[i]; + auto it = mod->m_mod_items.find( pc ); + if( it == mod->m_mod_items.end() ) { + BUG(Span(), "Couldn't find component " << i << " of " << path); + } + TU_MATCH_DEF( ::HIR::TypeItem, (it->second->ent), (e2), + ( + BUG(Span(), "Node " << i << " of path " << path << " wasn't a module"); + ), + (Module, + mod = &e2; + ) + ) + } + auto it = mod->m_mod_items.find( path.m_components.back() ); + if( it == mod->m_mod_items.end() ) { + BUG(Span(), "Could not find type name in " << path); + } + + TU_IFLET( ::HIR::TypeItem, it->second->ent, Trait, e, + return e; + ) + else { + BUG(Span(), "Trait path " << path << " didn't point to a trait"); + } + } + }; + +} + +void ConvertHIR_ResolveUFCS(::HIR::Crate& crate) +{ + Visitor exp { crate }; + exp.visit_crate( crate ); +} diff --git a/src/main.cpp b/src/main.cpp index f163e736..bc22654c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -154,6 +154,9 @@ int main(int argc, char *argv[]) CompilePhaseV("Resolve Type Aliases", [&]() {
ConvertHIR_ExpandAliases(*hir_crate);
});
+ CompilePhaseV("Resolve UFCS paths", [&]() {
+ ConvertHIR_ResolveUFCS(*hir_crate);
+ });
CompilePhaseV("Constant Evaluate", [&]() {
ConvertHIR_ConstantEvaluate(*hir_crate);
|