summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--src/hir/from_ast.cpp9
-rw-r--r--src/hir/generic_params.cpp30
-rw-r--r--src/hir/generic_params.hpp18
-rw-r--r--src/hir/hir.cpp16
-rw-r--r--src/hir/visitor.cpp7
-rw-r--r--src/hir_typeck/expr.cpp117
-rw-r--r--src/parse/root.cpp1
8 files changed, 170 insertions, 30 deletions
diff --git a/Makefile b/Makefile
index 8cd126c6..946bfba8 100644
--- a/Makefile
+++ b/Makefile
@@ -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 )
{