From d9f96dab336f27f4a8dae36d2f4d64fbc7f514e7 Mon Sep 17 00:00:00 2001 From: David Mak Date: Fri, 23 Aug 2024 13:10:55 +0800 Subject: [PATCH] [core] Add codegen_unreachable --- nac3core/src/codegen/builtin_fns.rs | 28 +++---- nac3core/src/codegen/expr.rs | 109 ++++++++++++++++------------ nac3core/src/codegen/irrt/mod.rs | 23 +++--- nac3core/src/codegen/mod.rs | 16 ++++ nac3core/src/codegen/numpy.rs | 26 ++++--- nac3core/src/codegen/stmt.rs | 46 ++++++------ 6 files changed, 145 insertions(+), 103 deletions(-) diff --git a/nac3core/src/codegen/builtin_fns.rs b/nac3core/src/codegen/builtin_fns.rs index 9914d81c..5608ec71 100644 --- a/nac3core/src/codegen/builtin_fns.rs +++ b/nac3core/src/codegen/builtin_fns.rs @@ -9,6 +9,7 @@ use crate::codegen::classes::{ }; use crate::codegen::expr::destructure_range; use crate::codegen::irrt::calculate_len_for_slice_range; +use crate::codegen::macros::codegen_unreachable; use crate::codegen::numpy::ndarray_elementwise_unaryop_impl; use crate::codegen::stmt::gen_for_callback_incrementing; use crate::codegen::{extern_fns, irrt, llvm_intrinsics, numpy, CodeGenContext, CodeGenerator}; @@ -20,7 +21,8 @@ use crate::typecheck::typedef::{Type, TypeEnum}; /// /// The generated message will contain the function name and the name of the unsupported type. fn unsupported_type(ctx: &CodeGenContext<'_, '_>, fn_name: &str, tys: &[Type]) -> ! { - unreachable!( + codegen_unreachable!( + ctx, "{fn_name}() not supported for '{}'", tys.iter().map(|ty| format!("'{}'", ctx.unifier.stringify(*ty))).join(", "), ) @@ -82,7 +84,7 @@ pub fn call_len<'ctx, G: CodeGenerator + ?Sized>( ctx.builder.build_int_truncate_or_bit_cast(len, llvm_i32, "len").unwrap() } - _ => unreachable!(), + _ => codegen_unreachable!(ctx), } }) } @@ -784,7 +786,7 @@ pub fn call_numpy_minimum<'ctx, G: CodeGenerator + ?Sized>( } else if is_ndarray2 { unpack_ndarray_var_tys(&mut ctx.unifier, x2_ty).0 } else { - unreachable!() + codegen_unreachable!(ctx) }; let x1_scalar_ty = if is_ndarray1 { dtype } else { x1_ty }; @@ -888,7 +890,7 @@ pub fn call_numpy_max_min<'ctx, G: CodeGenerator + ?Sized>( match fn_name { "np_argmin" | "np_argmax" => llvm_int64.const_zero().into(), "np_max" | "np_min" => a, - _ => unreachable!(), + _ => codegen_unreachable!(ctx), } } BasicValueEnum::PointerValue(n) @@ -943,7 +945,7 @@ pub fn call_numpy_max_min<'ctx, G: CodeGenerator + ?Sized>( "np_argmax" | "np_max" => { call_max(ctx, (elem_ty, accumulator), (elem_ty, elem)) } - _ => unreachable!(), + _ => codegen_unreachable!(ctx), }; let updated_idx = match (accumulator, result) { @@ -980,7 +982,7 @@ pub fn call_numpy_max_min<'ctx, G: CodeGenerator + ?Sized>( match fn_name { "np_argmin" | "np_argmax" => ctx.builder.build_load(res_idx, "").unwrap(), "np_max" | "np_min" => ctx.builder.build_load(accumulator_addr, "").unwrap(), - _ => unreachable!(), + _ => codegen_unreachable!(ctx), } } @@ -1046,7 +1048,7 @@ pub fn call_numpy_maximum<'ctx, G: CodeGenerator + ?Sized>( } else if is_ndarray2 { unpack_ndarray_var_tys(&mut ctx.unifier, x2_ty).0 } else { - unreachable!() + codegen_unreachable!(ctx) }; let x1_scalar_ty = if is_ndarray1 { dtype } else { x1_ty }; @@ -1486,7 +1488,7 @@ pub fn call_numpy_arctan2<'ctx, G: CodeGenerator + ?Sized>( } else if is_ndarray2 { unpack_ndarray_var_tys(&mut ctx.unifier, x2_ty).0 } else { - unreachable!() + codegen_unreachable!(ctx) }; let x1_scalar_ty = if is_ndarray1 { dtype } else { x1_ty }; @@ -1553,7 +1555,7 @@ pub fn call_numpy_copysign<'ctx, G: CodeGenerator + ?Sized>( } else if is_ndarray2 { unpack_ndarray_var_tys(&mut ctx.unifier, x2_ty).0 } else { - unreachable!() + codegen_unreachable!(ctx) }; let x1_scalar_ty = if is_ndarray1 { dtype } else { x1_ty }; @@ -1620,7 +1622,7 @@ pub fn call_numpy_fmax<'ctx, G: CodeGenerator + ?Sized>( } else if is_ndarray2 { unpack_ndarray_var_tys(&mut ctx.unifier, x2_ty).0 } else { - unreachable!() + codegen_unreachable!(ctx) }; let x1_scalar_ty = if is_ndarray1 { dtype } else { x1_ty }; @@ -1687,7 +1689,7 @@ pub fn call_numpy_fmin<'ctx, G: CodeGenerator + ?Sized>( } else if is_ndarray2 { unpack_ndarray_var_tys(&mut ctx.unifier, x2_ty).0 } else { - unreachable!() + codegen_unreachable!(ctx) }; let x1_scalar_ty = if is_ndarray1 { dtype } else { x1_ty }; @@ -1810,7 +1812,7 @@ pub fn call_numpy_hypot<'ctx, G: CodeGenerator + ?Sized>( } else if is_ndarray2 { unpack_ndarray_var_tys(&mut ctx.unifier, x2_ty).0 } else { - unreachable!() + codegen_unreachable!(ctx) }; let x1_scalar_ty = if is_ndarray1 { dtype } else { x1_ty }; @@ -1877,7 +1879,7 @@ pub fn call_numpy_nextafter<'ctx, G: CodeGenerator + ?Sized>( } else if is_ndarray2 { unpack_ndarray_var_tys(&mut ctx.unifier, x2_ty).0 } else { - unreachable!() + codegen_unreachable!(ctx) }; let x1_scalar_ty = if is_ndarray1 { dtype } else { x1_ty }; diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index 50d70eb7..18b490d7 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -11,6 +11,7 @@ use crate::{ call_expect, call_float_floor, call_float_pow, call_float_powi, call_int_smax, call_int_umin, call_memcpy_generic, }, + macros::codegen_unreachable, need_sret, numpy, stmt::{ gen_for_callback_incrementing, gen_if_callback, gen_if_else_expr_callback, gen_raise, @@ -112,7 +113,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { let obj_id = match &*self.unifier.get_ty(ty) { TypeEnum::TObj { obj_id, .. } => *obj_id, // we cannot have other types, virtual type should be handled by function calls - _ => unreachable!(), + _ => codegen_unreachable!(self), }; let def = &self.top_level.definitions.read()[obj_id.0]; let (index, value) = if let TopLevelDef::Class { fields, attributes, .. } = &*def.read() { @@ -123,7 +124,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { (attribute_index.0, Some(attribute_index.1 .2.clone())) } } else { - unreachable!() + codegen_unreachable!(self) }; (index, value) } @@ -133,7 +134,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { TypeEnum::TObj { fields, .. } => { fields.iter().find_position(|x| *x.0 == attr).unwrap().0 } - _ => unreachable!(), + _ => codegen_unreachable!(self), } } @@ -188,7 +189,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { { *params.iter().next().unwrap().1 } - _ => unreachable!("must be option type"), + _ => codegen_unreachable!(self, "must be option type"), }; let val = self.gen_symbol_val(generator, v, ty); let ptr = generator @@ -204,7 +205,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { { *params.iter().next().unwrap().1 } - _ => unreachable!("must be option type"), + _ => codegen_unreachable!(self, "must be option type"), }; let actual_ptr_type = self.get_llvm_type(generator, ty).ptr_type(AddressSpace::default()); @@ -271,7 +272,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { { self.ctx.i64_type() } else { - unreachable!() + codegen_unreachable!(self) }; Some(ty.const_int(*val as u64, false).into()) } @@ -285,7 +286,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { let (types, is_vararg_ctx) = if let TypeEnum::TTuple { ty, is_vararg_ctx } = &*ty { (ty.clone(), *is_vararg_ctx) } else { - unreachable!() + codegen_unreachable!(self) }; let values = zip(types, v.iter()) .map_while(|(ty, v)| self.gen_const(generator, v, ty)) @@ -330,7 +331,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { None } - _ => unreachable!(), + _ => codegen_unreachable!(self), } } @@ -344,7 +345,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { signed: bool, ) -> BasicValueEnum<'ctx> { let (BasicValueEnum::IntValue(lhs), BasicValueEnum::IntValue(rhs)) = (lhs, rhs) else { - unreachable!() + codegen_unreachable!(self) }; let float = self.ctx.f64_type(); match (op, signed) { @@ -419,7 +420,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { .build_right_shift(lhs, rhs, signed, "rshift") .map(Into::into) .unwrap(), - _ => unreachable!(), + _ => codegen_unreachable!(self), } } @@ -431,7 +432,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { } (Operator::Pow, s) => integer_power(generator, self, lhs, rhs, s).into(), // special implementation? - (Operator::MatMult, _) => unreachable!(), + (Operator::MatMult, _) => codegen_unreachable!(self), } } @@ -443,7 +444,8 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { rhs: BasicValueEnum<'ctx>, ) -> BasicValueEnum<'ctx> { let (BasicValueEnum::FloatValue(lhs), BasicValueEnum::FloatValue(rhs)) = (lhs, rhs) else { - unreachable!( + codegen_unreachable!( + self, "Expected (FloatValue, FloatValue), got ({}, {})", lhs.get_type(), rhs.get_type() @@ -687,7 +689,7 @@ pub fn gen_constructor<'ctx, 'a, G: CodeGenerator>( def: &TopLevelDef, params: Vec<(Option, ValueEnum<'ctx>)>, ) -> Result, String> { - let TopLevelDef::Class { methods, .. } = def else { unreachable!() }; + let TopLevelDef::Class { methods, .. } = def else { codegen_unreachable!(ctx) }; // TODO: what about other fields that require alloca? let fun_id = methods.iter().find(|method| method.0 == "__init__".into()).map(|method| method.2); @@ -719,7 +721,7 @@ pub fn gen_func_instance<'ctx>( key, ) = fun else { - unreachable!() + codegen_unreachable!(ctx) }; if let Some(sym) = instance_to_symbol.get(&key) { @@ -751,7 +753,7 @@ pub fn gen_func_instance<'ctx>( .collect(); let mut signature = store.from_signature(&mut ctx.unifier, &ctx.primitives, sign, &mut cache); - let ConcreteTypeEnum::TFunc { args, .. } = &mut signature else { unreachable!() }; + let ConcreteTypeEnum::TFunc { args, .. } = &mut signature else { codegen_unreachable!(ctx) }; if let Some(obj) = &obj { let zelf = store.from_unifier_type(&mut ctx.unifier, &ctx.primitives, obj.0, &mut cache); @@ -1117,7 +1119,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>( ctx: &mut CodeGenContext<'ctx, '_>, expr: &Expr>, ) -> Result>, String> { - let ExprKind::ListComp { elt, generators } = &expr.node else { unreachable!() }; + let ExprKind::ListComp { elt, generators } = &expr.node else { codegen_unreachable!(ctx) }; let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap(); @@ -1376,13 +1378,13 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>( if let TypeEnum::TObj { params, .. } = &*ctx.unifier.get_ty_immutable(ty1) { ctx.unifier.get_representative(*params.iter().next().unwrap().1) } else { - unreachable!() + codegen_unreachable!(ctx) }; let elem_ty2 = if let TypeEnum::TObj { params, .. } = &*ctx.unifier.get_ty_immutable(ty2) { ctx.unifier.get_representative(*params.iter().next().unwrap().1) } else { - unreachable!() + codegen_unreachable!(ctx) }; debug_assert!(ctx.unifier.unioned(elem_ty1, elem_ty2)); @@ -1455,7 +1457,7 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>( { *params.iter().next().unwrap().1 } else { - unreachable!() + codegen_unreachable!(ctx) }; (elem_ty, left_val, right_val) @@ -1465,12 +1467,12 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>( { *params.iter().next().unwrap().1 } else { - unreachable!() + codegen_unreachable!(ctx) }; (elem_ty, right_val, left_val) } else { - unreachable!() + codegen_unreachable!(ctx) }; let list_val = ListValue::from_ptr_val(list_val.into_pointer_value(), llvm_usize, None); @@ -1637,7 +1639,7 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>( } else { let left_ty_enum = ctx.unifier.get_ty_immutable(left_ty.unwrap()); let TypeEnum::TObj { fields, obj_id, .. } = left_ty_enum.as_ref() else { - unreachable!("must be tobj") + codegen_unreachable!(ctx, "must be tobj") }; let (op_name, id) = { let normal_method_name = Binop::normal(op.base).op_info().method_name; @@ -1658,19 +1660,19 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>( } else { let left_enum_ty = ctx.unifier.get_ty_immutable(left_ty.unwrap()); let TypeEnum::TObj { fields, .. } = left_enum_ty.as_ref() else { - unreachable!("must be tobj") + codegen_unreachable!(ctx, "must be tobj") }; let fn_ty = fields.get(&op_name).unwrap().0; let fn_ty_enum = ctx.unifier.get_ty_immutable(fn_ty); - let TypeEnum::TFunc(sig) = fn_ty_enum.as_ref() else { unreachable!() }; + let TypeEnum::TFunc(sig) = fn_ty_enum.as_ref() else { codegen_unreachable!(ctx) }; sig.clone() }; let fun_id = { let defs = ctx.top_level.definitions.read(); let obj_def = defs.get(id.0).unwrap().read(); - let TopLevelDef::Class { methods, .. } = &*obj_def else { unreachable!() }; + let TopLevelDef::Class { methods, .. } = &*obj_def else { codegen_unreachable!(ctx) }; methods.iter().find(|method| method.0 == op_name).unwrap().2 }; @@ -1801,7 +1803,8 @@ pub fn gen_unaryop_expr_with_values<'ctx, G: CodeGenerator>( if op == ast::Unaryop::Invert { ast::Unaryop::Not } else { - unreachable!( + codegen_unreachable!( + ctx, "ufunc {} not supported for ndarray[bool, N]", op.op_info().method_name, ) @@ -1868,8 +1871,8 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>( { let llvm_usize = generator.get_size_type(ctx.ctx); - let (Some(left_ty), lhs) = left else { unreachable!() }; - let (Some(right_ty), rhs) = comparators[0] else { unreachable!() }; + let (Some(left_ty), lhs) = left else { codegen_unreachable!(ctx) }; + let (Some(right_ty), rhs) = comparators[0] else { codegen_unreachable!(ctx) }; let op = ops[0]; let is_ndarray1 = @@ -1976,7 +1979,7 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>( let op = match op { ast::Cmpop::Eq | ast::Cmpop::Is => IntPredicate::EQ, ast::Cmpop::NotEq => IntPredicate::NE, - _ if left_ty == ctx.primitives.bool => unreachable!(), + _ if left_ty == ctx.primitives.bool => codegen_unreachable!(ctx), ast::Cmpop::Lt => { if use_unsigned_ops { IntPredicate::ULT @@ -2005,7 +2008,7 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>( IntPredicate::SGE } } - _ => unreachable!(), + _ => codegen_unreachable!(ctx), }; ctx.builder.build_int_compare(op, lhs, rhs, "cmp").unwrap() @@ -2022,7 +2025,7 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>( ast::Cmpop::LtE => inkwell::FloatPredicate::OLE, ast::Cmpop::Gt => inkwell::FloatPredicate::OGT, ast::Cmpop::GtE => inkwell::FloatPredicate::OGE, - _ => unreachable!(), + _ => codegen_unreachable!(ctx), }; ctx.builder.build_float_compare(op, lhs, rhs, "cmp").unwrap() } else if left_ty == ctx.primitives.str { @@ -2154,7 +2157,7 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>( match (op, val) { (Cmpop::Eq, true) | (Cmpop::NotEq, false) => llvm_i1.const_all_ones(), (Cmpop::Eq, false) | (Cmpop::NotEq, true) => llvm_i1.const_zero(), - (_, _) => unreachable!(), + (_, _) => codegen_unreachable!(ctx), } }; @@ -2167,14 +2170,14 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>( { *params.iter().next().unwrap().1 } else { - unreachable!() + codegen_unreachable!(ctx) }; let right_elem_ty = if let TypeEnum::TObj { params, .. } = &*ctx.unifier.get_ty_immutable(right_ty) { *params.iter().next().unwrap().1 } else { - unreachable!() + codegen_unreachable!(ctx) }; if !ctx.unifier.unioned(left_elem_ty, right_elem_ty) { @@ -2511,7 +2514,7 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>( let llvm_usize = generator.get_size_type(ctx.ctx); let TypeEnum::TLiteral { values, .. } = &*ctx.unifier.get_ty_immutable(ndims) else { - unreachable!() + codegen_unreachable!(ctx) }; let ndims = values @@ -2863,7 +2866,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( .const_null() .into() } - _ => unreachable!("must be option type"), + _ => codegen_unreachable!(ctx, "must be option type"), } } ExprKind::Name { id, .. } => match ctx.var_assignment.get(id) { @@ -2924,7 +2927,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( *params.iter().next().unwrap().1 } else { - unreachable!() + codegen_unreachable!(ctx) }; if let TypeEnum::TVar { .. } = &*ctx.unifier.get_ty_immutable(ty) { @@ -3018,7 +3021,9 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( return generator.gen_expr(ctx, &modified_expr); } - None => unreachable!("Function Type should not have attributes"), + None => { + codegen_unreachable!(ctx, "Function Type should not have attributes") + } } } else if let TypeEnum::TObj { obj_id, fields, params } = &*ctx.unifier.get_ty(c) { if fields.is_empty() && params.is_empty() { @@ -3040,7 +3045,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( return generator.gen_expr(ctx, &modified_expr); } - None => unreachable!(), + None => codegen_unreachable!(ctx), } } } @@ -3142,7 +3147,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( } (Some(a), None) => a.into(), (None, Some(b)) => b.into(), - (None, None) => unreachable!(), + (None, None) => codegen_unreachable!(ctx), } } ExprKind::BinOp { op, left, right } => { @@ -3232,7 +3237,9 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( ctx.unifier.get_call_signature(*call).unwrap() } else { let ty = func.custom.unwrap(); - let TypeEnum::TFunc(sign) = &*ctx.unifier.get_ty(ty) else { unreachable!() }; + let TypeEnum::TFunc(sign) = &*ctx.unifier.get_ty(ty) else { + codegen_unreachable!(ctx) + }; sign.clone() }; @@ -3256,12 +3263,14 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( { *obj_id } else { - unreachable!() + codegen_unreachable!(ctx) }; let fun_id = { let defs = ctx.top_level.definitions.read(); let obj_def = defs.get(id.0).unwrap().read(); - let TopLevelDef::Class { methods, .. } = &*obj_def else { unreachable!() }; + let TopLevelDef::Class { methods, .. } = &*obj_def else { + codegen_unreachable!(ctx) + }; methods.iter().find(|method| method.0 == *attr).unwrap().2 }; @@ -3332,7 +3341,9 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( .unwrap(), )); } - ValueEnum::Dynamic(_) => unreachable!("option must be static or ptr"), + ValueEnum::Dynamic(_) => { + codegen_unreachable!(ctx, "option must be static or ptr") + } } } @@ -3481,7 +3492,10 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( if let ExprKind::Constant { value: Constant::Int(v), .. } = &slice.node { (*v).try_into().unwrap() } else { - unreachable!("tuple subscript must be const int after type check"); + codegen_unreachable!( + ctx, + "tuple subscript must be const int after type check" + ); }; match generator.gen_expr(ctx, value)? { Some(ValueEnum::Dynamic(v)) => { @@ -3504,7 +3518,10 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( None => return Ok(None), } } - _ => unreachable!("should not be other subscriptable types after type check"), + _ => codegen_unreachable!( + ctx, + "should not be other subscriptable types after type check" + ), } } ExprKind::ListComp { .. } => { diff --git a/nac3core/src/codegen/irrt/mod.rs b/nac3core/src/codegen/irrt/mod.rs index 91e62e94..0a809e18 100644 --- a/nac3core/src/codegen/irrt/mod.rs +++ b/nac3core/src/codegen/irrt/mod.rs @@ -3,12 +3,13 @@ use crate::typecheck::typedef::Type; use super::{ classes::{ ArrayLikeIndexer, ArrayLikeValue, ArraySliceValue, ListValue, NDArrayValue, - TypedArrayLikeAdapter, UntypedArrayLikeAccessor, + TypedArrayLikeAccessor, TypedArrayLikeAdapter, UntypedArrayLikeAccessor, }, - llvm_intrinsics, CodeGenContext, CodeGenerator, + llvm_intrinsics, + macros::codegen_unreachable, + stmt::gen_for_callback_incrementing, + CodeGenContext, CodeGenerator, }; -use crate::codegen::classes::TypedArrayLikeAccessor; -use crate::codegen::stmt::gen_for_callback_incrementing; use inkwell::{ attributes::{Attribute, AttributeLoc}, context::Context, @@ -55,7 +56,7 @@ pub fn integer_power<'ctx, G: CodeGenerator + ?Sized>( (64, 64, true) => "__nac3_int_exp_int64_t", (32, 32, false) => "__nac3_int_exp_uint32_t", (64, 64, false) => "__nac3_int_exp_uint64_t", - _ => unreachable!(), + _ => codegen_unreachable!(ctx), }; let base_type = base.get_type(); let pow_fun = ctx.module.get_function(symbol).unwrap_or_else(|| { @@ -441,7 +442,7 @@ pub fn list_slice_assignment<'ctx, G: CodeGenerator + ?Sized>( BasicTypeEnum::IntType(t) => t.size_of(), BasicTypeEnum::PointerType(t) => t.size_of(), BasicTypeEnum::StructType(t) => t.size_of().unwrap(), - _ => unreachable!(), + _ => codegen_unreachable!(ctx), }; ctx.builder.build_int_truncate_or_bit_cast(s, int32, "size").unwrap() } @@ -586,7 +587,7 @@ where let ndarray_calc_size_fn_name = match llvm_usize.get_bit_width() { 32 => "__nac3_ndarray_calc_size", 64 => "__nac3_ndarray_calc_size64", - bw => unreachable!("Unsupported size type bit width: {}", bw), + bw => codegen_unreachable!(ctx, "Unsupported size type bit width: {}", bw), }; let ndarray_calc_size_fn_t = llvm_usize.fn_type( &[llvm_pusize.into(), llvm_usize.into(), llvm_usize.into(), llvm_usize.into()], @@ -637,7 +638,7 @@ pub fn call_ndarray_calc_nd_indices<'ctx, G: CodeGenerator + ?Sized>( let ndarray_calc_nd_indices_fn_name = match llvm_usize.get_bit_width() { 32 => "__nac3_ndarray_calc_nd_indices", 64 => "__nac3_ndarray_calc_nd_indices64", - bw => unreachable!("Unsupported size type bit width: {}", bw), + bw => codegen_unreachable!(ctx, "Unsupported size type bit width: {}", bw), }; let ndarray_calc_nd_indices_fn = ctx.module.get_function(ndarray_calc_nd_indices_fn_name).unwrap_or_else(|| { @@ -706,7 +707,7 @@ where let ndarray_flatten_index_fn_name = match llvm_usize.get_bit_width() { 32 => "__nac3_ndarray_flatten_index", 64 => "__nac3_ndarray_flatten_index64", - bw => unreachable!("Unsupported size type bit width: {}", bw), + bw => codegen_unreachable!(ctx, "Unsupported size type bit width: {}", bw), }; let ndarray_flatten_index_fn = ctx.module.get_function(ndarray_flatten_index_fn_name).unwrap_or_else(|| { @@ -774,7 +775,7 @@ pub fn call_ndarray_calc_broadcast<'ctx, G: CodeGenerator + ?Sized>( let ndarray_calc_broadcast_fn_name = match llvm_usize.get_bit_width() { 32 => "__nac3_ndarray_calc_broadcast", 64 => "__nac3_ndarray_calc_broadcast64", - bw => unreachable!("Unsupported size type bit width: {}", bw), + bw => codegen_unreachable!(ctx, "Unsupported size type bit width: {}", bw), }; let ndarray_calc_broadcast_fn = ctx.module.get_function(ndarray_calc_broadcast_fn_name).unwrap_or_else(|| { @@ -894,7 +895,7 @@ pub fn call_ndarray_calc_broadcast_index< let ndarray_calc_broadcast_fn_name = match llvm_usize.get_bit_width() { 32 => "__nac3_ndarray_calc_broadcast_idx", 64 => "__nac3_ndarray_calc_broadcast_idx64", - bw => unreachable!("Unsupported size type bit width: {}", bw), + bw => codegen_unreachable!(ctx, "Unsupported size type bit width: {}", bw), }; let ndarray_calc_broadcast_fn = ctx.module.get_function(ndarray_calc_broadcast_fn_name).unwrap_or_else(|| { diff --git a/nac3core/src/codegen/mod.rs b/nac3core/src/codegen/mod.rs index 71a2d52a..eecf5c2e 100644 --- a/nac3core/src/codegen/mod.rs +++ b/nac3core/src/codegen/mod.rs @@ -50,6 +50,22 @@ mod test; use concrete_type::{ConcreteType, ConcreteTypeEnum, ConcreteTypeStore}; pub use generator::{CodeGenerator, DefaultCodeGenerator}; +mod macros { + /// Codegen-variant of [`std::unreachable`] which accepts an instance of [`CodeGenContext`] as + /// its first argument to provide Python source information to indicate the codegen location + /// causing the assertion. + macro_rules! codegen_unreachable { + ($ctx:expr $(,)?) => { + std::unreachable!("unreachable code while processing {}", &$ctx.current_loc) + }; + ($ctx:expr, $($arg:tt)*) => { + std::unreachable!("unreachable code while processing {}: {}", &$ctx.current_loc, std::format!("{}", std::format_args!($($arg)+))) + }; + } + + pub(crate) use codegen_unreachable; +} + #[derive(Default)] pub struct StaticValueStore { pub lookup: HashMap, usize>, diff --git a/nac3core/src/codegen/numpy.rs b/nac3core/src/codegen/numpy.rs index d58b566b..41dad1f3 100644 --- a/nac3core/src/codegen/numpy.rs +++ b/nac3core/src/codegen/numpy.rs @@ -12,6 +12,7 @@ use crate::{ call_ndarray_calc_size, }, llvm_intrinsics::{self, call_memcpy_generic}, + macros::codegen_unreachable, stmt::{gen_for_callback_incrementing, gen_for_range_callback, gen_if_else_expr_callback}, CodeGenContext, CodeGenerator, }, @@ -259,7 +260,7 @@ fn ndarray_zero_value<'ctx, G: CodeGenerator + ?Sized>( } else if ctx.unifier.unioned(elem_ty, ctx.primitives.str) { ctx.gen_string(generator, "").into() } else { - unreachable!() + codegen_unreachable!(ctx) } } @@ -287,7 +288,7 @@ fn ndarray_one_value<'ctx, G: CodeGenerator + ?Sized>( } else if ctx.unifier.unioned(elem_ty, ctx.primitives.str) { ctx.gen_string(generator, "1").into() } else { - unreachable!() + codegen_unreachable!(ctx) } } @@ -355,7 +356,7 @@ fn call_ndarray_empty_impl<'ctx, G: CodeGenerator + ?Sized>( create_ndarray_const_shape(generator, ctx, elem_ty, &[shape_int]) } - _ => unreachable!(), + _ => codegen_unreachable!(ctx), } } @@ -626,7 +627,7 @@ fn call_ndarray_full_impl<'ctx, G: CodeGenerator + ?Sized>( } else if fill_value.is_int_value() || fill_value.is_float_value() { fill_value } else { - unreachable!() + codegen_unreachable!(ctx) }; Ok(value) @@ -2020,7 +2021,7 @@ pub fn gen_ndarray_fill<'ctx>( } else if value_arg.is_int_value() || value_arg.is_float_value() { value_arg } else { - unreachable!() + codegen_unreachable!(ctx) }; Ok(value) @@ -2129,7 +2130,8 @@ pub fn ndarray_transpose<'ctx, G: CodeGenerator + ?Sized>( Ok(out.as_base_value().into()) } else { - unreachable!( + codegen_unreachable!( + ctx, "{FN_NAME}() not supported for '{}'", format!("'{}'", ctx.unifier.stringify(x1_ty)) ) @@ -2371,7 +2373,7 @@ pub fn ndarray_reshape<'ctx, G: CodeGenerator + ?Sized>( .into_int_value(); create_ndarray_const_shape(generator, ctx, elem_ty, &[shape_int]) } - _ => unreachable!(), + _ => codegen_unreachable!(ctx), } .unwrap(); @@ -2415,7 +2417,8 @@ pub fn ndarray_reshape<'ctx, G: CodeGenerator + ?Sized>( Ok(out.as_base_value().into()) } else { - unreachable!( + codegen_unreachable!( + ctx, "{FN_NAME}() not supported for '{}'", format!("'{}'", ctx.unifier.stringify(x1_ty)) ) @@ -2483,7 +2486,7 @@ pub fn ndarray_dot<'ctx, G: CodeGenerator + ?Sized>( .build_float_mul(e1, elem2.into_float_value(), "") .unwrap() .as_basic_value_enum(), - _ => unreachable!(), + _ => codegen_unreachable!(ctx), }; let acc_val = ctx.builder.build_load(acc, "").unwrap(); let acc_val = match acc_val { @@ -2497,7 +2500,7 @@ pub fn ndarray_dot<'ctx, G: CodeGenerator + ?Sized>( .build_float_add(e1, product.into_float_value(), "") .unwrap() .as_basic_value_enum(), - _ => unreachable!(), + _ => codegen_unreachable!(ctx), }; ctx.builder.build_store(acc, acc_val).unwrap(); @@ -2514,7 +2517,8 @@ pub fn ndarray_dot<'ctx, G: CodeGenerator + ?Sized>( (BasicValueEnum::FloatValue(e1), BasicValueEnum::FloatValue(e2)) => { Ok(ctx.builder.build_float_mul(e1, e2, "").unwrap().as_basic_value_enum()) } - _ => unreachable!( + _ => codegen_unreachable!( + ctx, "{FN_NAME}() not supported for '{}'", format!("'{}'", ctx.unifier.stringify(x1_ty)) ), diff --git a/nac3core/src/codegen/stmt.rs b/nac3core/src/codegen/stmt.rs index 081a5cef..da4b6ee0 100644 --- a/nac3core/src/codegen/stmt.rs +++ b/nac3core/src/codegen/stmt.rs @@ -1,15 +1,13 @@ use super::{ - super::symbol_resolver::ValueEnum, - expr::destructure_range, + classes::{ArrayLikeIndexer, ArraySliceValue, ListValue, RangeValue}, + expr::{destructure_range, gen_binop_expr}, + gen_in_range_check, irrt::{handle_slice_indices, list_slice_assignment}, + macros::codegen_unreachable, CodeGenContext, CodeGenerator, }; use crate::{ - codegen::{ - classes::{ArrayLikeIndexer, ArraySliceValue, ListValue, RangeValue}, - expr::gen_binop_expr, - gen_in_range_check, - }, + symbol_resolver::ValueEnum, toplevel::{DefinitionId, TopLevelDef}, typecheck::{ magic_methods::Binop, @@ -121,7 +119,7 @@ pub fn gen_store_target<'ctx, G: CodeGenerator>( return Ok(None); }; let BasicValueEnum::PointerValue(ptr) = val else { - unreachable!(); + codegen_unreachable!(ctx); }; unsafe { ctx.builder.build_in_bounds_gep( @@ -135,7 +133,7 @@ pub fn gen_store_target<'ctx, G: CodeGenerator>( } .unwrap() } - _ => unreachable!(), + _ => codegen_unreachable!(ctx), })) } @@ -193,12 +191,12 @@ pub fn gen_assign_target_list<'ctx, G: CodeGenerator>( // Deconstruct the tuple `value` let BasicValueEnum::StructValue(tuple) = value.to_basic_value_enum(ctx, generator, value_ty)? else { - unreachable!() + codegen_unreachable!(ctx) }; // NOTE: Currently, RHS's type is forced to be a Tuple by the type inferencer. let TypeEnum::TTuple { ty: tuple_tys, .. } = &*ctx.unifier.get_ty(value_ty) else { - unreachable!(); + codegen_unreachable!(ctx); }; assert_eq!(tuple.get_type().count_fields() as usize, tuple_tys.len()); @@ -258,7 +256,7 @@ pub fn gen_assign_target_list<'ctx, G: CodeGenerator>( // Now assign with that sub-tuple to the starred target. generator.gen_assign(ctx, target, ValueEnum::Dynamic(sub_tuple_val), sub_tuple_ty)?; } else { - unreachable!() // The typechecker ensures this + codegen_unreachable!(ctx) // The typechecker ensures this } // Handle assignment after the starred target @@ -306,7 +304,9 @@ pub fn gen_setitem<'ctx, G: CodeGenerator>( if let ExprKind::Slice { .. } = &key.node { // Handle assigning to a slice - let ExprKind::Slice { lower, upper, step } = &key.node else { unreachable!() }; + let ExprKind::Slice { lower, upper, step } = &key.node else { + codegen_unreachable!(ctx) + }; let Some((start, end, step)) = handle_slice_indices( lower, upper, @@ -416,7 +416,9 @@ pub fn gen_for( ctx: &mut CodeGenContext<'_, '_>, stmt: &Stmt>, ) -> Result<(), String> { - let StmtKind::For { iter, target, body, orelse, .. } = &stmt.node else { unreachable!() }; + let StmtKind::For { iter, target, body, orelse, .. } = &stmt.node else { + codegen_unreachable!(ctx) + }; // var_assignment static values may be changed in another branch // if so, remove the static value as it may not be correct in this branch @@ -458,7 +460,7 @@ pub fn gen_for( let Some(target_i) = generator.gen_store_target(ctx, target, Some("for.target.addr"))? else { - unreachable!() + codegen_unreachable!(ctx) }; let (start, stop, step) = destructure_range(ctx, iter_val); @@ -901,7 +903,7 @@ pub fn gen_while( ctx: &mut CodeGenContext<'_, '_>, stmt: &Stmt>, ) -> Result<(), String> { - let StmtKind::While { test, body, orelse, .. } = &stmt.node else { unreachable!() }; + let StmtKind::While { test, body, orelse, .. } = &stmt.node else { codegen_unreachable!(ctx) }; // var_assignment static values may be changed in another branch // if so, remove the static value as it may not be correct in this branch @@ -931,7 +933,7 @@ pub fn gen_while( return Ok(()); }; - let BasicValueEnum::IntValue(test) = test else { unreachable!() }; + let BasicValueEnum::IntValue(test) = test else { codegen_unreachable!(ctx) }; ctx.builder .build_conditional_branch(generator.bool_to_i1(ctx, test), body_bb, orelse_bb) @@ -1079,7 +1081,7 @@ pub fn gen_if( ctx: &mut CodeGenContext<'_, '_>, stmt: &Stmt>, ) -> Result<(), String> { - let StmtKind::If { test, body, orelse, .. } = &stmt.node else { unreachable!() }; + let StmtKind::If { test, body, orelse, .. } = &stmt.node else { codegen_unreachable!(ctx) }; // var_assignment static values may be changed in another branch // if so, remove the static value as it may not be correct in this branch @@ -1202,11 +1204,11 @@ pub fn exn_constructor<'ctx>( let zelf_id = if let TypeEnum::TObj { obj_id, .. } = &*ctx.unifier.get_ty(zelf_ty) { obj_id.0 } else { - unreachable!() + codegen_unreachable!(ctx) }; let defs = ctx.top_level.definitions.read(); let def = defs[zelf_id].read(); - let TopLevelDef::Class { name: zelf_name, .. } = &*def else { unreachable!() }; + let TopLevelDef::Class { name: zelf_name, .. } = &*def else { codegen_unreachable!(ctx) }; let exception_name = format!("{}:{}", ctx.resolver.get_exception_id(zelf_id), zelf_name); unsafe { let id_ptr = ctx.builder.build_in_bounds_gep(zelf, &[zero, zero], "exn.id").unwrap(); @@ -1314,7 +1316,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>( target: &Stmt>, ) -> Result<(), String> { let StmtKind::Try { body, handlers, orelse, finalbody, .. } = &target.node else { - unreachable!() + codegen_unreachable!(ctx) }; // if we need to generate anything related to exception, we must have personality defined @@ -1391,7 +1393,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>( if let TypeEnum::TObj { obj_id, .. } = &*ctx.unifier.get_ty(type_.custom.unwrap()) { *obj_id } else { - unreachable!() + codegen_unreachable!(ctx) }; let exception_name = format!("{}:{}", ctx.resolver.get_exception_id(obj_id.0), exn_name); let exn_id = ctx.resolver.get_string_id(&exception_name);