diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | src/hir_typeck/expr_context.cpp | 1088 | ||||
-rw-r--r-- | src/hir_typeck/expr_simple.cpp | 2020 | ||||
-rw-r--r-- | src/hir_typeck/expr_simple.hpp | 188 | ||||
-rw-r--r-- | src/hir_typeck/helpers.cpp | 48 | ||||
-rw-r--r-- | src/hir_typeck/helpers.hpp | 2 |
6 files changed, 47 insertions, 3303 deletions
@@ -51,9 +51,9 @@ 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 OBJ += hir_conv/expand_type.o hir_conv/constant_evaluation.o hir_conv/resolve_ufcs.o hir_conv/bind.o -OBJ += hir_typeck/outer.o hir_typeck/expr_context.o hir_typeck/helpers.o hir_typeck/static.o +OBJ += hir_typeck/outer.o hir_typeck/helpers.o hir_typeck/static.o OBJ += hir_typeck/expr_visit.o -OBJ += hir_typeck/expr_simple.o hir_typeck/expr_cs.o +OBJ += hir_typeck/expr_cs.o OBJ += hir_typeck/expr_check.o OBJ += hir_expand/closures.o hir_expand/ufcs_everything.o OBJ += mir/mir.o mir/mir_ptr.o diff --git a/src/hir_typeck/expr_context.cpp b/src/hir_typeck/expr_context.cpp deleted file mode 100644 index e1cb6c1f..00000000 --- a/src/hir_typeck/expr_context.cpp +++ /dev/null @@ -1,1088 +0,0 @@ -/* - */ -#include "expr_simple.hpp" -#include <hir/hir.hpp> -#include <algorithm> // std::find_if -#include "helpers.hpp" - -void typeck::TypecheckContext::push_traits(const ::std::vector<::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > >& list) -{ - this->m_traits.insert( this->m_traits.end(), list.begin(), list.end() ); -} -void typeck::TypecheckContext::pop_traits(const ::std::vector<::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > >& list) -{ - this->m_traits.erase( this->m_traits.end() - list.size(), this->m_traits.end() ); -} - -void typeck::TypecheckContext::dump() const -{ - m_ivars.dump(); - DEBUG("TypecheckContext - " << m_locals.size() << " locals"); - unsigned int i = 0; - for(const auto& v : m_locals) { - DEBUG("VAR " << i << " '"<<v.name<<"' = " << v.type); - i ++; - } -} -void typeck::TypecheckContext::compact_ivars() -{ - TRACE_FUNCTION; - - this->m_resolve.compact_ivars(this->m_ivars); - - for(auto& v : m_locals) { - v.type = this->get_type(v.type).clone(); - } -} -bool typeck::TypecheckContext::apply_defaults() -{ - return m_ivars.apply_defaults(); -} - -void typeck::TypecheckContext::add_local(unsigned int index, const ::std::string& name, ::HIR::TypeRef type) -{ - if( m_locals.size() <= index ) - m_locals.resize(index+1); - m_locals[index] = Variable(name, mv$(type)); -} - -const ::HIR::TypeRef& typeck::TypecheckContext::get_var_type(const Span& sp, unsigned int index) -{ - if( index >= m_locals.size() ) { - this->dump(); - BUG(sp, "Local index out of range " << index << " >= " << m_locals.size()); - } - return m_locals.at(index).type; -} - - - - -void typeck::TypecheckContext::add_pattern_binding(const ::HIR::PatternBinding& pb, ::HIR::TypeRef type) -{ - assert( pb.is_valid() ); - switch( pb.m_type ) - { - case ::HIR::PatternBinding::Type::Move: - this->add_local( pb.m_slot, pb.m_name, mv$(type) ); - break; - case ::HIR::PatternBinding::Type::Ref: - this->add_local( pb.m_slot, pb.m_name, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, mv$(type)) ); - break; - case ::HIR::PatternBinding::Type::MutRef: - this->add_local( pb.m_slot, pb.m_name, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Unique, mv$(type)) ); - break; - } -} - -// ------------------------------------------------------------------------------------------------------------------- -// -// ------------------------------------------------------------------------------------------------------------------- -void typeck::TypecheckContext::add_binding(const Span& sp, ::HIR::Pattern& pat, ::HIR::TypeRef& type) -{ - TRACE_FUNCTION_F("pat = " << pat << ", type = " << type); - - if( pat.m_binding.is_valid() ) { - this->add_pattern_binding(pat.m_binding, type.clone()); - // TODO: Can there be bindings within a bound pattern? - //return ; - } - - // - TU_MATCH(::HIR::Pattern::Data, (pat.m_data), (e), - (Any, - // Just leave it, the pattern says nothing - ), - (Value, - //TODO(sp, "Value pattern"); - ), - (Range, - //TODO(sp, "Range pattern"); - ), - (Box, - TODO(sp, "Box pattern"); - ), - (Ref, - if( type.m_data.is_Infer() ) { - this->apply_equality(sp, type, ::HIR::TypeRef::new_borrow( e.type, this->new_ivar_tr() )); - type = this->get_type(type).clone(); - } - // Type must be a &-ptr - TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (te), - ( - ERROR(sp, E0000, "Pattern-type mismatch, expected &-ptr, got " << type); - ), - (Infer, throw "";), - (Borrow, - if( te.type != e.type ) { - ERROR(sp, E0000, "Pattern-type mismatch, expected &-ptr, got " << type); - } - this->add_binding(sp, *e.sub, *te.inner ); - ) - ) - ), - (Tuple, - if( type.m_data.is_Infer() ) { - ::std::vector< ::HIR::TypeRef> sub_types; - for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) - sub_types.push_back( this->new_ivar_tr() ); - this->apply_equality(sp, type, ::HIR::TypeRef( mv$(sub_types) )); - type = this->get_type(type).clone(); - } - TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (te), - ( - ERROR(sp, E0000, "Pattern-type mismatch, expected tuple, got " << type); - ), - (Infer, throw ""; ), - (Tuple, - if( te.size() != e.sub_patterns.size() ) { - ERROR(sp, E0000, "Pattern-type mismatch, expected " << e.sub_patterns.size() << "-tuple, got " << type); - } - for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) - this->add_binding(sp, e.sub_patterns[i], te[i] ); - ) - ) - ), - (Slice, - if( type.m_data.is_Infer() ) { - this->apply_equality(sp, type, ::HIR::TypeRef::new_slice( this->new_ivar_tr() )); - type = this->get_type(type).clone(); - } - TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (te), - ( - ERROR(sp, E0000, "Pattern-type mismatch, expected slice, got " << type); - ), - (Infer, throw""; ), - (Slice, - for(auto& sub : e.sub_patterns) - this->add_binding(sp, sub, *te.inner ); - ) - ) - ), - (SplitSlice, - if( type.m_data.is_Infer() ) { - this->apply_equality(sp, type, ::HIR::TypeRef::new_slice( this->new_ivar_tr() )); - type = this->get_type(type).clone(); - } - TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (te), - ( - ERROR(sp, E0000, "Pattern-type mismatch, expected slice, got " << type); - ), - (Infer, throw ""; ), - (Slice, - for(auto& sub : e.leading) - this->add_binding( sp, sub, *te.inner ); - for(auto& sub : e.trailing) - this->add_binding( sp, sub, *te.inner ); - if( e.extra_bind.is_valid() ) { - this->add_local( e.extra_bind.m_slot, e.extra_bind.m_name, type.clone() ); - } - ) - ) - ), - - // - Enums/Structs - (StructValue, - throw "TODO"; - ), - (StructTuple, - this->add_ivars_params( e.path.m_params ); - if( type.m_data.is_Infer() ) { - this->apply_equality( sp, type, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) ); - type = this->get_type(type).clone(); - } - assert(e.binding); - const auto& str = *e.binding; - // - assert check from earlier pass - assert( str.m_data.is_Tuple() ); - const auto& sd = str.m_data.as_Tuple(); - - TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (te), - ( - ERROR(sp, E0000, "Pattern-type mismatch, expected struct, got " << type); - ), - (Infer, throw ""; ), - (Path, - if( ! te.binding.is_Struct() || te.binding.as_Struct() != &str ) { - ERROR(sp, E0000, "Type mismatch in struct pattern - " << type << " is not " << e.path); - } - // NOTE: Must be Generic for the above to have passed - auto& gp = te.path.m_data.as_Generic(); - - if( e.sub_patterns.size() != sd.size() ) { - ERROR(sp, E0000, "Tuple struct pattern with an incorrect number of fields"); - } - for( unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) - { - const auto& field_type = sd[i].ent; - if( monomorphise_type_needed(field_type) ) { - auto var_ty = monomorphise_type(sp, str.m_params, gp.m_params, field_type); - this->add_binding(sp, e.sub_patterns[i], var_ty); - } - else { - // SAFE: Can't have _ as monomorphise_type_needed checks for that - this->add_binding(sp, e.sub_patterns[i], const_cast< ::HIR::TypeRef&>(field_type)); - } - } - ) - ) - ), - (StructTupleWildcard, - this->add_ivars_params( e.path.m_params ); - if( type.m_data.is_Infer() ) { - this->apply_equality( sp, type, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) ); - type = this->get_type(type).clone(); - } - assert(e.binding); - const auto& str = *e.binding; - // - assert check from earlier pass - assert( str.m_data.is_Tuple() ); - - TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (te), - ( - ERROR(sp, E0000, "Type mismatch in struct pattern - " << type << " is not " << e.path); - ), - (Infer, throw ""; ), - (Path, - if( ! te.binding.is_Struct() || te.binding.as_Struct() != &str ) { - ERROR(sp, E0000, "Type mismatch in struct pattern - " << type << " is not " << e.path); - } - ) - ) - ), - (Struct, - this->add_ivars_params( e.path.m_params ); - if( type.m_data.is_Infer() ) { - this->apply_equality( sp, type, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) ); - type = this->get_type(type).clone(); - } - assert(e.binding); - const auto& str = *e.binding; - // - assert check from earlier pass - assert( str.m_data.is_Named() ); - const auto& sd = str.m_data.as_Named(); - - TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (te), - ( - ERROR(sp, E0000, "Type mismatch in struct pattern - " << type << " is not " << e.path); - ), - (Infer, throw ""; ), - (Path, - if( ! te.binding.is_Struct() || te.binding.as_Struct() != &str ) { - ERROR(sp, E0000, "Type mismatch in struct pattern - " << type << " is not " << e.path); - } - // NOTE: Must be Generic for the above to have passed - auto& gp = te.path.m_data.as_Generic(); - for( auto& field_pat : e.sub_patterns ) - { - unsigned int f_idx = ::std::find_if( sd.begin(), sd.end(), [&](const auto& x){ return x.first == field_pat.first; } ) - sd.begin(); - if( f_idx == sd.size() ) { - ERROR(sp, E0000, "Struct " << e.path << " doesn't have a field " << field_pat.first); - } - const ::HIR::TypeRef& field_type = sd[f_idx].second.ent; - if( monomorphise_type_needed(field_type) ) { - auto field_type_mono = monomorphise_type(sp, str.m_params, gp.m_params, field_type); - this->add_binding(sp, field_pat.second, field_type_mono); - } - else { - // SAFE: Can't have _ as monomorphise_type_needed checks for that - this->add_binding(sp, field_pat.second, const_cast< ::HIR::TypeRef&>(field_type)); - } - } - ) - ) - ), - (EnumValue, - this->add_ivars_params( e.path.m_params ); - TODO(sp, "EnumValue"); - ), - (EnumTuple, - this->add_ivars_params( e.path.m_params ); - if( type.m_data.is_Infer() ) { - auto path = e.path.clone(); - path.m_path.m_components.pop_back(); - - this->apply_equality( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) ); - type = this->get_type(type).clone(); - } - assert(e.binding_ptr); - const auto& enm = *e.binding_ptr; - const auto& var = enm.m_variants[e.binding_idx].second; - assert(var.is_Tuple()); - const auto& tup_var = var.as_Tuple(); - - TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (te), - ( - ERROR(sp, E0000, "Type mismatch in enum pattern - " << type << " is not " << e.path); - ), - (Infer, throw ""; ), - (Path, - if( ! te.binding.is_Enum() || te.binding.as_Enum() != &enm ) { - ERROR(sp, E0000, "Type mismatch in enum pattern - " << type << " is not " << e.path); - } - // NOTE: Must be Generic for the above to have passed - auto& gp = te.path.m_data.as_Generic(); - if( e.sub_patterns.size() != tup_var.size() ) { - ERROR(sp, E0000, "Enum pattern with an incorrect number of fields - " << e.path << " - expected " << tup_var.size() << ", got " << e.sub_patterns.size()); - } - for( unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) - { - if( monomorphise_type_needed(tup_var[i].ent) ) { - auto var_ty = monomorphise_type(sp, enm.m_params, gp.m_params, tup_var[i].ent); - this->add_binding(sp, e.sub_patterns[i], var_ty); - } - else { - // SAFE: Can't have a _ (monomorphise_type_needed checks for that) - this->add_binding(sp, e.sub_patterns[i], const_cast< ::HIR::TypeRef&>(tup_var[i].ent)); - } - } - ) - ) - ), - (EnumTupleWildcard, - this->add_ivars_params( e.path.m_params ); - if( type.m_data.is_Infer() ) { - auto path = e.path.clone(); - path.m_path.m_components.pop_back(); - - this->apply_equality( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) ); - type = this->get_type(type).clone(); - } - assert(e.binding_ptr); - const auto& enm = *e.binding_ptr; - const auto& var = enm.m_variants[e.binding_idx].second; - assert(var.is_Tuple()); - - TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (te), - ( - ERROR(sp, E0000, "Type mismatch in enum pattern - " << type << " is not " << e.path); - ), - (Infer, throw ""; ), - (Path, - if( ! te.binding.is_Enum() || te.binding.as_Enum() != &enm ) { - ERROR(sp, E0000, "Type mismatch in enum pattern - " << type << " is not " << e.path); - } - ) - ) - ), - (EnumStruct, - this->add_ivars_params( e.path.m_params ); - if( type.m_data.is_Infer() ) { - auto path = e.path.clone(); - path.m_path.m_components.pop_back(); - - this->apply_equality( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) ); - type = this->get_type(type).clone(); - } - assert(e.binding_ptr); - const auto& enm = *e.binding_ptr; - const auto& var = enm.m_variants[e.binding_idx].second; - assert(var.is_Struct()); - const auto& tup_var = var.as_Struct(); - - TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (te), - ( - ERROR(sp, E0000, "Type mismatch in enum pattern - " << type << " is not " << e.path); - ), - (Infer, throw ""; ), - (Path, - if( ! te.binding.is_Enum() || te.binding.as_Enum() != &enm ) { - ERROR(sp, E0000, "Type mismatch in enum pattern - " << type << " is not " << e.path); - } - // NOTE: Must be Generic for the above to have passed - auto& gp = te.path.m_data.as_Generic(); - - for( auto& field_pat : e.sub_patterns ) - { - unsigned int f_idx = ::std::find_if( tup_var.begin(), tup_var.end(), [&](const auto& x){ return x.first == field_pat.first; } ) - tup_var.begin(); - if( f_idx == tup_var.size() ) { - ERROR(sp, E0000, "Enum variant " << e.path << " doesn't have a field " << field_pat.first); - } - const ::HIR::TypeRef& field_type = tup_var[f_idx].second.ent; - if( monomorphise_type_needed(field_type) ) { - auto field_type_mono = monomorphise_type(sp, enm.m_params, gp.m_params, field_type); - this->add_binding(sp, field_pat.second, field_type_mono); - } - else { - // SAFE: Can't have _ as monomorphise_type_needed checks for that - this->add_binding(sp, field_pat.second, const_cast< ::HIR::TypeRef&>(field_type)); - } - } - ) - ) - ) - ) -} - - -// ------------------------------------------------------------------------------------------------------------------- -// -// ------------------------------------------------------------------------------------------------------------------- -void typeck::TypecheckContext::apply_pattern(const ::HIR::Pattern& pat, ::HIR::TypeRef& type) -{ - static Span _sp; - const Span& sp = _sp; - - auto& ty = this->get_type(type); - - TU_MATCH(::HIR::Pattern::Data, (pat.m_data), (e), - (Any, - // Just leave it, the pattern says nothing about the type - ), - (Value, - //TODO(sp, "Value pattern"); - ), - (Range, - //TODO(sp, "Range pattern"); - ), - // - Pointer destructuring - (Box, - // Type must be box-able - //TODO(sp, "Box patterns"); - ), - (Ref, - if( ty.m_data.is_Infer() ) { - BUG(sp, "Infer type hit that should already have been fixed"); - } - // Type must be a &-ptr - TU_MATCH_DEF(::HIR::TypeRef::Data, (ty.m_data), (te), - ( - // TODO: Type mismatch - ), - (Infer, throw "";), - (Borrow, - if( te.type != e.type ) { - // TODO: Type mismatch - } - this->apply_pattern( *e.sub, *te.inner ); - ) - ) - ), - (Tuple, - if( ty.m_data.is_Infer() ) { - BUG(sp, "Infer type hit that should already have been fixed"); - } - TU_MATCH_DEF(::HIR::TypeRef::Data, (ty.m_data), (te), - ( - // TODO: Type mismatch - ), - (Infer, throw "";), - (Tuple, - if( te.size() != e.sub_patterns.size() ) { - // TODO: Type mismatch - } - for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) - this->apply_pattern( e.sub_patterns[i], te[i] ); - ) - ) - ), - // --- Slices - (Slice, - if( ty.m_data.is_Infer() ) { - BUG(sp, "Infer type hit that should already have been fixed"); - } - TU_MATCH_DEF(::HIR::TypeRef::Data, (ty.m_data), (te), - ( - // TODO: Type mismatch - ), - (Infer, throw "";), - (Slice, - for(const auto& sp : e.sub_patterns ) - this->apply_pattern( sp, *te.inner ); - ) - ) - ), - (SplitSlice, - if( ty.m_data.is_Infer() ) { - BUG(sp, "Infer type hit that should already have been fixed"); - } - TU_MATCH_DEF(::HIR::TypeRef::Data, (ty.m_data), (te), - ( - // TODO: Type mismatch - ), - (Infer, throw "";), - (Slice, - for(const auto& sp : e.leading) - this->apply_pattern( sp, *te.inner ); - for(const auto& sp : e.trailing) - this->apply_pattern( sp, *te.inner ); - // TODO: extra_bind? (see comment at start of function) - ) - ) - ), - - // - Enums/Structs - (StructValue, - throw "TODO"; - ), - (StructTuple, - if( ty.m_data.is_Infer() ) { - ty.m_data = ::HIR::TypeRef::Data::make_Path( {e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)} ); - this->mark_change(); - } - - TU_MATCH_DEF(::HIR::TypeRef::Data, (ty.m_data), (te), - ( - // TODO: Type mismatch - ), - (Infer, throw "";), - (Path, - // TODO: Does anything need to happen here? This can only introduce equalities? - ) - ) - ), - (StructTupleWildcard, - ), - (Struct, - if( ty.m_data.is_Infer() ) { - //TODO: Does this lead to issues with generic parameters? - ty.m_data = ::HIR::TypeRef::Data::make_Path( {e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)} ); - this->mark_change(); - } - - TU_MATCH_DEF(::HIR::TypeRef::Data, (ty.m_data), (te), - ( - // TODO: Type mismatch - ), - (Infer, throw "";), - (Path, - // TODO: Does anything need to happen here? This can only introduce equalities? - ) - ) - ), - (EnumValue, - ), - (EnumTuple, - if( ty.m_data.is_Infer() ) { - TODO(sp, "EnumTuple - infer"); - this->mark_change(); - } - - TU_MATCH_DEF(::HIR::TypeRef::Data, (ty.m_data), (te), - ( - // TODO: Type mismatch - ), - (Infer, throw "";), - (Path, - ) - ) - ), - (EnumTupleWildcard, - ), - (EnumStruct, - if( ty.m_data.is_Infer() ) { - TODO(sp, "EnumStruct - infer"); - this->mark_change(); - } - - TU_MATCH_DEF(::HIR::TypeRef::Data, (ty.m_data), (te), - ( - // TODO: Type mismatch - ), - (Infer, throw "";), - (Path, - ) - ) - ) - ) -} - -// ------------------------------------------------------------------------------------------------------------------- -// -// ------------------------------------------------------------------------------------------------------------------- -const ::HIR::TypeRef& typeck::TypecheckContext::expand_associated_types_to(const Span& sp, const ::HIR::TypeRef& t, ::HIR::TypeRef& tmp_t) const -{ - TU_IFLET(::HIR::TypeRef::Data, t.m_data, Path, e, - if( e.path.m_data.is_Generic() ) - return t; - else if( !e.binding.is_Unbound() ) { - return t; - } - else { - // HACK! Run twice, to expand deeper. - // - Should this recurse itself when it resolves? - tmp_t = this->expand_associated_types(sp, this->expand_associated_types(sp, t.clone())); - DEBUG("Expanded " << t << " into " << tmp_t); - return tmp_t; - } - ) - else { - return t; - } -} - -void typeck::TypecheckContext::apply_equality(const Span& sp, const ::HIR::TypeRef& left, t_cb_generic cb_left, const ::HIR::TypeRef& right, t_cb_generic cb_right, ::HIR::ExprNodeP* node_ptr_ptr) -{ - TRACE_FUNCTION_F(left << ", " << right); - assert( ! left.m_data.is_Infer() || left.m_data.as_Infer().index != ~0u ); - assert( !right.m_data.is_Infer() || right.m_data.as_Infer().index != ~0u ); - // - Convert left/right types into resolved versions (either root ivar, or generic replacement) - const auto& l_t1 = left .m_data.is_Generic() ? cb_left (left ) : this->get_type(left ); - const auto& r_t1 = right.m_data.is_Generic() ? cb_right(right) : this->get_type(right); - if( l_t1 == r_t1 ) { - DEBUG(l_t1 << " == " << r_t1); - return ; - } - - ::HIR::TypeRef left_tmp; - const auto& l_t = this->expand_associated_types_to(sp, l_t1, left_tmp); - ::HIR::TypeRef right_tmp; - const auto& r_t = this->expand_associated_types_to(sp, r_t1, right_tmp); - if( l_t == r_t ) { - DEBUG(l_t << " == " << r_t); - return ; - } - - if( /*l_t.m_data.is_Diverge() ||*/ r_t.m_data.is_Diverge() ) { - DEBUG("Refusing to unify with !"); - return ; - } - if( l_t.m_data.is_Diverge() ) { - // TODO: Error if the right type isn't infer - } - - DEBUG("- l_t = " << l_t << ", r_t = " << r_t); - TU_IFLET(::HIR::TypeRef::Data, r_t.m_data, Infer, r_e, - TU_IFLET(::HIR::TypeRef::Data, l_t.m_data, Infer, l_e, - // If both are infer, unify the two ivars (alias right to point to left) - this->ivar_unify(l_e.index, r_e.index); - ) - else { - // Righthand side is infer, alias it to the left - // TODO: that `true` should be `false` if the callback isn't unity (for bug checking) - this->set_ivar_to(r_e.index, this->expand_associated_types(sp, monomorphise_type_with(sp, left, cb_left, true))); - } - ) - else { - TU_IFLET(::HIR::TypeRef::Data, l_t.m_data, Infer, l_e, - // Lefthand side is infer, alias it to the right - // TODO: that `true` should be `false` if the callback isn't unity (for bug checking) - this->set_ivar_to(l_e.index, this->expand_associated_types(sp, monomorphise_type_with(sp, right, cb_right, true))); - ) - else { - // If generic replacement happened, clear the callback - if( left.m_data.is_Generic() || left.m_data.is_Infer() ) { - cb_left = [](const auto& x)->const auto&{return x;}; - } - if( right.m_data.is_Generic() || right.m_data.is_Infer() ) { - cb_right = [](const auto& x)->const auto&{return x;}; - } - - // Neither are infer - both should be of the same form - // - If either side is `!`, return early (diverging type, matches anything) - if( l_t.m_data.is_Diverge() || r_t.m_data.is_Diverge() ) { - // TODO: Should diverge check be done elsewhere? what happens if a ! ends up in an ivar? - return ; - } - - // Helper function for Path and TraitObject - auto equality_typeparams = [&](const ::HIR::PathParams& l, const ::HIR::PathParams& r) { - if( l.m_types.size() != r.m_types.size() ) { - ERROR(sp, E0000, "Type mismatch in type params `" << l << "` and `" << r << "`"); - } - for(unsigned int i = 0; i < l.m_types.size(); i ++) - { - this->apply_equality(sp, l.m_types[i], cb_left, r.m_types[i], cb_right, nullptr); - } - }; - - if( l_t.m_data.is_Pointer() && r_t.m_data.is_Borrow() ) { - const auto& l_e = l_t.m_data.as_Pointer(); - const auto& r_e = r_t.m_data.as_Borrow(); - if( l_e.type != r_e.type ) { - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t << " (pointer type mismatch)"); - } - // 1. Equate inner types - this->apply_equality(sp, *l_e.inner, cb_left, *r_e.inner, cb_right, nullptr); - - // 2. If that succeeds, add a coerce - if( node_ptr_ptr != nullptr ) - { - auto& node_ptr = *node_ptr_ptr; - auto span = node_ptr->span(); - // - Override the existing result type (to prevent infinite recursion) - node_ptr->m_res_type = r_t.clone(); - node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Cast( mv$(span), mv$(node_ptr), l_t.clone() )); - //node_ptr->m_res_type = l_t.clone(); // < Set by _Cast - - DEBUG("- Borrow->Pointer cast added - " << l_t << " <- " << r_t); - this->mark_change(); - return ; - } - else - { - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t << " (can't coerce)"); - } - } - - DEBUG("CoerceUnsized - " << this->m_ivars.type_contains_ivars(l_t) << this->m_ivars.type_contains_ivars(r_t) << this->m_ivars.types_equal(l_t, r_t)); - if( !this->m_ivars.type_contains_ivars(l_t) && !this->m_ivars.type_contains_ivars(r_t) && !this->m_ivars.types_equal(l_t, r_t) ) - { - // TODO: If the types are fully known, and not equal. Search for CoerceUnsized - ::HIR::PathParams pp; - pp.m_types.push_back( l_t.clone() ); - bool succ = this->find_trait_impls(sp, this->m_crate.get_lang_item_path(sp, "coerce_unsized"), pp, r_t, [&](const auto& args, const auto& ) { - DEBUG("- Found coerce_unsized from " << l_t << " to " << r_t); - return true; - }); - if( succ ) - { - // TODO: - TODO(sp, "Apply CoerceUnsized - " << l_t << " <- " << r_t); - } - } - - // - If tags don't match, error - if( l_t.m_data.tag() != r_t.m_data.tag() ) { - - // If either side is UFCS, and still contains unconstrained ivars - don't error - struct H { - static bool type_is_free_ufcs(const TypecheckContext& context, const ::HIR::TypeRef& ty) { - TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Path, e, - if( e.path.m_data.is_Generic() ) { - return false; - } - return context.m_ivars.type_contains_ivars(ty); - ) - return false; - } - }; - - if( H::type_is_free_ufcs(*this, l_t) || H::type_is_free_ufcs(*this, r_t) ) { - return ; - } - - // Deref coercions 1 (when a & op is destructured and expected value is the deref) - if( node_ptr_ptr ) - { - auto& node_ptr = *node_ptr_ptr; - - // - If right has a deref chain to left, build it - DEBUG("Trying deref coercion " << l_t << " " << r_t); - if( !l_t.m_data.is_Borrow() && ! this->m_ivars.type_contains_ivars(l_t) && ! this->m_ivars.type_contains_ivars(r_t) ) - { - DEBUG("Trying deref coercion (2)"); - ::HIR::TypeRef tmp_ty; - const ::HIR::TypeRef* out_ty = &r_t; - unsigned int count = 0; - while( (out_ty = this->m_resolve.autoderef(sp, *out_ty, tmp_ty)) ) - { - count += 1; - - if( l_t != *out_ty ) { - TODO(sp, "Deref coercions " << l_t << " <- " << r_t << " (became " << *out_ty << ")"); - } - - while(count --) - { - auto span = node_ptr->span(); - node_ptr->m_res_type = this->new_ivar_tr(); - node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Deref( mv$(span), mv$(node_ptr) )); - } - node_ptr->m_res_type = l_t.clone(); - - this->mark_change(); - return ; - //auto cmp = this->compare_types(left_inner_res, *out_ty); - //if( cmp == ::HIR::Compare::Equal ) { - // - //} - } - } - } - - - // Type error - this->dump(); - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t); - } - TU_MATCH(::HIR::TypeRef::Data, (l_t.m_data, r_t.m_data), (l_e, r_e), - (Infer, - throw ""; - ), - (Diverge, - TODO(sp, "Handle !"); - ), - (Primitive, - if( l_e != r_e ) { - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t); - } - ), - (Path, - if( l_e.path.m_data.tag() != r_e.path.m_data.tag() ) { - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t); - } - TU_MATCH(::HIR::Path::Data, (l_e.path.m_data, r_e.path.m_data), (lpe, rpe), - (Generic, - if( lpe.m_path != rpe.m_path ) { - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t); - } - equality_typeparams(lpe.m_params, rpe.m_params); - ), - (UfcsInherent, - equality_typeparams(lpe.params, rpe.params); - if( lpe.item != rpe.item ) - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t); - this->apply_equality(sp, *lpe.type, cb_left, *rpe.type, cb_right, nullptr); - ), - (UfcsKnown, - equality_typeparams(lpe.trait.m_params, rpe.trait.m_params); - equality_typeparams(lpe.params, rpe.params); - if( lpe.item != rpe.item ) - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t); - this->apply_equality(sp, *lpe.type, cb_left, *rpe.type, cb_right, nullptr); - ), - (UfcsUnknown, - // TODO: If the type is fully known, locate a suitable trait item - equality_typeparams(lpe.params, rpe.params); - if( lpe.item != rpe.item ) - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t); - this->apply_equality(sp, *lpe.type, cb_left, *rpe.type, cb_right, nullptr); - ) - ) - ), - (Generic, - if( l_e.binding != r_e.binding ) { - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t); - } - ), - (TraitObject, - if( l_e.m_trait.m_path.m_path != r_e.m_trait.m_path.m_path ) { - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t); - } - equality_typeparams(l_e.m_trait.m_path.m_params, r_e.m_trait.m_path.m_params); - for(auto it_l = l_e.m_trait.m_type_bounds.begin(), it_r = r_e.m_trait.m_type_bounds.begin(); it_l != l_e.m_trait.m_type_bounds.end(); it_l++, it_r++ ) { - if( it_l->first != it_r->first ) { - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t << " - associated bounds differ"); - } - this->apply_equality(sp, it_l->second, cb_left, it_r->second, cb_right, nullptr); - } - // TODO: Possibly allow inferrence reducing the set? - if( l_e.m_markers.size() != r_e.m_markers.size() ) { - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t << " - trait counts differ"); - } - // TODO: Is this list sorted in any way? (if it's not sorted, this could fail when source does Send+Any instead of Any+Send) - for(unsigned int i = 0; i < l_e.m_markers.size(); i ++ ) - { - auto& l_p = l_e.m_markers[i]; - auto& r_p = r_e.m_markers[i]; - if( l_p.m_path != r_p.m_path ) { - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t); - } - equality_typeparams(l_p.m_params, r_p.m_params); - } - // NOTE: Lifetime is ignored - ), - (Array, - this->apply_equality(sp, *l_e.inner, cb_left, *r_e.inner, cb_right, nullptr); - if( l_e.size_val != r_e.size_val ) { - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t << " - sizes differ"); - } - ), - (Slice, - this->apply_equality(sp, *l_e.inner, cb_left, *r_e.inner, cb_right, nullptr); - ), - (Tuple, - if( l_e.size() != r_e.size() ) { - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t << " - Tuples are of different length"); - } - for(unsigned int i = 0; i < l_e.size(); i ++) - { - this->apply_equality(sp, l_e[i], cb_left, r_e[i], cb_right, nullptr); - } - ), - (Borrow, - // If using `&mut T` where `&const T` is expected - insert a reborrow (&*) - if( l_e.type == ::HIR::BorrowType::Shared && r_e.type == ::HIR::BorrowType::Unique && node_ptr_ptr ) { - this->apply_equality(sp, *l_e.inner, cb_left, *r_e.inner, cb_right, nullptr); - - // Add cast down - auto& node_ptr = *node_ptr_ptr; - - auto span = node_ptr->span(); - // *<inner> - node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Deref(mv$(span), mv$(node_ptr))); - node_ptr->m_res_type = l_e.inner->clone(); - // &*<inner> - node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_UniOp(mv$(span), ::HIR::ExprNode_UniOp::Op::Ref, mv$(node_ptr))); - node_ptr->m_res_type = l_t.clone(); - - this->mark_change(); - return ; - } - - if( l_e.type != r_e.type ) { - // TODO: This could be allowed if left == Shared && right == Unique (reborrowing) - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t << " - Borrow classes differ"); - } - // ------------------ - // Coercions! - // ------------------ - if( node_ptr_ptr != nullptr ) - { - auto& node_ptr = *node_ptr_ptr; - const auto& left_inner_res = this->get_type(*l_e.inner); - const auto& right_inner_res = this->get_type(*r_e.inner); - - // Allow cases where `right`: ::core::marker::Unsize<`left`> - ::HIR::PathParams pp; - pp.m_types.push_back( left_inner_res.clone() ); - bool succ = this->find_trait_impls(sp, this->m_crate.get_lang_item_path(sp, "unsize"), pp, right_inner_res, [&](auto impl, auto match) { - DEBUG("- Found unsizing " << impl); - //return args.m_types[0] == left_inner_res; - return match == ::HIR::Compare::Equal;//args.m_types[0] == left_inner_res; - }); - if( succ ) { - auto span = node_ptr->span(); - node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Unsize( mv$(span), mv$(node_ptr), l_t.clone() )); - node_ptr->m_res_type = l_t.clone(); - - this->mark_change(); - return ; - } - // - If left is a trait object, right can unsize - if( left_inner_res.m_data.is_TraitObject() ) { - // If the righthand side is still an ivar - if( right_inner_res.m_data.is_Infer() ) { - // Assume it's valid for now, and return - return ; - } - - const auto& e = left_inner_res.m_data.as_TraitObject(); - if( right_inner_res.m_data.is_TraitObject() ) { - // TODO: Can Debug+Send be coerced to Debug? - if( left_inner_res != right_inner_res ) { - const auto& lie = left_inner_res .m_data.as_TraitObject(); - const auto& rie = right_inner_res.m_data.as_TraitObject(); - // 1. Check/equate the main trait (NOTE: Eventualy this may be a set of data traits) - if( lie.m_trait.m_path.m_path != rie.m_trait.m_path.m_path ) { - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t << " (trait mismatch)"); - } - equality_typeparams(lie.m_trait.m_path.m_params, rie.m_trait.m_path.m_params); - - // 2. Ensure that the LHS's marker traits are a strict subset of the RHS - // NOTE: This assumes sorting - will false fail if ordering differs - unsigned int r_i = 0; - for(unsigned int l_i = 0; l_i < lie.m_markers.size(); l_i ++) - { - while( r_i < rie.m_markers.size() && rie.m_markers[r_i].m_path != lie.m_markers[l_i].m_path ) { - r_i += 1; - } - if( r_i == rie.m_markers.size() ) { - ERROR(sp, E0000, "Can't coerce between trait objects - " << left_inner_res << " and " << right_inner_res << " (added marker)"); - } - } - // Coercion is possible and valid. - // HACK: Uses _Unsize as a coerce - auto span = node_ptr->span(); - node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Unsize( mv$(span), mv$(node_ptr), l_t.clone() )); - node_ptr->m_res_type = l_t.clone(); - - this->mark_change(); - return ; - } - // - Equal, nothing to do - return ; - } - - // 1. Search for an implementation of the data trait for this type - auto r = this->expand_associated_types(sp, right_inner_res.clone()); - //bool succ = this->find_trait_impls(sp, e.m_trait.m_path.m_path, e.m_trait.m_path.m_params, right_inner_res, [&](const auto& args,const auto& types) { - bool succ = this->find_trait_impls(sp, e.m_trait.m_path.m_path, e.m_trait.m_path.m_params, r, [&](auto impl, auto match) { - return match == ::HIR::Compare::Equal; - }); - if(!succ) { - // XXX: Debugging - Resolves to the correct type in a failing case - //auto ty2 = this->expand_associated_types(sp, this->expand_associated_types(sp, right_inner_res.clone()) ); - ERROR(sp, E0000, "Trait " << e.m_trait << " isn't implemented for " << m_ivars.fmt_type(right_inner_res) << " (converting to TraitObject) - (r="<<r<<")" ); - } - for(const auto& marker : e.m_markers) - { - TODO(sp, "Check for marker trait impls ("<<marker<<") when unsizing to " << left_inner_res << " from " << right_inner_res); - //bool succ = this->find_trait_impls(e.m_trait.m_path, right_inner_res, [&](const auto& args) { - // if( args.m_types.size() > 0 ) - // TODO(sp, "Handle unsizing to traits with params"); - // return true; - // }); - } - for(const auto& assoc : e.m_trait.m_type_bounds) - { - TODO(sp, "Check for associated type ("<<assoc.first<<") validity when unsizing to " << left_inner_res << " from " << right_inner_res); - } - - // Valid unsize, insert unsize operation - auto span = node_ptr->span(); - node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Unsize( mv$(span), mv$(node_ptr), l_t.clone() )); - node_ptr->m_res_type = l_t.clone(); - - this->mark_change(); - return ; - } - // - If left is a slice, right can unsize/deref - if( left_inner_res.m_data.is_Slice() && !right_inner_res.m_data.is_Slice() ) - { - const auto& left_slice = left_inner_res.m_data.as_Slice(); - TU_IFLET(::HIR::TypeRef::Data, right_inner_res.m_data, Array, right_array, - this->apply_equality(sp, *left_slice.inner, cb_left, *right_array.inner, cb_right, nullptr); - auto span = node_ptr->span(); - node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Unsize( mv$(span), mv$(node_ptr), l_t.clone() )); - node_ptr->m_res_type = l_t.clone(); - - this->mark_change(); - return ; - ) - else TU_IFLET(::HIR::TypeRef::Data, right_inner_res.m_data, Generic, right_arg, - TODO(sp, "Search for Unsize bound on generic"); - ) - else - { - // Apply deref coercions - } - } - } - this->apply_equality(sp, *l_e.inner, cb_left, *r_e.inner, cb_right, nullptr); - ), - (Pointer, - // If using `*mut T` where `*const T` is expected - add cast - if( l_e.type == ::HIR::BorrowType::Shared && r_e.type == ::HIR::BorrowType::Unique && node_ptr_ptr ) { - this->apply_equality(sp, *l_e.inner, cb_left, *r_e.inner, cb_right, nullptr); - - // Add cast down - auto& node_ptr = *node_ptr_ptr; - - auto span = node_ptr->span(); - node_ptr->m_res_type = r_t.clone(); - node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Cast( mv$(span), mv$(node_ptr), l_t.clone() )); - node_ptr->m_res_type = l_t.clone(); - - this->mark_change(); - return ; - } - - if( l_e.type != r_e.type ) { - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t << " - Pointer mutability differs"); - } - this->apply_equality(sp, *l_e.inner, cb_left, *r_e.inner, cb_right, nullptr); - ), - (Function, - if( l_e.is_unsafe != r_e.is_unsafe - || l_e.m_abi != r_e.m_abi - || l_e.m_arg_types.size() != r_e.m_arg_types.size() - ) - { - ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t); - } - // NOTE: No inferrence in fn types? Not sure, lazy way is to allow it. - this->apply_equality(sp, *l_e.m_rettype, cb_left, *r_e.m_rettype, cb_right, nullptr); - for(unsigned int i = 0; i < l_e.m_arg_types.size(); i ++ ) { - this->apply_equality(sp, l_e.m_arg_types[i], cb_left, r_e.m_arg_types[i], cb_right, nullptr); - } - ), - (Closure, - TODO(sp, "apply_equality - Closure"); - ) - ) - } - } -} - diff --git a/src/hir_typeck/expr_simple.cpp b/src/hir_typeck/expr_simple.cpp deleted file mode 100644 index 3d5f4e2b..00000000 --- a/src/hir_typeck/expr_simple.cpp +++ /dev/null @@ -1,2020 +0,0 @@ -/* - */ -#include "main_bindings.hpp" -#include <hir/expr.hpp> -#include <hir/hir.hpp> -#include <hir/visitor.hpp> -#include <algorithm> // std::find_if -#include "helpers.hpp" - -#include "expr_visit.hpp" -#include "expr_simple.hpp" - -namespace typeck { - - void check_type_class_primitive(const Span& sp, const ::HIR::TypeRef& type, ::HIR::InferClass ic, ::HIR::CoreType ct) - { - switch(ic) - { - case ::HIR::InferClass::None: - case ::HIR::InferClass::Diverge: - break; - case ::HIR::InferClass::Float: - switch(ct) - { - case ::HIR::CoreType::F32: - case ::HIR::CoreType::F64: - break; - default: - ERROR(sp, E0000, "Type unificiation of integer literal with non-integer - " << type); - } - break; - case ::HIR::InferClass::Integer: - switch(ct) - { - 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: - break; - default: - ERROR(sp, E0000, "Type unificiation of integer literal with non-integer - " << type); - } - break; - } - } - - template<typename T> - void fix_param_count_(const Span& sp, TypecheckContext& context, const T& path, const ::HIR::GenericParams& param_defs, ::HIR::PathParams& params) - { - if( params.m_types.size() == param_defs.m_types.size() ) { - // Nothing to do, all good - return ; - } - - if( params.m_types.size() == 0 ) { - for(const auto& typ : param_defs.m_types) { - (void)typ; - params.m_types.push_back( context.new_ivar_tr() ); - } - } - else if( params.m_types.size() > param_defs.m_types.size() ) { - ERROR(sp, E0000, "Too many type parameters passed to " << path); - } - else { - while( params.m_types.size() < param_defs.m_types.size() ) { - const auto& typ = param_defs.m_types[params.m_types.size()]; - if( typ.m_default.m_data.is_Infer() ) { - ERROR(sp, E0000, "Omitted type parameter with no default in " << path); - } - else { - // TODO: What if this contains a generic param? (is that valid? Self maybe, what about others?) - params.m_types.push_back( typ.m_default.clone() ); - } - } - } - } - void fix_param_count(const Span& sp, TypecheckContext& context, const ::HIR::Path& path, const ::HIR::GenericParams& param_defs, ::HIR::PathParams& params) { - fix_param_count_(sp, context, path, param_defs, params); - } - void fix_param_count(const Span& sp, TypecheckContext& context, const ::HIR::GenericPath& path, const ::HIR::GenericParams& param_defs, ::HIR::PathParams& params) { - fix_param_count_(sp, context, path, param_defs, params); - } - - - - // Enumerate inferrence variables (most of them) in the expression tree - // - // - Any type equalities here are mostly optimisations (as this gets run only once) - // - If ivars can be shared down the tree - good. - class ExprVisitor_Enum: - public ::HIR::ExprVisitorDef - { - TypecheckContext& context; - const ::HIR::TypeRef& ret_type; - public: - ExprVisitor_Enum(TypecheckContext& context, const ::HIR::TypeRef& ret_type): - context(context), - ret_type(ret_type) - { - } - - void visit_node_ptr(::std::unique_ptr< ::HIR::ExprNode>& node_ptr) override { - const auto& node = *node_ptr; - TRACE_FUNCTION_FR(typeid(node).name(), node.m_res_type << " = " << this->context.get_type(node.m_res_type)); - ::HIR::ExprVisitorDef::visit_node_ptr(node_ptr); - } - void visit_node(::HIR::ExprNode& node) override { - this->context.add_ivars(node.m_res_type); - DEBUG(typeid(node).name() << " : " << node.m_res_type); - } - void visit(::HIR::ExprNode_Block& node) override - { - if( node.m_nodes.size() > 0 ) { - auto unit = ::HIR::TypeRef::new_unit(); - for(unsigned int i = 0; i < node.m_nodes.size()-1; i++) { - auto& n = node.m_nodes[i]; - if( dynamic_cast< ::HIR::ExprNode_Block*>(&*n) ) { - this->context.add_ivars(n->m_res_type); - this->context.apply_equality(n->span(), unit, n->m_res_type, &n); - } - } - auto& ln = node.m_nodes.back(); - this->context.add_ivars(ln->m_res_type); - this->context.apply_equality(ln->span(), node.m_res_type, ln->m_res_type, &ln); - } - else { - node.m_res_type = ::HIR::TypeRef::new_unit(); - } - - this->context.push_traits( node.m_traits ); - ::HIR::ExprVisitorDef::visit(node); - this->context.pop_traits( node.m_traits ); - } - void visit(::HIR::ExprNode_Return& node) override - { - this->context.add_ivars( node.m_value->m_res_type ); - this->context.apply_equality(node.span(), this->ret_type, node.m_value->m_res_type, &node.m_value); - ::HIR::ExprVisitorDef::visit(node); - } - - void visit(::HIR::ExprNode_Loop& node) override - { - this->context.add_ivars( node.m_code->m_res_type ); - this->context.apply_equality(node.span(), ::HIR::TypeRef::new_unit(), node.m_code->m_res_type, &node.m_code); - ::HIR::ExprVisitorDef::visit(node); - } - - void visit(::HIR::ExprNode_Let& node) override - { - ::HIR::ExprVisitorDef::visit(node); - TRACE_FUNCTION_F("let " << node.m_pattern << ": " << node.m_type); - - this->context.add_ivars(node.m_type); - - this->context.add_binding(node.span(), node.m_pattern, node.m_type); - } - - void visit(::HIR::ExprNode_Match& node) override - { - TRACE_FUNCTION_F("match ..."); - - this->context.add_ivars(node.m_value->m_res_type); - - for(auto& arm : node.m_arms) - { - DEBUG("ARM " << arm.m_patterns); - for(auto& pat : arm.m_patterns) - { - this->context.add_binding(node.span(), pat, node.m_value->m_res_type); - } - - this->context.add_ivars( arm.m_code->m_res_type ); - this->context.apply_equality(node.span(), node.m_res_type, arm.m_code->m_res_type, &arm.m_code); - } - DEBUG("- match val : " << this->context.get_type(node.m_value->m_res_type)); - ::HIR::ExprVisitorDef::visit(node); - DEBUG("- match val : " << this->context.get_type(node.m_value->m_res_type)); - } - void visit(::HIR::ExprNode_If& node) override - { - node.m_cond->m_res_type = ::HIR::TypeRef( ::HIR::CoreType::Bool ); - this->context.add_ivars( node.m_true->m_res_type ); - if( node.m_false ) { - this->context.add_ivars( node.m_false->m_res_type ); - // NOTE: Removed to work around type inferrence failure in libcore/slice.rs - //this->context.apply_equality(node.span(), node.m_res_type, node.m_true->m_res_type, &node.m_true); - //this->context.apply_equality(node.span(), node.m_res_type, node.m_false->m_res_type, &node.m_false); - } - else { - this->context.apply_equality(node.span(), node.m_res_type, ::HIR::TypeRef::new_unit()); - node.m_true->m_res_type = node.m_res_type.clone(); - } - - ::HIR::ExprVisitorDef::visit(node); - } - - void visit(::HIR::ExprNode_UniOp& node) override - { - ::HIR::ExprVisitorDef::visit(node); - - switch(node.m_op) - { - case ::HIR::ExprNode_UniOp::Op::Ref: - this->context.apply_equality(node.span(), node.m_res_type, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, node.m_value->m_res_type.clone())); - break; - case ::HIR::ExprNode_UniOp::Op::RefMut: - this->context.apply_equality(node.span(), node.m_res_type, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Unique, node.m_value->m_res_type.clone())); - break; - case ::HIR::ExprNode_UniOp::Op::Invert: - break; - case ::HIR::ExprNode_UniOp::Op::Negate: - break; - } - } - - void visit(::HIR::ExprNode_ArraySized& node) override { - if(node.m_size_val == ~0u) { - BUG(node.span(), "sized array literal didn't have its size evaluated"); - } - - ::HIR::ExprVisitorDef::visit(node); - - this->context.apply_equality( node.span(), node.m_size->m_res_type, ::HIR::TypeRef(::HIR::CoreType::Usize) ); - } - void visit(::HIR::ExprNode_Tuple& node) override - { - ::HIR::ExprVisitorDef::visit(node); - - ::std::vector< ::HIR::TypeRef> types; - for( const auto& sn : node.m_vals ) - types.push_back( sn->m_res_type.clone() ); - auto tup_type = ::HIR::TypeRef( ::HIR::TypeRef::Data::make_Tuple(mv$(types)) ); - - this->context.apply_equality(node.span(), node.m_res_type, tup_type); - } - void visit(::HIR::ExprNode_Closure& node) override - { - ::HIR::TypeRef::Data::Data_Closure ty_data; - ty_data.node = &node; - - for(auto& a : node.m_args) { - this->context.add_ivars(a.second); - this->context.add_binding(node.span(), a.first, a.second); - ty_data.m_arg_types.push_back( a.second.clone() ); - } - this->context.add_ivars(node.m_return); - - ty_data.m_rettype = box$( node.m_return.clone() ); - - if( node.m_code->m_res_type == ::HIR::TypeRef() ) { - node.m_code->m_res_type = node.m_return.clone(); - } - else { - this->context.add_ivars( node.m_code->m_res_type ); - this->context.apply_equality( node.span(), node.m_code->m_res_type, node.m_return ); - } - - this->context.apply_equality( node.span(), node.m_res_type, ::HIR::TypeRef( ::HIR::TypeRef::Data::make_Closure(mv$(ty_data)) ) ); - - ::HIR::ExprVisitorDef::visit(node); - } - // - Variable: Bind to same ivar - void visit(::HIR::ExprNode_Variable& node) override - { - TRACE_FUNCTION_F("var #"<<node.m_slot<<" '"<<node.m_name<<"'"); - this->context.apply_equality(node.span(), node.m_res_type, this->context.get_var_type(node.span(), node.m_slot)); - } - - void visit_generic_path(const Span& sp, ::HIR::GenericPath& gp) { - for(auto& ty : gp.m_params.m_types) - this->context.add_ivars(ty); - } - void visit_path(const Span& sp, ::HIR::Path& path) { - TU_MATCH(::HIR::Path::Data, (path.m_data), (e), - (Generic, - this->visit_generic_path(sp, e); - ), - (UfcsKnown, - this->context.add_ivars(*e.type); - this->visit_generic_path(sp, e.trait); - for(auto& ty : e.params.m_types) - this->context.add_ivars(ty); - ), - (UfcsUnknown, - TODO(sp, "Hit a UfcsUnknown (" << path << ") - Is this an error?"); - ), - (UfcsInherent, - this->context.add_ivars(*e.type); - for(auto& ty : e.params.m_types) - this->context.add_ivars(ty); - ) - ) - } - void visit(::HIR::ExprNode_PathValue& node) override { - this->visit_path(node.span(), node.m_path); - ::HIR::ExprVisitorDef::visit(node); - } - void visit(::HIR::ExprNode_CallPath& node) override { - this->visit_path(node.span(), node.m_path); - ::HIR::ExprVisitorDef::visit(node); - } - void visit(::HIR::ExprNode_StructLiteral& node) override { - this->visit_generic_path(node.span(), node.m_path); - ::HIR::ExprVisitorDef::visit(node); - } - void visit(::HIR::ExprNode_TupleVariant& node) override { - this->visit_generic_path(node.span(), node.m_path); - ::HIR::ExprVisitorDef::visit(node); - } - void visit(::HIR::ExprNode_UnitVariant& node) override { - this->visit_generic_path(node.span(), node.m_path); - if( node.m_is_struct ) - { - const auto& str = this->context.m_crate.get_struct_by_path(node.span(), node.m_path.m_path); - fix_param_count(node.span(), this->context, node.m_path, str.m_params, node.m_path.m_params); - auto ty = ::HIR::TypeRef::new_path( node.m_path.clone(), ::HIR::TypeRef::TypePathBinding::make_Struct(&str) ); - this->context.apply_equality(node.span(), node.m_res_type, ty); - } - else - { - auto s_path = node.m_path.m_path; - s_path.m_components.pop_back(); - - const auto& enm = this->context.m_crate.get_enum_by_path(node.span(), s_path); - fix_param_count(node.span(), this->context, node.m_path, enm.m_params, node.m_path.m_params); - - auto ty = ::HIR::TypeRef::new_path( ::HIR::GenericPath(mv$(s_path), node.m_path.m_params.clone()), ::HIR::TypeRef::TypePathBinding::make_Enum(&enm) ); - this->context.apply_equality(node.span(), node.m_res_type, ty); - } - ::HIR::ExprVisitorDef::visit(node); - } - }; - - // Continually run over the expression tree until nothing changes - class ExprVisitor_Run: - public ::HIR::ExprVisitorDef - { - TypecheckContext& context; - ::HIR::ExprNodeP *m_node_ptr_ptr; - public: - ExprVisitor_Run(TypecheckContext& context): - context(context), - m_node_ptr_ptr(nullptr) - { - } - - void visit_node_ptr(::std::unique_ptr< ::HIR::ExprNode>& node_ptr) override { - m_node_ptr_ptr = &node_ptr; - ::HIR::ExprVisitorDef::visit_node_ptr(node_ptr); - m_node_ptr_ptr = nullptr; - } - - // - Block: Ignore all return values except the last one (which is yeilded) - void visit(::HIR::ExprNode_Block& node) override - { - TRACE_FUNCTION_F("{ }"); - this->context.push_traits( node.m_traits ); - if( node.m_nodes.size() ) { - auto& lastnode = node.m_nodes.back(); - this->context.apply_equality(node.span(), node.m_res_type, lastnode->m_res_type, &lastnode); - } - else { - this->context.apply_equality(node.span(), node.m_res_type, ::HIR::TypeRef::new_unit()); - } - ::HIR::ExprVisitorDef::visit(node); - this->context.pop_traits( node.m_traits ); - } - // - Let: Equates inner to outer - void visit(::HIR::ExprNode_Let& node) override - { - TRACE_FUNCTION_F("let " << node.m_pattern << " : " << node.m_type); - if( node.m_value ) { - this->context.apply_equality(node.span(), node.m_type, node.m_value->m_res_type, &node.m_value); - } - - ::HIR::ExprVisitorDef::visit(node); - } - - // - If: Both branches have to agree - void visit(::HIR::ExprNode_If& node) override - { - TRACE_FUNCTION_F("if ..."); - - this->context.apply_equality(node.span(), node.m_res_type, node.m_true->m_res_type, &node.m_true); - if( node.m_false ) { - this->context.apply_equality(node.span(), node.m_res_type, node.m_false->m_res_type, &node.m_false); - } - - ::HIR::ExprVisitorDef::visit(node); - } - // - Match: all branches match - void visit(::HIR::ExprNode_Match& node) override - { - TRACE_FUNCTION_F("match (...: " << this->context.get_type(node.m_value->m_res_type) << ")"); - - for(auto& arm : node.m_arms) - { - DEBUG("ARM " << arm.m_patterns); - for(auto& pat : arm.m_patterns) { - this->context.apply_pattern(/*node.span(),*/ pat, node.m_value->m_res_type); - } - // TODO: Span on the arm - this->context.apply_equality(node.span(), node.m_res_type, arm.m_code->m_res_type, &arm.m_code); - } - ::HIR::ExprVisitorDef::visit(node); - } - // - Assign: both sides equal - void visit(::HIR::ExprNode_Assign& node) override - { - TRACE_FUNCTION_F("... "<<::HIR::ExprNode_Assign::opname(node.m_op)<<"= ..."); - // Plain assignment can't be overloaded, requires equal types - if( node.m_op == ::HIR::ExprNode_Assign::Op::None ) { - this->context.apply_equality(node.span(), - node.m_slot->m_res_type, node.m_value->m_res_type, - &node.m_value - ); - - ::HIR::ExprVisitorDef::visit(node); - } - else { - ::HIR::ExprVisitorDef::visit(node); - - const auto& ty_left = this->context.get_type(node.m_slot->m_res_type ); - const auto& ty_right = this->context.get_type(node.m_value->m_res_type); - - bool isprim_l = ty_left .m_data.is_Primitive() || (ty_left .m_data.is_Infer() && ty_left .m_data.as_Infer().ty_class != ::HIR::InferClass::None); - bool isprim_r = ty_right.m_data.is_Primitive() || (ty_right.m_data.is_Infer() && ty_right.m_data.as_Infer().ty_class != ::HIR::InferClass::None); - // SHORTCUT - If both sides are primitives (either confirmed or literals) - if( isprim_l && isprim_r ) { - // - The only option is for them both to be the same type (because primitives can't have multiple overloads) - // TODO: Check that this operation is valid to peform. (e.g. not doing f32_val <<= f32_val) - // TODO: Aren't the bitwise shift operators valid with any integer type count? - if( node.m_op == ::HIR::ExprNode_Assign::Op::Shr || node.m_op == ::HIR::ExprNode_Assign::Op::Shl ) { - } - else { - this->context.apply_equality(node.span(), node.m_slot->m_res_type, node.m_value->m_res_type); - } - } - // - Only go looking for an impl if the lefthand side is known - else if( ! ty_left.m_data.is_Infer() ) { - const char *lang_item = nullptr; - switch( node.m_op ) - { - case ::HIR::ExprNode_Assign::Op::None: throw ""; - case ::HIR::ExprNode_Assign::Op::Add: lang_item = "add_assign"; break; - case ::HIR::ExprNode_Assign::Op::Sub: lang_item = "sub_assign"; break; - case ::HIR::ExprNode_Assign::Op::Mul: lang_item = "mul_assign"; break; - case ::HIR::ExprNode_Assign::Op::Div: lang_item = "div_assign"; break; - case ::HIR::ExprNode_Assign::Op::Mod: lang_item = "rem_assign"; break; - case ::HIR::ExprNode_Assign::Op::And: lang_item = "bitand_assign"; break; - case ::HIR::ExprNode_Assign::Op::Or : lang_item = "bitor_assign" ; break; - case ::HIR::ExprNode_Assign::Op::Xor: lang_item = "bitxor_assign"; break; - case ::HIR::ExprNode_Assign::Op::Shr: lang_item = "shl_assign"; break; - case ::HIR::ExprNode_Assign::Op::Shl: lang_item = "shr_assign"; break; - } - assert(lang_item); - const auto& trait_path = this->context.m_crate.get_lang_item_path(node.span(), lang_item); - ::HIR::PathParams trait_path_pp; - trait_path_pp.m_types.push_back( ty_right.clone() ); - - - ::HIR::TypeRef possible_right_type; - unsigned int count = 0; - bool rv = this->context.find_trait_impls(node.span(), trait_path,trait_path_pp, ty_left, [&](auto impl, auto ) { - auto impl_right = impl.get_trait_ty_param(0); - assert(impl_right != ::HIR::TypeRef()); - - // NOTE: `find_trait_impls` has already done this (and did it better)! Need to get that info off it - auto cmp = impl_right.compare_with_placeholders(node.span(), ty_right, this->context.callback_resolve_infer()); - if( cmp == ::HIR::Compare::Unequal) - return false; - count += 1; - if( cmp == ::HIR::Compare::Equal ) { - return true; - } - - possible_right_type = mv$(impl_right); - return false; - }); - - if( rv ) { - // True - Concrete impl located, both types should be fully known - } - else if( count > 1 ) { - // Multiple options - Leave as-is - } - else if( count == 1 ) { - // Only possible match, assume it's the correct one. - assert( !possible_right_type.m_data.is_Infer() ); - this->context.apply_equality( node.span(), ty_right, possible_right_type ); - } - else { - // TODO: is this an error? - this->context.dump(); - TODO(node.span(), "Search for implementation of " << trait_path << "<" << ty_right << "> for " << ty_left); - } - } - else { - } - } - } - // - BinOp: Look for overload or primitive - void visit(::HIR::ExprNode_BinOp& node) override - { - const auto& sp = node.span(); - ::HIR::ExprVisitorDef::visit(node); - 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); - const auto& ty_res = this->context.get_type(node.m_res_type); - - TRACE_FUNCTION_FR("... {"<<ty_left<<"} "<<::HIR::ExprNode_BinOp::opname(node.m_op)<<" ...{"<<ty_right<<"}", "BinOp"); - - // 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 ; - } - - struct H { - static bool type_is_num_prim(const ::HIR::TypeRef& ty) { - TU_MATCH_DEF(::HIR::TypeRef::Data, (ty.m_data), (e), - ( - return false; - ), - (Primitive, - switch(e) - { - case ::HIR::CoreType::Str: - case ::HIR::CoreType::Char: - case ::HIR::CoreType::Bool: - return false; - default: - return true; - } - ), - (Infer, - switch(e.ty_class) - { - case ::HIR::InferClass::None: - case ::HIR::InferClass::Diverge: - return false; - case ::HIR::InferClass::Integer: - case ::HIR::InferClass::Float: - return true; - } - ) - ) - return false; - } - }; - - // Result is known to be a primitive, and left is infer - if( H::type_is_num_prim(ty_res) && H::type_is_num_prim(ty_left) ) { - // If the op is a aritmatic op, and the left is a primtive ivar - // - The result must be the same as the input - switch(node.m_op) - { - case ::HIR::ExprNode_BinOp::Op::CmpEqu: - case ::HIR::ExprNode_BinOp::Op::CmpNEqu: - case ::HIR::ExprNode_BinOp::Op::CmpLt: - case ::HIR::ExprNode_BinOp::Op::CmpLtE: - case ::HIR::ExprNode_BinOp::Op::CmpGt: - case ::HIR::ExprNode_BinOp::Op::CmpGtE: - case ::HIR::ExprNode_BinOp::Op::BoolAnd: - case ::HIR::ExprNode_BinOp::Op::BoolOr: - break; - default: - this->context.apply_equality(node.span(), node.m_res_type, ty_left); - break; - } - } - - // NOTE: 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( H::type_is_num_prim(ty_left) && H::type_is_num_prim(ty_right) ) - { - switch(node.m_op) - { - case ::HIR::ExprNode_BinOp::Op::CmpEqu: - case ::HIR::ExprNode_BinOp::Op::CmpNEqu: - case ::HIR::ExprNode_BinOp::Op::CmpLt: - case ::HIR::ExprNode_BinOp::Op::CmpLtE: - case ::HIR::ExprNode_BinOp::Op::CmpGt: - case ::HIR::ExprNode_BinOp::Op::CmpGtE: - this->context.apply_equality(node.span(), node.m_left->m_res_type, node.m_right->m_res_type); - this->context.apply_equality(node.span(), node.m_res_type, ::HIR::TypeRef(::HIR::CoreType::Bool)); - 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: - case ::HIR::ExprNode_BinOp::Op::Mul: - case ::HIR::ExprNode_BinOp::Op::Div: - case ::HIR::ExprNode_BinOp::Op::Mod: { - this->context.apply_equality(node.span(), node.m_left->m_res_type, node.m_right->m_res_type); - this->context.apply_equality(node.span(), node.m_res_type, node.m_left->m_res_type); - - const auto& ty = this->context.get_type(node.m_left->m_res_type); - TU_IFLET( ::HIR::TypeRef::Data, ty.m_data, Primitive, e, - switch(e) - { - case ::HIR::CoreType::Str: - case ::HIR::CoreType::Char: - case ::HIR::CoreType::Bool: - ERROR(node.span(), E0000, "Invalid use of arithmatic on " << ty); - break; - default: - break; - } - ) - } break; - case ::HIR::ExprNode_BinOp::Op::And: - case ::HIR::ExprNode_BinOp::Op::Or: - case ::HIR::ExprNode_BinOp::Op::Xor: { - this->context.apply_equality(node.span(), node.m_left->m_res_type, node.m_right->m_res_type); - this->context.apply_equality(node.span(), node.m_res_type, node.m_left->m_res_type); - const auto& ty = this->context.get_type(node.m_left->m_res_type); - TU_IFLET( ::HIR::TypeRef::Data, ty.m_data, Primitive, e, - switch(e) - { - case ::HIR::CoreType::Str: - case ::HIR::CoreType::Char: - case ::HIR::CoreType::Bool: - case ::HIR::CoreType::F32: - case ::HIR::CoreType::F64: - ERROR(node.span(), E0000, "Invalid use of bitwise operation on " << ty); - break; - default: - break; - } - ) - } break; - case ::HIR::ExprNode_BinOp::Op::Shr: - case ::HIR::ExprNode_BinOp::Op::Shl: { - TU_MATCH_DEF(::HIR::TypeRef::Data, (ty_right.m_data), (e), - ( - ), - (Primitive, - switch(e) - { - case ::HIR::CoreType::Str: - case ::HIR::CoreType::Char: - case ::HIR::CoreType::Bool: - case ::HIR::CoreType::F32: - case ::HIR::CoreType::F64: - ERROR(node.span(), E0000, "Invalid type for shift count - " << ty_right); - default: - break; - } - ), - (Infer, - if( e.ty_class != ::HIR::InferClass::Integer ) { - ERROR(node.span(), E0000, "Invalid type for shift count - " << ty_right); - } - ) - ) - - this->context.apply_equality(node.span(), node.m_res_type, node.m_left->m_res_type); - const auto& ty = this->context.get_type(node.m_left->m_res_type); - TU_IFLET( ::HIR::TypeRef::Data, ty.m_data, Primitive, e, - switch(e) - { - case ::HIR::CoreType::Str: - case ::HIR::CoreType::Char: - case ::HIR::CoreType::Bool: - case ::HIR::CoreType::F32: - case ::HIR::CoreType::F64: - ERROR(node.span(), E0000, "Invalid use of bitwise operation on " << ty); - break; - default: - break; - } - ) - } break; - } - } - else - { - 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); - //const auto& ty_res = this->context.get_type(node.m_res_type); - - 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 = "bitand"; break; - case ::HIR::ExprNode_BinOp::Op::Or: item_name = "bitor"; break; - case ::HIR::ExprNode_BinOp::Op::Xor: item_name = "bitxor"; break; - - case ::HIR::ExprNode_BinOp::Op::Shr: item_name = "shr"; break; - case ::HIR::ExprNode_BinOp::Op::Shl: item_name = "shl"; break; - } - assert(item_name); - - //bool found = this->conext.find_trait_impls(sp, ops_trait, ops_trait_pp, ty_left,[&](const auto& args, const auto& assoc) { - // // TODO: Receive fuzzyness from `find_trait_impls` - // }); - - // Search for ops trait impl - ::HIR::TypeRef possible_right_type; - unsigned int count = 0; - const auto& ops_trait = this->context.m_crate.get_lang_item_path(node.span(), item_name); - ::HIR::PathParams ops_trait_pp; - ops_trait_pp.m_types.push_back( ty_right.clone() ); - DEBUG("Searching for impl " << ops_trait << "< " << ty_right << "> for " << ty_left); - bool found_bound = this->context.find_trait_impls_bound(sp, ops_trait, ops_trait_pp, ty_left, - [&](auto impl, auto impl_cmp) { - auto arg_type = impl.get_trait_ty_param(0); - assert(arg_type != ::HIR::TypeRef()); - - // TODO: if arg_type mentions Self? - auto cmp = arg_type.compare_with_placeholders(node.span(), ty_right, this->context.callback_resolve_infer()); - if( cmp == ::HIR::Compare::Unequal ) { - DEBUG("- (fail) bounded impl " << ops_trait << "<" << arg_type << "> (ty_right = " << this->context.get_type(ty_right)); - return false; - } - count += 1; - if( cmp == ::HIR::Compare::Equal ) { - return true; - } - else { - if( possible_right_type == ::HIR::TypeRef() ) { - DEBUG("- Set possibility for " << ty_right << " - " << arg_type); - possible_right_type = arg_type.clone(); - } - - return false; - } - }); - // - Only set found_exact if either found_bound returned true, XOR this returns true - const ::HIR::TraitImpl* impl_ptr = nullptr; - bool found_exact = found_bound ^ this->context.m_crate.find_trait_impls(ops_trait, ty_left, this->context.callback_resolve_infer(), - [&](const auto& impl) { - assert( impl.m_trait_args.m_types.size() == 1 ); - const auto& arg_type = impl.m_trait_args.m_types[0]; - - DEBUG("impl" << impl.m_params.fmt_args() << " " << ops_trait << impl.m_trait_args << " for " << impl.m_type); - - bool fail = false; - bool fuzzy = false; - ::std::vector< const ::HIR::TypeRef*> impl_params; - impl_params.resize( impl.m_params.m_types.size() ); - auto cb = [&](auto idx, const auto& ty) { - DEBUG("[_BinOp] " << idx << " = " << ty); - assert( idx < impl_params.size() ); - if( ! impl_params[idx] ) { - impl_params[idx] = &ty; - return ::HIR::Compare::Equal; - } - else { - switch( impl_params[idx]->compare_with_placeholders(node.span(), ty, this->context.callback_resolve_infer()) ) - { - case ::HIR::Compare::Unequal: - fail = true; - return ::HIR::Compare::Unequal; - case ::HIR::Compare::Fuzzy: - fuzzy = true; - return ::HIR::Compare::Fuzzy; - case ::HIR::Compare::Equal: - return ::HIR::Compare::Equal; - } - return ::HIR::Compare::Equal; - } - }; - fail |= !impl.m_type.match_test_generics(sp, ty_left, this->context.callback_resolve_infer(), cb); - fail |= !arg_type.match_test_generics(sp, ty_right, this->context.callback_resolve_infer(), cb); - if( fail ) { - return false; - } - count += 1; - impl_ptr = &impl; - if( !fuzzy ) { - DEBUG("Operator impl exact match - '"<<item_name<<"' - " << arg_type << " == " << ty_right); - return true; - } - else { - DEBUG("Operator impl fuzzy match - '"<<item_name<<"' - " << arg_type << " == " << ty_right); - if( possible_right_type == ::HIR::TypeRef() ) { - DEBUG("- Set possibility for " << ty_right << " - " << arg_type); - possible_right_type = arg_type.clone(); - } - return false; - } - } - ); - // If there wasn't an exact match, BUT there was one partial match - assume the partial match is what we want - if( !found_exact && count == 1 ) { - assert( possible_right_type != ::HIR::TypeRef() ); - this->context.apply_equality(node.span(), possible_right_type, ty_right); - } - if( count > 0 ) { - // - If the output type is variable - if( has_output ) - { - // - If an impl block was found - if( impl_ptr ) - { - assert(impl_ptr->m_types.count("Output") != 0); - const ::HIR::TypeRef& type = impl_ptr->m_types.at("Output").data; - if( monomorphise_type_needed(type) ) { - TODO(node.span(), "BinOp output = " << type); - } - else { - this->context.apply_equality(node.span(), node.m_res_type, type); - } - } - else - { - const auto& ty_right = this->context.get_type(node.m_right->m_res_type); - - ::HIR::PathParams tpp; - DEBUG("- ty_right = " << ty_right); - tpp.m_types.push_back( ty_right.clone() ); - auto type = ::HIR::TypeRef( ::HIR::Path::Data::make_UfcsKnown({ - box$( ty_left.clone() ), - ::HIR::GenericPath( ops_trait, mv$(tpp) ), - "Output", - {} - }) ); - this->context.apply_equality(node.span(), node.m_res_type, 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. - // - Likely `count` can help, but only if fuzzy matching of the impl type is done - } - } - } - // - UniOp: Look for overload or primitive - void visit(::HIR::ExprNode_UniOp& node) override - { - TRACE_FUNCTION_F(::HIR::ExprNode_UniOp::opname(node.m_op) << "..."); - ::HIR::ExprVisitorDef::visit(node); - - const auto& ty = this->context.get_type(node.m_value->m_res_type); - switch(node.m_op) - { - case ::HIR::ExprNode_UniOp::Op::Ref: - // - Handled above? - break; - case ::HIR::ExprNode_UniOp::Op::RefMut: - // - Handled above? - break; - case ::HIR::ExprNode_UniOp::Op::Invert: - TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Primitive, e, - switch(e) - { - case ::HIR::CoreType::Str: - case ::HIR::CoreType::Char: - case ::HIR::CoreType::F32: - case ::HIR::CoreType::F64: - ERROR(node.span(), E0000, "Invalid use of ! on " << ty); - break; - default: - this->context.apply_equality(node.span(), node.m_res_type, ty); - break; - } - ) - else { - TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Infer, e, - if( e.ty_class == ::HIR::InferClass::Integer ) { - this->context.apply_equality(node.span(), node.m_res_type, ty); - break; - } - ) - // TODO: Search for an implementation of ops::Not - } - break; - case ::HIR::ExprNode_UniOp::Op::Negate: - TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Primitive, e, - switch(e) - { - case ::HIR::CoreType::Str: - case ::HIR::CoreType::Char: - case ::HIR::CoreType::Bool: - ERROR(node.span(), E0000, "Invalid use of - on " << ty); - break; - default: - this->context.apply_equality(node.span(), node.m_res_type, ty); - break; - } - ) - else { - TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Infer, e, - if( e.ty_class == ::HIR::InferClass::Integer || e.ty_class == ::HIR::InferClass::Float ) { - this->context.apply_equality(node.span(), node.m_res_type, ty); - break; - } - ) - // TODO: Search for an implementation of ops::Neg - } - break; - } - } - // - Cast: Nothing needs to happen - void visit(::HIR::ExprNode_Cast& node) override - { - const auto& val_ty = this->context.get_type( node.m_value->m_res_type ); - const auto& target_ty = this->context.get_type( node.m_res_type ); - TRACE_FUNCTION_F("Cast {" << val_ty << "} as " << target_ty); - TU_MATCH_DEF(::HIR::TypeRef::Data, (target_ty.m_data), (e), - ( - ERROR(node.span(), E0000, "Invalid cast"); - ), - (Primitive, - switch(e) - { - case ::HIR::CoreType::Char: - break; - case ::HIR::CoreType::Str: - case ::HIR::CoreType::Bool: - ERROR(node.span(), E0000, "Invalid cast"); - break; - default: - // TODO: Check that the source and destination are integer types. - break; - } - ), - (Borrow, - // TODO: Actually a coerce - check it - ), - (Infer, - // - wait - ), - (Pointer, - // Valid source: - // *<same> <any> - // *<other> <same> - // &<same> <same> - TU_MATCH_DEF(::HIR::TypeRef::Data, (val_ty.m_data), (e2), - ( - ), - (Infer, - ), - (Borrow, - if( e.type != e2.type ) { - // TODO: What is this condition for? - } - DEBUG("_Cast: Borrow coerce"); - this->context.apply_equality(node.span(), *e2.inner, *e.inner); - ), - (Pointer, - if( e.type != e2.type ) { - //DEBUG("_Cast: Pointer classes mismatch"); - //this->context.apply_equality(node.span(), *e2.inner, *e.inner); - } - else { - // Nothing - } - ) - ) - ) - ) - ::HIR::ExprVisitorDef::visit(node); - } - // - Index: Look for implementation of the Index trait - void visit(::HIR::ExprNode_Index& node) override - { - TRACE_FUNCTION_FR("_Index","_Index"); - ::HIR::ExprVisitorDef::visit(node); - const auto& path_Index = this->context.m_crate.get_lang_item_path(node.span(), "index"); - - // NOTE: Indexing triggers autoderef - unsigned int deref_count = 0; - ::HIR::TypeRef tmp_type; // Temporary type used for handling Deref - const auto* current_ty = &node.m_value->m_res_type; - - ::HIR::PathParams trait_pp; - trait_pp.m_types.push_back( this->context.get_type(node.m_index->m_res_type).clone() ); - do { - const auto& ty = this->context.get_type(*current_ty); - DEBUG("_Index: (: " << ty << ")[: " << trait_pp.m_types[0] << "]"); - - ::HIR::TypeRef possible_index_type; - unsigned int count = 0; - bool rv = this->context.find_trait_impls(node.span(), path_Index,trait_pp, ty, [&](auto impl, auto ) { - auto impl_index = impl.get_trait_ty_param(0); - assert(impl_index != ::HIR::TypeRef()); - - auto cmp = impl_index.compare_with_placeholders(node.span(), trait_pp.m_types[0], this->context.callback_resolve_infer()); - if( cmp == ::HIR::Compare::Unequal) - return false; - // TODO: use `assoc` - if( cmp == ::HIR::Compare::Equal ) { - return true; - } - possible_index_type = impl_index.clone(); - count += 1; - return false; - }); - if( rv ) { - break; - } - else if( count == 1 ) { - assert( possible_index_type != ::HIR::TypeRef() ); - this->context.apply_equality(node.span(), node.m_index->m_res_type, possible_index_type); - break; - } - else { - // Either no matches, or multiple fuzzy matches - } - - - deref_count += 1; - current_ty = this->context.autoderef(node.span(), ty, tmp_type); - } while( current_ty ); - - if( current_ty ) - { - const auto& index_ty = this->context.get_type(node.m_index->m_res_type); - if( deref_count > 0 ) - DEBUG("Adding " << deref_count << " dereferences"); - while( deref_count > 0 ) - { - node.m_value = ::HIR::ExprNodeP( new ::HIR::ExprNode_Deref(node.span(), mv$(node.m_value)) ); - this->context.add_ivars( node.m_value->m_res_type ); - deref_count -= 1; - } - - // Set output to `< "*current_ty" as Index<"index_ty> >::Output` - // TODO: Get the output type from the bound/impl in `find_trait_impls` (reduces load on expand_associated_types) - auto tp = ::HIR::GenericPath( path_Index ); - tp.m_params.m_types.push_back( index_ty.clone() ); - auto out_type = ::HIR::TypeRef::new_path( - ::HIR::Path(::HIR::Path::Data::Data_UfcsKnown { - box$(this->context.get_type(*current_ty).clone()), - mv$(tp), - "Output", - {} - }), - {} - ); - - this->context.apply_equality( node.span(), node.m_res_type, out_type ); - } - } - // - Deref: Look for impl of Deref - void visit(::HIR::ExprNode_Deref& node) override - { - const auto& ty = this->context.get_type( node.m_value->m_res_type ); - TRACE_FUNCTION_FR("Deref *{" << ty << "}", this->context.get_type(node.m_res_type)); - TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Borrow, e, - this->context.apply_equality(node.span(), node.m_res_type, *e.inner); - ) - else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e, - this->context.apply_equality(node.span(), node.m_res_type, ::HIR::TypeRef::new_slice(e.inner->clone())); - ) - else if( ty.m_data.is_Infer() ) { - // Leave it for now - } - else { - // TODO: Search for Deref impl - ::HIR::TypeRef res; - const auto& op_deref = this->context.m_crate.get_lang_item_path(node.span(), "deref"); - bool rv = this->context.find_trait_impls(node.span(), op_deref, ::HIR::PathParams{}, ty, [&](auto impl, auto ) { - if( res != ::HIR::TypeRef() ) - TODO(node.span(), "Handle multiple implementations of Deref"); - res = impl.get_type("Target"); - if( res == ::HIR::TypeRef() ) - BUG(node.span(), "Impl of Deref didn't include `Target` associated type (TODO: Is this a bug, what about bounds?)"); - return true; - }); - if( rv ) { - this->context.apply_equality(node.span(), node.m_res_type, res); - } - else { - // TODO: Error (since this can't be dereferenced) - } - } - ::HIR::ExprVisitorDef::visit(node); - } - - void visit(::HIR::ExprNode_TupleVariant& node) override { - const Span& sp = node.span(); - auto& arg_types = node.m_arg_types; - if( arg_types.size() == 0 ) - { - auto& path_params = node.m_path.m_params; - auto monomorph_cb = [&](const auto& gt)->const auto& { - const auto& e = gt.m_data.as_Generic(); - if( e.name == "Self" ) - TODO(sp, "Handle 'Self' when monomorphising type"); - if( e.binding < 256 ) { - auto idx = e.binding; - if( idx >= path_params.m_types.size() ) { - BUG(sp, "Generic param out of input range - " << idx << " '"<<e.name<<"' >= " << path_params.m_types.size()); - } - return path_params.m_types[idx]; - } - else if( e.binding < 512 ) { - BUG(sp, "Method-level parameter on struct/enum"); - } - else { - BUG(sp, "Generic bounding out of total range"); - } - }; - - if( node.m_is_struct ) - { - const auto& str = this->context.m_crate.get_struct_by_path(sp, node.m_path.m_path); - fix_param_count(sp, this->context, node.m_path, str.m_params, path_params); - const auto& fields = str.m_data.as_Tuple(); - arg_types.reserve( fields.size() ); - for(const auto& fld : fields) - { - if( monomorphise_type_needed(fld.ent) ) { - arg_types.push_back( this->context.expand_associated_types(sp, monomorphise_type_with(sp, fld.ent, monomorph_cb)) ); - } - else { - arg_types.push_back( fld.ent.clone() ); - } - } - - arg_types.push_back( ::HIR::TypeRef(node.m_path.clone()) ); - } - else - { - const auto& variant_name = node.m_path.m_path.m_components.back(); - auto type_path = node.m_path.m_path; - type_path.m_components.pop_back(); - - const auto& enm = this->context.m_crate.get_enum_by_path(sp, type_path); - fix_param_count(sp, this->context, node.m_path, enm.m_params, path_params); - - auto it = ::std::find_if( enm.m_variants.begin(), enm.m_variants.end(), [&](const auto& x){ return x.first == variant_name; }); - if( it == enm.m_variants.end() ) { - ERROR(sp, E0000, "Unable to find variant '" << variant_name << " of " << type_path); - } - const auto& fields = it->second.as_Tuple(); - arg_types.reserve( fields.size() ); - for(const auto& fld : fields) - { - if( monomorphise_type_needed(fld.ent) ) { - arg_types.push_back( this->context.expand_associated_types(sp, monomorphise_type_with(sp, fld.ent, monomorph_cb)) ); - } - else { - arg_types.push_back( fld.ent.clone() ); - } - } - arg_types.push_back( ::HIR::TypeRef( ::HIR::GenericPath(type_path, path_params.clone()) ) ); - } - - if( node.m_args.size() != arg_types.size() - 1 ) { - ERROR(sp, E0000, "Incorrect number of arguments to " << node.m_path); - } - DEBUG("--- RESOLVED"); - } - - for( unsigned int i = 0; i < arg_types.size() - 1; i ++ ) - { - auto& arg_expr_ptr = node.m_args[i]; - const auto& arg_ty = arg_types[i]; - DEBUG("Arg " << i << ": " << arg_ty); - this->context.apply_equality(sp, arg_ty, arg_expr_ptr->m_res_type, &arg_expr_ptr); - } - - DEBUG("_TupleVariant - Return: " << arg_types.back()); - this->context.apply_equality(sp, node.m_res_type, arg_types.back() /*, &this_node_ptr*/); - - ::HIR::ExprVisitorDef::visit(node); - } - - /// (HELPER) Populate the cache for nodes that use visit_call - void visit_call_populate_cache(const Span& sp, ::HIR::Path& path, ::HIR::ExprCallCache& cache) const - { - assert(cache.m_arg_types.size() == 0); - - const ::HIR::Function* fcn_ptr = nullptr; - ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> monomorph_cb; - - TU_MATCH(::HIR::Path::Data, (path.m_data), (e), - (Generic, - const auto& fcn = this->context.m_crate.get_function_by_path(sp, e.m_path); - fix_param_count(sp, this->context, path, fcn.m_params, e.m_params); - fcn_ptr = &fcn; - cache.m_fcn_params = &fcn.m_params; - - //const auto& params_def = fcn.m_params; - const auto& path_params = e.m_params; - monomorph_cb = [&](const auto& gt)->const auto& { - const auto& e = gt.m_data.as_Generic(); - if( e.name == "Self" || e.binding == 0xFFFF ) - TODO(sp, "Handle 'Self' when monomorphising"); - if( e.binding < 256 ) { - BUG(sp, "Impl-level parameter on free function (#" << e.binding << " " << e.name << ")"); - } - else if( e.binding < 512 ) { - auto idx = e.binding - 256; - if( idx >= path_params.m_types.size() ) { - BUG(sp, "Generic param out of input range - " << idx << " '"<<e.name<<"' >= " << path_params.m_types.size()); - } - return this->context.get_type(path_params.m_types[idx]); - } - else { - BUG(sp, "Generic bounding out of total range"); - } - }; - ), - (UfcsKnown, - const auto& trait = this->context.m_crate.get_trait_by_path(sp, e.trait.m_path); - fix_param_count(sp, this->context, path, trait.m_params, e.trait.m_params); - if( trait.m_values.count(e.item) == 0 ) { - BUG(sp, "Method '" << e.item << "' of trait " << e.trait.m_path << " doesn't exist"); - } - const auto& fcn = trait.m_values.at(e.item).as_Function(); - fix_param_count(sp, this->context, path, fcn.m_params, e.params); - cache.m_fcn_params = &fcn.m_params; - cache.m_top_params = &trait.m_params; - - // TODO: Check/apply trait bounds (apply = closure arguments or fixed trait args) - - fcn_ptr = &fcn; - - const auto& trait_params = e.trait.m_params; - const auto& path_params = e.params; - monomorph_cb = [&](const auto& gt)->const auto& { - const auto& ge = gt.m_data.as_Generic(); - if( ge.binding == 0xFFFF ) { - return *e.type; - } - else if( ge.binding < 256 ) { - auto idx = ge.binding; - if( idx >= trait_params.m_types.size() ) { - BUG(sp, "Generic param (impl) out of input range - " << idx << " '"<<ge.name<<"' >= " << trait_params.m_types.size()); - } - return this->context.get_type(trait_params.m_types[idx]); - } - else if( ge.binding < 512 ) { - auto idx = ge.binding - 256; - if( idx >= path_params.m_types.size() ) { - BUG(sp, "Generic param out of input range - " << idx << " '"<<ge.name<<"' >= " << path_params.m_types.size()); - } - return this->context.get_type(path_params.m_types[idx]); - } - else { - BUG(sp, "Generic bounding out of total range"); - } - }; - ), - (UfcsUnknown, - TODO(sp, "Hit a UfcsUnknown (" << path << ") - Is this an error?"); - ), - (UfcsInherent, - // - Locate function (and impl block) - const ::HIR::TypeImpl* impl_ptr = nullptr; - this->context.m_crate.find_type_impls(*e.type, [&](const auto& ty)->const auto& { - if( ty.m_data.is_Infer() ) - return this->context.get_type(ty); - else - return ty; - }, - [&](const auto& impl) { - DEBUG("- impl" << impl.m_params.fmt_args() << " " << impl.m_type); - auto it = impl.m_methods.find(e.item); - if( it == impl.m_methods.end() ) - return false; - fcn_ptr = &it->second.data; - impl_ptr = &impl; - return true; - }); - if( !fcn_ptr ) { - ERROR(sp, E0000, "Failed to locate function " << path); - } - assert(impl_ptr); - fix_param_count(sp, this->context, path, fcn_ptr->m_params, e.params); - cache.m_fcn_params = &fcn_ptr->m_params; - - - // If the impl block has parameters, figure out what types they map to - // - The function params are already mapped (from fix_param_count) - auto& impl_params = cache.m_ty_impl_params; - if( impl_ptr->m_params.m_types.size() > 0 ) { - impl_params.m_types.resize( impl_ptr->m_params.m_types.size() ); - impl_ptr->m_type.match_generics(sp, *e.type, this->context.callback_resolve_infer(), [&](auto idx, const auto& ty) { - assert( idx < impl_params.m_types.size() ); - impl_params.m_types[idx] = ty.clone(); - return ::HIR::Compare::Equal; - }); - for(const auto& ty : impl_params.m_types) - assert( !( ty.m_data.is_Infer() && ty.m_data.as_Infer().index == ~0u) ); - } - - // Create monomorphise callback - const auto& fcn_params = e.params; - monomorph_cb = [&](const auto& gt)->const auto& { - const auto& ge = gt.m_data.as_Generic(); - if( ge.binding == 0xFFFF ) { - return this->context.get_type(*e.type); - } - else if( ge.binding < 256 ) { - auto idx = ge.binding; - if( idx >= impl_params.m_types.size() ) { - BUG(sp, "Generic param out of input range - " << idx << " '" << ge.name << "' >= " << impl_params.m_types.size()); - } - return this->context.get_type(impl_params.m_types[idx]); - } - else if( ge.binding < 512 ) { - auto idx = ge.binding - 256; - if( idx >= fcn_params.m_types.size() ) { - BUG(sp, "Generic param out of input range - " << idx << " '" << ge.name << "' >= " << fcn_params.m_types.size()); - } - return this->context.get_type(fcn_params.m_types[idx]); - } - else { - BUG(sp, "Generic bounding out of total range"); - } - }; - ) - ) - - assert( fcn_ptr ); - const auto& fcn = *fcn_ptr; - - // --- Monomorphise the argument/return types (into current context) - for(const auto& arg : fcn.m_args) { - if( monomorphise_type_needed(arg.second) ) { - cache.m_arg_types.push_back( this->context.expand_associated_types(sp, monomorphise_type_with(sp, arg.second, monomorph_cb)) ); - } - else { - cache.m_arg_types.push_back( arg.second.clone() ); - } - } - if( monomorphise_type_needed(fcn.m_return) ) { - cache.m_arg_types.push_back( this->context.expand_associated_types(sp, monomorphise_type_with(sp, fcn.m_return, monomorph_cb)) ); - } - else { - cache.m_arg_types.push_back( fcn.m_return.clone() ); - } - - cache.m_monomorph_cb = mv$(monomorph_cb); - } - - /// Common handling for function/method calls - void visit_call(const Span& sp, - ::HIR::Path& path, bool is_method, - ::std::vector< ::HIR::ExprNodeP>& args, ::HIR::TypeRef& res_type, ::HIR::ExprNodeP& this_node_ptr, - ::HIR::ExprCallCache& cache - ) - { - TRACE_FUNCTION_F("path = " << path); - unsigned int arg_ofs = (is_method ? 1 : 0); - - // If the cache is empty, figure out the function and argument/return types - if( cache.m_arg_types.size() == 0 ) - { - // Fixes any missing parameters in the path, and populates the cache - this->visit_call_populate_cache(sp, path, cache); - assert( cache.m_arg_types.size() >= 1); - - if( args.size() + (is_method ? 1 : 0) != cache.m_arg_types.size() - 1 ) { - ERROR(sp, E0000, "Incorrect number of arguments to " << path); - } - } - - // --- Apply equalities from return and arguments --- - DEBUG("RV " << cache.m_arg_types.back()); - this->context.apply_equality(sp, res_type, cache.m_arg_types.back(), &this_node_ptr); - - for( unsigned int i = arg_ofs; i < cache.m_arg_types.size() - 1; i ++ ) - { - auto& arg_expr_ptr = args[i - arg_ofs]; - const auto& arg_ty = cache.m_arg_types[i]; - DEBUG("Arg " << i << ": " << arg_ty); - this->context.apply_equality(sp, arg_ty, arg_expr_ptr->m_res_type, &arg_expr_ptr); - } - - // --- Check generic bounds (after links between args and params are known) --- - // - HACK! Below just handles closures and fn traits. - // - TODO: Make this FAR more generic than it is - for(const auto& bound : cache.m_fcn_params->m_bounds) - { - TU_MATCH(::HIR::GenericBound, (bound), (be), - (Lifetime, - ), - (TypeLifetime, - ), - (TraitBound, - auto real_type = monomorphise_type_with(sp, be.type, cache.m_monomorph_cb); - auto real_trait = monomorphise_genericpath_with(sp, be.trait.m_path, cache.m_monomorph_cb, false); - DEBUG("Bound " << be.type << ": " << be.trait); - DEBUG("= (" << real_type << ": " << real_trait << ")"); - //auto monomorph_bound = [&](const auto& gt)->const auto& { - // return gt; - // }; - const auto& trait_params = be.trait.m_path.m_params; - // TODO: Detect marker traits - const auto& trait_gp = be.trait.m_path; - auto rv = this->context.find_trait_impls(sp, trait_gp.m_path, real_trait.m_params, real_type, [&](auto impl, auto ) { - TODO(sp, impl << " cmp with " << trait_params); - #if 0 - if( pp.m_types.size() != trait_params.m_types.size() ) { - BUG(sp, "Parameter mismatch"); - } - DEBUG("Apply equality of " << pp << " and " << trait_params << " (once monomorphed)"); - for(unsigned int i = 0; i < pp.m_types.size(); i ++ ) { - auto& l = pp.m_types[i]; - auto r = monomorphise_type_with(sp, trait_params.m_types[i], cache.m_monomorph_cb); - DEBUG(i << " " << l << " and " << r); - //this->context.apply_equality(sp, pp.m_types[i], monomorph_bound, trait_params.m_types[i], cache.m_monomorph_cb, nullptr); - this->context.apply_equality(sp, pp.m_types[i], monomorph_bound, real_trait.m_params.m_types[i], IDENT_CR, nullptr); - } - #endif - // TODO: Use `at` - // - Check if the associated type bounds are present - #if 0 - for( const auto& assoc : be.trait.m_type_bounds ) { - auto it = at.find( assoc.first ); - if( it == at.end() ) - TODO(sp, "Bounded associated type " << assoc.first << " wasn't in list provided by find_trait_impls"); - DEBUG("Equate (impl) " << it->second << " and (bound) " << assoc.second); - //this->context.apply_equality(sp, it->second, IDENT_CR, assoc.second, cache.m_monomorph_cb, nullptr); - auto other_ty = monomorphise_type_with(sp, assoc.second, cache.m_monomorph_cb, true); - this->context.apply_equality(sp, it->second, other_ty); - } - DEBUG("at = " << at); - #endif - return true; - }); - if( !rv ) { - // TODO: Enable this once marker impls are checked correctly - //if( this->context.type_contains_ivars(real_type) ) { - // ERROR(sp, E0000, "No suitable impl of " << real_trait << " for " << real_type); - //} - DEBUG("- No impl of " << be.trait.m_path << " for " << real_type); - continue ; - } - // TODO: Only do this if associated type was missing in list from impl - // - E.g. FnMut<Output=Bar> - #if 1 - for( const auto& assoc : be.trait.m_type_bounds ) { - auto ty = ::HIR::TypeRef( ::HIR::Path(::HIR::Path::Data::Data_UfcsKnown { box$(real_type.clone()), be.trait.m_path.clone(), assoc.first, {} }) ); - // TODO: I'd like to avoid this copy, but expand_associated_types doesn't use the monomorph callback - auto other_ty = monomorphise_type_with(sp, assoc.second, cache.m_monomorph_cb, true); - DEBUG("Checking associated type bound " << assoc.first << " (" << ty << ") = " << assoc.second << " (" << other_ty << ")"); - //this->context.apply_equality( sp, ty, [](const auto&x)->const auto&{return x;}, assoc.csecond, cache.m_monomorph_cb, nullptr ); - this->context.apply_equality( sp, ty, other_ty ); - } - #endif - ), - (TypeEquality, - #if 0 - this->context.apply_equality(sp, be.type, cache.m_monomorph_cb, be.other_type, cache.m_monomorph_cb, nullptr); - #else - // Search for an impl of this trait? Or just do a ufcs expand and force equality - auto real_type_left = this->context.expand_associated_types(sp, monomorphise_type_with(sp, be.type, cache.m_monomorph_cb)); - DEBUG("real_type_left = " << real_type_left); - auto real_type_right = this->context.expand_associated_types(sp, monomorphise_type_with(sp, be.other_type, cache.m_monomorph_cb)); - DEBUG("real_type_right = " << real_type_right); - - this->context.apply_equality(sp, real_type_left, real_type_right); - #endif - ) - ) - } - } - - // - Call Path: Locate path and build return - void visit(::HIR::ExprNode_CallPath& node) override - { - auto& node_ptr = *m_node_ptr_ptr; - TRACE_FUNCTION_F("CallPath " << node.m_path); - assert(node_ptr.get() == &node); - // - Pass m_arg_types as a cache to avoid constant lookups - visit_call(node.span(), node.m_path, false, node.m_args, node.m_res_type, node_ptr, node.m_cache); - - ::HIR::ExprVisitorDef::visit(node); - } - // - Call Value: If type is known, locate impl of Fn/FnMut/FnOnce - void visit(::HIR::ExprNode_CallValue& node) override - { - const auto& ty = this->context.get_type(node.m_value->m_res_type); - DEBUG("(CallValue) ty = " << ty); - - if( node.m_arg_types.size() == 0 ) - { - TU_MATCH_DEF(decltype(ty.m_data), (ty.m_data), (e), - ( - ::HIR::TypeRef fcn_args_tup; - ::HIR::TypeRef fcn_ret; - // Locate impl of FnOnce - const auto& lang_FnOnce = this->context.m_crate.get_lang_item_path(node.span(), "fn_once"); - ::HIR::PathParams trait_pp; - trait_pp.m_types.push_back( this->context.new_ivar_tr() ); // TODO: Bind to arguments? - auto was_bounded = this->context.find_trait_impls_bound(node.span(), lang_FnOnce, trait_pp, ty, [&](auto impl, auto ) { - auto tup = impl.get_trait_ty_param(0); - if( !tup.m_data.is_Tuple() ) - ERROR(node.span(), E0000, "FnOnce expects a tuple argument, got " << tup); - fcn_args_tup = mv$(tup); - return true; - }); - if( was_bounded ) - { - // RV must be in a bound - fcn_ret = ::HIR::TypeRef( ::HIR::Path(::HIR::Path::Data::make_UfcsKnown({ - box$( ty.clone() ), - ::HIR::GenericPath(lang_FnOnce), - "Output", - {} - })) ); - fcn_ret.m_data.as_Path().path.m_data.as_UfcsKnown().trait.m_params.m_types.push_back( fcn_args_tup.clone() ); - } - else if( !ty.m_data.is_Generic() ) - { - TODO(node.span(), "Search for other implementations of FnOnce for " << ty); - } - else - { - // Didn't find anything. Error? - ERROR(node.span(), E0000, "Unable to find an implementation of Fn* for " << ty); - } - - node.m_arg_types = mv$( fcn_args_tup.m_data.as_Tuple() ); - node.m_arg_types.push_back( mv$(fcn_ret) ); - ), - (Closure, - for( const auto& arg : e.m_arg_types ) - node.m_arg_types.push_back( arg.clone() ); - node.m_arg_types.push_back( e.m_rettype->clone() ); - ), - (Function, - for( const auto& arg : e.m_arg_types ) - node.m_arg_types.push_back( arg.clone() ); - node.m_arg_types.push_back( e.m_rettype->clone() ); - ), - (Infer, - ) - ) - } - - if( node.m_arg_types.size() > 0 ) - { - if( node.m_args.size() + 1 != node.m_arg_types.size() ) { - ERROR(node.span(), E0000, "Incorrect number of arguments when calling " << ty); - } - - for( unsigned int i = 0; i < node.m_args.size(); i ++ ) - { - auto& arg_node = node.m_args[i]; - this->context.apply_equality(node.span(), node.m_arg_types[i], arg_node->m_res_type, &arg_node); - } - // TODO: Allow infer - this->context.apply_equality(node.span(), node.m_res_type, node.m_arg_types.back()); - } - - ::HIR::ExprVisitorDef::visit(node); - } - // - Call Method: Locate method on type - void visit(::HIR::ExprNode_CallMethod& node) override - { - auto& node_ptr = *m_node_ptr_ptr; - - ::HIR::ExprVisitorDef::visit(node); - if( node.m_method_path.m_data.is_Generic() && node.m_method_path.m_data.as_Generic().m_path.m_components.size() == 0 ) - { - //const auto& ty = this->context.get_type(node.m_value->m_res_type); - const auto ty = this->context.expand_associated_types(node.span(), this->context.get_type(node.m_value->m_res_type).clone()); - - DEBUG("(CallMethod) ty = " << ty); - // Using autoderef, locate this method on the type - ::HIR::Path fcn_path { ::HIR::SimplePath() }; - unsigned int deref_count = this->context.autoderef_find_method(node.span(), ty, node.m_method, fcn_path); - if( deref_count != ~0u ) - { - DEBUG("Found method " << fcn_path); - node.m_method_path = mv$(fcn_path); - // NOTE: Steals the params from the node - TU_MATCH(::HIR::Path::Data, (node.m_method_path.m_data), (e), - (Generic, - ), - (UfcsUnknown, - ), - (UfcsKnown, - e.params = mv$(node.m_params); - ), - (UfcsInherent, - e.params = mv$(node.m_params); - ) - ) - DEBUG("Adding " << deref_count << " dereferences"); - while( deref_count > 0 ) - { - node.m_value = ::HIR::ExprNodeP( new ::HIR::ExprNode_Deref(node.span(), mv$(node.m_value)) ); - this->context.add_ivars( node.m_value->m_res_type ); - deref_count -= 1; - } - } - else - { - // Return early, don't know enough yet - return ; - } - } - - assert(node_ptr.get() == &node); - visit_call(node.span(), node.m_method_path, true, node.m_args, node.m_res_type, node_ptr, node.m_cache); - } - // - Field: Locate field on type - void visit(::HIR::ExprNode_Field& node) override - { - ::HIR::ExprVisitorDef::visit(node); - - ::HIR::TypeRef out_type; - unsigned int deref_count = this->context.autoderef_find_field(node.span(), node.m_value->m_res_type, node.m_field, out_type); - if( deref_count != ~0u ) - { - assert( out_type != ::HIR::TypeRef() ); - if( deref_count > 0 ) - DEBUG("Adding " << deref_count << " dereferences"); - while( deref_count > 0 ) - { - node.m_value = ::HIR::ExprNodeP( new ::HIR::ExprNode_Deref(node.span(), mv$(node.m_value)) ); - this->context.add_ivars( node.m_value->m_res_type ); - deref_count -= 1; - } - this->context.apply_equality(node.span(), node.m_res_type, out_type); - } - } - // - PathValue: Insert type from path - void visit(::HIR::ExprNode_PathValue& node) override - { - const auto& sp = node.span(); - auto& path = node.m_path; - TU_MATCH(::HIR::Path::Data, (path.m_data), (e), - (Generic, - switch(node.m_target) { - case ::HIR::ExprNode_PathValue::UNKNOWN: - BUG(sp, "Unknown target PathValue encountered with Generic path"); - case ::HIR::ExprNode_PathValue::STRUCT_CONSTR: - TODO(sp, "STRUCT_CONSTR"); - case ::HIR::ExprNode_PathValue::FUNCTION: { - const auto& f = this->context.m_crate.get_function_by_path(sp, e.m_path); - ::HIR::FunctionType ft { - f.m_unsafe, - f.m_abi, - box$( f.m_return.clone() ), - {} - }; - for( const auto& arg : f.m_args ) - ft.m_arg_types.push_back( arg.second.clone() ); - auto ty = ::HIR::TypeRef( ::HIR::TypeRef::Data::make_Function(mv$(ft)) ); - this->context.apply_equality(sp, node.m_res_type, ty); - } break; - case ::HIR::ExprNode_PathValue::STATIC: { - const auto& v = this->context.m_crate.get_static_by_path(sp, e.m_path); - DEBUG("static v.m_type = " << v.m_type); - this->context.apply_equality(sp, node.m_res_type, v.m_type); - } break; - case ::HIR::ExprNode_PathValue::CONSTANT: { - const auto& v = this->context.m_crate.get_constant_by_path(sp, e.m_path); - DEBUG("const"<<v.m_params.fmt_args()<<" v.m_type = " << v.m_type); - if( v.m_params.m_types.size() > 0 ) { - TODO(sp, "Support generic constants in typeck"); - } - this->context.apply_equality(sp, node.m_res_type, v.m_type); - } break; - } - DEBUG("TODO: Get type for constant/static - " << e); - ), - (UfcsUnknown, - BUG(sp, "Encountered UfcsUnknown"); - ), - (UfcsKnown, - TODO(sp, "Look up associated constants/statics (trait)"); - ), - (UfcsInherent, - // - Locate function (and impl block) - const ::HIR::Function* fcn_ptr = nullptr; - const ::HIR::TypeImpl* impl_ptr = nullptr; - this->context.m_crate.find_type_impls(*e.type, [&](const auto& ty)->const auto& { - if( ty.m_data.is_Infer() ) - return this->context.get_type(ty); - else - return ty; - }, - [&](const auto& impl) { - DEBUG("- impl" << impl.m_params.fmt_args() << " " << impl.m_type); - auto it = impl.m_methods.find(e.item); - if( it == impl.m_methods.end() ) - return false; - fcn_ptr = &it->second.data; - impl_ptr = &impl; - return true; - }); - if( !fcn_ptr ) { - ERROR(sp, E0000, "Failed to locate function " << path); - } - assert(impl_ptr); - fix_param_count(sp, this->context, path, fcn_ptr->m_params, e.params); - - // If the impl block has parameters, figure out what types they map to - // - The function params are already mapped (from fix_param_count) - ::HIR::PathParams impl_params; - if( impl_ptr->m_params.m_types.size() > 0 ) { - impl_params.m_types.resize( impl_ptr->m_params.m_types.size() ); - impl_ptr->m_type.match_generics(sp, *e.type, this->context.callback_resolve_infer(), [&](auto idx, const auto& ty) { - assert( idx < impl_params.m_types.size() ); - impl_params.m_types[idx] = ty.clone(); - return ::HIR::Compare::Equal; - }); - for(const auto& ty : impl_params.m_types) - assert( !( ty.m_data.is_Infer() && ty.m_data.as_Infer().index == ~0u) ); - } - - // Create monomorphise callback - const auto& fcn_params = e.params; - auto monomorph_cb = [&](const auto& gt)->const auto& { - const auto& ge = gt.m_data.as_Generic(); - if( ge.binding == 0xFFFF ) { - return this->context.get_type(*e.type); - } - else if( ge.binding < 256 ) { - auto idx = ge.binding; - if( idx >= impl_params.m_types.size() ) { - BUG(sp, "Generic param out of input range - " << idx << " '" << ge.name << "' >= " << impl_params.m_types.size()); - } - return this->context.get_type(impl_params.m_types[idx]); - } - else if( ge.binding < 512 ) { - auto idx = ge.binding - 256; - if( idx >= fcn_params.m_types.size() ) { - BUG(sp, "Generic param out of input range - " << idx << " '" << ge.name << "' >= " << fcn_params.m_types.size()); - } - return this->context.get_type(fcn_params.m_types[idx]); - } - else { - BUG(sp, "Generic bounding out of total range"); - } - }; - - ::HIR::FunctionType ft { - fcn_ptr->m_unsafe, fcn_ptr->m_abi, - box$( monomorphise_type_with(sp, fcn_ptr->m_return, monomorph_cb) ), - {} - }; - for(const auto& arg : fcn_ptr->m_args) - ft.m_arg_types.push_back( monomorphise_type_with(sp, arg.second, monomorph_cb) ); - auto ty = ::HIR::TypeRef(mv$(ft)); - - this->context.apply_equality(node.span(), node.m_res_type, ty); - ) - ) - ::HIR::ExprVisitorDef::visit(node); - } - // - Variable: Bind to same ivar - void visit(::HIR::ExprNode_Variable& node) override - { - // TODO: How to apply deref coercions here? - // - Don't need to, instead construct "higher" nodes to avoid it - TRACE_FUNCTION_F("var #"<<node.m_slot<<" '"<<node.m_name<<"' = " << this->context.get_type(node.m_res_type)); - this->context.apply_equality(node.span(), - node.m_res_type, this->context.get_var_type(node.span(), node.m_slot) - ); - } - // - Struct literal: Semi-known types - void visit(::HIR::ExprNode_StructLiteral& node) override - { - const Span& sp = node.span(); - // TODO: what if this is an enum struct variant constructor? - - auto& val_types = node.m_value_types; - - if( val_types.size() == 0 ) - { - const auto& str = this->context.m_crate.get_struct_by_path(node.span(), node.m_path.m_path); - fix_param_count(node.span(), this->context, node.m_path.clone(), str.m_params, node.m_path.m_params); - - auto ty = ::HIR::TypeRef( ::HIR::TypeRef::Data::Data_Path { node.m_path.clone(), ::HIR::TypeRef::TypePathBinding::make_Struct(&str) } ); - this->context.apply_equality(node.span(), node.m_res_type, ty); - - if( !str.m_data.is_Named() ) - ERROR(sp, E0000, "Struct literal constructor for non-struct-like struct"); - const auto& flds_def = str.m_data.as_Named(); - - for(auto& field : node.m_values) - { - auto fld_def_it = ::std::find_if( flds_def.begin(), flds_def.end(), [&](const auto& x){ return x.first == field.first; } ); - if( fld_def_it == flds_def.end() ) { - ERROR(sp, E0000, "Struct " << node.m_path << " doesn't have a field " << field.first); - } - const ::HIR::TypeRef& field_type = fld_def_it->second.ent; - - if( monomorphise_type_needed(field_type) ) { - val_types.push_back( monomorphise_type(sp, str.m_params, node.m_path.m_params, field_type) ); - } - else { - // SAFE: Can't have _ as monomorphise_type_needed checks for that - val_types.push_back( field_type.clone() ); - } - } - } - - for( unsigned int i = 0; i < node.m_values.size(); i ++ ) - { - auto& field = node.m_values[i]; - this->context.apply_equality(sp, val_types[i], field.second->m_res_type, &field.second); - } - - if( node.m_base_value ) { - this->context.apply_equality(node.span(), node.m_res_type, node.m_base_value->m_res_type); - } - - ::HIR::ExprVisitorDef::visit(node); - } - // - Tuple literal: - void visit(::HIR::ExprNode_Tuple& node) override - { - auto& ty = this->context.get_type(node.m_res_type); - if( !ty.m_data.is_Tuple() ) { - if( ty.m_data.is_Diverge() ) { - return ; - } - this->context.dump(); - BUG(node.span(), "Return type of tuple literal wasn't a tuple - " << node.m_res_type << " = " << ty); - } - auto& tup_ents = ty.m_data.as_Tuple(); - assert( tup_ents.size() == node.m_vals.size() ); - - for(unsigned int i = 0; i < tup_ents.size(); i ++) - { - this->context.apply_equality(node.span(), tup_ents[i], node.m_vals[i]->m_res_type, &node.m_vals[i]); - } - - ::HIR::ExprVisitorDef::visit(node); - } - // - Array list - void visit(::HIR::ExprNode_ArrayList& node) override - { - auto& ty = this->context.get_type(node.m_res_type); - if( !ty.m_data.is_Array() ) { - this->context.dump(); - BUG(node.span(), "Return type of array literal wasn't an array - " << node.m_res_type << " = " << ty); - } - const auto& val_type = *ty.m_data.as_Array().inner; - ::HIR::ExprVisitorDef::visit(node); - for(auto& sn : node.m_vals) - this->context.apply_equality(sn->span(), val_type, sn->m_res_type, &sn); - } - // - Array (sized) - void visit(::HIR::ExprNode_ArraySized& node) override - { - if( !this->context.get_type(node.m_res_type).m_data.is_Array() ) { - this->context.apply_equality(node.span(), node.m_res_type, ::HIR::TypeRef::new_array(node.m_val->m_res_type.clone(), node.m_size_val) ); - } - auto& ty = this->context.get_type(node.m_res_type); - const auto& val_type = *ty.m_data.as_Array().inner; - ::HIR::ExprVisitorDef::visit(node); - this->context.apply_equality(node.span(), val_type, node.m_val->m_res_type, &node.m_val); - } - // - Closure - void visit(::HIR::ExprNode_Closure& node) override - { - ::HIR::ExprVisitorDef::visit(node); - - DEBUG("_Closure: " << node.m_return << " = " << node.m_code->m_res_type); - this->context.apply_equality(node.span(), node.m_return, node.m_code->m_res_type, &node.m_code); - } - }; - - /// Visitor that applies the inferred types, and checks that all of them are fully resolved - class ExprVisitor_Apply: - public ::HIR::ExprVisitorDef - { - TypecheckContext& context; - public: - ExprVisitor_Apply(TypecheckContext& context): - context(context) - { - } - void visit_node_ptr(::HIR::ExprNodeP& node_ptr) override { - auto& node = *node_ptr; - const char* node_ty = typeid(node).name(); - TRACE_FUNCTION_FR(node_ty << " : " << node.m_res_type, node_ty); - this->check_type_resolved(node.span(), node.m_res_type, node.m_res_type); - DEBUG(node_ty << " : = " << node.m_res_type); - ::HIR::ExprVisitorDef::visit_node_ptr(node_ptr); - } - - private: - void check_type_resolved(const Span& sp, ::HIR::TypeRef& ty, const ::HIR::TypeRef& top_type) const { - TU_MATCH(::HIR::TypeRef::Data, (ty.m_data), (e), - (Infer, - auto new_ty = this->context.get_type(ty).clone(); - // - Move over before checking, so that the source type mentions the correct ivar - ty = mv$(new_ty); - if( ty.m_data.is_Infer() ) { - ERROR(sp, E0000, "Failed to infer type " << ty << " in " << top_type); - } - check_type_resolved(sp, ty, top_type); - ), - (Diverge, - // Leaf - ), - (Primitive, - // Leaf - ), - (Path, - // TODO: - ), - (Generic, - // Leaf - ), - (TraitObject, - // TODO: - ), - (Array, - this->check_type_resolved(sp, *e.inner, top_type); - ), - (Slice, - this->check_type_resolved(sp, *e.inner, top_type); - ), - (Tuple, - for(auto& st : e) - this->check_type_resolved(sp, st, top_type); - ), - (Borrow, - this->check_type_resolved(sp, *e.inner, top_type); - ), - (Pointer, - this->check_type_resolved(sp, *e.inner, top_type); - ), - (Function, - this->check_type_resolved(sp, *e.m_rettype, top_type); - for(auto& st : e.m_arg_types) - this->check_type_resolved(sp, st, top_type); - ), - (Closure, - this->check_type_resolved(sp, *e.m_rettype, top_type); - for(auto& st : e.m_arg_types) - this->check_type_resolved(sp, st, top_type); - ) - ) - } - }; -}; - -void Typecheck_Code(typeck::TypecheckContext context, const ::HIR::TypeRef& result_type, ::HIR::ExprPtr& expr) -{ - TRACE_FUNCTION; - - // Convert ExprPtr into unique_ptr for the execution of this function - auto root_ptr = expr.into_unique(); - - //context.apply_equality(expr->span(), result_type, expr->m_res_type); - - // 1. Enumerate inferrence variables and assign indexes to them - { - typeck::ExprVisitor_Enum visitor { context, result_type }; - if( root_ptr->m_res_type.m_data.is_Infer() ) { - root_ptr->m_res_type = result_type.clone(); - } - else { - context.add_ivars( root_ptr->m_res_type ); - context.apply_equality(root_ptr->span(), result_type, root_ptr->m_res_type, &root_ptr); - } - visitor.visit_node_ptr(root_ptr); - } - - context.dump(); - // 2. Iterate through nodes applying rules until nothing changes - { - typeck::ExprVisitor_Run visitor { context }; - unsigned int count = 0; - do { - count += 1; - assert(count < 1000); - DEBUG("==== PASS " << count << " ===="); - visitor.visit_node_ptr(root_ptr); - context.compact_ivars(); - } while( context.take_changed() || context.apply_defaults() ); - DEBUG("==== STOPPED: " << count << " passes ===="); - } - - // 3. Check that there's no unresolved types left - expr = ::HIR::ExprPtr( mv$(root_ptr) ); - context.dump(); - { - DEBUG("==== VALIDATE ===="); - typeck::ExprVisitor_Apply visitor { context }; - expr->visit( visitor ); - } -} -void Typecheck_Code_Simple(const typeck::ModuleState& ms, t_args& args, const ::HIR::TypeRef& result_type, ::HIR::ExprPtr& expr) -{ - typeck::TypecheckContext typeck_context { ms.m_crate, ms.m_impl_generics, ms.m_item_generics }; - typeck_context.init_traits( ms.m_traits ); - for( auto& arg : args ) { - typeck_context.add_binding( Span(), arg.first, arg.second ); - } - Typecheck_Code( mv$(typeck_context), result_type, expr ); -} diff --git a/src/hir_typeck/expr_simple.hpp b/src/hir_typeck/expr_simple.hpp deleted file mode 100644 index 957fbc67..00000000 --- a/src/hir_typeck/expr_simple.hpp +++ /dev/null @@ -1,188 +0,0 @@ -/* - */ -#pragma once -#include <hir/expr.hpp> -#include <hir/hir.hpp> -#include <hir/visitor.hpp> - -#define IDENT_CR ([](const auto& v)->const auto&{return v;}) - -#include "helpers.hpp" - -namespace typeck { - -extern void check_type_class_primitive(const Span& sp, const ::HIR::TypeRef& type, ::HIR::InferClass ic, ::HIR::CoreType ct); - -class TypecheckContext -{ - struct Variable - { - ::std::string name; - ::HIR::TypeRef type; - - Variable() - {} - Variable(const ::std::string& name, ::HIR::TypeRef type): - name( name ), - type( mv$(type) ) - {} - Variable(Variable&&) = default; - - Variable& operator=(Variable&&) = default; - }; -public: - const ::HIR::Crate& m_crate; -private: - ::std::vector< ::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > > m_traits; - ::std::vector< Variable> m_locals; - HMTypeInferrence m_ivars; - TraitResolution m_resolve; - -public: - TypecheckContext(const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params): - m_crate(crate), - m_resolve(m_ivars, crate, impl_params, item_params) - { - } - - void dump() const; - - bool take_changed() { - return m_ivars.take_changed(); - } - void mark_change() { - m_ivars.mark_change(); - } - - void init_traits(const ::std::vector<::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > >& list) { - assert(m_traits.size() == 0); - m_traits = list; - } - void push_traits(const ::std::vector<::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > >& list); - void pop_traits(const ::std::vector<::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > >& list); - - void compact_ivars(); - /// Apply defaults (i32 or f64), returns true if a default was applied - bool apply_defaults(); - - //bool pathparams_contain_ivars(const ::HIR::PathParams& pps) const; - //bool type_contains_ivars(const ::HIR::TypeRef& ty) const; - //bool pathparams_equal(const ::HIR::PathParams& pps_l, const ::HIR::PathParams& pps_r) const; - //bool types_equal(const ::HIR::TypeRef& l, const ::HIR::TypeRef& r) const; - - //void print_type(::std::ostream& os, const ::HIR::TypeRef& tr) const; - - /// Adds a local variable binding (type is mutable so it can be inferred if required) - void add_local(unsigned int index, const ::std::string& name, ::HIR::TypeRef type); - - /// Get the type associated with a variable - const ::HIR::TypeRef& get_var_type(const Span& sp, unsigned int index); - - /// Add (and bind) all '_' types in `type` - void add_ivars(::HIR::TypeRef& type) { - m_ivars.add_ivars(type); - } - // (helper) Add ivars to path parameters - void add_ivars_params(::HIR::PathParams& params) { - m_ivars.add_ivars_params(params); - } - - // (helper) Add a new local based on the pattern binding - void add_pattern_binding(const ::HIR::PatternBinding& pb, ::HIR::TypeRef type); - // (first pass) Add locals using the pssed pattern - void add_binding(const Span& sp, ::HIR::Pattern& pat, ::HIR::TypeRef& type); - - /// Run inferrence using a pattern - void apply_pattern(const ::HIR::Pattern& pat, ::HIR::TypeRef& type); - - /// (wrapper) - void apply_equality(const Span& sp, const ::HIR::TypeRef& left, const ::HIR::TypeRef& right, ::HIR::ExprNodeP* node_ptr_ptr = nullptr) { - apply_equality(sp, left, [](const auto& x)->const auto&{return x;}, right, [](const auto& x)->const auto&{return x;}, node_ptr_ptr); - } - - /// Equates the two types, checking that they are equal (and binding ivars) - /// \note !! The ordering DOES matter, as the righthand side will get unsizing/deref coercions applied if possible (using node_ptr_ptr) - /// \param sp Span for reporting errors - /// \param left Lefthand type (destination for coercions) - /// \param right Righthand type (source for coercions) - /// \param node_ptr Pointer to ExprNodeP, updated with new nodes for coercions - void apply_equality(const Span& sp, const ::HIR::TypeRef& left, t_cb_generic cb_left, const ::HIR::TypeRef& right, t_cb_generic cb_right, ::HIR::ExprNodeP* node_ptr_ptr); - - /// (helper) Expands a top-level associated type into `tmp_t`, returning either `t` or `tmp_t` - const ::HIR::TypeRef& expand_associated_types_to(const Span& sp, const ::HIR::TypeRef& t, ::HIR::TypeRef& tmp_t) const; - - /// Expand any located associated types in the input, operating in-place and returning the result - ::HIR::TypeRef expand_associated_types(const Span& sp, ::HIR::TypeRef input) const { - return m_resolve.expand_associated_types(sp, mv$(input)); - } - - /// Iterate over in-scope bounds (function then top) - bool iterate_bounds( ::std::function<bool(const ::HIR::GenericBound&)> cb) const { - return m_resolve.iterate_bounds(cb); - } - - typedef ::std::function<bool(const ::HIR::PathParams&, const ::std::map< ::std::string,::HIR::TypeRef>&)> t_cb_trait_impl; - typedef TraitResolution::t_cb_trait_impl_r t_cb_trait_impl_r; - - /// Searches for a trait impl that matches the provided trait name and type - bool find_trait_impls(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback) const { - return m_resolve.find_trait_impls(sp, trait, params, type, [&](auto a, auto b){ return callback( mv$(a), b ); }); - } - - /// Search for a trait implementation in current bounds - bool find_trait_impls_bound(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback) const { - return m_resolve.find_trait_impls_bound(sp, trait, params, type, callback); - } - /// Search for a trait implementation in the crate - bool find_trait_impls_crate(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, TraitResolution::t_cb_trait_impl_r callback) const { - return m_resolve.find_trait_impls_crate(sp, trait, params, type, [&](auto r, auto m){ return callback( mv$(r), m ); }); - } - - /// Locate the named method by applying auto-dereferencing. - /// \return Number of times deref was applied (or ~0 if _ was hit) - unsigned int autoderef_find_method(const Span& sp, const ::HIR::TypeRef& top_ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const { - return m_resolve.autoderef_find_method(sp, m_traits, top_ty, method_name, fcn_path); - } - - unsigned int autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_type) const { - return m_resolve.autoderef_find_field(sp, /*m_traits,*/ top_ty, name, field_type); - } - const ::HIR::TypeRef* autoderef(const Span& sp, const ::HIR::TypeRef& ty, ::HIR::TypeRef& tmp_type) const { - return m_resolve.autoderef(sp, ty, tmp_type); - } - -public: - ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> callback_resolve_infer() const { - return [&](const auto& ty)->const auto& { - if( ty.m_data.is_Infer() ) - return this->get_type(ty); - else - return ty; - }; - } - - unsigned int new_ivar() { - return m_ivars.new_ivar(); - } - ::HIR::TypeRef new_ivar_tr() { - return m_ivars.new_ivar_tr(); - } - - ::HIR::TypeRef& get_type(::HIR::TypeRef& type) { - return m_ivars.get_type(type); - } - const ::HIR::TypeRef& get_type(const ::HIR::TypeRef& type) const { - return m_ivars.get_type(type); - } - -private: - void set_ivar_to(unsigned int slot, ::HIR::TypeRef type) { - m_ivars.set_ivar_to(slot, mv$(type)); - } - void ivar_unify(unsigned int left_slot, unsigned int right_slot) { - m_ivars.ivar_unify(left_slot, right_slot); - } -}; - -} // namespace typeck - diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 8c623783..dc0178bd 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -1,6 +1,12 @@ - +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * hir_typeck/helpers.cpp + * - Typecheck helpers + */ #include "helpers.hpp" -#include "expr_simple.hpp" +//#include "expr_simple.hpp" bool monomorphise_type_needed(const ::HIR::TypeRef& tpl); @@ -245,6 +251,38 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl) }, false); } +void check_type_class_primitive(const Span& sp, const ::HIR::TypeRef& type, ::HIR::InferClass ic, ::HIR::CoreType ct) +{ + switch(ic) + { + case ::HIR::InferClass::None: + case ::HIR::InferClass::Diverge: + break; + case ::HIR::InferClass::Float: + switch(ct) + { + case ::HIR::CoreType::F32: + case ::HIR::CoreType::F64: + break; + default: + ERROR(sp, E0000, "Type unificiation of integer literal with non-integer - " << type); + } + break; + case ::HIR::InferClass::Integer: + switch(ct) + { + 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: + break; + default: + ERROR(sp, E0000, "Type unificiation of integer literal with non-integer - " << type); + } + break; + } +} void HMTypeInferrence::dump() const @@ -655,7 +693,7 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type) ERROR(sp, E0000, "Type unificiation of literal with invalid type - " << *root_ivar.type); ), (Primitive, - typeck::check_type_class_primitive(sp, type, l_e.ty_class, e); + check_type_class_primitive(sp, type, l_e.ty_class, e); ), (Infer, // TODO: Check for right having a ty_class @@ -688,7 +726,7 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type) ( ), (Primitive, - typeck::check_type_class_primitive(sp, type, e.ty_class, l_e); + check_type_class_primitive(sp, type, e.ty_class, l_e); ) ) break; @@ -739,7 +777,7 @@ void HMTypeInferrence::ivar_unify(unsigned int left_slot, unsigned int right_slo le.ty_class = re.ty_class; ), (Primitive, - typeck::check_type_class_primitive(sp, *left_ivar.type, re.ty_class, le); + check_type_class_primitive(sp, *left_ivar.type, re.ty_class, le); ) ) } diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp index 34ea4185..19e97787 100644 --- a/src/hir_typeck/helpers.hpp +++ b/src/hir_typeck/helpers.hpp @@ -24,6 +24,8 @@ extern ::HIR::TraitPath monomorphise_traitpath_with(const Span& sp, const ::HIR: extern ::HIR::TypeRef monomorphise_type_with(const Span& sp, const ::HIR::TypeRef& tpl, t_cb_generic callback, bool allow_infer=true); extern ::HIR::TypeRef monomorphise_type(const Span& sp, const ::HIR::GenericParams& params_def, const ::HIR::PathParams& params, const ::HIR::TypeRef& tpl); +extern void check_type_class_primitive(const Span& sp, const ::HIR::TypeRef& type, ::HIR::InferClass ic, ::HIR::CoreType ct); + class HMTypeInferrence { public: |