diff options
-rw-r--r-- | src/hir/type.cpp | 139 | ||||
-rw-r--r-- | src/hir/type.hpp | 8 | ||||
-rw-r--r-- | src/hir_typeck/expr.cpp | 45 |
3 files changed, 179 insertions, 13 deletions
diff --git a/src/hir/type.cpp b/src/hir/type.cpp index acd5ab1c..a3ed3597 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -325,3 +325,142 @@ namespace { ) throw ""; } +::HIR::TypeRef::Compare HIR::TypeRef::compare_with_paceholders(const Span& sp, const ::HIR::TypeRef& x, ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> resolve_placeholder) const +{ + assert( !this->m_data.is_Infer() ); + const auto& right = (x.m_data.is_Infer() ? resolve_placeholder(x) : (x.m_data.is_Generic() ? resolve_placeholder(x) : x)); + + // If righthand side is infer, it's a fuzzy match (or not a match) + TU_IFLET(::HIR::TypeRef::Data, right.m_data, Infer, e, + switch( e.ty_class ) + { + case ::HIR::InferClass::None: + return Compare::Fuzzy; + case ::HIR::InferClass::Integer: + TU_IFLET( ::HIR::TypeRef::Data, this->m_data, Primitive, le, + switch(le) + { + case ::HIR::CoreType::I8: case ::HIR::CoreType::U8: + case ::HIR::CoreType::I16: case ::HIR::CoreType::U16: + case ::HIR::CoreType::I32: case ::HIR::CoreType::U32: + case ::HIR::CoreType::I64: case ::HIR::CoreType::U64: + case ::HIR::CoreType::Isize: case ::HIR::CoreType::Usize: + return Compare::Fuzzy; + default: + return Compare::Unequal; + } + ) + else { + return Compare::Unequal; + } + case ::HIR::InferClass::Float: + TU_IFLET( ::HIR::TypeRef::Data, this->m_data, Primitive, le, + switch(le) + { + case ::HIR::CoreType::F32: + case ::HIR::CoreType::F64: + return Compare::Fuzzy; + default: + return Compare::Unequal; + } + ) + else { + return Compare::Unequal; + } + } + throw ""; + ) + + if( this->m_data.tag() != right.m_data.tag() ) { + return Compare::Unequal; + } + TU_MATCH(::HIR::TypeRef::Data, (this->m_data, right.m_data), (le, re), + (Infer, assert(!"infer");), + (Diverge, + return Compare::Equal; + ), + (Primitive, + return (le == re ? Compare::Equal : Compare::Unequal); + ), + (Path, + if( le.path.m_data.tag() != re.path.m_data.tag() ) + return Compare::Unequal; + TU_MATCH_DEF(::HIR::Path::Data, (le.path.m_data, re.path.m_data), (ple, pre), + ( + TODO(sp, "TypeRef::compare_with_paceholders - non-generic paths"); + ), + (Generic, + if( ple.m_path.m_crate_name != pre.m_path.m_crate_name ) + return Compare::Unequal; + if( ple.m_path.m_components.size() != pre.m_path.m_components.size() ) + return Compare::Unequal; + 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 Compare::Unequal; + } + + auto rv = Compare::Equal; + if( ple.m_params.m_types.size() > 0 || pre.m_params.m_types.size() > 0 ) { + if( ple.m_params.m_types.size() != pre.m_params.m_types.size() ) { + return Compare::Unequal; + } + for( unsigned int i = 0; i < pre.m_params.m_types.size(); i ++ ) + { + auto rv2 = ple.m_params.m_types[i].compare_with_paceholders( sp, pre.m_params.m_types[i], resolve_placeholder ); + if( rv2 == Compare::Unequal ) + return Compare::Unequal; + if( rv2 == Compare::Fuzzy ) + rv = Compare::Fuzzy; + } + } + return rv; + ) + ) + ), + (Generic, + if( le.binding != re.binding ) + return Compare::Unequal; + return Compare::Equal; + ), + (TraitObject, + TODO(sp, "Compare " << *this << " and " << right); + ), + (Array, + if( le.size_val != re.size_val ) + return Compare::Unequal; + return le.inner->compare_with_paceholders(sp, *re.inner, resolve_placeholder); + ), + (Slice, + return le.inner->compare_with_paceholders(sp, *re.inner, resolve_placeholder); + ), + (Tuple, + if( le.size() != re.size() ) + return Compare::Unequal; + auto rv = Compare::Equal; + for( unsigned int i = 0; i < le.size(); i ++ ) + { + auto rv2 = le[i].compare_with_paceholders( sp, re[i], resolve_placeholder ); + if( rv2 == Compare::Unequal ) + return Compare::Unequal; + if( rv2 == Compare::Fuzzy ) + rv = Compare::Fuzzy; + } + return rv; + ), + (Borrow, + if( le.type != re.type ) + return Compare::Unequal; + return le.inner->compare_with_paceholders(sp, *re.inner, resolve_placeholder); + ), + (Pointer, + if( le.type != re.type ) + return Compare::Unequal; + return le.inner->compare_with_paceholders(sp, *re.inner, resolve_placeholder); + ), + (Function, + TODO(sp, "Compare " << *this << " and " << right); + ) + ) + throw ""; +} diff --git a/src/hir/type.hpp b/src/hir/type.hpp index 01254270..75cf4485 100644 --- a/src/hir/type.hpp +++ b/src/hir/type.hpp @@ -169,6 +169,14 @@ public: // Match generics in `this` with types from `x` // Raises a bug against `sp` if there is a form mismatch or `this` has an infer void match_generics(const Span& sp, const ::HIR::TypeRef& x, ::std::function<void(unsigned int, const ::HIR::TypeRef&)> callback) const; + + enum Compare { + Equal, + Fuzzy, + Unequal, + }; + // Compares this type with another, using `resolve_placeholder` to get replacements for generics/infers in `x` + Compare compare_with_paceholders(const Span& sp, const ::HIR::TypeRef& x, ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> resolve_placeholder) const; }; extern ::std::ostream& operator<<(::std::ostream& os, const ::HIR::TypeRef& ty); diff --git a/src/hir_typeck/expr.cpp b/src/hir_typeck/expr.cpp index 06332d49..f044cae8 100644 --- a/src/hir_typeck/expr.cpp +++ b/src/hir_typeck/expr.cpp @@ -1356,6 +1356,15 @@ namespace { } public: + ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> callback_resolve_infer() { + return [&](const auto& ty)->const auto& { + if( ty.m_data.is_Infer() ) + return this->get_type(ty); + else + return ty; + }; + } + unsigned int new_ivar() { m_ivars.push_back( IVar() ); @@ -1924,23 +1933,28 @@ namespace { 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; - }, + bool found_exact = this->context.m_crate.find_trait_impls(ops_trait, ty_left, this->context.callback_resolve_infer(), [&](const auto& impl) { + // TODO: Check how concretely the types matched 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; + // TODO: What if the trait arguments depend on a generic parameter? + if( monomorphise_type_needed(arg_type) ) + TODO(node.span(), "Compare trait type when it contains generics"); + auto cmp = arg_type.compare_with_paceholders(node.span(), ty_right, this->context.callback_resolve_infer()); + if( cmp == ::HIR::TypeRef::Compare::Unequal ) { + return false; } count += 1; - return false; + impl_ptr = &impl; + if( cmp == ::HIR::TypeRef::Compare::Equal ) { + DEBUG("Operator impl exact match - '"<<item_name<<"' - " << arg_type << " == " << ty_right); + return true; + } + else { + DEBUG("Operator fuzzy exact match - '"<<item_name<<"' - " << arg_type << " == " << ty_right); + return false; + } } ); // If the above returned success, get output type @@ -1952,7 +1966,12 @@ namespace { if( has_output ) { const auto& type = impl_ptr->m_types.at("Output"); - DEBUG("TODO: BinOp output = " << type); + if( monomorphise_type_needed(type) ) { + TODO(node.span(), "BinOp output = " << type); + } + else { + this->context.apply_equality(node.span(), node.m_res_type, type); + } } else { |