diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/hir/from_ast.cpp | 9 | ||||
-rw-r--r-- | src/hir/generic_params.cpp | 30 | ||||
-rw-r--r-- | src/hir/generic_params.hpp | 18 | ||||
-rw-r--r-- | src/hir/hir.cpp | 16 | ||||
-rw-r--r-- | src/hir/visitor.cpp | 7 | ||||
-rw-r--r-- | src/hir_typeck/expr.cpp | 117 | ||||
-rw-r--r-- | src/parse/root.cpp | 1 |
8 files changed, 170 insertions, 30 deletions
@@ -45,7 +45,7 @@ OBJ += expand/std_prelude.o OBJ += macro_rules/mod.o macro_rules/eval.o macro_rules/parse.o OBJ += resolve/use.o resolve/index.o resolve/absolute.o OBJ += hir/from_ast.o hir/from_ast_expr.o -OBJ += hir/hir.o +OBJ += hir/hir.o hir/generic_params.o OBJ += hir/crate_ptr.o hir/type_ptr.o hir/expr_ptr.o OBJ += hir/type.o hir/path.o hir/expr.o hir/pattern.o OBJ += hir/visitor.o diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index fff4c94a..21c3695d 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -857,10 +857,11 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat if( impl.def().trait().ent.is_valid() ) { - bool is_marker = impl.def().trait().ent.binding().as_Trait().trait_->is_marker(); - auto trait = LowerHIR_GenericPath(impl.def().trait().sp, impl.def().trait().ent); - auto trait_name = mv$(trait.m_path); - auto trait_args = mv$(trait.m_params); + const auto& trait_def = *impl.def().trait().ent.binding().as_Trait().trait_; + bool is_marker = trait_def.is_marker(); + auto trait_path = LowerHIR_GenericPath(impl.def().trait().sp, impl.def().trait().ent); + auto trait_name = mv$(trait_path.m_path); + auto trait_args = mv$(trait_path.m_params); // TODO: Determine if a trait is a marker (i.e. is a OIBIT) diff --git a/src/hir/generic_params.cpp b/src/hir/generic_params.cpp new file mode 100644 index 00000000..b2b72148 --- /dev/null +++ b/src/hir/generic_params.cpp @@ -0,0 +1,30 @@ +/* + */ +#include "generic_params.hpp" + +namespace HIR { + ::std::ostream& operator<<(::std::ostream& os, const ::HIR::GenericParams::PrintArgs& x) + { + if( x.gp.m_lifetimes.size() > 0 || x.gp.m_types.size() > 0 ) + { + os << "<"; + for(const auto& lft : x.gp.m_lifetimes) { + os << "'" << lft << ","; + } + for(const auto& typ : x.gp.m_types) { + os << typ.m_name; + if( ! typ.m_is_sized ) + os << ": ?Sized"; + if( !typ.m_default.m_data.is_Infer() ) + os << " = " << typ.m_default; + os << ","; + } + os << ">"; + } + return os; + } + ::std::ostream& operator<<(::std::ostream& os, const ::HIR::GenericParams::PrintBounds& x) + { + return os; + } +} diff --git a/src/hir/generic_params.hpp b/src/hir/generic_params.hpp index 1fe92163..1870b904 100644 --- a/src/hir/generic_params.hpp +++ b/src/hir/generic_params.hpp @@ -1,6 +1,10 @@ /* */ #pragma once +#include <string> +#include <vector> +#include <iostream> +#include "type.hpp" namespace HIR { @@ -40,6 +44,20 @@ struct GenericParams ::std::vector< ::std::string> m_lifetimes; ::std::vector<GenericBound> m_bounds; + + + struct PrintArgs { + const GenericParams& gp; + PrintArgs(const GenericParams& gp): gp(gp) {} + friend ::std::ostream& operator<<(::std::ostream& os, const PrintArgs& x); + }; + PrintArgs fmt_args() const { return PrintArgs(*this); } + struct PrintBounds { + const GenericParams& gp; + PrintBounds(const GenericParams& gp): gp(gp) {} + friend ::std::ostream& operator<<(::std::ostream& os, const PrintBounds& x); + }; + PrintBounds fmt_bounds() const { return PrintBounds(*this); } }; } // namespace HIR diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index 29d7e975..81a4d488 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -154,11 +154,23 @@ const ::HIR::SimplePath& ::HIR::Crate::get_lang_item_path(const Span& sp, const return lang_index; } else if( ::std::strcmp(name, "unsize") == 0 ) { - static ::HIR::SimplePath lang_unsize {"", {"marker", "Unsize"} }; + static ::HIR::SimplePath lang_unsize { "", {"marker", "Unsize"} }; return lang_unsize; } + else if( ::std::strcmp(name, "add") == 0 ) { + static ::HIR::SimplePath lang_path { "", {"ops", "Add"} }; + return lang_path; + } + else if( ::std::strcmp(name, "ord") == 0 ) { + static ::HIR::SimplePath lang_path { "", {"cmp", "PartialOrd"} }; + return lang_path; + } + else if( ::std::strcmp(name, "eq") == 0 ) { + static ::HIR::SimplePath lang_path { "", {"cmp", "PartialEq"} }; + return lang_path; + } else { - throw ""; + ERROR(sp, E0000, "Unknown language item '" << name << "' encountered"); } } diff --git a/src/hir/visitor.cpp b/src/hir/visitor.cpp index d4eeec50..cb9874c2 100644 --- a/src/hir/visitor.cpp +++ b/src/hir/visitor.cpp @@ -103,7 +103,12 @@ void ::HIR::Visitor::visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR ::HIR::PathChain p { "#impl" }; TRACE_FUNCTION_F("trait_path=" << trait_path); this->visit_params(impl.m_params); - this->visit_path_params(impl.m_trait_args); + // - HACK: Create a generic path to visit (so that proper checks are performed) + { + ::HIR::GenericPath gp { trait_path, mv$(impl.m_trait_args) }; + this->visit_generic_path(gp, PathContext::TRAIT); + impl.m_trait_args = mv$(gp.m_params); + } this->visit_type(impl.m_type); for(auto& ent : impl.m_methods) { diff --git a/src/hir_typeck/expr.cpp b/src/hir_typeck/expr.cpp index 592cc7d4..de0d11e3 100644 --- a/src/hir_typeck/expr.cpp +++ b/src/hir_typeck/expr.cpp @@ -1243,21 +1243,17 @@ namespace { } bool find_trait_impls_crate(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, ::std::function<bool(const ::HIR::PathParams&)> callback) const { - auto its = m_crate.m_trait_impls.equal_range( trait ); - if( its.first != its.second ) - { - for( auto it = its.first; it != its.second; ++ it ) - { - const auto& impl = it->second; - DEBUG("Compare " << type << " and " << impl.m_type); - if( impl.matches_type(type) ) { - if( callback(impl.m_trait_args) ) { - return true; - } - } + return this->m_crate.find_trait_impls(trait, type, [&](const auto& ty)->const auto&{ + if( ty.m_data.is_Infer() ) + return this->get_type(ty); + else + return ty; + }, + [&](const auto& impl) { + DEBUG("[find_trait_impls_crate] Found impl" << impl.m_params.fmt_args() << " " << trait << impl.m_trait_args << " for " << impl.m_type); + return callback(impl.m_trait_args); } - } - return false; + ); } /// Locate the named method by applying auto-dereferencing. /// \return Number of times deref was applied (or ~0 if _ was hit) @@ -1716,6 +1712,20 @@ namespace { const auto& ty_left = this->context.get_type(node.m_left->m_res_type ); const auto& ty_right = this->context.get_type(node.m_right->m_res_type); + // Boolean ops can't be overloaded, and require `bool` on both sides + if( node.m_op == ::HIR::ExprNode_BinOp::Op::BoolAnd || node.m_op == ::HIR::ExprNode_BinOp::Op::BoolOr ) + { + assert(node.m_res_type.m_data.is_Primitive() && node.m_res_type.m_data.as_Primitive() == ::HIR::CoreType::Bool); + this->context.apply_equality( node.span(), node.m_res_type, node.m_left->m_res_type ); + this->context.apply_equality( node.span(), node.m_res_type, node.m_right->m_res_type ); + return ; + } + + // TODO: Inferrence rules when untyped integer literals are in play + // - `impl Add<Foo> for u32` is valid, and makes `1 + Foo` work + // - But `[][0] + Foo` doesn't + // - Adding `impl Add<Foo> for u64` leads to "`Add<Foo>` is not implemented for `i32`" + // - HACK! (kinda?) libcore includes impls of `Add<i32> for i32`, which means that overloads work for inferrence purposes if( ty_left.m_data.is_Primitive() && ty_right.m_data.is_Primitive() ) { const auto& prim_left = ty_left.m_data.as_Primitive(); @@ -1733,12 +1743,8 @@ namespace { } break; - case ::HIR::ExprNode_BinOp::Op::BoolAnd: - case ::HIR::ExprNode_BinOp::Op::BoolOr: - if( prim_left != ::HIR::CoreType::Bool || prim_right != ::HIR::CoreType::Bool ) { - ERROR(node.span(), E0000, "Use of non-boolean in boolean and/or"); - } - break; + case ::HIR::ExprNode_BinOp::Op::BoolAnd: BUG(node.span(), "Encountered BoolAnd in primitive op"); + case ::HIR::ExprNode_BinOp::Op::BoolOr: BUG(node.span(), "Encountered BoolOr in primitive op"); case ::HIR::ExprNode_BinOp::Op::Add: case ::HIR::ExprNode_BinOp::Op::Sub: @@ -1808,7 +1814,76 @@ namespace { } else { - // TODO: Search for ops trait impl + const char* item_name = nullptr; + bool has_output = true; + switch(node.m_op) + { + case ::HIR::ExprNode_BinOp::Op::CmpEqu: item_name = "eq"; has_output = false; break; + case ::HIR::ExprNode_BinOp::Op::CmpNEqu: item_name = "eq"; has_output = false; break; + case ::HIR::ExprNode_BinOp::Op::CmpLt: item_name = "ord"; has_output = false; break; + case ::HIR::ExprNode_BinOp::Op::CmpLtE: item_name = "ord"; has_output = false; break; + case ::HIR::ExprNode_BinOp::Op::CmpGt: item_name = "ord"; has_output = false; break; + case ::HIR::ExprNode_BinOp::Op::CmpGtE: item_name = "ord"; has_output = false; break; + case ::HIR::ExprNode_BinOp::Op::BoolAnd: BUG(node.span(), "Encountered BoolAnd in overload search"); + case ::HIR::ExprNode_BinOp::Op::BoolOr: BUG(node.span(), "Encountered BoolOr in overload search"); + + case ::HIR::ExprNode_BinOp::Op::Add: item_name = "add"; break; + case ::HIR::ExprNode_BinOp::Op::Sub: item_name = "sub"; break; + case ::HIR::ExprNode_BinOp::Op::Mul: item_name = "mul"; break; + case ::HIR::ExprNode_BinOp::Op::Div: item_name = "div"; break; + case ::HIR::ExprNode_BinOp::Op::Mod: item_name = "rem"; break; + + case ::HIR::ExprNode_BinOp::Op::And: item_name = "bit_and"; break; + case ::HIR::ExprNode_BinOp::Op::Or: item_name = "bit_or"; break; + case ::HIR::ExprNode_BinOp::Op::Xor: item_name = "bit_xor"; break; + + case ::HIR::ExprNode_BinOp::Op::Shr: item_name = "shr"; break; + case ::HIR::ExprNode_BinOp::Op::Shl: item_name = "shl"; break; + } + assert(item_name); + + // Search for ops trait impl + const ::HIR::TraitImpl* impl_ptr = nullptr; + unsigned int count = 0; + const auto& ops_trait = this->context.m_crate.get_lang_item_path(node.span(), item_name); + bool found_exact = this->context.m_crate.find_trait_impls(ops_trait, ty_left, [&](const auto& ty)->const auto&{ + if( ty.m_data.is_Infer() ) + return this->context.get_type(ty); + else + return ty; + }, + [&](const auto& impl) { + assert( impl.m_trait_args.m_types.size() == 1 ); + const auto& arg_type = impl.m_trait_args.m_types[0]; + DEBUG("TODO: Handle operator overload '"<<item_name<<"' - " << arg_type << " == " << ty_right); + // TODO: Filter out completly incompatible implementations (e.g. &-ptr with integers) + if( arg_type == ty_right ) { + impl_ptr = &impl; + return true; + } + count += 1; + return false; + } + ); + // If the above returned success, get output type + if( !found_exact && count == 1 ) { + assert(impl_ptr); + this->context.apply_equality(node.span(), impl_ptr->m_trait_args.m_types[0], ty_right); + } + if( impl_ptr ) { + if( has_output ) + { + const auto& type = impl_ptr->m_types.at("Output"); + DEBUG("TODO: BinOp output = " << type); + } + else + { + this->context.apply_equality(node.span(), node.m_res_type, ::HIR::TypeRef(::HIR::CoreType::Bool)); + } + } + else { + // TODO: Determine if this could ever succeed, and error if not + } } } // - UniOp: Look for overload or primitive diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 847ffa75..5bd32225 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -893,7 +893,6 @@ void Parse_Impl(TokenStream& lex, AST::Module& mod, AST::MetaItems attrs, bool i PUTBACK(tok, lex);
impl_type = Parse_Type(lex, true);
- // TODO: Handle the "impl Any + Send" syntax here
if( GET_TOK(tok, lex) == TOK_RWORD_FOR )
{
|