diff --git a/nac3artiq/src/lib.rs b/nac3artiq/src/lib.rs index 0b70b6d7a..30d439e4a 100644 --- a/nac3artiq/src/lib.rs +++ b/nac3artiq/src/lib.rs @@ -374,7 +374,7 @@ impl Nac3 { }); let (name, def_id, ty) = composer - .register_top_level(stmt.clone(), Some(resolver.clone()), path.clone(), false) + .register_top_level(stmt.clone(), Some(resolver.clone()), path, false) .map_err(|e| { CompileError::new_err(format!( "compilation failed\n----------\n{}", @@ -596,7 +596,7 @@ impl Nac3 { threads, top_level.clone(), &self.llvm_options, - f + &f ); registry.add_task(task); registry.wait_tasks_complete(handles); diff --git a/nac3core/build.rs b/nac3core/build.rs index f7e7e92df..281e28325 100644 --- a/nac3core/build.rs +++ b/nac3core/build.rs @@ -9,15 +9,11 @@ use std::{ fn main() { const FILE: &str = "src/codegen/irrt/irrt.c"; - println!("cargo:rerun-if-changed={}", FILE); - let out_dir = env::var("OUT_DIR").unwrap(); - let out_path = Path::new(&out_dir); /* * HACK: Sadly, clang doesn't let us emit generic LLVM bitcode. * Compiling for WASM32 and filtering the output with regex is the closest we can get. */ - const FLAG: &[&str] = &[ "--target=wasm32", FILE, @@ -29,6 +25,11 @@ fn main() { "-o", "-", ]; + + println!("cargo:rerun-if-changed={FILE}"); + let out_dir = env::var("OUT_DIR").unwrap(); + let out_path = Path::new(&out_dir); + let output = Command::new("clang-irrt") .args(FLAG) .output() @@ -68,5 +69,5 @@ fn main() { .spawn() .unwrap(); llvm_as.stdin.as_mut().unwrap().write_all(filtered_output.as_bytes()).unwrap(); - assert!(llvm_as.wait().unwrap().success()) + assert!(llvm_as.wait().unwrap().success()); } diff --git a/nac3core/src/codegen/concrete_type.rs b/nac3core/src/codegen/concrete_type.rs index f3f619d42..9181a1cad 100644 --- a/nac3core/src/codegen/concrete_type.rs +++ b/nac3core/src/codegen/concrete_type.rs @@ -63,6 +63,7 @@ pub enum ConcreteTypeEnum { } impl ConcreteTypeStore { + #[must_use] pub fn new() -> ConcreteTypeStore { ConcreteTypeStore { store: vec![ @@ -80,6 +81,7 @@ impl ConcreteTypeStore { } } + #[must_use] pub fn get(&self, cty: ConcreteType) -> &ConcreteTypeEnum { &self.store[cty.0] } diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index 88d68f7ff..6615a696d 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -47,7 +47,7 @@ pub fn get_subst_key( }) .unwrap_or_default(); vars.extend(fun_vars.iter()); - let sorted = vars.keys().filter(|id| filter.map(|v| v.contains(id)).unwrap_or(true)).sorted(); + let sorted = vars.keys().filter(|id| filter.map_or(true, |v| v.contains(id))).sorted(); sorted .map(|id| { unifier.internal_stringify( @@ -119,7 +119,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { } SymbolValue::Tuple(ls) => { let vals = ls.iter().map(|v| self.gen_symbol_val(generator, v, ty)).collect_vec(); - let fields = vals.iter().map(|v| v.get_type()).collect_vec(); + let fields = vals.iter().map(BasicValueEnum::get_type).collect_vec(); let ty = self.ctx.struct_type(&fields, false); let ptr = gen_var(self, ty.into(), Some("tuple")).unwrap(); let zero = self.ctx.i32_type().const_zero(); @@ -165,7 +165,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { } } - /// See [get_llvm_type]. + /// See [`get_llvm_type`]. pub fn get_llvm_type( &mut self, generator: &mut dyn CodeGenerator, @@ -183,7 +183,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { ) } - /// See [get_llvm_abi_type]. + /// See [`get_llvm_abi_type`]. pub fn get_llvm_abi_type( &mut self, generator: &mut dyn CodeGenerator, @@ -212,7 +212,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { Constant::Bool(v) => { assert!(self.unifier.unioned(ty, self.primitives.bool)); let ty = self.ctx.i8_type(); - Some(ty.const_int(if *v { 1 } else { 0 }, false).into()) + Some(ty.const_int(u64::from(*v), false).into()) } Constant::Int(val) => { let ty = if self.unifier.unioned(ty, self.primitives.int32) @@ -290,12 +290,9 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { rhs: BasicValueEnum<'ctx>, signed: bool ) -> BasicValueEnum<'ctx> { - let (lhs, rhs) = - if let (BasicValueEnum::IntValue(lhs), BasicValueEnum::IntValue(rhs)) = (lhs, rhs) { - (lhs, rhs) - } else { - unreachable!() - }; + let (BasicValueEnum::IntValue(lhs), BasicValueEnum::IntValue(rhs)) = (lhs, rhs) else { + unreachable!() + }; let float = self.ctx.f64_type(); match (op, signed) { (Operator::Add, _) => self.builder.build_int_add(lhs, rhs, "add").into(), @@ -318,7 +315,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { (Operator::BitAnd, _) => self.builder.build_and(lhs, rhs, "and").into(), // Sign-ness of bitshift operators are always determined by the left operand - (Operator::LShift, signed) | (Operator::RShift, signed) => { + (Operator::LShift | Operator::RShift, signed) => { // RHS operand is always 32 bits assert_eq!(rhs.get_type().get_bit_width(), 32); @@ -365,11 +362,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { lhs: BasicValueEnum<'ctx>, rhs: BasicValueEnum<'ctx>, ) -> BasicValueEnum<'ctx> { - let (lhs, rhs) = if let (BasicValueEnum::FloatValue(lhs), BasicValueEnum::FloatValue(rhs)) = - (lhs, rhs) - { - (lhs, rhs) - } else { + let (BasicValueEnum::FloatValue(lhs), BasicValueEnum::FloatValue(rhs)) = (lhs, rhs) else { unreachable!() }; let float = self.ctx.f64_type(); @@ -474,7 +467,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { .collect_vec(); let result = if let Some(target) = self.unwind_target { let current = self.builder.get_insert_block().unwrap().get_parent().unwrap(); - let then_block = self.ctx.append_basic_block(current, &format!("after.{}", call_name)); + let then_block = self.ctx.append_basic_block(current, &format!("after.{call_name}")); let result = self .builder .build_invoke(fun, ¶ms, then_block, target, call_name) @@ -516,7 +509,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { let ty = self.get_llvm_type(generator, self.primitives.exception).into_pointer_type(); let zelf_ty: BasicTypeEnum = ty.get_element_type().into_struct_type().into(); let zelf = generator.gen_var_alloc(self, zelf_ty, Some("exn")).unwrap(); - self.exception_val.insert(zelf).to_owned() + *self.exception_val.insert(zelf) }; let int32 = self.ctx.i32_type(); let zero = int32.const_zero(); @@ -556,7 +549,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { loc: Location, ) { let err_msg = self.gen_string(generator, err_msg); - self.make_assert_impl(generator, cond, err_name, err_msg, params, loc) + self.make_assert_impl(generator, cond, err_name, err_msg, params, loc); } pub fn make_assert_impl( @@ -598,7 +591,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { } } -/// See [CodeGenerator::gen_constructor]. +/// See [`CodeGenerator::gen_constructor`]. pub fn gen_constructor<'ctx, 'a, G: CodeGenerator>( generator: &mut G, ctx: &mut CodeGenContext<'ctx, 'a>, @@ -626,14 +619,14 @@ pub fn gen_constructor<'ctx, 'a, G: CodeGenerator>( } Ok(zelf) } - _ => unreachable!(), + TopLevelDef::Function { .. } => unreachable!(), } } -/// See [CodeGenerator::gen_func_instance]. +/// See [`CodeGenerator::gen_func_instance`]. pub fn gen_func_instance<'ctx>( ctx: &mut CodeGenContext<'ctx, '_>, - obj: Option<(Type, ValueEnum<'ctx>)>, + obj: &Option<(Type, ValueEnum<'ctx>)>, fun: (&FunSignature, &mut TopLevelDef, String), id: usize, ) -> Result { @@ -683,7 +676,7 @@ pub fn gen_func_instance<'ctx>( args.insert( 0, ConcreteFuncArg { name: "self".into(), ty: zelf, default_value: None }, - ) + ); } else { unreachable!() } @@ -707,7 +700,7 @@ pub fn gen_func_instance<'ctx>( } } -/// See [CodeGenerator::gen_call]. +/// See [`CodeGenerator::gen_call`]. pub fn gen_call<'ctx, G: CodeGenerator>( generator: &mut G, ctx: &mut CodeGenContext<'ctx, '_>, @@ -738,11 +731,11 @@ pub fn gen_call<'ctx, G: CodeGenerator>( let old_key = ctx.get_subst_key(obj.as_ref().map(|a| a.0), fun.0, None); let mut keys = fun.0.args.clone(); let mut mapping = HashMap::new(); - for (key, value) in params.into_iter() { + for (key, value) in params { mapping.insert(key.unwrap_or_else(|| keys.remove(0).name), value); } // default value handling - for k in keys.into_iter() { + for k in keys { if mapping.get(&k.name).is_some() { continue; } @@ -774,27 +767,26 @@ pub fn gen_call<'ctx, G: CodeGenerator>( .map(|(i, v)| (*i, v.get_unique_identifier())) .collect_vec(); let mut store = ctx.static_value_store.lock(); - match store.lookup.get(&ids) { - Some(index) => *index, - None => { - let length = store.store.len(); - store.lookup.insert(ids, length); - store.store.push(static_params.into_iter().collect()); - length - } + if let Some(index) = store.lookup.get(&ids) { + *index + } else { + let length = store.store.len(); + store.lookup.insert(ids, length); + store.store.push(static_params.into_iter().collect()); + length } }; // special case: extern functions key = if instance_to_stmt.is_empty() { - "".to_string() + String::new() } else { - format!("{}:{}", id, old_key) + format!("{id}:{old_key}") }; param_vals = real_params .into_iter() .map(|(p, t)| p.to_basic_value_enum(ctx, generator, t)) .collect::, String>>()?; - instance_to_symbol.get(&key).cloned().ok_or_else(|| "".into()) + instance_to_symbol.get(&key).cloned().ok_or_else(String::new) } TopLevelDef::Class { .. } => { return Ok(Some(generator.gen_constructor(ctx, fun.0, &def, params)?)) @@ -900,7 +892,7 @@ pub fn destructure_range<'ctx>( /// Allocates a List structure with the given [type][ty] and [length]. The name of the resulting /// LLVM value is `{name}.addr`, or `list.addr` if [name] is not specified. /// -/// Returns an instance of [PointerValue] pointing to the List structure. The List structure is +/// Returns an instance of [`PointerValue`] pointing to the List structure. The List structure is /// defined as `type { ty*, size_t }` in LLVM, where the first element stores the pointer to the /// data, and the second element stores the size of the List. pub fn allocate_list<'ctx, G: CodeGenerator>( @@ -1083,7 +1075,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>( ctx.builder.build_store(len_ptr, ctx.builder.build_load(index, "index")); }; - for cond in ifs.iter() { + for cond in ifs { let result = if let Some(v) = generator.gen_expr(ctx, cond)? { v.to_basic_value_enum(ctx, generator, cond.custom.unwrap())?.into_int_value() } else { @@ -1226,11 +1218,11 @@ pub fn gen_binop_expr<'ctx, G: CodeGenerator>( Some((left.custom.unwrap(), left_val.into())), (&signature, fun_id), vec![(None, right_val.into())], - ).map(|f| f.map(|f| f.into())) + ).map(|f| f.map(Into::into)) } } -/// See [CodeGenerator::gen_expr]. +/// See [`CodeGenerator::gen_expr`]. pub fn gen_expr<'ctx, G: CodeGenerator>( generator: &mut G, ctx: &mut CodeGenContext<'ctx, '_>, @@ -1462,7 +1454,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( ast::Unaryop::USub => ctx.builder.build_int_neg(val, "neg").into(), ast::Unaryop::Invert => ctx.builder.build_not(val, "not").into(), ast::Unaryop::Not => ctx.builder.build_xor(val, val.get_type().const_all_ones(), "not").into(), - _ => val.into(), + ast::Unaryop::UAdd => val.into(), } } else if ty == ctx.primitives.float { let val = val.into_float_value(); @@ -1574,11 +1566,11 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( let test = generator.bool_to_i1(ctx, test); let body_ty = body.custom.unwrap(); let is_none = ctx.unifier.get_representative(body_ty) == ctx.primitives.none; - let result = if !is_none { + let result = if is_none { + None + } else { let llvm_ty = ctx.get_llvm_type(generator, body_ty); Some(ctx.builder.build_alloca(llvm_ty, "if_exp_result")) - } else { - None }; let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap(); let then_bb = ctx.ctx.append_basic_block(current, "then"); @@ -1640,15 +1632,14 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( let kw_iter = kw_iter.collect::, _>>()?; params.extend(kw_iter); let call = ctx.calls.get(&expr.location.into()); - let signature = match call { - Some(call) => ctx.unifier.get_call_signature(*call).unwrap(), - None => { - let ty = func.custom.unwrap(); - if let TypeEnum::TFunc(sign) = &*ctx.unifier.get_ty(ty) { - sign.clone() - } else { - unreachable!() - } + let signature = if let Some(call) = call { + ctx.unifier.get_call_signature(*call).unwrap() + } else { + let ty = func.custom.unwrap(); + if let TypeEnum::TFunc(sign) = &*ctx.unifier.get_ty(ty) { + sign.clone() + } else { + unreachable!() } }; let func = func.as_ref(); @@ -1661,12 +1652,11 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( .map_err(|e| format!("{} (at {})", e, func.location))?; return Ok(generator .gen_call(ctx, None, (&signature, fun), params)? - .map(|v| v.into())); + .map(Into::into)); } ExprKind::Attribute { value, attr, .. } => { - let val = match generator.gen_expr(ctx, value)? { - Some(v) => v, - None => return Ok(None), + let Some(val) = generator.gen_expr(ctx, value)? else { + return Ok(None) }; let id = if let TypeEnum::TObj { obj_id, .. } = @@ -1745,7 +1735,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( "unwrap_some_load" ).into())) } - _ => unreachable!("option must be static or ptr") + ValueEnum::Dynamic(_) => unreachable!("option must be static or ptr") } } @@ -1759,7 +1749,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( (&signature, fun_id), params, )? - .map(|v| v.into())); + .map(Into::into)); } _ => unimplemented!(), } @@ -1871,14 +1861,13 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( ctx.builder.build_extract_value(v, index, "tup_elem").unwrap().into() } Some(ValueEnum::Static(v)) => { - match v.get_tuple_element(index) { - Some(v) => v, - None => { - let tup = v - .to_basic_value_enum(ctx, generator, value.custom.unwrap())? - .into_struct_value(); - ctx.builder.build_extract_value(tup, index, "tup_elem").unwrap().into() - } + if let Some(v) = v.get_tuple_element(index) { + v + } else { + let tup = v + .to_basic_value_enum(ctx, generator, value.custom.unwrap())? + .into_struct_value(); + ctx.builder.build_extract_value(tup, index, "tup_elem").unwrap().into() } } None => return Ok(None), diff --git a/nac3core/src/codegen/generator.rs b/nac3core/src/codegen/generator.rs index ae92ab55a..7a86c0bb6 100644 --- a/nac3core/src/codegen/generator.rs +++ b/nac3core/src/codegen/generator.rs @@ -66,7 +66,7 @@ pub trait CodeGenerator { fun: (&FunSignature, &mut TopLevelDef, String), id: usize, ) -> Result { - gen_func_instance(ctx, obj, fun, id) + gen_func_instance(ctx, &obj, fun, id) } /// Generate the code for an expression. @@ -194,7 +194,7 @@ pub trait CodeGenerator { gen_block(self, ctx, stmts) } - /// See [bool_to_i1]. + /// See [`bool_to_i1`]. fn bool_to_i1<'ctx>( &self, ctx: &CodeGenContext<'ctx, '_>, @@ -203,7 +203,7 @@ pub trait CodeGenerator { bool_to_i1(&ctx.builder, bool_value) } - /// See [bool_to_i8]. + /// See [`bool_to_i8`]. fn bool_to_i8<'ctx>( &self, ctx: &CodeGenContext<'ctx, '_>, @@ -219,6 +219,7 @@ pub struct DefaultCodeGenerator { } impl DefaultCodeGenerator { + #[must_use] pub fn new(name: String, size_t: u32) -> DefaultCodeGenerator { assert!(matches!(size_t, 32 | 64)); DefaultCodeGenerator { name, size_t } @@ -227,7 +228,7 @@ impl DefaultCodeGenerator { impl CodeGenerator for DefaultCodeGenerator { - /// Returns the name for this [CodeGenerator]. + /// Returns the name for this [`CodeGenerator`]. fn get_name(&self) -> &str { &self.name } diff --git a/nac3core/src/codegen/irrt/mod.rs b/nac3core/src/codegen/irrt/mod.rs index 76e50a0d1..0cd0ebdda 100644 --- a/nac3core/src/codegen/irrt/mod.rs +++ b/nac3core/src/codegen/irrt/mod.rs @@ -12,6 +12,7 @@ use inkwell::{ }; use nac3parser::ast::Expr; +#[must_use] pub fn load_irrt(ctx: &Context) -> Module { let bitcode_buf = MemoryBuffer::create_from_memory_range( include_bytes!(concat!(env!("OUT_DIR"), "/irrt.bc")), @@ -288,7 +289,7 @@ pub fn handle_slice_index_bound<'ctx, G: CodeGenerator>( } /// This function handles 'end' **inclusively**. -/// Order of tuples assign_idx and value_idx is ('start', 'end', 'step'). +/// Order of tuples `assign_idx` and `value_idx` is ('start', 'end', 'step'). /// Negative index should be handled before entering this function pub fn list_slice_assignment<'ctx>( generator: &mut dyn CodeGenerator, diff --git a/nac3core/src/codegen/mod.rs b/nac3core/src/codegen/mod.rs index 2f4aca58f..06c0fc890 100644 --- a/nac3core/src/codegen/mod.rs +++ b/nac3core/src/codegen/mod.rs @@ -81,8 +81,9 @@ pub struct CodeGenTargetMachineOptions { impl CodeGenTargetMachineOptions { - /// Creates an instance of [CodeGenTargetMachineOptions] using the triple of the host machine. + /// Creates an instance of [`CodeGenTargetMachineOptions`] using the triple of the host machine. /// Other options are set to defaults. + #[must_use] pub fn from_host_triple() -> CodeGenTargetMachineOptions { CodeGenTargetMachineOptions { triple: TargetMachine::get_default_triple().as_str().to_string_lossy().into_owned(), @@ -93,8 +94,9 @@ impl CodeGenTargetMachineOptions { } } - /// Creates an instance of [CodeGenTargetMachineOptions] using the properties of the host + /// Creates an instance of [`CodeGenTargetMachineOptions`] using the properties of the host /// machine. Other options are set to defaults. + #[must_use] pub fn from_host() -> CodeGenTargetMachineOptions { CodeGenTargetMachineOptions { cpu: TargetMachine::get_host_cpu_name().to_string(), @@ -103,9 +105,10 @@ impl CodeGenTargetMachineOptions { } } - /// Creates a [TargetMachine] using the target options specified by this struct. + /// Creates a [`TargetMachine`] using the target options specified by this struct. /// - /// See [Target::create_target_machine]. + /// See [`Target::create_target_machine`]. + #[must_use] pub fn create_target_machine( &self, level: OptimizationLevel, @@ -195,7 +198,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { /// Whether the [current basic block][Builder::get_insert_block] referenced by `builder` /// contains a [terminator statement][BasicBlock::get_terminator]. pub fn is_terminated(&self) -> bool { - self.builder.get_insert_block().and_then(|bb| bb.get_terminator()).is_some() + self.builder.get_insert_block().and_then(BasicBlock::get_terminator).is_some() } } @@ -206,12 +209,13 @@ pub struct WithCall { } impl WithCall { + #[must_use] pub fn new(fp: Fp) -> WithCall { WithCall { fp } } pub fn run(&self, m: &Module) { - (self.fp)(m) + (self.fp)(m); } } @@ -238,20 +242,21 @@ pub struct WorkerRegistry { impl WorkerRegistry { /// Creates workers for this registry. + #[must_use] pub fn create_workers( generators: Vec>, top_level_ctx: Arc, llvm_options: &CodeGenLLVMOptions, - f: Arc, + f: &Arc, ) -> (Arc, Vec>) { let (sender, receiver) = unbounded(); let task_count = Mutex::new(0); let wait_condvar = Condvar::new(); // init: 0 to be empty - let mut static_value_store: StaticValueStore = Default::default(); - static_value_store.lookup.insert(Default::default(), 0); - static_value_store.store.push(Default::default()); + let mut static_value_store = StaticValueStore::default(); + static_value_store.lookup.insert(Vec::default(), 0); + static_value_store.store.push(HashMap::default()); let registry = Arc::new(WorkerRegistry { sender: Arc::new(sender), @@ -266,19 +271,19 @@ impl WorkerRegistry { }); let mut handles = Vec::new(); - for mut generator in generators.into_iter() { + for mut generator in generators { let registry = registry.clone(); let registry2 = registry.clone(); let f = f.clone(); let handle = thread::spawn(move || { - registry.worker_thread(generator.as_mut(), f); + registry.worker_thread(generator.as_mut(), &f); }); let handle = thread::spawn(move || { if let Err(e) = handle.join() { if let Some(e) = e.downcast_ref::<&'static str>() { - eprintln!("Got an error: {}", e); + eprintln!("Got an error: {e}"); } else { - eprintln!("Got an unknown error: {:?}", e); + eprintln!("Got an unknown error: {e:?}"); } registry2.panicked.store(true, Ordering::SeqCst); registry2.wait_condvar.notify_all(); @@ -314,19 +319,17 @@ impl WorkerRegistry { for handle in handles { handle.join().unwrap(); } - if self.panicked.load(Ordering::SeqCst) { - panic!("tasks panicked"); - } + assert!(!self.panicked.load(Ordering::SeqCst), "tasks panicked"); } - /// Adds a task to this [WorkerRegistry]. + /// Adds a task to this [`WorkerRegistry`]. pub fn add_task(&self, task: CodeGenTask) { *self.task_count.lock() += 1; self.sender.send(Some(task)).unwrap(); } /// Function executed by worker thread for generating IR for each function. - fn worker_thread(&self, generator: &mut G, f: Arc) { + fn worker_thread(&self, generator: &mut G, f: &Arc) { let context = Context::create(); let mut builder = context.create_builder(); let mut module = context.create_module(generator.get_name()); @@ -359,9 +362,7 @@ impl WorkerRegistry { *self.task_count.lock() -= 1; self.wait_condvar.notify_all(); } - if !errors.is_empty() { - panic!("Codegen error: {}", errors.into_iter().sorted().join("\n----------\n")); - } + assert!(errors.is_empty(), "Codegen error: {}", errors.into_iter().sorted().join("\n----------\n")); let result = module.verify(); if let Err(err) = result { @@ -419,7 +420,7 @@ fn get_llvm_type<'ctx>( use TypeEnum::*; // we assume the type cache should already contain primitive types, // and they should be passed by value instead of passing as pointer. - type_cache.get(&unifier.get_representative(ty)).cloned().unwrap_or_else(|| { + type_cache.get(&unifier.get_representative(ty)).copied().unwrap_or_else(|| { let ty_enum = unifier.get_ty(ty); let result = match &*ty_enum { TObj { obj_id, fields, .. } => { @@ -454,32 +455,31 @@ fn get_llvm_type<'ctx>( &*definition.read() { let name = unifier.stringify(ty); - match module.get_struct_type(&name) { - Some(t) => t.ptr_type(AddressSpace::default()).into(), - None => { - let struct_type = ctx.opaque_struct_type(&name); - type_cache.insert( - unifier.get_representative(ty), - struct_type.ptr_type(AddressSpace::default()).into() - ); - let fields = fields_list - .iter() - .map(|f| { - get_llvm_type( - ctx, - module, - generator, - unifier, - top_level, - type_cache, - primitives, - fields[&f.0].0, - ) - }) - .collect_vec(); - struct_type.set_body(&fields, false); + if let Some(t) = module.get_struct_type(&name) { + t.ptr_type(AddressSpace::default()).into() + } else { + let struct_type = ctx.opaque_struct_type(&name); + type_cache.insert( + unifier.get_representative(ty), struct_type.ptr_type(AddressSpace::default()).into() - } + ); + let fields = fields_list + .iter() + .map(|f| { + get_llvm_type( + ctx, + module, + generator, + unifier, + top_level, + type_cache, + primitives, + fields[&f.0].0, + ) + }) + .collect_vec(); + struct_type.set_body(&fields, false); + struct_type.ptr_type(AddressSpace::default()).into() } } else { unreachable!() @@ -517,12 +517,12 @@ fn get_llvm_type<'ctx>( }) } -/// Retrieves the [LLVM type][BasicTypeEnum] corresponding to the [Type]. +/// Retrieves the [LLVM type][`BasicTypeEnum`] corresponding to the [`Type`]. /// /// This function is used mainly to obtain the ABI representation of `ty`, e.g. a `bool` is /// would be represented by an `i1`. /// -/// The difference between the in-memory representation (as returned by [get_llvm_type]) and the +/// The difference between the in-memory representation (as returned by [`get_llvm_type`]) and the /// ABI representation is that the in-memory representation must be at least byte-sized and must /// be byte-aligned for the variable to be addressable in memory, whereas there is no such /// restriction for ABI representations. @@ -551,7 +551,7 @@ fn get_llvm_abi_type<'ctx>( /// the target processor) by value, a synthetic parameter with a pointer type will be passed in the /// slot of the first parameter to act as the location of which the return value is passed into. /// -/// See [https://releases.llvm.org/14.0.0/docs/LangRef.html#parameter-attributes] for more +/// See for more /// information. fn need_sret(ty: BasicTypeEnum) -> bool { fn need_sret_impl(ty: BasicTypeEnum, maybe_large: bool) -> bool { @@ -585,7 +585,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte unifier.top_level = Some(top_level_ctx.clone()); let mut cache = HashMap::new(); - for (a, b) in task.subst.iter() { + for (a, b) in &task.subst { // this should be unification between variables and concrete types // and should not cause any problem... let b = task.store.to_unifier_type(&mut unifier, &primitives, *b, &mut cache); @@ -599,7 +599,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte Err(err) } }) - .unwrap() + .unwrap(); } // rebuild primitive store with unique representatives @@ -642,22 +642,21 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte (primitives.range, context.i32_type().array_type(3).ptr_type(AddressSpace::default()).into()), (primitives.exception, { let name = "Exception"; - match module.get_struct_type(name) { - Some(t) => t.ptr_type(AddressSpace::default()).as_basic_type_enum(), - None => { - let exception = context.opaque_struct_type("Exception"); - let int32 = context.i32_type().into(); - let int64 = context.i64_type().into(); - let str_ty = module.get_struct_type("str").unwrap().as_basic_type_enum(); - let fields = [int32, str_ty, int32, int32, str_ty, str_ty, int64, int64, int64]; - exception.set_body(&fields, false); - exception.ptr_type(AddressSpace::default()).as_basic_type_enum() - } + if let Some(t) = module.get_struct_type(name) { + t.ptr_type(AddressSpace::default()).as_basic_type_enum() + } else { + let exception = context.opaque_struct_type("Exception"); + let int32 = context.i32_type().into(); + let int64 = context.i64_type().into(); + let str_ty = module.get_struct_type("str").unwrap().as_basic_type_enum(); + let fields = [int32, str_ty, int32, int32, str_ty, str_ty, int64, int64, int64]; + exception.set_body(&fields, false); + exception.ptr_type(AddressSpace::default()).as_basic_type_enum() } }) ] .iter() - .cloned() + .copied() .collect(); // NOTE: special handling of option cannot use this type cache since it contains type var, // handled inside get_llvm_type instead @@ -733,7 +732,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte let body_bb = context.append_basic_block(fn_val, "body"); let mut var_assignment = HashMap::new(); - let offset = if has_sret { 1 } else { 0 }; + let offset = u32::from(has_sret); for (n, arg) in args.iter().enumerate() { let param = fn_val.get_nth_param((n as u32) + offset).unwrap(); let local_type = get_llvm_type( @@ -779,7 +778,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte let store = registry.static_value_store.lock(); store.store[task.id].clone() }; - for (k, v) in static_values.into_iter() { + for (k, v) in static_values { let (_, static_val, _) = var_assignment.get_mut(&args[k].name).unwrap(); *static_val = Some(v); } @@ -849,19 +848,19 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte return_buffer, unwind_target: None, outer_catch_clauses: None, - const_strings: Default::default(), + const_strings: HashMap::default(), registry, var_assignment, type_cache, primitives, init_bb, - exception_val: Default::default(), + exception_val: Option::default(), builder, module, unifier, static_value_store, need_sret: has_sret, - current_loc: Default::default(), + current_loc: Location::default(), debug_info: (dibuilder, compile_unit, func_scope.as_debug_info_scope()), }; @@ -894,12 +893,12 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte /// Generates LLVM IR for a function. /// -/// * `context` - The [LLVM Context][Context] used in generating the function body. -/// * `generator` - The [CodeGenerator] for generating various program constructs. -/// * `registry` - The [WorkerRegistry] responsible for monitoring this function generation task. -/// * `builder` - The [Builder] used for generating LLVM IR. -/// * `module` - The [Module] of which the generated LLVM function will be inserted into. -/// * `task` - The [CodeGenTask] associated with this function generation task. +/// * `context` - The [LLVM Context][`Context`] used in generating the function body. +/// * `generator` - The [`CodeGenerator`] for generating various program constructs. +/// * `registry` - The [`WorkerRegistry`] responsible for monitoring this function generation task. +/// * `builder` - The [`Builder`] used for generating LLVM IR. +/// * `module` - The [`Module`] of which the generated LLVM function will be inserted into. +/// * `task` - The [`CodeGenTask`] associated with this function generation task. /// pub fn gen_func<'ctx, G: CodeGenerator>( context: &'ctx Context, @@ -917,15 +916,15 @@ pub fn gen_func<'ctx, G: CodeGenerator>( /// Converts the value of a boolean-like value `bool_value` into an `i1`. fn bool_to_i1<'ctx>(builder: &Builder<'ctx>, bool_value: IntValue<'ctx>) -> IntValue<'ctx> { - if bool_value.get_type().get_bit_width() != 1 { + if bool_value.get_type().get_bit_width() == 1 { + bool_value + } else { builder.build_int_compare( IntPredicate::NE, bool_value, bool_value.get_type().const_zero(), "tobool" ) - } else { - bool_value } } @@ -966,7 +965,7 @@ fn bool_to_i8<'ctx>( /// let cmp = lo < hi; /// ``` /// -/// Returns an `i1` [IntValue] representing the result of whether the `value` is in the range. +/// Returns an `i1` [`IntValue`] representing the result of whether the `value` is in the range. fn gen_in_range_check<'ctx>( ctx: &CodeGenContext<'ctx, '_>, value: IntValue<'ctx>, diff --git a/nac3core/src/codegen/stmt.rs b/nac3core/src/codegen/stmt.rs index a0d6b19d6..8f76f416f 100644 --- a/nac3core/src/codegen/stmt.rs +++ b/nac3core/src/codegen/stmt.rs @@ -24,7 +24,7 @@ use nac3parser::ast::{ }; use std::convert::TryFrom; -/// See [CodeGenerator::gen_var_alloc]. +/// See [`CodeGenerator::gen_var_alloc`]. pub fn gen_var<'ctx>( ctx: &mut CodeGenContext<'ctx, '_>, ty: BasicTypeEnum<'ctx>, @@ -54,7 +54,7 @@ pub fn gen_var<'ctx>( Ok(ptr) } -/// See [CodeGenerator::gen_store_target]. +/// See [`CodeGenerator::gen_store_target`]. pub fn gen_store_target<'ctx, G: CodeGenerator>( generator: &mut G, ctx: &mut CodeGenContext<'ctx, '_>, @@ -84,9 +84,7 @@ pub fn gen_store_target<'ctx, G: CodeGenerator>( } else { return Ok(None) }; - let ptr = if let BasicValueEnum::PointerValue(v) = val { - v - } else { + let BasicValueEnum::PointerValue(ptr) = val else { unreachable!(); }; unsafe { @@ -164,7 +162,7 @@ pub fn gen_store_target<'ctx, G: CodeGenerator>( })) } -/// See [CodeGenerator::gen_assign]. +/// See [`CodeGenerator::gen_assign`]. pub fn gen_assign<'ctx, G: CodeGenerator>( generator: &mut G, ctx: &mut CodeGenContext<'ctx, '_>, @@ -212,14 +210,14 @@ pub fn gen_assign<'ctx, G: CodeGenerator>( let Some(src_ind) = handle_slice_indices(&None, &None, &None, ctx, generator, value)? else { return Ok(()) }; - list_slice_assignment(generator, ctx, ty, ls, (start, end, step), value, src_ind) + list_slice_assignment(generator, ctx, ty, ls, (start, end, step), value, src_ind); } else { unreachable!() } } _ => { let name = if let ExprKind::Name { id, .. } = &target.node { - format!("{}.addr", id) + format!("{id}.addr") } else { String::from("target.addr") }; @@ -241,7 +239,7 @@ pub fn gen_assign<'ctx, G: CodeGenerator>( Ok(()) } -/// See [CodeGenerator::gen_for]. +/// See [`CodeGenerator::gen_for`]. pub fn gen_for( generator: &mut G, ctx: &mut CodeGenContext<'_, '_>, @@ -255,7 +253,7 @@ pub fn gen_for( let int32 = ctx.ctx.i32_type(); let size_t = generator.get_size_type(ctx.ctx); let zero = int32.const_zero(); - let current = ctx.builder.get_insert_block().and_then(|bb| bb.get_parent()).unwrap(); + let current = ctx.builder.get_insert_block().and_then(BasicBlock::get_parent).unwrap(); let body_bb = ctx.ctx.append_basic_block(current, "for.body"); let cont_bb = ctx.ctx.append_basic_block(current, "for.end"); // if there is no orelse, we just go to cont_bb @@ -368,7 +366,7 @@ pub fn gen_for( generator.gen_block(ctx, body.iter())?; } - for (k, (_, _, counter)) in var_assignment.iter() { + for (k, (_, _, counter)) in &var_assignment { let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap(); if counter != counter2 { *static_val = None; @@ -387,7 +385,7 @@ pub fn gen_for( } } - for (k, (_, _, counter)) in var_assignment.iter() { + for (k, (_, _, counter)) in &var_assignment { let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap(); if counter != counter2 { *static_val = None; @@ -402,7 +400,7 @@ pub fn gen_for( Ok(()) } -/// See [CodeGenerator::gen_while]. +/// See [`CodeGenerator::gen_while`]. pub fn gen_while( generator: &mut G, ctx: &mut CodeGenContext<'_, '_>, @@ -441,7 +439,7 @@ pub fn gen_while( }; ctx.builder.position_at_end(body_bb); generator.gen_block(ctx, body.iter())?; - for (k, (_, _, counter)) in var_assignment.iter() { + for (k, (_, _, counter)) in &var_assignment { let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap(); if counter != counter2 { *static_val = None; @@ -457,7 +455,7 @@ pub fn gen_while( ctx.builder.build_unconditional_branch(cont_bb); } } - for (k, (_, _, counter)) in var_assignment.iter() { + for (k, (_, _, counter)) in &var_assignment { let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap(); if counter != counter2 { *static_val = None; @@ -471,7 +469,7 @@ pub fn gen_while( Ok(()) } -/// See [CodeGenerator::gen_if]. +/// See [`CodeGenerator::gen_if`]. pub fn gen_if( generator: &mut G, ctx: &mut CodeGenContext<'_, '_>, @@ -503,7 +501,7 @@ pub fn gen_if( }; ctx.builder.position_at_end(body_bb); generator.gen_block(ctx, body.iter())?; - for (k, (_, _, counter)) in var_assignment.iter() { + for (k, (_, _, counter)) in &var_assignment { let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap(); if counter != counter2 { *static_val = None; @@ -529,7 +527,7 @@ pub fn gen_if( if let Some(cont_bb) = cont_bb { ctx.builder.position_at_end(cont_bb); } - for (k, (_, _, counter)) in var_assignment.iter() { + for (k, (_, _, counter)) in &var_assignment { let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap(); if counter != counter2 { *static_val = None; @@ -571,8 +569,7 @@ pub fn get_builtins<'ctx>( .ctx .void_type() .fn_type(&[ctx.get_llvm_type(generator, ctx.primitives.exception).into()], false), - "__nac3_resume" => ctx.ctx.void_type().fn_type(&[], false), - "__nac3_end_catch" => ctx.ctx.void_type().fn_type(&[], false), + "__nac3_resume" | "__nac3_end_catch" => ctx.ctx.void_type().fn_type(&[], false), _ => unimplemented!(), }; let fun = ctx.module.add_function(symbol, ty, None); @@ -613,20 +610,20 @@ pub fn exn_constructor<'ctx>( let id_ptr = ctx.builder.build_in_bounds_gep(zelf, &[zero, zero], "exn.id"); let id = ctx.resolver.get_string_id(&exception_name); ctx.builder.build_store(id_ptr, int32.const_int(id as u64, false)); - let empty_string = ctx.gen_const(generator, &Constant::Str("".into()), ctx.primitives.str); + let empty_string = ctx.gen_const(generator, &Constant::Str(String::new()), ctx.primitives.str); let ptr = ctx.builder.build_in_bounds_gep(zelf, &[zero, int32.const_int(5, false)], "exn.msg"); - let msg = if !args.is_empty() { - args.remove(0).1.to_basic_value_enum(ctx, generator, ctx.primitives.str)? - } else { + let msg = if args.is_empty() { empty_string.unwrap() + } else { + args.remove(0).1.to_basic_value_enum(ctx, generator, ctx.primitives.str)? }; ctx.builder.build_store(ptr, msg); - for i in [6, 7, 8].iter() { - let value = if !args.is_empty() { - args.remove(0).1.to_basic_value_enum(ctx, generator, ctx.primitives.int64)? - } else { + for i in &[6, 7, 8] { + let value = if args.is_empty() { ctx.ctx.i64_type().const_zero().into() + } else { + args.remove(0).1.to_basic_value_enum(ctx, generator, ctx.primitives.int64)? }; let ptr = ctx.builder.build_in_bounds_gep( zelf, @@ -636,7 +633,7 @@ pub fn exn_constructor<'ctx>( ctx.builder.build_store(ptr, value); } // set file, func to empty string - for i in [1, 4].iter() { + for i in &[1, 4] { let ptr = ctx.builder.build_in_bounds_gep( zelf, &[zero, int32.const_int(*i, false)], @@ -645,7 +642,7 @@ pub fn exn_constructor<'ctx>( ctx.builder.build_store(ptr, empty_string.unwrap()); } // set ints to zero - for i in [2, 3].iter() { + for i in &[2, 3] { let ptr = ctx.builder.build_in_bounds_gep( zelf, &[zero, int32.const_int(*i, false)], @@ -768,7 +765,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>( let mut clauses = Vec::new(); let mut found_catch_all = false; - for handler_node in handlers.iter() { + for handler_node in handlers { let ExcepthandlerKind::ExceptHandler { type_, .. } = &handler_node.node; // none or Exception if type_.is_none() @@ -779,30 +776,30 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>( clauses.push(None); found_catch_all = true; break; - } else { - let type_ = type_.as_ref().unwrap(); - let exn_name = ctx.resolver.get_type_name( - &ctx.top_level.definitions.read(), - &mut ctx.unifier, - type_.custom.unwrap(), - ); - let obj_id = if let TypeEnum::TObj { obj_id, .. } = &*ctx.unifier.get_ty(type_.custom.unwrap()) { - *obj_id - } else { - unreachable!() - }; - let exception_name = format!("{}:{}", ctx.resolver.get_exception_id(obj_id.0), exn_name); - let exn_id = ctx.resolver.get_string_id(&exception_name); - let exn_id_global = - ctx.module.add_global(ctx.ctx.i32_type(), None, &format!("exn.{}", exn_id)); - exn_id_global.set_initializer(&ctx.ctx.i32_type().const_int(exn_id as u64, false)); - clauses.push(Some(exn_id_global.as_pointer_value().as_basic_value_enum())); } + + let type_ = type_.as_ref().unwrap(); + let exn_name = ctx.resolver.get_type_name( + &ctx.top_level.definitions.read(), + &mut ctx.unifier, + type_.custom.unwrap(), + ); + let obj_id = if let TypeEnum::TObj { obj_id, .. } = &*ctx.unifier.get_ty(type_.custom.unwrap()) { + *obj_id + } else { + unreachable!() + }; + let exception_name = format!("{}:{}", ctx.resolver.get_exception_id(obj_id.0), exn_name); + let exn_id = ctx.resolver.get_string_id(&exception_name); + let exn_id_global = + ctx.module.add_global(ctx.ctx.i32_type(), None, &format!("exn.{exn_id}")); + exn_id_global.set_initializer(&ctx.ctx.i32_type().const_int(exn_id as u64, false)); + clauses.push(Some(exn_id_global.as_pointer_value().as_basic_value_enum())); } let mut all_clauses = clauses.clone(); if let Some(old_clauses) = &ctx.outer_catch_clauses { if !found_catch_all { - all_clauses.extend_from_slice(&old_clauses.0) + all_clauses.extend_from_slice(&old_clauses.0); } } let old_clauses = ctx.outer_catch_clauses.replace((all_clauses, dispatcher, exn)); @@ -819,7 +816,9 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>( ctx.return_target = old_return; ctx.loop_target = old_loop_target.or(ctx.loop_target).take(); - let old_unwind = if !finalbody.is_empty() { + let old_unwind = if finalbody.is_empty() { + None + } else { let final_landingpad = ctx.ctx.append_basic_block(current_fun, "try.catch.final"); ctx.builder.position_at_end(final_landingpad); ctx.builder.build_landing_pad( @@ -832,8 +831,6 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>( ctx.builder.build_unconditional_branch(cleanup.unwrap()); ctx.builder.position_at_end(body); ctx.unwind_target.replace(final_landingpad) - } else { - None }; // run end_catch before continue/break/return @@ -886,7 +883,9 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>( let mut post_handlers = Vec::new(); - let exnid = if !handlers.is_empty() { + let exnid = if handlers.is_empty() { + None + } else { ctx.builder.position_at_end(dispatcher); unsafe { let zero = ctx.ctx.i32_type().const_zero(); @@ -897,8 +896,6 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>( ); Some(ctx.builder.build_load(exnid_ptr, "exnid")) } - } else { - None }; for (handler_node, exn_type) in handlers.iter().zip(clauses.iter()) { @@ -1011,7 +1008,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>( let dest = ctx.builder.build_load(final_state, "final_dest"); ctx.builder.build_indirect_branch(dest, &final_targets); } - for block in final_paths.iter() { + for block in &final_paths { if block.get_terminator().is_none() { ctx.builder.position_at_end(*block); ctx.builder.build_unconditional_branch(finalizer); @@ -1034,7 +1031,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>( } } -/// See [CodeGenerator::gen_with]. +/// See [`CodeGenerator::gen_with`]. pub fn gen_with( _: &mut G, _: &mut CodeGenContext<'_, '_>, @@ -1050,7 +1047,7 @@ pub fn gen_return( ctx: &mut CodeGenContext<'_, '_>, value: &Option>>>, ) -> Result<(), String> { - let func = ctx.builder.get_insert_block().and_then(|bb| bb.get_parent()).unwrap(); + let func = ctx.builder.get_insert_block().and_then(BasicBlock::get_parent).unwrap(); let value = if let Some(v_expr) = value.as_ref() { if let Some(v) = generator.gen_expr(ctx, v_expr).transpose() { Some( @@ -1096,7 +1093,7 @@ pub fn gen_return( Ok(()) } -/// See [CodeGenerator::gen_stmt]. +/// See [`CodeGenerator::gen_stmt`]. pub fn gen_stmt( generator: &mut G, ctx: &mut CodeGenContext<'_, '_>, @@ -1133,7 +1130,7 @@ pub fn gen_stmt( let Some(value) = generator.gen_expr(ctx, value)? else { return Ok(()) }; - for target in targets.iter() { + for target in targets { generator.gen_assign(ctx, target, value.clone())?; } } @@ -1185,7 +1182,7 @@ pub fn gen_stmt( err_msg, [None, None, None], stmt.location, - ) + ); } _ => unimplemented!() }; diff --git a/nac3core/src/symbol_resolver.rs b/nac3core/src/symbol_resolver.rs index 02e3fa6c9..5224659d1 100644 --- a/nac3core/src/symbol_resolver.rs +++ b/nac3core/src/symbol_resolver.rs @@ -35,10 +35,10 @@ pub enum SymbolValue { } impl SymbolValue { - /// Creates a [SymbolValue] from a [Constant]. + /// Creates a [`SymbolValue`] from a [`Constant`]. /// /// * `constant` - The constant to create the value from. - /// * `expected_ty` - The expected type of the [SymbolValue]. + /// * `expected_ty` - The expected type of the [`SymbolValue`]. pub fn from_constant( constant: &Constant, expected_ty: Type, @@ -50,21 +50,21 @@ impl SymbolValue { if unifier.unioned(expected_ty, primitives.option) { Ok(SymbolValue::OptionNone) } else { - Err(format!("Expected {:?}, but got Option", expected_ty)) + Err(format!("Expected {expected_ty:?}, but got Option")) } } Constant::Bool(b) => { if unifier.unioned(expected_ty, primitives.bool) { Ok(SymbolValue::Bool(*b)) } else { - Err(format!("Expected {:?}, but got bool", expected_ty)) + Err(format!("Expected {expected_ty:?}, but got bool")) } } Constant::Str(s) => { if unifier.unioned(expected_ty, primitives.str) { Ok(SymbolValue::Str(s.to_string())) } else { - Err(format!("Expected {:?}, but got str", expected_ty)) + Err(format!("Expected {expected_ty:?}, but got str")) } }, Constant::Int(i) => { @@ -107,14 +107,14 @@ impl SymbolValue { if unifier.unioned(expected_ty, primitives.float) { Ok(SymbolValue::Double(*f)) } else { - Err(format!("Expected {:?}, but got float", expected_ty)) + Err(format!("Expected {expected_ty:?}, but got float")) } }, - _ => Err(format!("Unsupported value type {:?}", constant)), + _ => Err(format!("Unsupported value type {constant:?}")), } } - /// Returns the [Type] representing the data type of this value. + /// Returns the [`Type`] representing the data type of this value. pub fn get_type(&self, primitives: &PrimitiveStore, unifier: &mut Unifier) -> Type { match self { SymbolValue::I32(_) => primitives.int32, @@ -133,12 +133,11 @@ impl SymbolValue { ty: vs_tys, }) } - SymbolValue::OptionSome(_) => primitives.option, - SymbolValue::OptionNone => primitives.option, + SymbolValue::OptionSome(_) | SymbolValue::OptionNone => primitives.option, } } - /// Returns the [TypeAnnotation] representing the data type of this value. + /// Returns the [`TypeAnnotation`] representing the data type of this value. pub fn get_type_annotation(&self, primitives: &PrimitiveStore, unifier: &mut Unifier) -> TypeAnnotation { match self { SymbolValue::Bool(..) => TypeAnnotation::Primitive(primitives.bool), @@ -157,7 +156,7 @@ impl SymbolValue { } SymbolValue::OptionNone => TypeAnnotation::CustomClass { id: primitives.option.get_obj_id(unifier), - params: Default::default(), + params: Vec::default(), }, SymbolValue::OptionSome(v) => { let ty = v.get_type_annotation(primitives, unifier); @@ -169,7 +168,7 @@ impl SymbolValue { } } - /// Returns the [TypeEnum] representing the data type of this value. + /// Returns the [`TypeEnum`] representing the data type of this value. pub fn get_type_enum(&self, primitives: &PrimitiveStore, unifier: &mut Unifier) -> Rc { let ty = self.get_type(primitives, unifier); unifier.get_ty(ty) @@ -179,12 +178,12 @@ impl SymbolValue { impl Display for SymbolValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - SymbolValue::I32(i) => write!(f, "{}", i), - SymbolValue::I64(i) => write!(f, "int64({})", i), - SymbolValue::U32(i) => write!(f, "uint32({})", i), - SymbolValue::U64(i) => write!(f, "uint64({})", i), - SymbolValue::Str(s) => write!(f, "\"{}\"", s), - SymbolValue::Double(d) => write!(f, "{}", d), + SymbolValue::I32(i) => write!(f, "{i}"), + SymbolValue::I64(i) => write!(f, "int64({i})"), + SymbolValue::U32(i) => write!(f, "uint32({i})"), + SymbolValue::U64(i) => write!(f, "uint64({i})"), + SymbolValue::Str(s) => write!(f, "\"{s}\""), + SymbolValue::Double(d) => write!(f, "{d}"), SymbolValue::Bool(b) => { if *b { write!(f, "True") @@ -193,9 +192,9 @@ impl Display for SymbolValue { } } SymbolValue::Tuple(t) => { - write!(f, "({})", t.iter().map(|v| format!("{}", v)).collect::>().join(", ")) + write!(f, "({})", t.iter().map(|v| format!("{v}")).collect::>().join(", ")) } - SymbolValue::OptionSome(v) => write!(f, "Some({})", v), + SymbolValue::OptionSome(v) => write!(f, "Some({v})"), SymbolValue::OptionNone => write!(f, "none"), } } @@ -212,7 +211,7 @@ pub trait StaticValue { generator: &mut dyn CodeGenerator, ) -> BasicValueEnum<'ctx>; - /// Converts this value to a LLVM [BasicValueEnum]. + /// Converts this value to a LLVM [`BasicValueEnum`]. fn to_basic_value_enum<'ctx>( &self, ctx: &mut CodeGenContext<'ctx, '_>, @@ -272,7 +271,7 @@ impl<'ctx> From> for ValueEnum<'ctx> { impl<'ctx> ValueEnum<'ctx> { - /// Converts this [ValueEnum] to a [BasicValueEnum]. + /// Converts this [`ValueEnum`] to a [`BasicValueEnum`]. pub fn to_basic_value_enum<'a>( self, ctx: &mut CodeGenContext<'ctx, 'a>, @@ -376,39 +375,36 @@ pub fn parse_type_annotation( Ok(primitives.exception) } else { let obj_id = resolver.get_identifier_def(*id); - match obj_id { - Ok(obj_id) => { - let def = top_level_defs[obj_id.0].read(); - if let TopLevelDef::Class { fields, methods, type_vars, .. } = &*def { - if !type_vars.is_empty() { - return Err(format!( - "Unexpected number of type parameters: expected {} but got 0", - type_vars.len() - )); - } - let fields = chain( - fields.iter().map(|(k, v, m)| (*k, (*v, *m))), - methods.iter().map(|(k, v, _)| (*k, (*v, false))), - ) + if let Ok(obj_id) = obj_id { + let def = top_level_defs[obj_id.0].read(); + if let TopLevelDef::Class { fields, methods, type_vars, .. } = &*def { + if !type_vars.is_empty() { + return Err(format!( + "Unexpected number of type parameters: expected {} but got 0", + type_vars.len() + )); + } + let fields = chain( + fields.iter().map(|(k, v, m)| (*k, (*v, *m))), + methods.iter().map(|(k, v, _)| (*k, (*v, false))), + ) .collect(); - Ok(unifier.add_ty(TypeEnum::TObj { - obj_id, - fields, - params: Default::default(), - })) - } else { - Err(format!("Cannot use function name as type at {}", loc)) - } + Ok(unifier.add_ty(TypeEnum::TObj { + obj_id, + fields, + params: HashMap::default(), + })) + } else { + Err(format!("Cannot use function name as type at {loc}")) } - Err(_) => { - let ty = resolver - .get_symbol_type(unifier, top_level_defs, primitives, *id) - .map_err(|e| format!("Unknown type annotation at {}: {}", loc, e))?; - if let TypeEnum::TVar { .. } = &*unifier.get_ty(ty) { - Ok(ty) - } else { - Err(format!("Unknown type annotation {} at {}", id, loc)) - } + } else { + let ty = resolver + .get_symbol_type(unifier, top_level_defs, primitives, *id) + .map_err(|e| format!("Unknown type annotation at {loc}: {e}"))?; + if let TypeEnum::TVar { .. } = &*unifier.get_ty(ty) { + Ok(ty) + } else { + Err(format!("Unknown type annotation {id} at {loc}")) } } } @@ -520,7 +516,7 @@ impl dyn SymbolResolver + Send + Sync { unreachable!("expected class definition") } }, - &mut |id| format!("typevar{}", id), + &mut |id| format!("typevar{id}"), &mut None, ) } diff --git a/nac3core/src/toplevel/builtins.rs b/nac3core/src/toplevel/builtins.rs index 341ee132d..298f18978 100644 --- a/nac3core/src/toplevel/builtins.rs +++ b/nac3core/src/toplevel/builtins.rs @@ -49,7 +49,7 @@ pub fn get_exn_constructor( FuncArg { name: "msg".into(), ty: string, - default_value: Some(SymbolValue::Str("".into())), + default_value: Some(SymbolValue::Str(String::new())), }, FuncArg { name: "param0".into(), ty: int64, default_value: Some(SymbolValue::I64(0)) }, FuncArg { name: "param1".into(), ty: int64, default_value: Some(SymbolValue::I64(0)) }, @@ -58,20 +58,20 @@ pub fn get_exn_constructor( let exn_type = unifier.add_ty(TypeEnum::TObj { obj_id: DefinitionId(class_id), fields: exception_fields.iter().map(|(a, b, c)| (*a, (*b, *c))).collect(), - params: Default::default(), + params: HashMap::default(), }); let signature = unifier.add_ty(TypeEnum::TFunc(FunSignature { args: exn_cons_args, ret: exn_type, - vars: Default::default(), + vars: HashMap::default(), })); let fun_def = TopLevelDef::Function { - name: format!("{}.__init__", name), + name: format!("{name}.__init__"), simple_name: "__init__".into(), signature, - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + var_id: Vec::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new(exn_constructor)))), loc: None, @@ -79,12 +79,12 @@ pub fn get_exn_constructor( let class_def = TopLevelDef::Class { name: name.into(), object_id: DefinitionId(class_id), - type_vars: Default::default(), + type_vars: Vec::default(), fields: exception_fields, methods: vec![("__init__".into(), signature, DefinitionId(cons_id))], ancestors: vec![ - TypeAnnotation::CustomClass { id: DefinitionId(class_id), params: Default::default() }, - TypeAnnotation::CustomClass { id: DefinitionId(7), params: Default::default() }, + TypeAnnotation::CustomClass { id: DefinitionId(class_id), params: Vec::default() }, + TypeAnnotation::CustomClass { id: DefinitionId(7), params: Vec::default() }, ], constructor: Some(signature), resolver: None, @@ -93,7 +93,7 @@ pub fn get_exn_constructor( (fun_def, class_def, signature, exn_type) } -/// Creates a NumPy [TopLevelDef] function by code generation. +/// Creates a NumPy [`TopLevelDef`] function by code generation. /// /// * `name`: The name of the implemented NumPy function. /// * `ret_ty`: The return type of this function. @@ -120,16 +120,16 @@ fn create_fn_by_codegen( ret: ret_ty, vars: var_map.clone(), })), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + var_id: Vec::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(codegen_callback))), loc: None, })) } -/// Creates a NumPy [TopLevelDef] function using an LLVM intrinsic. +/// Creates a NumPy [`TopLevelDef`] function using an LLVM intrinsic. /// /// * `name`: The name of the implemented NumPy function. /// * `ret_ty`: The return type of this function. @@ -191,7 +191,7 @@ fn create_fn_by_intrinsic( ) } -/// Creates a unary NumPy [TopLevelDef] function using an extern function (e.g. from `libc` or +/// Creates a unary NumPy [`TopLevelDef`] function using an extern function (e.g. from `libc` or /// `libm`). /// /// * `name`: The name of the implemented NumPy function. @@ -363,9 +363,9 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { Arc::new(RwLock::new(TopLevelDef::Class { name: "Exception".into(), object_id: DefinitionId(7), - type_vars: Default::default(), + type_vars: Vec::default(), fields: exception_fields, - methods: Default::default(), + methods: Vec::default(), ancestors: vec![], constructor: None, resolver: None, @@ -398,7 +398,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { ], ancestors: vec![TypeAnnotation::CustomClass { id: DefinitionId(10), - params: Default::default(), + params: Vec::default(), }], constructor: None, resolver: None, @@ -410,8 +410,8 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { simple_name: "is_some".into(), signature: is_some_ty.0, var_id: vec![option_ty_var_id], - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, obj, _, _, generator| { @@ -435,8 +435,8 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { simple_name: "is_none".into(), signature: is_some_ty.0, var_id: vec![option_ty_var_id], - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, obj, _, _, generator| { @@ -460,8 +460,8 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { simple_name: "unwrap".into(), signature: unwrap_ty.0, var_id: vec![option_ty_var_id], - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |_, _, _, _, _| { @@ -478,9 +478,9 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { ret: int32, vars: var_map.clone(), })), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + var_id: Vec::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, _, fun, args, generator| { @@ -553,9 +553,9 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { ret: int64, vars: var_map.clone(), })), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + var_id: Vec::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, _, fun, args, generator| { @@ -624,9 +624,9 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { ret: uint32, vars: var_map.clone(), })), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + var_id: Vec::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, _, fun, args, generator| { @@ -701,9 +701,9 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { ret: uint64, vars: var_map.clone(), })), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + var_id: Vec::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, _, fun, args, generator| { @@ -777,9 +777,9 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { ret: float, vars: var_map.clone(), })), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + var_id: Vec::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, _, fun, args, generator| { @@ -927,11 +927,11 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { }, ], ret: range, - vars: Default::default(), + vars: HashMap::default(), })), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + var_id: Vec::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, _, _, args, generator| { @@ -1013,11 +1013,11 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { signature: primitives.1.add_ty(TypeEnum::TFunc(FunSignature { args: vec![FuncArg { name: "s".into(), ty: string, default_value: None }], ret: string, - vars: Default::default(), + vars: HashMap::default(), })), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + var_id: Vec::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, _, fun, args, generator| { @@ -1035,9 +1035,9 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { ret: primitives.0.bool, vars: var_map.clone(), })), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + var_id: Vec::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, _, fun, args, generator| { @@ -1283,8 +1283,8 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { .collect(), })), var_id: vec![arg_ty.1], - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, _, fun, args, generator| { @@ -1305,10 +1305,10 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { None, ) .into_int_value(); - if len.get_type().get_bit_width() != 32 { - Some(ctx.builder.build_int_truncate(len, int32, "len2i32").into()) - } else { + if len.get_type().get_bit_width() == 32 { Some(len.into()) + } else { + Some(ctx.builder.build_int_truncate(len, int32, "len2i32").into()) } }) }, @@ -1327,9 +1327,9 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { ret: num_ty.0, vars: var_map.clone(), })), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + var_id: Vec::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, _, fun, args, generator| { @@ -1389,9 +1389,9 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { ret: num_ty.0, vars: var_map.clone(), })), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + var_id: Vec::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, _, fun, args, generator| { @@ -1448,9 +1448,9 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { ret: num_ty.0, vars: var_map.clone(), })), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + var_id: Vec::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, _, fun, args, generator| { @@ -1888,8 +1888,8 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { vars: HashMap::from([(option_ty_var_id, option_ty_var)]), })), var_id: vec![option_ty_var_id], - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, _, fun, args, generator| { diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index f5d264449..d47be350c 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -41,13 +41,14 @@ pub struct TopLevelComposer { impl Default for TopLevelComposer { fn default() -> Self { - Self::new(vec![], Default::default()).0 + Self::new(vec![], ComposerConfig::default()).0 } } impl TopLevelComposer { /// return a composer and things to make a "primitive" symbol resolver, so that the symbol /// resolver can later figure out primitive type definitions when passed a primitive type name + #[must_use] pub fn new( builtins: Vec<(StrRef, FunSignature, Arc)>, core_config: ComposerConfig, @@ -77,11 +78,11 @@ impl TopLevelComposer { "Some".into(), "Option".into(), ]); - let defined_names: HashSet = Default::default(); - let method_class: HashMap = Default::default(); + let defined_names = HashSet::default(); + let method_class = HashMap::default(); - let mut builtin_id: HashMap = Default::default(); - let mut builtin_ty: HashMap = Default::default(); + let mut builtin_id = HashMap::default(); + let mut builtin_ty = HashMap::default(); let builtin_name_list = definition_ast_list.iter() .map(|def_ast| match *def_ast.0.read() { @@ -123,9 +124,9 @@ impl TopLevelComposer { name: name.into(), simple_name: name, signature: fun_sig, - instance_to_stmt: Default::default(), - instance_to_symbol: Default::default(), - var_id: Default::default(), + instance_to_stmt: HashMap::default(), + instance_to_symbol: HashMap::default(), + var_id: Vec::default(), resolver: None, codegen_callback: Some(codegen_callback), loc: None, @@ -151,6 +152,7 @@ impl TopLevelComposer { ) } + #[must_use] pub fn make_top_level_context(&self) -> TopLevelContext { TopLevelContext { definitions: RwLock::new( @@ -166,6 +168,7 @@ impl TopLevelComposer { } } + #[must_use] pub fn extract_def_list(&self) -> Vec>> { self.definition_ast_list.iter().map(|(def, ..)| def.clone()).collect_vec() } @@ -176,9 +179,19 @@ impl TopLevelComposer { &mut self, ast: Stmt<()>, resolver: Option>, - mod_path: String, + mod_path: &str, allow_no_constructor: bool, ) -> Result<(StrRef, DefinitionId, Option), String> { + type MethodInfo = ( + // the simple method name without class name + StrRef, + // in this top level def, method name is prefixed with the class name + Arc>, + DefinitionId, + Type, + Stmt<()>, + ); + let defined_names = &mut self.defined_names; match &ast.node { ast::StmtKind::ClassDef { name: class_name, bases, body, .. } => { @@ -222,15 +235,6 @@ impl TopLevelComposer { // parse class def body and register class methods into the def list. // module's symbol resolver would not know the name of the class methods, // thus cannot return their definition_id - type MethodInfo = ( - // the simple method name without class name - StrRef, - // in this top level def, method name is prefixed with the class name - Arc>, - DefinitionId, - Type, - Stmt<()>, - ); let mut class_method_name_def_ids: Vec = Vec::new(); // we do not push anything to the def list, so we keep track of the index // and then push in the correct order after the for loop @@ -288,9 +292,6 @@ impl TopLevelComposer { dummy_method_type, b.clone(), )); - } else { - // do nothing - continue; } } @@ -299,7 +300,7 @@ impl TopLevelComposer { // get the methods into the top level class_def for (name, _, id, ty, ..) in &class_method_name_def_ids { let mut class_def = class_def_ast.0.write(); - if let TopLevelDef::Class { methods, .. } = class_def.deref_mut() { + if let TopLevelDef::Class { methods, .. } = &mut *class_def { methods.push((*name, *ty, *id)); self.method_class.insert(*id, DefinitionId(class_def_id)); } else { @@ -320,7 +321,7 @@ impl TopLevelComposer { let global_fun_name = if mod_path.is_empty() { name.to_string() } else { - format!("{}.{}", mod_path, name) + format!("{mod_path}.{name}") }; if !defined_names.insert(global_fun_name.clone()) { return Err(format!( @@ -383,7 +384,7 @@ impl TopLevelComposer { // only deal with class def here let mut class_def = class_def.write(); let (class_bases_ast, class_def_type_vars, class_resolver) = { - if let TopLevelDef::Class { type_vars, resolver, .. } = class_def.deref_mut() { + if let TopLevelDef::Class { type_vars, resolver, .. } = &mut *class_def { if let Some(ast::Located { node: ast::StmtKind::ClassDef { bases, .. }, .. }) = class_ast @@ -397,7 +398,7 @@ impl TopLevelComposer { } }; let class_resolver = class_resolver.as_ref().unwrap(); - let class_resolver = class_resolver.deref(); + let class_resolver = &**class_resolver; let mut is_generic = false; for b in class_bases_ast { @@ -415,14 +416,13 @@ impl TopLevelComposer { ) } => { - if !is_generic { - is_generic = true; - } else { + if is_generic { return Err(format!( "only single Generic[...] is allowed (at {})", b.location )); } + is_generic = true; let type_var_list: Vec<&ast::Expr<()>>; // if `class A(Generic[T, V, G])` @@ -430,7 +430,7 @@ impl TopLevelComposer { type_var_list = elts.iter().collect_vec(); // `class A(Generic[T])` } else { - type_var_list = vec![slice.deref()]; + type_var_list = vec![&**slice]; } // parse the type vars @@ -509,7 +509,7 @@ impl TopLevelComposer { let (class_def_id, class_bases, class_ancestors, class_resolver, class_type_vars) = { if let TopLevelDef::Class { ancestors, resolver, object_id, type_vars, .. - } = class_def.deref_mut() + } = &mut *class_def { if let Some(ast::Located { node: ast::StmtKind::ClassDef { bases, .. }, @@ -525,7 +525,7 @@ impl TopLevelComposer { } }; let class_resolver = class_resolver.as_ref().unwrap(); - let class_resolver = class_resolver.deref(); + let class_resolver = &**class_resolver; let mut has_base = false; for b in class_bases { @@ -589,11 +589,11 @@ impl TopLevelComposer { } // second, get all ancestors - let mut ancestors_store: HashMap> = Default::default(); + let mut ancestors_store: HashMap> = HashMap::default(); let mut get_all_ancestors = |class_def: &Arc>| { let class_def = class_def.read(); let (class_ancestors, class_id) = { - if let TopLevelDef::Class { ancestors, object_id, .. } = class_def.deref() { + if let TopLevelDef::Class { ancestors, object_id, .. } = &*class_def { (ancestors, *object_id) } else { return Ok(()); @@ -630,7 +630,7 @@ impl TopLevelComposer { let mut class_def = class_def.write(); let (class_ancestors, class_id, class_type_vars) = { if let TopLevelDef::Class { ancestors, object_id, type_vars, .. } = - class_def.deref_mut() + &mut *class_def { (ancestors, *object_id, type_vars) } else { @@ -652,7 +652,7 @@ impl TopLevelComposer { { // if inherited from Exception, the body should be a pass if let ast::StmtKind::ClassDef { body, .. } = &class_ast.as_ref().unwrap().node { - for stmt in body.iter() { + for stmt in body { if matches!( stmt.node, ast::StmtKind::FunctionDef { .. } | ast::StmtKind::AnnAssign { .. } @@ -695,7 +695,7 @@ impl TopLevelComposer { } if matches!(&*class_def.read(), TopLevelDef::Class { .. }) { if let Err(e) = Self::analyze_single_class_methods_fields( - class_def.clone(), + class_def, &class_ast.as_ref().unwrap().node, &temp_def_list, unifier, @@ -724,13 +724,13 @@ impl TopLevelComposer { continue; } let mut class_def = class_def.write(); - if let TopLevelDef::Class { ancestors, .. } = class_def.deref() { + if let TopLevelDef::Class { ancestors, .. } = &*class_def { // if the length of the ancestor is equal to the current depth // it means that all the ancestors of the class is handled if ancestors.len() == current_ancestor_depth { finished = false; Self::analyze_single_class_ancestors( - class_def.deref_mut(), + &mut class_def, &temp_def_list, unifier, primitives, @@ -742,10 +742,9 @@ impl TopLevelComposer { if finished { break; - } else { - current_ancestor_depth += 1; } + current_ancestor_depth += 1; if current_ancestor_depth > def_ast_list.len() + 1 { unreachable!("cannot be longer than the whole top level def list") } @@ -764,11 +763,11 @@ impl TopLevelComposer { errors.insert(e); } } - for ty in subst_list.unwrap().into_iter() { + for ty in subst_list.unwrap() { if let TypeEnum::TObj { obj_id, params, fields } = &*unifier.get_ty(ty) { let mut new_fields = HashMap::new(); let mut need_subst = false; - for (name, (ty, mutable)) in fields.iter() { + for (name, (ty, mutable)) in fields { let substituted = unifier.subst(*ty, params); need_subst |= substituted.is_some(); new_fields.insert(*name, (substituted.unwrap_or(*ty), *mutable)); @@ -817,10 +816,8 @@ impl TopLevelComposer { let mut errors = HashSet::new(); let mut analyze = |function_def: &Arc>, function_ast: &Option| { let mut function_def = function_def.write(); - let function_def = function_def.deref_mut(); - let function_ast = if let Some(x) = function_ast.as_ref() { - x - } else { + let function_def = &mut *function_def; + let Some(function_ast) = function_ast.as_ref() else { // if let TopLevelDef::Function { name, .. } = `` return Ok(()); }; @@ -835,13 +832,13 @@ impl TopLevelComposer { if let ast::StmtKind::FunctionDef { args, returns, .. } = &function_ast.node { let resolver = resolver.as_ref(); let resolver = resolver.unwrap(); - let resolver = resolver.deref(); + let resolver = &**resolver; let mut function_var_map: HashMap = HashMap::new(); let arg_types = { // make sure no duplicate parameter let mut defined_parameter_name: HashSet<_> = HashSet::new(); - for x in args.args.iter() { + for x in &args.args { if !defined_parameter_name.insert(x.node.arg) || keyword_list.contains(&x.node.arg) { @@ -1037,7 +1034,7 @@ impl TopLevelComposer { } fn analyze_single_class_methods_fields( - class_def: Arc>, + class_def: &Arc>, class_ast: &ast::StmtKind<()>, temp_def_list: &[Arc>], unifier: &mut Unifier, @@ -1091,7 +1088,7 @@ impl TopLevelComposer { // check method parameters cannot have same name let mut defined_parameter_name: HashSet<_> = HashSet::new(); let zelf: StrRef = "self".into(); - for x in args.args.iter() { + for x in &args.args { if !defined_parameter_name.insert(x.node.arg) || (keyword_list.contains(&x.node.arg) && x.node.arg != zelf) { @@ -1206,7 +1203,7 @@ impl TopLevelComposer { // into the list for later unification type_var_to_concrete_def .insert(dummy_func_arg.ty, type_ann.clone()); - result.push(dummy_func_arg) + result.push(dummy_func_arg); } } result @@ -1255,7 +1252,7 @@ impl TopLevelComposer { }; if let TopLevelDef::Function { var_id, .. } = - temp_def_list.get(method_id.0).unwrap().write().deref_mut() + &mut *temp_def_list.get(method_id.0).unwrap().write() { var_id.extend_from_slice(method_var_map .iter() @@ -1410,7 +1407,7 @@ impl TopLevelComposer { // find if there is a method with same name in the child class let mut to_be_added = (*anc_method_name, *anc_method_ty, *anc_method_def_id); for (class_method_name, class_method_ty, class_method_defid) in - class_methods_def.iter() + &*class_methods_def { if class_method_name == anc_method_name { // ignore and handle self @@ -1424,8 +1421,7 @@ impl TopLevelComposer { ); if !ok { return Err(format!( - "method {} has same name as ancestors' method, but incompatible type", - class_method_name + "method {class_method_name} has same name as ancestors' method, but incompatible type" )); } // mark it as added @@ -1439,7 +1435,7 @@ impl TopLevelComposer { } // add those that are not overriding method to the new_child_methods for (class_method_name, class_method_ty, class_method_defid) in - class_methods_def.iter() + &*class_methods_def { if !is_override.contains(class_method_name) { new_child_methods.push(( @@ -1459,17 +1455,16 @@ impl TopLevelComposer { for (anc_field_name, anc_field_ty, mutable) in fields { let to_be_added = (*anc_field_name, *anc_field_ty, *mutable); // find if there is a fields with the same name in the child class - for (class_field_name, ..) in class_fields_def.iter() { + for (class_field_name, ..) in &*class_fields_def { if class_field_name == anc_field_name { return Err(format!( - "field `{}` has already declared in the ancestor classes", - class_field_name + "field `{class_field_name}` has already declared in the ancestor classes" )); } } new_child_fields.push(to_be_added); } - for (class_field_name, class_field_ty, mutable) in class_fields_def.iter() { + for (class_field_name, class_field_ty, mutable) in &*class_fields_def { if !is_override.contains(class_field_name) { new_child_fields.push((*class_field_name, *class_field_ty, *mutable)); } @@ -1486,7 +1481,8 @@ impl TopLevelComposer { Ok(()) } - /// step 5, analyze and call type inferencer to fill the `instance_to_stmt` of topleveldef::function + /// step 5, analyze and call type inferencer to fill the `instance_to_stmt` of + /// [`TopLevelDef::Function`] fn analyze_function_instance(&mut self) -> Result<(), String> { // first get the class constructor type correct for the following type check in function body // also do class field instantiation check @@ -1558,7 +1554,7 @@ impl TopLevelComposer { FuncArg { name: "msg".into(), ty: string, - default_value: Some(SymbolValue::Str("".into())), + default_value: Some(SymbolValue::Str(String::new())), }, FuncArg { name: "param0".into(), @@ -1577,15 +1573,15 @@ impl TopLevelComposer { }, ], ret: self_type, - vars: Default::default(), + vars: HashMap::default(), })); let cons_fun = TopLevelDef::Function { name: format!("{}.{}", class_name, "__init__"), simple_name: init_str_id, signature, - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + var_id: Vec::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new(exn_constructor)))), loc: None, @@ -1661,7 +1657,7 @@ impl TopLevelComposer { return Err(errors.into_iter().sorted().join("\n---------\n")); } - for (i, signature, id) in constructors.into_iter() { + for (i, signature, id) in constructors { if let TopLevelDef::Class { methods, .. } = &mut *self.definition_ast_list[i].0.write() { methods.push(( @@ -1748,13 +1744,13 @@ impl TopLevelComposer { }) .multi_cartesian_product() .collect_vec(); - let mut result: Vec> = Default::default(); + let mut result: Vec> = Vec::default(); for comb in var_combs { - result.push(vars.keys().cloned().zip(comb).collect()); + result.push(vars.keys().copied().zip(comb).collect()); } // NOTE: if is empty, means no type var, append a empty subst, ok to do this? if result.is_empty() { - result.push(HashMap::new()) + result.push(HashMap::new()); } (result, no_ranges) }; @@ -1844,14 +1840,14 @@ impl TopLevelComposer { && matches!(&decorator_list[0].node, ast::ExprKind::Name{ id, .. } if id == &"extern".into()) { - instance_to_symbol.insert("".into(), simple_name.to_string()); + instance_to_symbol.insert(String::new(), simple_name.to_string()); continue; } if !decorator_list.is_empty() && matches!(&decorator_list[0].node, ast::ExprKind::Name{ id, .. } if id == &"rpc".into()) { - instance_to_symbol.insert("".into(), simple_name.to_string()); + instance_to_symbol.insert(String::new(), simple_name.to_string()); continue; } body @@ -1867,15 +1863,14 @@ impl TopLevelComposer { { // check virtuals let defs = ctx.definitions.read(); - for (subtype, base, loc) in inferencer.virtual_checks.iter() { + for (subtype, base, loc) in &*inferencer.virtual_checks { let base_id = { let base = inferencer.unifier.get_ty(*base); if let TypeEnum::TObj { obj_id, .. } = &*base { *obj_id } else { return Err(format!( - "Base type should be a class (at {})", - loc + "Base type should be a class (at {loc})" )); } }; @@ -1887,8 +1882,7 @@ impl TopLevelComposer { let base_repr = inferencer.unifier.stringify(*base); let subtype_repr = inferencer.unifier.stringify(*subtype); return Err(format!( - "Expected a subtype of {}, but got {} (at {})", - base_repr, subtype_repr, loc + "Expected a subtype of {base_repr}, but got {subtype_repr} (at {loc})" )); } }; @@ -1900,8 +1894,7 @@ impl TopLevelComposer { let base_repr = inferencer.unifier.stringify(*base); let subtype_repr = inferencer.unifier.stringify(*subtype); return Err(format!( - "Expected a subtype of {}, but got {} (at {})", - base_repr, subtype_repr, loc + "Expected a subtype of {base_repr}, but got {subtype_repr} (at {loc})" )); } } else { @@ -1922,7 +1915,7 @@ impl TopLevelComposer { unreachable!("must be class id here") } }, - &mut |id| format!("typevar{}", id), + &mut |id| format!("typevar{id}"), &mut None, ); return Err(format!( @@ -1934,7 +1927,7 @@ impl TopLevelComposer { } instance_to_stmt.insert( - get_subst_key(unifier, self_type, &subst, Some(&vars.keys().cloned().collect())), + get_subst_key(unifier, self_type, &subst, Some(&vars.keys().copied().collect())), FunInstance { body: Arc::new(fun_body), unifier_id: 0, diff --git a/nac3core/src/toplevel/helper.rs b/nac3core/src/toplevel/helper.rs index b7f60802e..6399f6dac 100644 --- a/nac3core/src/toplevel/helper.rs +++ b/nac3core/src/toplevel/helper.rs @@ -43,6 +43,7 @@ impl TopLevelDef { } impl TopLevelComposer { + #[must_use] pub fn make_primitives() -> (PrimitiveStore, Unifier) { let mut unifier = Unifier::new(); let int32 = unifier.add_ty(TypeEnum::TObj { @@ -134,22 +135,23 @@ impl TopLevelComposer { let primitives = PrimitiveStore { int32, int64, + uint32, + uint64, float, bool, none, range, str, exception, - uint32, - uint64, option, }; crate::typecheck::magic_methods::set_primitives_magic_methods(&primitives, &mut unifier); (primitives, unifier) } - /// already include the definition_id of itself inside the ancestors vector - /// when first registering, the type_vars, fields, methods, ancestors are invalid + /// already include the `definition_id` of itself inside the ancestors vector + /// when first registering, the `type_vars`, fields, methods, ancestors are invalid + #[must_use] pub fn make_top_level_class_def( index: usize, resolver: Option>, @@ -160,10 +162,10 @@ impl TopLevelComposer { TopLevelDef::Class { name, object_id: DefinitionId(index), - type_vars: Default::default(), - fields: Default::default(), - methods: Default::default(), - ancestors: Default::default(), + type_vars: Vec::default(), + fields: Vec::default(), + methods: Vec::default(), + ancestors: Vec::default(), constructor, resolver, loc, @@ -171,6 +173,7 @@ impl TopLevelComposer { } /// when first registering, the type is a invalid value + #[must_use] pub fn make_top_level_function_def( name: String, simple_name: StrRef, @@ -182,15 +185,16 @@ impl TopLevelComposer { name, simple_name, signature: ty, - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), + var_id: Vec::default(), + instance_to_symbol: HashMap::default(), + instance_to_stmt: HashMap::default(), resolver, codegen_callback: None, loc, } } + #[must_use] pub fn make_class_method_name(mut class_name: String, method_name: &str) -> String { class_name.push('.'); class_name.push_str(method_name); @@ -206,7 +210,7 @@ impl TopLevelComposer { return Ok((*ty, *def_id)); } } - Err(format!("no method {} in the current class", method_name)) + Err(format!("no method {method_name} in the current class")) } /// get all base class def id of a class, excluding itself. \ @@ -257,17 +261,17 @@ impl TopLevelComposer { let child_def = temp_def_list.get(child_id.0).unwrap(); let child_def = child_def.read(); if let TopLevelDef::Class { ancestors, .. } = &*child_def { - if !ancestors.is_empty() { - Some(ancestors[0].clone()) - } else { + if ancestors.is_empty() { None + } else { + Some(ancestors[0].clone()) } } else { unreachable!("child must be top level class def") } } - /// get the var_id of a given TVar type + /// get the `var_id` of a given `TVar` type pub fn get_var_id(var_ty: Type, unifier: &mut Unifier) -> Result { if let TypeEnum::TVar { id, .. } = unifier.get_ty(var_ty).as_ref() { Ok(*id) @@ -376,14 +380,14 @@ impl TopLevelComposer { ast::StmtKind::If { body, orelse, .. } => { let inited_for_sure = Self::get_all_assigned_field(body.as_slice())? .intersection(&Self::get_all_assigned_field(orelse.as_slice())?) - .cloned() + .copied() .collect::>(); result.extend(inited_for_sure); } ast::StmtKind::Try { body, orelse, finalbody, .. } => { let inited_for_sure = Self::get_all_assigned_field(body.as_slice())? .intersection(&Self::get_all_assigned_field(orelse.as_slice())?) - .cloned() + .copied() .collect::>(); result.extend(inited_for_sure); result.extend(Self::get_all_assigned_field(finalbody.as_slice())?); @@ -391,9 +395,9 @@ impl TopLevelComposer { ast::StmtKind::With { body, .. } => { result.extend(Self::get_all_assigned_field(body.as_slice())?); } - ast::StmtKind::Pass { .. } => {} - ast::StmtKind::Assert { .. } => {} - ast::StmtKind::Expr { .. } => {} + ast::StmtKind::Pass { .. } + | ast::StmtKind::Assert { .. } + | ast::StmtKind::Expr { .. } => {} _ => { unimplemented!() @@ -448,14 +452,14 @@ impl TopLevelComposer { } let found = val.get_type_annotation(primitive, unifier); - if !is_compatible(&found, ty, unifier, primitive) { + if is_compatible(&found, ty, unifier, primitive) { + Ok(()) + } else { Err(format!( "incompatible default parameter type, expect {}, found {}", ty.stringify(unifier), found.stringify(unifier), )) - } else { - Ok(()) } } } @@ -470,7 +474,7 @@ pub fn parse_parameter_default_value( if let Ok(v) = (*v).try_into() { Ok(SymbolValue::I32(v)) } else { - Err(format!("integer value out of range at {}", loc)) + Err(format!("integer value out of range at {loc}")) } } Constant::Float(v) => Ok(SymbolValue::Double(*v)), @@ -479,8 +483,7 @@ pub fn parse_parameter_default_value( tuple.iter().map(|x| handle_constant(x, loc)).collect::, _>>()?, )), Constant::None => Err(format!( - "`None` is not supported, use `none` for option type instead ({})", - loc + "`None` is not supported, use `none` for option type instead ({loc})" )), _ => unimplemented!("this constant is not supported at {}", loc), } diff --git a/nac3core/src/toplevel/mod.rs b/nac3core/src/toplevel/mod.rs index 6b9566201..c62c5c0a1 100644 --- a/nac3core/src/toplevel/mod.rs +++ b/nac3core/src/toplevel/mod.rs @@ -3,7 +3,6 @@ use std::{ collections::{HashMap, HashSet}, fmt::Debug, iter::FromIterator, - ops::{Deref, DerefMut}, sync::Arc, }; @@ -49,6 +48,7 @@ pub struct GenCall { } impl GenCall { + #[must_use] pub fn new(fp: GenCallCallback) -> GenCall { GenCall { fp } } diff --git a/nac3core/src/toplevel/type_annotation.rs b/nac3core/src/toplevel/type_annotation.rs index 3020abb0a..549227762 100644 --- a/nac3core/src/toplevel/type_annotation.rs +++ b/nac3core/src/toplevel/type_annotation.rs @@ -33,17 +33,16 @@ impl TypeAnnotation { match self { Primitive(ty) | TypeVar(ty) => unifier.stringify(*ty), CustomClass { id, params } => { - let class_name = match unifier.top_level { - Some(ref top) => { - if let TopLevelDef::Class { name, .. } = - &*top.definitions.read()[id.0].read() - { - (*name).into() - } else { - unreachable!() - } + let class_name = if let Some(ref top) = unifier.top_level { + if let TopLevelDef::Class { name, .. } = + &*top.definitions.read()[id.0].read() + { + (*name).into() + } else { + unreachable!() } - None => format!("class_def_{}", id.0), + } else { + format!("class_def_{}", id.0) }; format!( "{}{}", @@ -51,9 +50,9 @@ impl TypeAnnotation { { let param_list = params.iter().map(|p| p.stringify(unifier)).collect_vec().join(", "); if param_list.is_empty() { - "".into() + String::new() } else { - format!("[{}]", param_list) + format!("[{param_list}]") } } ) @@ -68,12 +67,12 @@ impl TypeAnnotation { } } -/// Parses an AST expression `expr` into a [TypeAnnotation]. +/// Parses an AST expression `expr` into a [`TypeAnnotation`]. /// -/// * `locked` - A [HashMap] containing the IDs of known definitions, mapped to a [Vec] of all +/// * `locked` - A [`HashMap`] containing the IDs of known definitions, mapped to a [`Vec`] of all /// generic variables associated with the definition. /// * `type_var` - The type variable associated with the type argument currently being parsed. Pass -/// [None] when this function is invoked externally. +/// [`None`] when this function is invoked externally. pub fn parse_ast_to_type_annotation_kinds( resolver: &(dyn SymbolResolver + Send + Sync), top_level_defs: &[Arc>], @@ -102,7 +101,7 @@ pub fn parse_ast_to_type_annotation_kinds( } else if id == &"str".into() { Ok(TypeAnnotation::Primitive(primitives.str)) } else if id == &"Exception".into() { - Ok(TypeAnnotation::CustomClass { id: DefinitionId(7), params: Default::default() }) + Ok(TypeAnnotation::CustomClass { id: DefinitionId(7), params: Vec::default() }) } else if let Ok(obj_id) = resolver.get_identifier_def(*id) { let type_vars = { let def_read = top_level_defs[obj_id.0].try_read(); @@ -356,7 +355,7 @@ pub fn get_type_from_type_annotation_kinds( match ann { TypeAnnotation::CustomClass { id: obj_id, params } => { let def_read = top_level_defs[obj_id.0].read(); - let class_def: &TopLevelDef = def_read.deref(); + let class_def: &TopLevelDef = &def_read; let TopLevelDef::Class { fields, methods, type_vars, .. } = class_def else { unreachable!("should be class def here") }; @@ -406,8 +405,8 @@ pub fn get_type_from_type_annotation_kinds( "cannot apply type {} to type variable with id {:?}", unifier.internal_stringify( p, - &mut |id| format!("class{}", id), - &mut |id| format!("typevar{}", id), + &mut |id| format!("class{id}"), + &mut |id| format!("typevar{id}"), &mut None ), *id @@ -521,9 +520,10 @@ pub fn get_type_from_type_annotation_kinds( /// considered to be type variables associated with the class \ /// \ /// But note that here we do not make a duplication of `T`, `V`, we directly -/// use them as they are in the TopLevelDef::Class since those in the -/// TopLevelDef::Class.type_vars will be substitute later when seeing applications/instantiations +/// use them as they are in the [`TopLevelDef::Class`] since those in the +/// `TopLevelDef::Class.type_vars` will be substitute later when seeing applications/instantiations /// the Type of their fields and methods will also be subst when application/instantiation +#[must_use] pub fn make_self_type_annotation(type_vars: &[Type], object_id: DefinitionId) -> TypeAnnotation { TypeAnnotation::CustomClass { id: object_id, @@ -534,21 +534,19 @@ pub fn make_self_type_annotation(type_vars: &[Type], object_id: DefinitionId) -> /// get all the occurences of type vars contained in a type annotation /// e.g. `A[int, B[T], V, virtual[C[G]]]` => [T, V, G] /// this function will not make a duplicate of type var +#[must_use] pub fn get_type_var_contained_in_type_annotation(ann: &TypeAnnotation) -> Vec { let mut result: Vec = Vec::new(); match ann { TypeAnnotation::TypeVar(..) => result.push(ann.clone()), - TypeAnnotation::Virtual(ann) => { - result.extend(get_type_var_contained_in_type_annotation(ann.as_ref())) + TypeAnnotation::Virtual(ann) | TypeAnnotation::List(ann) => { + result.extend(get_type_var_contained_in_type_annotation(ann.as_ref())); } TypeAnnotation::CustomClass { params, .. } => { for p in params { result.extend(get_type_var_contained_in_type_annotation(p)); } } - TypeAnnotation::List(ann) => { - result.extend(get_type_var_contained_in_type_annotation(ann.as_ref())) - } TypeAnnotation::Tuple(anns) => { for a in anns { result.extend(get_type_var_contained_in_type_annotation(a)); @@ -569,9 +567,9 @@ pub fn check_overload_type_annotation_compatible( (TypeAnnotation::Primitive(a), TypeAnnotation::Primitive(b)) => a == b, (TypeAnnotation::TypeVar(a), TypeAnnotation::TypeVar(b)) => { let a = unifier.get_ty(*a); - let a = a.deref(); + let a = &*a; let b = unifier.get_ty(*b); - let b = b.deref(); + let b = &*b; if let ( TypeEnum::TVar { id: a, fields: None, .. }, TypeEnum::TVar { id: b, fields: None, .. }, diff --git a/nac3core/src/typecheck/function_check.rs b/nac3core/src/typecheck/function_check.rs index b7e0e5b83..212646c3c 100644 --- a/nac3core/src/typecheck/function_check.rs +++ b/nac3core/src/typecheck/function_check.rs @@ -30,7 +30,7 @@ impl<'a> Inferencer<'a> { Ok(()) } ExprKind::Tuple { elts, .. } => { - for elt in elts.iter() { + for elt in elts { self.check_pattern(elt, defined_identifiers)?; self.should_have_value(elt)?; } @@ -98,7 +98,7 @@ impl<'a> Inferencer<'a> { ExprKind::List { elts, .. } | ExprKind::Tuple { elts, .. } | ExprKind::BoolOp { values: elts, .. } => { - for elt in elts.iter() { + for elt in elts { self.check_expr(elt, defined_identifiers)?; self.should_have_value(elt)?; } @@ -116,9 +116,8 @@ impl<'a> Inferencer<'a> { // Check whether a bitwise shift has a negative RHS constant value if *op == LShift || *op == RShift { if let ExprKind::Constant { value, .. } = &right.node { - let rhs_val = match value { - Constant::Int(v) => v, - _ => unreachable!(), + let Constant::Int(rhs_val) = value else { + unreachable!() }; if *rhs_val < 0 { @@ -158,7 +157,7 @@ impl<'a> Inferencer<'a> { } ExprKind::Lambda { args, body } => { let mut defined_identifiers = defined_identifiers.clone(); - for arg in args.args.iter() { + for arg in &args.args { // TODO: should we check the types here? if !defined_identifiers.contains(&arg.node.arg) { defined_identifiers.insert(arg.node.arg); @@ -207,13 +206,13 @@ impl<'a> Inferencer<'a> { self.check_expr(iter, defined_identifiers)?; self.should_have_value(iter)?; let mut local_defined_identifiers = defined_identifiers.clone(); - for stmt in orelse.iter() { + for stmt in orelse { self.check_stmt(stmt, &mut local_defined_identifiers)?; } let mut local_defined_identifiers = defined_identifiers.clone(); self.check_pattern(target, &mut local_defined_identifiers)?; self.should_have_value(target)?; - for stmt in body.iter() { + for stmt in body { self.check_stmt(stmt, &mut local_defined_identifiers)?; } Ok(false) @@ -226,7 +225,7 @@ impl<'a> Inferencer<'a> { let body_returned = self.check_block(body, &mut body_identifiers)?; let orelse_returned = self.check_block(orelse, &mut orelse_identifiers)?; - for ident in body_identifiers.iter() { + for ident in &body_identifiers { if !defined_identifiers.contains(ident) && orelse_identifiers.contains(ident) { defined_identifiers.insert(*ident); } @@ -243,7 +242,7 @@ impl<'a> Inferencer<'a> { } StmtKind::With { items, body, .. } => { let mut new_defined_identifiers = defined_identifiers.clone(); - for item in items.iter() { + for item in items { self.check_expr(&item.context_expr, defined_identifiers)?; if let Some(var) = item.optional_vars.as_ref() { self.check_pattern(var, &mut new_defined_identifiers)?; @@ -255,7 +254,7 @@ impl<'a> Inferencer<'a> { StmtKind::Try { body, handlers, orelse, finalbody, .. } => { self.check_block(body, &mut defined_identifiers.clone())?; self.check_block(orelse, &mut defined_identifiers.clone())?; - for handler in handlers.iter() { + for handler in handlers { let mut defined_identifiers = defined_identifiers.clone(); let ast::ExcepthandlerKind::ExceptHandler { name, body, .. } = &handler.node; if let Some(name) = name { @@ -312,7 +311,7 @@ impl<'a> Inferencer<'a> { let mut ret = false; for stmt in block { if ret { - println!("warning: dead code at {:?}\n", stmt.location) + println!("warning: dead code at {:?}\n", stmt.location); } if self.check_stmt(stmt, defined_identifiers)? { ret = true; diff --git a/nac3core/src/typecheck/magic_methods.rs b/nac3core/src/typecheck/magic_methods.rs index 0593cf6d5..9d92c08c6 100644 --- a/nac3core/src/typecheck/magic_methods.rs +++ b/nac3core/src/typecheck/magic_methods.rs @@ -7,6 +7,7 @@ use nac3parser::ast::{Cmpop, Operator, Unaryop}; use std::collections::HashMap; use std::rc::Rc; +#[must_use] pub fn binop_name(op: &Operator) -> &'static str { match op { Operator::Add => "__add__", @@ -25,6 +26,7 @@ pub fn binop_name(op: &Operator) -> &'static str { } } +#[must_use] pub fn binop_assign_name(op: &Operator) -> &'static str { match op { Operator::Add => "__iadd__", @@ -43,6 +45,7 @@ pub fn binop_assign_name(op: &Operator) -> &'static str { } } +#[must_use] pub fn unaryop_name(op: &Unaryop) -> &'static str { match op { Unaryop::UAdd => "__pos__", @@ -52,6 +55,7 @@ pub fn unaryop_name(op: &Unaryop) -> &'static str { } } +#[must_use] pub fn comparison_name(op: &Cmpop) -> Option<&'static str> { match op { Cmpop::Lt => Some("__lt__"), @@ -183,7 +187,7 @@ pub fn impl_cmpop( }); } -/// Add, Sub, Mult +/// `Add`, `Sub`, `Mult` pub fn impl_basic_arithmetic( unifier: &mut Unifier, store: &PrimitiveStore, @@ -198,10 +202,10 @@ pub fn impl_basic_arithmetic( other_ty, ret_ty, &[Operator::Add, Operator::Sub, Operator::Mult], - ) + ); } -/// Pow +/// `Pow` pub fn impl_pow( unifier: &mut Unifier, store: &PrimitiveStore, @@ -209,10 +213,10 @@ pub fn impl_pow( other_ty: &[Type], ret_ty: Type, ) { - impl_binop(unifier, store, ty, other_ty, ret_ty, &[Operator::Pow]) + impl_binop(unifier, store, ty, other_ty, ret_ty, &[Operator::Pow]); } -/// BitOr, BitXor, BitAnd +/// `BitOr`, `BitXor`, `BitAnd` pub fn impl_bitwise_arithmetic(unifier: &mut Unifier, store: &PrimitiveStore, ty: Type) { impl_binop( unifier, @@ -221,20 +225,20 @@ pub fn impl_bitwise_arithmetic(unifier: &mut Unifier, store: &PrimitiveStore, ty &[ty], ty, &[Operator::BitAnd, Operator::BitOr, Operator::BitXor], - ) + ); } -/// LShift, RShift +/// `LShift`, `RShift` pub fn impl_bitwise_shift(unifier: &mut Unifier, store: &PrimitiveStore, ty: Type) { impl_binop(unifier, store, ty, &[store.int32, store.uint32], ty, &[Operator::LShift, Operator::RShift]); } -/// Div +/// `Div` pub fn impl_div(unifier: &mut Unifier, store: &PrimitiveStore, ty: Type, other_ty: &[Type]) { - impl_binop(unifier, store, ty, other_ty, store.float, &[Operator::Div]) + impl_binop(unifier, store, ty, other_ty, store.float, &[Operator::Div]); } -/// FloorDiv +/// `FloorDiv` pub fn impl_floordiv( unifier: &mut Unifier, store: &PrimitiveStore, @@ -242,10 +246,10 @@ pub fn impl_floordiv( other_ty: &[Type], ret_ty: Type, ) { - impl_binop(unifier, store, ty, other_ty, ret_ty, &[Operator::FloorDiv]) + impl_binop(unifier, store, ty, other_ty, ret_ty, &[Operator::FloorDiv]); } -/// Mod +/// `Mod` pub fn impl_mod( unifier: &mut Unifier, store: &PrimitiveStore, @@ -253,25 +257,25 @@ pub fn impl_mod( other_ty: &[Type], ret_ty: Type, ) { - impl_binop(unifier, store, ty, other_ty, ret_ty, &[Operator::Mod]) + impl_binop(unifier, store, ty, other_ty, ret_ty, &[Operator::Mod]); } -/// UAdd, USub +/// `UAdd`, `USub` pub fn impl_sign(unifier: &mut Unifier, _store: &PrimitiveStore, ty: Type) { - impl_unaryop(unifier, ty, ty, &[Unaryop::UAdd, Unaryop::USub]) + impl_unaryop(unifier, ty, ty, &[Unaryop::UAdd, Unaryop::USub]); } -/// Invert +/// `Invert` pub fn impl_invert(unifier: &mut Unifier, _store: &PrimitiveStore, ty: Type) { - impl_unaryop(unifier, ty, ty, &[Unaryop::Invert]) + impl_unaryop(unifier, ty, ty, &[Unaryop::Invert]); } -/// Not +/// `Not` pub fn impl_not(unifier: &mut Unifier, store: &PrimitiveStore, ty: Type) { - impl_unaryop(unifier, ty, store.bool, &[Unaryop::Not]) + impl_unaryop(unifier, ty, store.bool, &[Unaryop::Not]); } -/// Lt, LtE, Gt, GtE +/// `Lt`, `LtE`, `Gt`, `GtE` pub fn impl_comparison(unifier: &mut Unifier, store: &PrimitiveStore, ty: Type, other_ty: Type) { impl_cmpop( unifier, @@ -279,12 +283,12 @@ pub fn impl_comparison(unifier: &mut Unifier, store: &PrimitiveStore, ty: Type, ty, other_ty, &[Cmpop::Lt, Cmpop::Gt, Cmpop::LtE, Cmpop::GtE], - ) + ); } -/// Eq, NotEq +/// `Eq`, `NotEq` pub fn impl_eq(unifier: &mut Unifier, store: &PrimitiveStore, ty: Type) { - impl_cmpop(unifier, store, ty, ty, &[Cmpop::Eq, Cmpop::NotEq]) + impl_cmpop(unifier, store, ty, ty, &[Cmpop::Eq, Cmpop::NotEq]); } pub fn set_primitives_magic_methods(store: &PrimitiveStore, unifier: &mut Unifier) { diff --git a/nac3core/src/typecheck/type_error.rs b/nac3core/src/typecheck/type_error.rs index a12098934..ac36b331a 100644 --- a/nac3core/src/typecheck/type_error.rs +++ b/nac3core/src/typecheck/type_error.rs @@ -43,15 +43,18 @@ pub struct TypeError { } impl TypeError { + #[must_use] pub fn new(kind: TypeErrorKind, loc: Option) -> TypeError { TypeError { kind, loc } } + #[must_use] pub fn at(mut self, loc: Option) -> TypeError { self.loc = self.loc.or(loc); self } + #[must_use] pub fn to_display(self, unifier: &Unifier) -> DisplayTypeError { DisplayTypeError { err: self, unifier } } @@ -64,8 +67,8 @@ pub struct DisplayTypeError<'a> { fn loc_to_str(loc: Option) -> String { match loc { - Some(loc) => format!("(in {})", loc), - None => "".to_string(), + Some(loc) => format!("(in {loc})"), + None => String::new(), } } @@ -75,21 +78,20 @@ impl<'a> Display for DisplayTypeError<'a> { let mut notes = Some(HashMap::new()); match &self.err.kind { TooManyArguments { expected, got } => { - write!(f, "Too many arguments. Expected {} but got {}", expected, got) + write!(f, "Too many arguments. Expected {expected} but got {got}") } MissingArgs(args) => { - write!(f, "Missing arguments: {}", args) + write!(f, "Missing arguments: {args}") } UnknownArgName(name) => { - write!(f, "Unknown argument name: {}", name) + write!(f, "Unknown argument name: {name}") } IncorrectArgType { name, expected, got } => { let expected = self.unifier.stringify_with_notes(*expected, &mut notes); let got = self.unifier.stringify_with_notes(*got, &mut notes); write!( f, - "Incorrect argument type for {}. Expected {}, but got {}", - name, expected, got + "Incorrect argument type for {name}. Expected {expected}, but got {got}" ) } FieldUnificationError { field, types, loc } => { @@ -126,7 +128,7 @@ impl<'a> Display for DisplayTypeError<'a> { ); if let Some(loc) = loc { result?; - write!(f, " (in {})", loc)?; + write!(f, " (in {loc})")?; return Ok(()); } result @@ -136,12 +138,12 @@ impl<'a> Display for DisplayTypeError<'a> { { let t1 = self.unifier.stringify_with_notes(*t1, &mut notes); let t2 = self.unifier.stringify_with_notes(*t2, &mut notes); - write!(f, "Tuple length mismatch: got {} and {}", t1, t2) + write!(f, "Tuple length mismatch: got {t1} and {t2}") } _ => { let t1 = self.unifier.stringify_with_notes(*t1, &mut notes); let t2 = self.unifier.stringify_with_notes(*t2, &mut notes); - write!(f, "Incompatible types: {} and {}", t1, t2) + write!(f, "Incompatible types: {t1} and {t2}") } } } @@ -150,18 +152,17 @@ impl<'a> Display for DisplayTypeError<'a> { write!(f, "Cannot assign to an element of a tuple") } else { let t = self.unifier.stringify_with_notes(*t, &mut notes); - write!(f, "Cannot assign to field {} of {}, which is immutable", name, t) + write!(f, "Cannot assign to field {name} of {t}, which is immutable") } } NoSuchField(name, t) => { let t = self.unifier.stringify_with_notes(*t, &mut notes); - write!(f, "`{}::{}` field/method does not exist", t, name) + write!(f, "`{t}::{name}` field/method does not exist") } TupleIndexOutOfBounds { index, len } => { write!( f, - "Tuple index out of bounds. Got {} but tuple has only {} elements", - index, len + "Tuple index out of bounds. Got {index} but tuple has only {len} elements" ) } RequiresTypeAnn => { @@ -172,13 +173,13 @@ impl<'a> Display for DisplayTypeError<'a> { } }?; if let Some(loc) = self.err.loc { - write!(f, " at {}", loc)?; + write!(f, " at {loc}")?; } let notes = notes.unwrap(); if !notes.is_empty() { write!(f, "\n\nNotes:")?; for line in notes.values() { - write!(f, "\n {}", line)?; + write!(f, "\n {line}")?; } } Ok(()) diff --git a/nac3core/src/typecheck/type_inferencer/mod.rs b/nac3core/src/typecheck/type_inferencer/mod.rs index a0c619260..a7b73de2a 100644 --- a/nac3core/src/typecheck/type_inferencer/mod.rs +++ b/nac3core/src/typecheck/type_inferencer/mod.rs @@ -65,20 +65,20 @@ struct NaiveFolder(); impl Fold<()> for NaiveFolder { type TargetU = Option; type Error = String; - fn map_user(&mut self, _: ()) -> Result { + fn map_user(&mut self, (): ()) -> Result { Ok(None) } } fn report_error(msg: &str, location: Location) -> Result { - Err(format!("{} at {}", msg, location)) + Err(format!("{msg} at {location}")) } impl<'a> Fold<()> for Inferencer<'a> { type TargetU = Option; type Error = String; - fn map_user(&mut self, _: ()) -> Result { + fn map_user(&mut self, (): ()) -> Result { Ok(None) } @@ -138,7 +138,7 @@ impl<'a> Fold<()> for Inferencer<'a> { { let top_level_defs = self.top_level.definitions.read(); let mut naive_folder = NaiveFolder(); - for handler in handlers.into_iter() { + for handler in handlers { let ast::ExcepthandlerKind::ExceptHandler { type_, name, body } = handler.node; let type_ = if let Some(type_) = type_ { @@ -226,65 +226,65 @@ impl<'a> Fold<()> for Inferencer<'a> { } } ast::StmtKind::Assign { ref mut targets, ref config_comment, .. } => { - for target in targets.iter_mut() { + for target in &mut *targets { if let ExprKind::Attribute { ctx, .. } = &mut target.node { *ctx = ExprContext::Store; } } if targets.iter().all(|t| matches!(t.node, ExprKind::Name { .. })) { - if let ast::StmtKind::Assign { targets, value, .. } = node.node { - let value = self.fold_expr(*value)?; - let value_ty = value.custom.unwrap(); - let targets: Result, _> = targets - .into_iter() - .map(|target| { - if let ExprKind::Name { id, ctx } = target.node { - self.defined_identifiers.insert(id); - let target_ty = if let Some(ty) = self.variable_mapping.get(&id) - { - *ty - } else { - let unifier = &mut self.unifier; - self.function_data - .resolver - .get_symbol_type( - unifier, - &self.top_level.definitions.read(), - self.primitives, - id, - ) - .unwrap_or_else(|_| { - self.variable_mapping.insert(id, value_ty); - value_ty - }) - }; - let location = target.location; - self.unifier.unify(value_ty, target_ty).map(|_| Located { - location, - node: ExprKind::Name { id, ctx }, - custom: Some(target_ty), - }) - } else { - unreachable!() - } - }) - .collect(); - let loc = node.location; - let targets = targets - .map_err(|e| e.at(Some(loc)).to_display(self.unifier).to_string())?; - return Ok(Located { - location: node.location, - node: ast::StmtKind::Assign { - targets, - value: Box::new(value), - type_comment: None, - config_comment: config_comment.clone(), - }, - custom: None, - }); - } else { + let ast::StmtKind::Assign { targets, value, .. } = node.node else { unreachable!() - } + }; + + let value = self.fold_expr(*value)?; + let value_ty = value.custom.unwrap(); + let targets: Result, _> = targets + .into_iter() + .map(|target| { + if let ExprKind::Name { id, ctx } = target.node { + self.defined_identifiers.insert(id); + let target_ty = if let Some(ty) = self.variable_mapping.get(&id) + { + *ty + } else { + let unifier: &mut Unifier = self.unifier; + self.function_data + .resolver + .get_symbol_type( + unifier, + &self.top_level.definitions.read(), + self.primitives, + id, + ) + .unwrap_or_else(|_| { + self.variable_mapping.insert(id, value_ty); + value_ty + }) + }; + let location = target.location; + self.unifier.unify(value_ty, target_ty).map(|()| Located { + location, + node: ExprKind::Name { id, ctx }, + custom: Some(target_ty), + }) + } else { + unreachable!() + } + }) + .collect(); + let loc = node.location; + let targets = targets + .map_err(|e| e.at(Some(loc)).to_display(self.unifier).to_string())?; + return Ok(Located { + location: node.location, + node: ast::StmtKind::Assign { + targets, + value: Box::new(value), + type_comment: None, + config_comment: config_comment.clone(), + }, + custom: None, + }); } for target in targets { self.infer_pattern(target)?; @@ -292,7 +292,7 @@ impl<'a> Fold<()> for Inferencer<'a> { fold::fold_stmt(self, node)? } ast::StmtKind::With { ref items, .. } => { - for item in items.iter() { + for item in items { if let Some(var) = &item.optional_vars { self.infer_pattern(var)?; } @@ -302,20 +302,21 @@ impl<'a> Fold<()> for Inferencer<'a> { _ => fold::fold_stmt(self, node)?, }; match &stmt.node { - ast::StmtKind::For { .. } => {} - ast::StmtKind::Try { .. } => {} + ast::StmtKind::AnnAssign { .. } + | ast::StmtKind::Break { .. } + | ast::StmtKind::Continue { .. } + | ast::StmtKind::Expr { .. } + | ast::StmtKind::For { .. } + | ast::StmtKind::Pass { .. } + | ast::StmtKind::Try { .. } => {} ast::StmtKind::If { test, .. } | ast::StmtKind::While { test, .. } => { self.unify(test.custom.unwrap(), self.primitives.bool, &test.location)?; } ast::StmtKind::Assign { targets, value, .. } => { - for target in targets.iter() { + for target in targets { self.unify(target.custom.unwrap(), value.custom.unwrap(), &target.location)?; } } - ast::StmtKind::AnnAssign { .. } | ast::StmtKind::Expr { .. } => {} - ast::StmtKind::Break { .. } - | ast::StmtKind::Continue { .. } - | ast::StmtKind::Pass { .. } => {} ast::StmtKind::Raise { exc, cause, .. } => { if let Some(cause) = cause { return report_error("raise ... from cause is not supported", cause.location); @@ -334,13 +335,13 @@ impl<'a> Fold<()> for Inferencer<'a> { } } ast::StmtKind::With { items, .. } => { - for item in items.iter() { + for item in items { let ty = item.context_expr.custom.unwrap(); // if we can simply unify without creating new types... let mut fast_path = false; if let TypeEnum::TObj { fields, .. } = &*self.unifier.get_ty(ty) { fast_path = true; - if let Some(enter) = fields.get(&"__enter__".into()).cloned() { + if let Some(enter) = fields.get(&"__enter__".into()).copied() { if let TypeEnum::TFunc(signature) = &*self.unifier.get_ty(enter.0) { if !signature.args.is_empty() { return report_error( @@ -368,7 +369,7 @@ impl<'a> Fold<()> for Inferencer<'a> { stmt.location, ); } - if let Some(exit) = fields.get(&"__exit__".into()).cloned() { + if let Some(exit) = fields.get(&"__exit__".into()).copied() { if let TypeEnum::TFunc(signature) = &*self.unifier.get_ty(exit.0) { if !signature.args.is_empty() { return report_error( @@ -393,13 +394,13 @@ impl<'a> Fold<()> for Inferencer<'a> { || self.unifier.get_dummy_var().0, |var| var.custom.unwrap(), ), - vars: Default::default(), + vars: HashMap::default(), }); let enter = self.unifier.add_ty(enter); let exit = TypeEnum::TFunc(FunSignature { args: vec![], ret: self.unifier.get_dummy_var().0, - vars: Default::default(), + vars: HashMap::default(), }); let exit = self.unifier.add_ty(exit); let mut fields = HashMap::new(); @@ -489,7 +490,7 @@ impl<'a> Fold<()> for Inferencer<'a> { } Err(e) => { return report_error( - &format!("type error at identifier `{}` ({})", id, e), + &format!("type error at identifier `{id}` ({e})"), expr.location, ); } @@ -551,7 +552,7 @@ impl<'a> Inferencer<'a> { Ok(()) } ExprKind::Tuple { elts, .. } => { - for elt in elts.iter() { + for elt in elts { self.infer_pattern(elt)?; } Ok(()) @@ -637,7 +638,7 @@ impl<'a> Inferencer<'a> { } let mut defined_identifiers = self.defined_identifiers.clone(); - for arg in args.args.iter() { + for arg in &args.args { let name = &arg.node.arg; if !defined_identifiers.contains(name) { defined_identifiers.insert(*name); @@ -649,7 +650,7 @@ impl<'a> Inferencer<'a> { .map(|v| (v.node.arg, self.unifier.get_fresh_var(Some(v.node.arg), Some(v.location)).0)) .collect(); let mut variable_mapping = self.variable_mapping.clone(); - variable_mapping.extend(fn_args.iter().cloned()); + variable_mapping.extend(fn_args.iter().copied()); let ret = self.unifier.get_dummy_var().0; let mut new_context = Inferencer { @@ -670,7 +671,7 @@ impl<'a> Inferencer<'a> { .map(|(k, ty)| FuncArg { name: *k, ty: *ty, default_value: None }) .collect(), ret, - vars: Default::default(), + vars: HashMap::default(), }; let body = new_context.fold_expr(body)?; new_context.unify(fun.ret, body.custom.unwrap(), &location)?; @@ -739,7 +740,7 @@ impl<'a> Inferencer<'a> { // iter should be a list of targets... // actually it should be an iterator of targets, but we don't have iter type for now // if conditions should be bool - for v in ifs.iter() { + for v in &ifs { new_context.unify(v.custom.unwrap(), new_context.primitives.bool, &v.location)?; } @@ -926,12 +927,12 @@ impl<'a> Inferencer<'a> { } fn infer_identifier(&mut self, id: StrRef) -> InferenceResult { - if let Some(ty) = self.variable_mapping.get(&id) { - Ok(*ty) + Ok(if let Some(ty) = self.variable_mapping.get(&id) { + *ty } else { let variable_mapping = &mut self.variable_mapping; - let unifier = &mut self.unifier; - Ok(self + let unifier: &mut Unifier = self.unifier; + self .function_data .resolver .get_symbol_type(unifier, &self.top_level.definitions.read(), self.primitives, id) @@ -939,8 +940,8 @@ impl<'a> Inferencer<'a> { let ty = unifier.get_dummy_var().0; variable_mapping.insert(id, ty); ty - })) - } + }) + }) } fn infer_constant(&mut self, constant: &ast::Constant, loc: &Location) -> InferenceResult { @@ -971,7 +972,7 @@ impl<'a> Inferencer<'a> { fn infer_list(&mut self, elts: &[ast::Expr>]) -> InferenceResult { let ty = self.unifier.get_dummy_var().0; - for t in elts.iter() { + for t in elts { self.unify(ty, t.custom.unwrap(), &t.location)?; } Ok(self.unifier.add_ty(TypeEnum::TList { ty })) @@ -992,14 +993,13 @@ impl<'a> Inferencer<'a> { if let TypeEnum::TObj { fields, .. } = &*self.unifier.get_ty(ty) { // just a fast path match (fields.get(&attr), ctx == &ExprContext::Store) { - (Some((ty, true)), _) => Ok(*ty), - (Some((ty, false)), false) => Ok(*ty), + (Some((ty, true)), _) | (Some((ty, false)), false) => Ok(*ty), (Some((_, false)), true) => { - report_error(&format!("Field `{}` is immutable", attr), value.location) + report_error(&format!("Field `{attr}` is immutable"), value.location) } (None, _) => { let t = self.unifier.stringify(ty); - report_error(&format!("`{}::{}` field/method does not exist", t, attr), value.location) + report_error(&format!("`{t}::{attr}` field/method does not exist"), value.location) }, } } else { diff --git a/nac3core/src/typecheck/typedef/mod.rs b/nac3core/src/typecheck/typedef/mod.rs index 04d8df54b..1be280a21 100644 --- a/nac3core/src/typecheck/typedef/mod.rs +++ b/nac3core/src/typecheck/typedef/mod.rs @@ -97,8 +97,8 @@ impl From for RecordKey { impl Display for RecordKey { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - RecordKey::Str(s) => write!(f, "{}", s), - RecordKey::Int(i) => write!(f, "{}", i), + RecordKey::Str(s) => write!(f, "{s}"), + RecordKey::Int(i) => write!(f, "{i}"), } } } @@ -111,6 +111,7 @@ pub struct RecordField { } impl RecordField { + #[must_use] pub fn new(ty: Type, mutable: bool, loc: Option) -> RecordField { RecordField { ty, mutable, loc } } @@ -185,6 +186,7 @@ pub enum TypeEnum { } impl TypeEnum { + #[must_use] pub fn get_type_name(&self) -> &'static str { match self { TypeEnum::TRigidVar { .. } => "TRigidVar", @@ -220,6 +222,7 @@ impl Default for Unifier { impl Unifier { /// Get an empty unifier + #[must_use] pub fn new() -> Unifier { Unifier { unification_table: UnificationTable::new(), @@ -252,6 +255,7 @@ impl Unifier { } } + #[must_use] pub fn get_shared_unifier(&self) -> SharedUnifier { Arc::new(Mutex::new(( self.unification_table.get_send(), @@ -261,7 +265,7 @@ impl Unifier { } /// Register a type to the unifier. - /// Returns a key in the unification_table. + /// Returns a key in the `unification_table`. pub fn add_ty(&mut self, a: TypeEnum) -> Type { self.unification_table.new_key(Rc::new(a)) } @@ -294,6 +298,7 @@ impl Unifier { } } + #[must_use] pub fn get_call_signature_immutable(&self, id: CallId) -> Option { let fun = self.calls.get(id.0).unwrap().fun.borrow().unwrap(); if let TypeEnum::TFunc(sign) = &*self.get_ty_immutable(fun) { @@ -307,11 +312,12 @@ impl Unifier { self.unification_table.get_representative(ty) } - /// Get the TypeEnum of a type. + /// Get the `TypeEnum` of a type. pub fn get_ty(&mut self, a: Type) -> Rc { self.unification_table.probe_value(a).clone() } + #[must_use] pub fn get_ty_immutable(&self, a: Type) -> Rc { self.unification_table.probe_value_immutable(a).clone() } @@ -435,7 +441,7 @@ impl Unifier { .map(|params| { self.subst( ty, - &zip(keys.iter().cloned(), params.iter().cloned()).collect(), + &zip(keys.iter().copied(), params.iter().copied()).collect(), ) .unwrap_or(ty) }) @@ -453,7 +459,7 @@ impl Unifier { TRigidVar { .. } | TConstant { .. } => true, TVar { .. } => allowed_typevars.iter().any(|b| self.unification_table.unioned(a, *b)), TCall { .. } => false, - TList { ty } => self.is_concrete(*ty, allowed_typevars), + TList { ty } | TVirtual { ty } => self.is_concrete(*ty, allowed_typevars), TTuple { ty } => ty.iter().all(|ty| self.is_concrete(*ty, allowed_typevars)), TObj { params: vars, .. } => { vars.values().all(|ty| self.is_concrete(*ty, allowed_typevars)) @@ -461,7 +467,6 @@ impl Unifier { // functions are instantiated for each call sites, so the function type can contain // type variables. TFunc { .. } => true, - TVirtual { ty } => self.is_concrete(*ty, allowed_typevars), } } @@ -522,7 +527,7 @@ impl Unifier { TypeError::new(TypeErrorKind::IncorrectArgType { name, expected, got: *t }, *loc) })?; } - for (k, t) in kwargs.iter() { + for (k, t) in kwargs { if let Some(i) = required.iter().position(|v| v == k) { required.remove(i); } @@ -609,7 +614,7 @@ impl Unifier { } (Some(fields1), Some(fields2)) => { let mut new_fields: Mapping<_, _> = fields2.clone(); - for (key, val1) in fields1.iter() { + for (key, val1) in fields1 { if let Some(val2) = fields2.get(key) { self.unify_impl(val1.ty, val2.ty, false).map_err(|_| { TypeError::new( @@ -638,7 +643,7 @@ impl Unifier { }; let intersection = self .get_intersection(a, b) - .map_err(|_| TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None))? + .map_err(|()| TypeError::new(TypeErrorKind::IncompatibleTypes(a, b), None))? .unwrap(); let range = if let TVar { range, .. } = &*self.get_ty(intersection) { range.clone() @@ -677,7 +682,7 @@ impl Unifier { } (TVar { fields: Some(fields), range, is_const_generic: false, .. }, TTuple { ty }) => { let len = ty.len() as i32; - for (k, v) in fields.iter() { + for (k, v) in fields { match *k { RecordKey::Int(i) => { if v.mutable { @@ -706,10 +711,10 @@ impl Unifier { self.set_a_to_b(a, x); } (TVar { fields: Some(fields), range, is_const_generic: false, .. }, TList { ty }) => { - for (k, v) in fields.iter() { + for (k, v) in fields { match *k { RecordKey::Int(_) => { - self.unify_impl(v.ty, *ty, false).map_err(|e| e.at(v.loc))? + self.unify_impl(v.ty, *ty, false).map_err(|e| e.at(v.loc))?; } RecordKey::Str(_) => { return Err(TypeError::new(TypeErrorKind::NoSuchField(*k, b), v.loc)) @@ -767,7 +772,7 @@ impl Unifier { self.set_a_to_b(a, b); } (TVar { fields: Some(map), range, .. }, TObj { fields, .. }) => { - for (k, field) in map.iter() { + for (k, field) in map { match *k { RecordKey::Str(s) => { let (ty, mutable) = fields.get(&s).copied().ok_or_else(|| { @@ -799,7 +804,7 @@ impl Unifier { (TVar { fields: Some(map), range, .. }, TVirtual { ty }) => { let ty = self.get_ty(*ty); if let TObj { fields, .. } = ty.as_ref() { - for (k, field) in map.iter() { + for (k, field) in map { match *k { RecordKey::Str(s) => { let (ty, _) = fields.get(&s).copied().ok_or_else(|| { @@ -866,7 +871,7 @@ impl Unifier { (TCall(calls1), TCall(calls2)) => { // we do not unify individual calls, instead we defer until the unification wtih a // function definition. - let calls = calls1.iter().chain(calls2.iter()).cloned().collect(); + let calls = calls1.iter().chain(calls2.iter()).copied().collect(); self.set_a_to_b(a, b); self.unification_table.set_value(b, Rc::new(TCall(calls))); } @@ -879,7 +884,7 @@ impl Unifier { .rev() .collect(); // we unify every calls to the function signature. - for c in calls.iter() { + for c in calls { let call = self.calls[c.0].clone(); self.unify_call(&call, b, signature, &required)?; } @@ -912,9 +917,9 @@ impl Unifier { _ => { if swapped { return self.incompatible_types(a, b); - } else { - self.unify_impl(b, a, true)?; } + + self.unify_impl(b, a, true)?; } } Ok(()) @@ -934,7 +939,7 @@ impl Unifier { ty, &mut |id| { top_level.as_ref().map_or_else( - || format!("{}", id), + || format!("{id}"), |top_level| { if let TopLevelDef::Class { name, .. } = &*top_level.definitions.read()[id].read() @@ -946,7 +951,7 @@ impl Unifier { }, ) }, - &mut |id| format!("typevar{}", id), + &mut |id| format!("typevar{id}"), notes, ) } @@ -989,7 +994,7 @@ impl Unifier { if !range.is_empty() && notes.is_some() && !notes.as_ref().unwrap().contains_key(id) { // just in case if there is any cyclic dependency - notes.as_mut().unwrap().insert(*id, "".into()); + notes.as_mut().unwrap().insert(*id, String::new()); let body = format!( "{} ∈ {{{}}}", n, @@ -1022,15 +1027,15 @@ impl Unifier { } TypeEnum::TObj { obj_id, params, .. } => { let name = obj_to_name(obj_id.0); - if !params.is_empty() { + if params.is_empty() { + name + } else { let params = params .iter() .map(|(_, v)| self.internal_stringify(*v, obj_to_name, var_to_name, notes)); // sort to preserve order let mut params = params.sorted(); format!("{}[{}]", name, params.join(", ")) - } else { - name } } TypeEnum::TCall { .. } => "call".to_owned(), @@ -1056,7 +1061,7 @@ impl Unifier { }) .join(", "); let ret = self.internal_stringify(signature.ret, obj_to_name, var_to_name, notes); - format!("fn[[{}], {}]", params, ret) + format!("fn[[{params}], {ret}]") } } } @@ -1066,7 +1071,7 @@ impl Unifier { let table = &mut self.unification_table; let ty_b = table.probe_value(b).clone(); table.unify(a, b); - table.set_value(a, ty_b) + table.set_value(a, ty_b); } fn incompatible_types(&mut self, a: Type, b: Type) -> Result<(), TypeError> { @@ -1079,7 +1084,7 @@ impl Unifier { fn instantiate_fun(&mut self, ty: Type, fun: &FunSignature) -> Type { let mut instantiated = true; let mut vars = Vec::new(); - for (k, v) in fun.vars.iter() { + for (k, v) in &fun.vars { if let TypeEnum::TVar { id, name, loc, range, .. } = self.unification_table.probe_value(*v).as_ref() { @@ -1134,7 +1139,7 @@ impl Unifier { // should be safe to not implement the substitution for those variants. match &*ty { TypeEnum::TRigidVar { .. } => None, - TypeEnum::TVar { id, .. } => mapping.get(id).cloned(), + TypeEnum::TVar { id, .. } => mapping.get(id).copied(), TypeEnum::TTuple { ty } => { let mut new_ty = Cow::from(ty); for (i, t) in ty.iter().enumerate() { @@ -1219,7 +1224,7 @@ impl Unifier { K: std::hash::Hash + Eq + Clone, { let mut map2 = None; - for (k, v) in map.iter() { + for (k, v) in map { if let Some(v1) = self.subst_impl(*v, mapping, cache) { if map2.is_none() { map2 = Some(map.clone()); @@ -1240,7 +1245,7 @@ impl Unifier { K: std::hash::Hash + Eq + Clone, { let mut map2 = None; - for (k, (v, mutability)) in map.iter() { + for (k, (v, mutability)) in map { if let Some(v1) = self.subst_impl(*v, mapping, cache) { if map2.is_none() { map2 = Some(map.clone()); @@ -1296,7 +1301,7 @@ impl Unifier { if range.is_empty() { Ok(Some(a)) } else { - for v in range.iter() { + for v in range { let result = self.get_intersection(a, *v); if let Ok(result) = result { return Ok(result.or(Some(a))); @@ -1338,7 +1343,7 @@ impl Unifier { if range.is_empty() { return Ok(None); } - for t in range.iter() { + for t in range { let result = self.get_intersection(*t, b); if let Ok(result) = result { return Ok(result); diff --git a/nac3standalone/src/main.rs b/nac3standalone/src/main.rs index 4b69be7b5..c22bd56f9 100644 --- a/nac3standalone/src/main.rs +++ b/nac3standalone/src/main.rs @@ -393,7 +393,7 @@ fn main() { let threads = (0..threads) .map(|i| Box::new(DefaultCodeGenerator::new(format!("module{}", i), 64))) .collect(); - let (registry, handles) = WorkerRegistry::create_workers(threads, top_level, &llvm_options, f); + let (registry, handles) = WorkerRegistry::create_workers(threads, top_level, &llvm_options, &f); registry.add_task(task); registry.wait_tasks_complete(handles);