diff options
-rw-r--r-- | src/hir_typeck/expr_check.cpp | 17 | ||||
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 32 | ||||
-rw-r--r-- | src/mir/from_hir.cpp | 5 |
3 files changed, 52 insertions, 2 deletions
diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index aa26ae1f..7abe5532 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -365,8 +365,21 @@ namespace { default: ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty); break; - //TU_ARMA(Function, se) { - // } + TU_ARMA(Function, se) { + if( se.is_unsafe != de.is_unsafe && se.is_unsafe ) + ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty << " - removing unsafe"); + if( se.m_abi != de.m_abi ) + ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty << " - different ABI"); + if( *se.m_rettype != *de.m_rettype ) + ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty << " - return type different"); + if( se.m_arg_types.size() != de.m_arg_types.size() ) + ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty << " - argument count different"); + for( size_t i = 0; i < se.m_arg_types.size(); i ++) + { + if( se.m_arg_types[i] != de.m_arg_types[i] ) + ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty << " - argument " << i << " different"); + } + } TU_ARMA(Closure, se) { // Allowed, but won't exist after expansion // TODO: Check argument types diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 6f6e7703..10cb9407 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -6549,6 +6549,38 @@ namespace { return CoerceResult::Equality; } } + else if( const auto* se = src.m_data.opt_Function() ) + { + if( const auto* de = dst.m_data.opt_Function() ) + { + auto& node_ptr = *node_ptr_ptr; + auto span = node_ptr->span(); + DEBUG("Function pointer coercion"); + // ABI must match + if( se->m_abi != de->m_abi ) + return CoerceResult::Equality; + // const can be removed + //if( se->is_const != de->is_const && de->is_const ) // Error going TO a const function pointer + // return CoerceResult::Equality; + // unsafe can be added + if( se->is_unsafe != de->is_unsafe && se->is_unsafe ) // Error going FROM an unsafe function pointer + return CoerceResult::Equality; + // argument/return types must match + if( de->m_arg_types.size() != se->m_arg_types.size() ) + return CoerceResult::Equality; + for(size_t i = 0; i < de->m_arg_types.size(); i++) + { + context.equate_types(sp, de->m_arg_types[i], se->m_arg_types[i]); + } + context.equate_types(sp, *de->m_rettype, *se->m_rettype); + node_ptr = NEWNODE( dst.clone(), span, _Cast, mv$(node_ptr), dst.clone() ); + return CoerceResult::Custom; + } + else + { + return CoerceResult::Equality; + } + } else { // TODO: ! should be handled above or in caller? diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index b8033a00..4ab1bf00 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -1279,6 +1279,11 @@ namespace { TU_MATCH_HDRA( (ty_out.m_data), {) default: BUG(node.span(), "Invalid cast to " << ty_out << " from " << ty_in); + TU_ARMA(Function, de) { + // Just trust the previous stages. + ASSERT_BUG(node.span(), ty_in.m_data.is_Function(), ty_in); + ASSERT_BUG(node.span(), de.m_arg_types == ty_in.m_data.as_Function().m_arg_types, ty_in); + } TU_ARMA(Pointer, de) { if( ty_in.m_data.is_Primitive() ) { const auto& ie = ty_in.m_data.as_Primitive(); |