From 8432a26a3f237cab622334e63ba3fde7694979ed Mon Sep 17 00:00:00 2001 From: Tobias Tom Hodapp Date: Thu, 30 Jan 2025 19:33:27 +0100 Subject: [PATCH 1/6] fmt --- build.rs | 7 +- src/alloc.rs | 33 +- src/block_vector.rs | 140 ++++--- src/codegen/mod.rs | 47 ++- src/codegen/shared.rs | 6 +- src/codegen/system_verilog.rs | 22 +- src/codegen/vhdl.rs | 16 +- src/compiler_top.rs | 130 ++++-- src/debug.rs | 16 +- src/dev_aid/ariadne_interface.rs | 54 +-- src/dev_aid/lsp/hover_info.rs | 48 ++- src/dev_aid/lsp/mod.rs | 63 ++- src/dev_aid/lsp/tree_walk.rs | 69 ++-- src/errors.rs | 52 +-- src/file_position.rs | 4 +- src/flattening/flatten.rs | 513 +++++++++++++++--------- src/flattening/initialization.rs | 86 ++-- src/flattening/lints.rs | 25 +- src/flattening/mod.rs | 209 +++++----- src/flattening/name_context.rs | 9 +- src/flattening/parser.rs | 8 +- src/flattening/typechecking.rs | 275 ++++++++----- src/flattening/walk.rs | 10 +- src/instantiation/concrete_typecheck.rs | 316 ++++++++++----- src/instantiation/execute.rs | 37 +- src/instantiation/latency_algorithm.rs | 10 +- src/instantiation/latency_count.rs | 21 +- src/instantiation/list_of_lists.rs | 2 +- src/instantiation/mod.rs | 63 +-- src/instantiation/unique_names.rs | 16 +- src/linker/checkpoint.rs | 6 +- src/linker/mod.rs | 113 +++--- src/linker/resolver.rs | 69 +++- src/main.rs | 6 +- src/prelude.rs | 1 - src/to_string.rs | 9 +- src/typing/abstract_type.rs | 257 ++++++++---- src/typing/concrete_type.rs | 30 +- src/typing/template.rs | 7 +- src/typing/type_inference.rs | 352 ++++++++++------ src/value.rs | 54 ++- sus-proc-macro/src/lib.rs | 17 +- 42 files changed, 2001 insertions(+), 1227 deletions(-) diff --git a/build.rs b/build.rs index 84d9470..c792420 100644 --- a/build.rs +++ b/build.rs @@ -4,13 +4,16 @@ fn main() { let mut install_dir = get_sus_dir(); install_dir.push(env!("CARGO_PKG_VERSION")); install_dir.push("std"); - + fs::create_dir_all(&install_dir).expect("Failed to create std_lib directory"); copy_dir("std", &install_dir).expect("Failed to copy STD folder"); // Print the path to make it available during the build - println!("cargo:rustc-env=SUS_COMPILER_STD_LIB_PATH={}", install_dir.display()); + println!( + "cargo:rustc-env=SUS_COMPILER_STD_LIB_PATH={}", + install_dir.display() + ); } fn get_sus_dir() -> PathBuf { diff --git a/src/alloc.rs b/src/alloc.rs index 834cc90..0e5810a 100644 --- a/src/alloc.rs +++ b/src/alloc.rs @@ -8,9 +8,9 @@ use std::{ }; /// UUIDs are type-safe integers. They are used for [FlatAlloc] and [ArenaAllocator] -/// -/// They don't support arithmetic, as they're just meant to represent pointers. -/// +/// +/// They don't support arithmetic, as they're just meant to represent pointers. +/// /// TODO add custom niche for more efficient Options, wait until custom niches are stabilized (https://internals.rust-lang.org/t/nonmaxusize-and-niche-value-optimisation/19661) /// Maybe use NonZeroUsize (https://doc.rust-lang.org/std/num/struct.NonZeroUsize.html) pub struct UUID(usize, PhantomData); @@ -59,29 +59,29 @@ impl UUID { } pub struct UUIDAllocator { - cur : UUID + cur: UUID, } impl Clone for UUIDAllocator { fn clone(&self) -> Self { - Self { cur: self.cur.clone() } + Self { + cur: self.cur.clone(), + } } } impl UUIDAllocator { pub fn new() -> Self { Self { - cur: UUID(0, PhantomData) + cur: UUID(0, PhantomData), } } pub fn new_start_from(start: UUID) -> Self { - Self { - cur: start - } + Self { cur: start } } pub fn alloc(&mut self) -> UUID { let allocated_id = self.cur; - self.cur.0+=1; + self.cur.0 += 1; allocated_id } pub fn peek(&self) -> UUID { @@ -101,7 +101,9 @@ impl UUIDAllocator { impl std::fmt::Debug for UUIDAllocator { fn fmt(&self, f: &mut Formatter<'_>) -> Result { - f.debug_struct("UUIDAllocator").field("count: ", &self.cur.0).finish() + f.debug_struct("UUIDAllocator") + .field("count: ", &self.cur.0) + .finish() } } @@ -484,7 +486,7 @@ pub struct FlatAlloc { } impl FlatAlloc { - pub const EMPTY_FLAT_ALLOC : Self = Self::new(); + pub const EMPTY_FLAT_ALLOC: Self = Self::new(); pub const fn new() -> Self { Self { @@ -498,12 +500,15 @@ impl FlatAlloc { _ph: PhantomData, } } - pub fn with_size(size: usize, v: T) -> Self where T: Clone { + pub fn with_size(size: usize, v: T) -> Self + where + T: Clone, + { let mut data = Vec::new(); data.resize(size, v); Self { data, - _ph: PhantomData + _ph: PhantomData, } } pub fn get_next_alloc_id(&self) -> UUID { diff --git a/src/block_vector.rs b/src/block_vector.rs index 06c138e..fd9626d 100644 --- a/src/block_vector.rs +++ b/src/block_vector.rs @@ -1,35 +1,44 @@ -use std::{cell::{UnsafeCell, Cell}, mem::MaybeUninit, ops::{DerefMut, Deref, IndexMut, Index}}; - - - -/// Has the property that appends don't move other elements. References are always preserved, therefore append is const -/// +use std::{ + cell::{Cell, UnsafeCell}, + mem::MaybeUninit, + ops::{Deref, DerefMut, Index, IndexMut}, +}; + +/// Has the property that appends don't move other elements. References are always preserved, therefore append is const +/// /// Critically, alloc takes a CONST self, because using this will not invalidate any references derived from this /// However, IndexMut still requires a mutable reference, since we can edit any arbitrary element, and the compiler can't check for overlap there -/// +/// /// The const iterator exists, though it is not recommended to append elements while iterating over it. The const iterator would continue even onto newer elements /// Existence of the mutable iterator disallows updating the container of course #[derive(Default)] -pub struct BlockVec { - blocks : UnsafeCell; BLOCK_SIZE]>>>, - length : Cell, +pub struct BlockVec { + blocks: UnsafeCell; BLOCK_SIZE]>>>, + length: Cell, } -impl BlockVec { +impl BlockVec { pub fn new() -> Self { - Self{blocks : UnsafeCell::new(Vec::new()), length : Cell::new(0)} + Self { + blocks: UnsafeCell::new(Vec::new()), + length: Cell::new(0), + } } - pub fn alloc(&self, obj : T) -> usize { + pub fn alloc(&self, obj: T) -> usize { let b = self.blocks.get(); let allocated_id = self.length.get(); if allocated_id % BLOCK_SIZE == 0 { // New block - - let new_block : Box; BLOCK_SIZE]>> = Box::new(MaybeUninit::uninit()); + + let new_block: Box; BLOCK_SIZE]>> = + Box::new(MaybeUninit::uninit()); unsafe { - let mut new_block_box = std::mem::transmute::; BLOCK_SIZE]>>, Box<[MaybeUninit; BLOCK_SIZE]>>(new_block); + let mut new_block_box = std::mem::transmute::< + Box; BLOCK_SIZE]>>, + Box<[MaybeUninit; BLOCK_SIZE]>, + >(new_block); let slice = new_block_box.as_mut(); slice[0].write(obj); @@ -67,7 +76,7 @@ impl BlockVec { } } -impl Drop for BlockVec { +impl Drop for BlockVec { fn drop(&mut self) { let num_full_blocks = self.length.get() / BLOCK_SIZE; let num_remaining = self.length.get() % BLOCK_SIZE; @@ -75,20 +84,22 @@ impl Drop for BlockVec { let block_vec = self.blocks.get_mut(); for i in 0..num_full_blocks { for v in block_vec[i].deref_mut() { - unsafe{v.assume_init_drop();} + unsafe { + v.assume_init_drop(); + } } } if num_remaining > 0 { let last_block = block_vec[num_full_blocks].deref_mut(); for i in 0..num_remaining { - unsafe{last_block[i].assume_init_drop()}; + unsafe { last_block[i].assume_init_drop() }; } } } } -impl std::fmt::Debug for BlockVec { +impl std::fmt::Debug for BlockVec { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let len = self.length.get(); f.write_fmt(format_args!("BlockVec(Size = {len})["))?; @@ -100,49 +111,52 @@ impl std::fmt::Debug for BlockVec } } -impl Index for BlockVec { +impl Index for BlockVec { type Output = T; fn index(&self, index: usize) -> &T { let self_len = self.length.get(); - if index >= self_len {panic!("Index is out of bounds (idx is {index}, len is {self_len})")} + if index >= self_len { + panic!("Index is out of bounds (idx is {index}, len is {self_len})") + } let block = index / BLOCK_SIZE; let idx_in_block = index % BLOCK_SIZE; - unsafe{ + unsafe { let vec = self.blocks.get(); (*vec)[block].deref()[idx_in_block].assume_init_ref() } } } -impl IndexMut for BlockVec { +impl IndexMut for BlockVec { fn index_mut(&mut self, index: usize) -> &mut T { let self_len = self.length.get(); - if index >= self_len {panic!("Index is out of bounds (idx is {index}, len is {self_len})")} + if index >= self_len { + panic!("Index is out of bounds (idx is {index}, len is {self_len})") + } let block = index / BLOCK_SIZE; let idx_in_block = index % BLOCK_SIZE; let vec = self.blocks.get_mut(); - unsafe{vec[block].deref_mut()[idx_in_block].assume_init_mut()} + unsafe { vec[block].deref_mut()[idx_in_block].assume_init_mut() } } } - -pub struct BlockVecIter<'bv, T, const BLOCK_SIZE : usize = 64> { - block_vec : &'bv BlockVec, - cur_idx : usize +pub struct BlockVecIter<'bv, T, const BLOCK_SIZE: usize = 64> { + block_vec: &'bv BlockVec, + cur_idx: usize, } -impl<'bv, T, const BLOCK_SIZE : usize> Iterator for BlockVecIter<'bv, T, BLOCK_SIZE> { +impl<'bv, T, const BLOCK_SIZE: usize> Iterator for BlockVecIter<'bv, T, BLOCK_SIZE> { type Item = &'bv T; fn next(&mut self) -> Option<&'bv T> { if self.cur_idx < self.block_vec.length.get() { let selected_idx = self.cur_idx; self.cur_idx += 1; - + Some(self.block_vec.index(selected_idx)) } else { return None; @@ -150,84 +164,84 @@ impl<'bv, T, const BLOCK_SIZE : usize> Iterator for BlockVecIter<'bv, T, BLOCK_S } } -impl<'bv, T, const BLOCK_SIZE : usize> IntoIterator for &'bv BlockVec { +impl<'bv, T, const BLOCK_SIZE: usize> IntoIterator for &'bv BlockVec { type Item = &'bv T; type IntoIter = BlockVecIter<'bv, T, BLOCK_SIZE>; fn into_iter(self) -> Self::IntoIter { - BlockVecIter{ - block_vec : self, - cur_idx : 0 + BlockVecIter { + block_vec: self, + cur_idx: 0, } } } -pub struct BlockVecIterMut<'bv, T, const BLOCK_SIZE : usize = 64> { - block_vec : &'bv mut BlockVec, - cur_idx : usize +pub struct BlockVecIterMut<'bv, T, const BLOCK_SIZE: usize = 64> { + block_vec: &'bv mut BlockVec, + cur_idx: usize, } -impl<'bv, T, const BLOCK_SIZE : usize> Iterator for BlockVecIterMut<'bv, T, BLOCK_SIZE> { +impl<'bv, T, const BLOCK_SIZE: usize> Iterator for BlockVecIterMut<'bv, T, BLOCK_SIZE> { type Item = &'bv mut T; fn next(&mut self) -> Option<&'bv mut T> { if self.cur_idx < self.block_vec.length.get() { let selected_idx = self.cur_idx; self.cur_idx += 1; - + // SAFETY - // Have to cast away the added 'self lifetime. The borrow checker adds it on self.block_vec to prevent us from mutably referencing the same location twice. - // This code always indexes unique elements, and thus we can safely cast away this lifetime. + // Have to cast away the added 'self lifetime. The borrow checker adds it on self.block_vec to prevent us from mutably referencing the same location twice. + // This code always indexes unique elements, and thus we can safely cast away this lifetime. let original_ref: *mut T = self.block_vec.index_mut(selected_idx); - Some(unsafe{&mut *original_ref}) + Some(unsafe { &mut *original_ref }) } else { return None; } } } -impl<'bv, T, const BLOCK_SIZE : usize> IntoIterator for &'bv mut BlockVec { +impl<'bv, T, const BLOCK_SIZE: usize> IntoIterator for &'bv mut BlockVec { type Item = &'bv mut T; type IntoIter = BlockVecIterMut<'bv, T, BLOCK_SIZE>; fn into_iter(self) -> Self::IntoIter { - BlockVecIterMut{ - block_vec : self, - cur_idx : 0 + BlockVecIterMut { + block_vec: self, + cur_idx: 0, } } } -pub struct BlockVecConsumingIter { - block_vec_iter : ; BLOCK_SIZE]>> as IntoIterator>::IntoIter, - current_block : Option; BLOCK_SIZE]>>, - current_idx : usize, - total_vec_size : usize +pub struct BlockVecConsumingIter { + block_vec_iter: ; BLOCK_SIZE]>> as IntoIterator>::IntoIter, + current_block: Option; BLOCK_SIZE]>>, + current_idx: usize, + total_vec_size: usize, } -impl Iterator for BlockVecConsumingIter { +impl Iterator for BlockVecConsumingIter { type Item = T; fn next(&mut self) -> Option { if self.current_idx < self.total_vec_size { let idx_in_block = self.current_idx % BLOCK_SIZE; self.current_idx += 1; - + if idx_in_block == 0 { self.current_block = Some(self.block_vec_iter.next().unwrap()); // Vec will always be big enough } let found = &mut self.current_block.as_mut().unwrap().as_mut_slice()[idx_in_block]; - unsafe{Some(found.assume_init_read())} + unsafe { Some(found.assume_init_read()) } } else { return None; } } } -impl IntoIterator for BlockVec { +impl IntoIterator for BlockVec { type Item = T; type IntoIter = BlockVecConsumingIter; @@ -237,22 +251,22 @@ impl IntoIterator for BlockVec { self.length.set(0); let block_vec = std::mem::replace(self.blocks.get_mut(), Vec::new()); let block_vec_iter = block_vec.into_iter(); - BlockVecConsumingIter{ + BlockVecConsumingIter { block_vec_iter, - current_block : None, - current_idx : 0, - total_vec_size + current_block: None, + current_idx: 0, + total_vec_size, } } } -impl Drop for BlockVecConsumingIter { +impl Drop for BlockVecConsumingIter { fn drop(&mut self) { while let Some(_) = self.next() {} // Automatically drops all remaining elements of the iterator } } -impl<'bv, T, const BLOCK_SIZE : usize> FromIterator for BlockVec { +impl<'bv, T, const BLOCK_SIZE: usize> FromIterator for BlockVec { fn from_iter>(iter: Iter) -> Self { let new_coll = BlockVec::new(); for v in iter { diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index c960498..3aee9b0 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1,38 +1,57 @@ +mod shared; pub mod system_verilog; pub mod vhdl; -mod shared; pub use system_verilog::VerilogCodegenBackend; pub use vhdl::VHDLCodegenBackend; use crate::{InstantiatedModule, Linker, Module}; -use std::{fs::{self, File}, io::Write, path::PathBuf, rc::Rc}; +use std::{ + fs::{self, File}, + io::Write, + path::PathBuf, + rc::Rc, +}; /// Implemented for SystemVerilog [self::system_verilog] or VHDL [self::vhdl] pub trait CodeGenBackend { fn file_extension(&self) -> &str; fn output_dir_name(&self) -> &str; - fn codegen(&self, md: &Module, instance: &InstantiatedModule, linker: &Linker, use_latency: bool) -> String; + fn codegen( + &self, + md: &Module, + instance: &InstantiatedModule, + linker: &Linker, + use_latency: bool, + ) -> String; fn make_output_file(&self, name: &str) -> File { - let mut path = PathBuf::with_capacity(name.len() + self.output_dir_name().len() + self.file_extension().len() + 2); + let mut path = PathBuf::with_capacity( + name.len() + self.output_dir_name().len() + self.file_extension().len() + 2, + ); path.push(self.output_dir_name()); fs::create_dir_all(&path).unwrap(); path.push(name); path.set_extension(self.file_extension()); let mut file = File::create(path).unwrap(); - + file.write_fmt(format_args!( "// DO NOT EDIT THIS FILE\n// This file was generated with SUS Compiler {}\n", std::env!("CARGO_PKG_VERSION") )) .unwrap(); - + file } - fn codegen_instance(&self, inst: &InstantiatedModule, md: &Module, linker: &Linker, out_file: &mut File) { + fn codegen_instance( + &self, + inst: &InstantiatedModule, + md: &Module, + linker: &Linker, + out_file: &mut File, + ) { let inst_name = &inst.name; if inst.errors.did_error { println!("Instantiating error: {inst_name}"); @@ -60,15 +79,15 @@ pub trait CodeGenBackend { .iter() .map(|v| (v.as_ref(), md)) .collect(); - + let mut cur_idx = 0; - + while cur_idx < to_process_queue.len() { let (cur_instance, cur_md) = to_process_queue[cur_idx]; - + for (_, sub_mod) in &cur_instance.submodules { let new_inst = sub_mod.instance.get().unwrap().as_ref(); - + // Skip duplicates // Yeah yeah I know O(n²) but this list shouldn't grow too big. Fix if needed if to_process_queue @@ -77,12 +96,12 @@ pub trait CodeGenBackend { { continue; } - + to_process_queue.push((new_inst, &linker.modules[sub_mod.module_uuid])); } - + self.codegen_instance(cur_instance, cur_md, linker, &mut out_file); - + cur_idx += 1; } } diff --git a/src/codegen/shared.rs b/src/codegen/shared.rs index 1e5fc09..a5579c9 100644 --- a/src/codegen/shared.rs +++ b/src/codegen/shared.rs @@ -4,7 +4,11 @@ use std::borrow::Cow; use crate::instantiation::RealWire; -pub fn wire_name_with_latency(wire: &RealWire, absolute_latency: i64, use_latency: bool) -> Cow { +pub fn wire_name_with_latency( + wire: &RealWire, + absolute_latency: i64, + use_latency: bool, +) -> Cow { assert!(wire.absolute_latency <= absolute_latency); if use_latency && (wire.absolute_latency != absolute_latency) { if absolute_latency < 0 { diff --git a/src/codegen/system_verilog.rs b/src/codegen/system_verilog.rs index e5c7e6e..d9587c4 100644 --- a/src/codegen/system_verilog.rs +++ b/src/codegen/system_verilog.rs @@ -141,12 +141,17 @@ impl<'g> CodeGenerationContext<'g> { Ok(()) } - fn comment_out(&mut self, f : impl FnOnce(&mut Self)) { + fn comment_out(&mut self, f: impl FnOnce(&mut Self)) { let store_program_text_temporary = std::mem::replace(&mut self.program_text, String::new()); f(self); let added_text = std::mem::replace(&mut self.program_text, store_program_text_temporary); - write!(self.program_text, "// {}\n", added_text.replace("\n", "\n// ")).unwrap(); + write!( + self.program_text, + "// {}\n", + added_text.replace("\n", "\n// ") + ) + .unwrap(); } fn write_verilog_code(&mut self) { @@ -311,7 +316,11 @@ impl<'g> CodeGenerationContext<'g> { let sm_name = &sm.name; let submodule_clk_name = sm_md.get_clock_name(); writeln!(self.program_text, " {sm_name}(").unwrap(); - write!(self.program_text, "\t.{submodule_clk_name}({parent_clk_name})").unwrap(); + write!( + self.program_text, + "\t.{submodule_clk_name}({parent_clk_name})" + ) + .unwrap(); for (port_id, iport) in sm_inst.interface_ports.iter_valids() { let port_name = wire_name_self_latency(&sm_inst.wires[iport.wire], self.use_latency); @@ -344,9 +353,7 @@ impl<'g> CodeGenerationContext<'g> { ConcreteType::Named(..) | ConcreteType::Array(..) => { unreachable!("No extern module type arguments. Should have been caught by Lint") } - ConcreteType::Value(value) => { - value.inline_constant_to_string() - } + ConcreteType::Value(value) => value.inline_constant_to_string(), ConcreteType::Unknown(_) => unreachable!("All args are known at codegen"), }; if first { @@ -370,7 +377,8 @@ impl<'g> CodeGenerationContext<'g> { let output_name = wire_name_self_latency(w, self.use_latency); let arrow_str = if is_state.is_some() { let clk_name = self.md.get_clock_name(); - writeln!(self.program_text, "always_ff @(posedge {clk_name}) begin").unwrap(); + writeln!(self.program_text, "always_ff @(posedge {clk_name}) begin") + .unwrap(); "<=" } else { writeln!(self.program_text, "always_comb begin\n\t// Combinatorial wires are not defined when not valid. This is just so that the synthesis tool doesn't generate latches").unwrap(); diff --git a/src/codegen/vhdl.rs b/src/codegen/vhdl.rs index 9996e8c..1cc63e5 100644 --- a/src/codegen/vhdl.rs +++ b/src/codegen/vhdl.rs @@ -1,9 +1,11 @@ - use crate::{ - flattening::{DeclarationKind, Instruction}, linker::IsExtern, typing::concrete_type::ConcreteType, FlatAlloc, InstantiatedModule, Linker, Module, WireIDMarker + flattening::{DeclarationKind, Instruction}, + linker::IsExtern, + typing::concrete_type::ConcreteType, + FlatAlloc, InstantiatedModule, Linker, Module, WireIDMarker, }; -use std::ops::Deref; use std::fmt::Write; +use std::ops::Deref; use super::shared::*; @@ -17,7 +19,13 @@ impl super::CodeGenBackend for VHDLCodegenBackend { fn output_dir_name(&self) -> &str { "vhdl_output" } - fn codegen(&self, md: &Module, instance: &InstantiatedModule, linker: &Linker, use_latency: bool) -> String { + fn codegen( + &self, + md: &Module, + instance: &InstantiatedModule, + linker: &Linker, + use_latency: bool, + ) -> String { gen_vhdl_code(md, instance, use_latency) } } diff --git a/src/compiler_top.rs b/src/compiler_top.rs index 340d3d5..9ebe939 100644 --- a/src/compiler_top.rs +++ b/src/compiler_top.rs @@ -15,72 +15,110 @@ use crate::{ }; use crate::flattening::{ - flatten_all_globals, gather_initial_file_data, perform_lints, typecheck_all_modules, Module + flatten_all_globals, gather_initial_file_data, perform_lints, typecheck_all_modules, Module, }; const STD_LIB_PATH: &str = env!("SUS_COMPILER_STD_LIB_PATH"); -/// Any extra operations that should happen when files are added or removed from the linker. Such as caching line offsets. +/// Any extra operations that should happen when files are added or removed from the linker. Such as caching line offsets. pub trait LinkerExtraFileInfoManager { /// This is there to give an acceptable identifier that can be printed - fn convert_filename(&self, path : &PathBuf) -> String { + fn convert_filename(&self, path: &PathBuf) -> String { path.to_string_lossy().into_owned() } - fn on_file_added(&mut self, _file_id : FileUUID, _linker : &Linker) {} - fn on_file_updated(&mut self, _file_id : FileUUID, _linker : &Linker) {} - fn before_file_remove(&mut self, _file_id : FileUUID, _linker : &Linker) {} + fn on_file_added(&mut self, _file_id: FileUUID, _linker: &Linker) {} + fn on_file_updated(&mut self, _file_id: FileUUID, _linker: &Linker) {} + fn before_file_remove(&mut self, _file_id: FileUUID, _linker: &Linker) {} } impl LinkerExtraFileInfoManager for () {} impl Linker { - pub fn add_standard_library(&mut self, info_mngr : &mut ExtraInfoManager) { + pub fn add_standard_library( + &mut self, + info_mngr: &mut ExtraInfoManager, + ) { assert!(self.modules.is_empty()); assert!(self.types.is_empty()); assert!(self.constants.is_empty()); if !config().ci { println!("Standard Library Directory: {STD_LIB_PATH}"); } - let std_path = PathBuf::from_str(STD_LIB_PATH).expect("Standard library directory is not a valid path?"); + let std_path = PathBuf::from_str(STD_LIB_PATH) + .expect("Standard library directory is not a valid path?"); self.add_all_files_in_directory(&std_path, info_mngr); - // Sanity check for the names the compiler knows internally. + // Sanity check for the names the compiler knows internally. // They are defined in std/core.sus // Critically, std/core.sus MUST be the first file to be loaded into the linker. Otherwise the IDs don't point to the correct objects assert_eq!(self.types[get_builtin_type!("int")].link_info.name, "int"); assert_eq!(self.types[get_builtin_type!("bool")].link_info.name, "bool"); - assert_eq!(self.constants[get_builtin_const!("true")].link_info.name, "true"); - assert_eq!(self.constants[get_builtin_const!("false")].link_info.name, "false"); - assert_eq!(self.constants[get_builtin_const!("__crash_compiler")].link_info.name, "__crash_compiler"); - assert_eq!(self.constants[get_builtin_const!("assert")].link_info.name, "assert"); - assert_eq!(self.constants[get_builtin_const!("sizeof")].link_info.name, "sizeof"); - assert_eq!(self.constants[get_builtin_const!("clog2")].link_info.name, "clog2"); + assert_eq!( + self.constants[get_builtin_const!("true")].link_info.name, + "true" + ); + assert_eq!( + self.constants[get_builtin_const!("false")].link_info.name, + "false" + ); + assert_eq!( + self.constants[get_builtin_const!("__crash_compiler")] + .link_info + .name, + "__crash_compiler" + ); + assert_eq!( + self.constants[get_builtin_const!("assert")].link_info.name, + "assert" + ); + assert_eq!( + self.constants[get_builtin_const!("sizeof")].link_info.name, + "sizeof" + ); + assert_eq!( + self.constants[get_builtin_const!("clog2")].link_info.name, + "clog2" + ); } - pub fn add_all_files_in_directory(&mut self, directory : &PathBuf, info_mngr : &mut ExtraInfoManager) { - let mut files = std::fs::read_dir(directory).unwrap() + pub fn add_all_files_in_directory( + &mut self, + directory: &PathBuf, + info_mngr: &mut ExtraInfoManager, + ) { + let mut files = std::fs::read_dir(directory) + .unwrap() .map(|res| res.map(|e| e.path())) - .collect::, std::io::Error>>().unwrap(); + .collect::, std::io::Error>>() + .unwrap(); files.sort(); for file in files { let file_path = file.canonicalize().unwrap(); if file_path.is_file() && file_path.extension() == Some(OsStr::new("sus")) { let file_text = std::fs::read_to_string(&file_path).unwrap(); - let file_identifier : String = info_mngr.convert_filename(&file_path); + let file_identifier: String = info_mngr.convert_filename(&file_path); self.add_file(file_identifier, file_text, info_mngr); } } } - pub fn add_file(&mut self, file_identifier: String, text: String, info_mngr : &mut ExtraInfoManager) -> FileUUID { + pub fn add_file( + &mut self, + file_identifier: String, + text: String, + info_mngr: &mut ExtraInfoManager, + ) -> FileUUID { // File doesn't yet exist - assert!(!self.files.iter().any(|fd| fd.1.file_identifier == file_identifier)); + assert!(!self + .files + .iter() + .any(|fd| fd.1.file_identifier == file_identifier)); let mut parser = Parser::new(); parser.set_language(&tree_sitter_sus::language()).unwrap(); let tree = parser.parse(&text, None).unwrap(); - + let file_id = self.files.reserve(); self.files.alloc_reservation( file_id, @@ -92,7 +130,7 @@ impl Linker { parsing_errors: ErrorStore::new(), }, ); - + self.with_file_builder(file_id, |builder| { let mut span_debugger = SpanDebugger::new("gather_initial_file_data in add_file", builder.file_data); @@ -107,21 +145,26 @@ impl Linker { // When --feature lsp is not used, this gives a warning #[allow(dead_code)] - pub fn add_or_update_file(&mut self, file_identifier: &str, text: String, info_mngr : &mut ExtraInfoManager) { + pub fn add_or_update_file( + &mut self, + file_identifier: &str, + text: String, + info_mngr: &mut ExtraInfoManager, + ) { if let Some(file_id) = self.find_file(file_identifier) { let file_data = self.remove_everything_in_file(file_id); - + let mut parser = Parser::new(); parser.set_language(&tree_sitter_sus::language()).unwrap(); let tree = parser.parse(&text, None).unwrap(); - + file_data.parsing_errors = ErrorStore::new(); file_data.file_text = FileText::new(text); file_data.tree = tree; - + self.with_file_builder(file_id, |builder| { let mut span_debugger = - SpanDebugger::new("gather_initial_file_data in update_file", builder.file_data); + SpanDebugger::new("gather_initial_file_data in update_file", builder.file_data); gather_initial_file_data(builder); span_debugger.defuse(); }); @@ -133,7 +176,8 @@ impl Linker { } pub fn find_file(&self, file_identifier: &str) -> Option { - self.files.find(|_id, f| f.file_identifier == file_identifier) + self.files + .find(|_id, f| f.file_identifier == file_identifier) } pub fn recompile_all(&mut self) { @@ -154,24 +198,32 @@ impl Linker { for (_, cst) in &mut self.constants { cst.link_info.reset_to(AFTER_INITIAL_PARSE_CP); } - if config().early_exit == EarlyExitUpTo::Initialize {return} + if config().early_exit == EarlyExitUpTo::Initialize { + return; + } flatten_all_globals(self); config().for_each_debug_module(config().debug_print_module_contents, &self.modules, |md| { md.print_flattened_module(&self.files[md.link_info.file]); }); - if config().early_exit == EarlyExitUpTo::Flatten {return} + if config().early_exit == EarlyExitUpTo::Flatten { + return; + } typecheck_all_modules(self); config().for_each_debug_module(config().debug_print_module_contents, &self.modules, |md| { md.print_flattened_module(&self.files[md.link_info.file]); }); - if config().early_exit == EarlyExitUpTo::AbstractTypecheck {return} + if config().early_exit == EarlyExitUpTo::AbstractTypecheck { + return; + } perform_lints(self); - - if config().early_exit == EarlyExitUpTo::Lint {return} + + if config().early_exit == EarlyExitUpTo::Lint { + return; + } // Make an initial instantiation of all modules // Won't be possible once we have template modules @@ -180,16 +232,16 @@ impl Linker { // Already instantiate any modules without parameters // Currently this is all modules let span_debug_message = format!("instantiating {}", &md.link_info.name); - let mut span_debugger = SpanDebugger::new( - &span_debug_message, - &self.files[md.link_info.file], - ); + let mut span_debugger = + SpanDebugger::new(&span_debug_message, &self.files[md.link_info.file]); // Can immediately instantiate modules that have no template args if md.link_info.template_parameters.is_empty() { let _inst = md.instantiations.instantiate(md, self, FlatAlloc::new()); } span_debugger.defuse(); } - if config().early_exit == EarlyExitUpTo::Instantiate {return} + if config().early_exit == EarlyExitUpTo::Instantiate { + return; + } } } diff --git a/src/debug.rs b/src/debug.rs index 142e5de..b81e438 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,6 +1,9 @@ use std::{cell::RefCell, ops::Range}; -use crate::{alloc::ArenaAllocator, config::ConfigStruct, flattening::Module, linker::FileData, pretty_print_spans_in_reverse_order, ModuleUUIDMarker}; +use crate::{ + alloc::ArenaAllocator, config::ConfigStruct, flattening::Module, linker::FileData, + pretty_print_spans_in_reverse_order, ModuleUUIDMarker, +}; /// Many duplicates will be produced, and filtering them out in the code itself is inefficient. Therefore just keep a big buffer and deduplicate as needed const SPAN_TOUCH_HISTORY_SIZE: usize = 256; @@ -117,11 +120,14 @@ impl<'text> Drop for SpanDebugger<'text> { } } - - impl ConfigStruct { - /// The reason we pass an explicit bool here is because it merges the "if config().debug_xyz" with the for loop. - pub fn for_each_debug_module(&self, should_debug: bool, modules: &ArenaAllocator, mut f : F) { + /// The reason we pass an explicit bool here is because it merges the "if config().debug_xyz" with the for loop. + pub fn for_each_debug_module( + &self, + should_debug: bool, + modules: &ArenaAllocator, + mut f: F, + ) { if should_debug { for (_, md) in modules { let passes_whitelist = if let Some(wl) = &self.debug_whitelist { diff --git a/src/dev_aid/ariadne_interface.rs b/src/dev_aid/ariadne_interface.rs index 5f275b2..8a5c3c8 100644 --- a/src/dev_aid/ariadne_interface.rs +++ b/src/dev_aid/ariadne_interface.rs @@ -12,7 +12,6 @@ use crate::{ use ariadne::*; - impl Cache for (&Linker, &mut ArenaVector, FileUUIDMarker>) { type Storage = String; @@ -21,18 +20,21 @@ impl Cache for (&Linker, &mut ArenaVector, FileUUIDMark } fn display<'a>(&self, id: &'a FileUUID) -> Option> { if config().ci { - let filename = self.0.files[*id].file_identifier.rsplit("/").next().unwrap_or(self.0.files[*id].file_identifier.as_str()); + let filename = self.0.files[*id] + .file_identifier + .rsplit("/") + .next() + .unwrap_or(self.0.files[*id].file_identifier.as_str()); Some(Box::new(filename.to_string())) } else { Some(Box::new(self.0.files[*id].file_identifier.clone())) } - } } struct NamedSource<'s> { - source : Source, - name : &'s str + source: Source, + name: &'s str, } impl Cache<()> for NamedSource<'_> { @@ -47,37 +49,35 @@ impl Cache<()> for NamedSource<'_> { } pub struct FileSourcesManager { - pub file_sources: ArenaVector + pub file_sources: ArenaVector, } impl LinkerExtraFileInfoManager for FileSourcesManager { - fn convert_filename(&self, path : &PathBuf) -> String { + fn convert_filename(&self, path: &PathBuf) -> String { path.to_string_lossy().into_owned() } - fn on_file_added(&mut self, file_id : FileUUID, linker : &Linker) { + fn on_file_added(&mut self, file_id: FileUUID, linker: &Linker) { let source = Source::from(linker.files[file_id].file_text.file_text.clone()); self.file_sources.insert(file_id, source); } - fn on_file_updated(&mut self, file_id : FileUUID, linker : &Linker) { + fn on_file_updated(&mut self, file_id: FileUUID, linker: &Linker) { let source = Source::from(linker.files[file_id].file_text.file_text.clone()); - + self.file_sources[file_id] = source; } - fn before_file_remove(&mut self, file_id : FileUUID, _linker : &Linker) { + fn before_file_remove(&mut self, file_id: FileUUID, _linker: &Linker) { self.file_sources.remove(file_id) } } -pub fn compile_all( - file_paths: Vec, -) -> (Linker, FileSourcesManager) { +pub fn compile_all(file_paths: Vec) -> (Linker, FileSourcesManager) { let mut linker = Linker::new(); - let mut file_source_manager = FileSourcesManager{ - file_sources: ArenaVector::new() + let mut file_source_manager = FileSourcesManager { + file_sources: ArenaVector::new(), }; linker.add_standard_library(&mut file_source_manager); @@ -90,7 +90,11 @@ pub fn compile_all( } }; - linker.add_file(file_path.to_string_lossy().into_owned(), file_text, &mut file_source_manager); + linker.add_file( + file_path.to_string_lossy().into_owned(), + file_text, + &mut file_source_manager, + ); } linker.recompile_all(); @@ -157,13 +161,13 @@ pub fn print_all_errors( } } -pub fn pretty_print_spans_in_reverse_order(file_data : &FileData, spans: Vec>) { +pub fn pretty_print_spans_in_reverse_order(file_data: &FileData, spans: Vec>) { let text_len = file_data.file_text.len(); - let mut source = NamedSource{ - source : Source::from(file_data.file_text.file_text.clone()), - name : &file_data.file_identifier + let mut source = NamedSource { + source: Source::from(file_data.file_text.file_text.clone()), + name: &file_data.file_identifier, }; - + for span in spans.into_iter().rev() { // If span not in file, just don't print it. This happens. if span.end > text_len { @@ -190,9 +194,9 @@ pub fn pretty_print_spans_in_reverse_order(file_data : &FileData, spans: Vec)]) { let text_len = file_data.file_text.len(); - let mut source = NamedSource{ - source : Source::from(file_data.file_text.file_text.clone()), - name : &file_data.file_identifier + let mut source = NamedSource { + source: Source::from(file_data.file_text.file_text.clone()), + name: &file_data.file_identifier, }; let config = ariadne_config(); diff --git a/src/dev_aid/lsp/hover_info.rs b/src/dev_aid/lsp/hover_info.rs index b538d5d..2debf13 100644 --- a/src/dev_aid/lsp/hover_info.rs +++ b/src/dev_aid/lsp/hover_info.rs @@ -8,7 +8,7 @@ use lsp_types::{LanguageString, MarkedString}; use crate::flattening::{DeclarationKind, IdentifierType, InterfaceToDomainMap, Module}; use crate::instantiation::{SubModuleOrWire, CALCULATE_LATENCY_LATER}; -use crate::linker::{Documentation, FileData, LinkInfo, GlobalUUID}; +use crate::linker::{Documentation, FileData, GlobalUUID, LinkInfo}; use crate::typing::{ abstract_type::DomainType, @@ -84,13 +84,20 @@ impl<'l> HoverCollector<'l> { if sm.original_instruction != id { continue; } - self.sus_code(pretty_print_concrete_instance(&submodule.link_info, &sm.template_args, &self.linker.types)); + self.sus_code(pretty_print_concrete_instance( + &submodule.link_info, + &sm.template_args, + &self.linker.types, + )); } }); } } -fn try_get_module(linker_modules: &ArenaAllocator, id: GlobalUUID) -> Option<&Module> { +fn try_get_module( + linker_modules: &ArenaAllocator, + id: GlobalUUID, +) -> Option<&Module> { if let GlobalUUID::Module(md_id) = id { Some(&linker_modules[md_id]) } else { @@ -122,7 +129,7 @@ pub fn hover(info: LocationInfo, linker: &Linker, file_data: &FileData) -> Vec details_vec.push(if is_input { "input" } else { "output" }.to_owned()), - DeclarationKind::NotPort | DeclarationKind::StructField { field_id:_ } => {} + DeclarationKind::NotPort | DeclarationKind::StructField { field_id: _ } => {} DeclarationKind::GenerativeInput(_) => details_vec.push("param".to_owned()), } @@ -135,7 +142,8 @@ pub fn hover(info: LocationInfo, linker: &Linker, file_data: &FileData) -> Vec Vec Vec unreachable!("Variables should have been eliminated already") + DomainType::Unknown(_) => { + unreachable!("Variables should have been eliminated already") + } }; details_vec.push(Cow::Owned( wire.typ .typ - .display(&linker.types, &link_info.template_parameters).to_string(), + .display(&linker.types, &link_info.template_parameters) + .to_string(), )); hover.sus_code(details_vec.join(" ")); hover.gather_hover_infos(obj_id, id, wire.typ.domain.is_generative()); } LocationInfo::Type(typ, link_info) => { hover.sus_code( - typ.display(&linker.types, &link_info.template_parameters).to_string(), + typ.display(&linker.types, &link_info.template_parameters) + .to_string(), ); } LocationInfo::Parameter(obj_id, link_info, _template_id, template_arg) => { match &template_arg.kind { - ParameterKind::Type(TypeParameterKind { }) => { + ParameterKind::Type(TypeParameterKind {}) => { hover.monospace(format!("type {}", template_arg.name)); } ParameterKind::Generative(GenerativeParameterKind { decl_span: _, declaration_instruction, }) => { - let decl = link_info.instructions[*declaration_instruction].unwrap_declaration(); + let decl = + link_info.instructions[*declaration_instruction].unwrap_declaration(); hover.sus_code(format!( "param {} {}", decl.typ_expr @@ -226,7 +241,10 @@ pub fn hover(info: LocationInfo, linker: &Linker, file_data: &FileData) -> Vec { let md = &linker.modules[md_uuid]; diff --git a/src/dev_aid/lsp/mod.rs b/src/dev_aid/lsp/mod.rs index a1587c4..6c33a89 100644 --- a/src/dev_aid/lsp/mod.rs +++ b/src/dev_aid/lsp/mod.rs @@ -66,7 +66,7 @@ fn cvt_location_list_of_lists( for span in vec { let range = span_to_lsp_range(&file.file_text, span); result.push(Location { - uri : uri.clone(), + uri: uri.clone(), range, }) } @@ -78,17 +78,17 @@ impl Linker { fn find_uri(&self, uri: &Url) -> Option { self.find_file(uri.as_str()) } - fn update_text(&mut self, uri: &Url, new_file_text: String, manager : &mut LSPFileManager) { + fn update_text(&mut self, uri: &Url, new_file_text: String, manager: &mut LSPFileManager) { self.add_or_update_file(uri.as_str(), new_file_text, manager); self.recompile_all(); } - fn ensure_contains_file(&mut self, uri: &Url, manager : &mut LSPFileManager) -> FileUUID { + fn ensure_contains_file(&mut self, uri: &Url, manager: &mut LSPFileManager) -> FileUUID { if let Some(found) = self.find_uri(uri) { found } else { let file_text = std::fs::read_to_string(uri.to_file_path().unwrap()).unwrap(); - + let file_uuid = self.add_file(uri.to_string(), file_text, manager); self.recompile_all(); file_uuid @@ -97,7 +97,7 @@ impl Linker { fn location_in_file( &mut self, text_pos: &lsp_types::TextDocumentPositionParams, - manager : &mut LSPFileManager, + manager: &mut LSPFileManager, ) -> (FileUUID, usize) { let file_id = self.ensure_contains_file(&text_pos.text_document.uri, manager); let file_data = &self.files[file_id]; @@ -114,7 +114,7 @@ impl Linker { fn convert_diagnostic( err: &CompileError, main_file_text: &FileText, - linker: &Linker + linker: &Linker, ) -> Diagnostic { assert!( main_file_text.is_span_valid(err.position), @@ -168,11 +168,7 @@ fn push_all_errors( let mut diag_vec: Vec = Vec::new(); linker.for_all_errors_in_file(file_id, |err| { - diag_vec.push(convert_diagnostic( - err, - &file_data.file_text, - &linker - )); + diag_vec.push(convert_diagnostic(err, &file_data.file_text, &linker)); }); let params = &PublishDiagnosticsParams { @@ -195,20 +191,22 @@ fn push_all_errors( struct LSPFileManager {} impl LinkerExtraFileInfoManager for LSPFileManager { - fn convert_filename(&self, path : &PathBuf) -> String { + fn convert_filename(&self, path: &PathBuf) -> String { Url::from_file_path(path).unwrap().into() } } fn initialize_all_files(init_params: &InitializeParams) -> (Linker, LSPFileManager) { let mut linker = Linker::new(); - let mut manager = LSPFileManager{}; + let mut manager = LSPFileManager {}; linker.add_standard_library(&mut manager); if let Some(workspace_folder) = &init_params.workspace_folders { for folder in workspace_folder { - let Ok(path) = folder.uri.to_file_path() else {continue}; + let Ok(path) = folder.uri.to_file_path() else { + continue; + }; linker.add_all_files_in_directory(&path, &mut manager); } @@ -338,7 +336,7 @@ fn handle_request( method: &str, params: serde_json::Value, linker: &mut Linker, - manager : &mut LSPFileManager, + manager: &mut LSPFileManager, ) -> Result { match method { request::HoverRequest::METHOD => { @@ -351,8 +349,7 @@ fn handle_request( let file_data = &linker.files[file_uuid]; let mut hover_list: Vec = Vec::new(); - let range = if let Some((location, info)) = - get_selected_object(linker, file_uuid, pos) + let range = if let Some((location, info)) = get_selected_object(linker, file_uuid, pos) { if config().lsp_debug_mode { hover_list.push(MarkedString::String(format!("{info:?}"))) @@ -378,10 +375,14 @@ fn handle_request( let mut goto_definition_list: Vec = Vec::new(); - if let Some((_location, info)) = get_selected_object(linker, file_uuid, pos) - { + if let Some((_location, info)) = get_selected_object(linker, file_uuid, pos) { match info { - LocationInfo::InGlobal(_obj_id, link_info, _decl_id, InGlobal::NamedLocal(decl)) => { + LocationInfo::InGlobal( + _obj_id, + link_info, + _decl_id, + InGlobal::NamedLocal(decl), + ) => { goto_definition_list.push((decl.name_span, link_info.file)); } LocationInfo::InGlobal( @@ -422,8 +423,7 @@ fn handle_request( let uuid = linker.ensure_contains_file(¶ms.text_document.uri, manager); serde_json::to_value(SemanticTokensResult::Tokens(make_semantic_tokens( - uuid, - linker, + uuid, linker, ))) } request::DocumentHighlightRequest::METHOD => { @@ -431,7 +431,8 @@ fn handle_request( serde_json::from_value(params).expect("JSON Encoding Error while parsing params"); println!("DocumentHighlight"); - let (file_id, pos) = linker.location_in_file(¶ms.text_document_position_params, manager); + let (file_id, pos) = + linker.location_in_file(¶ms.text_document_position_params, manager); let file_data = &linker.files[file_id]; let ref_locations = gather_all_references_in_one_file(linker, file_id, pos); @@ -452,8 +453,7 @@ fn handle_request( let (file_id, pos) = linker.location_in_file(¶ms.text_document_position, manager); - let ref_locations = - gather_all_references_across_all_files(linker, file_id, pos); + let ref_locations = gather_all_references_across_all_files(linker, file_id, pos); serde_json::to_value(cvt_location_list_of_lists(ref_locations, linker)) } @@ -464,8 +464,7 @@ fn handle_request( let (file_id, pos) = linker.location_in_file(¶ms.text_document_position, manager); - let ref_locations_lists = - gather_all_references_across_all_files(linker, file_id, pos); + let ref_locations_lists = gather_all_references_across_all_files(linker, file_id, pos); let changes: HashMap<_, _> = ref_locations_lists .into_iter() @@ -497,12 +496,11 @@ fn handle_request( serde_json::from_value(params).expect("JSON Encoding Error while parsing params"); println!("Completion"); - let (file_uuid, position) = linker.location_in_file(¶ms.text_document_position, manager); + let (file_uuid, position) = + linker.location_in_file(¶ms.text_document_position, manager); serde_json::to_value(&CompletionResponse::Array(gather_completions( - linker, - file_uuid, - position, + linker, file_uuid, position, ))) } req => { @@ -568,7 +566,8 @@ fn main_loop( return Ok(()); } - let response_value = handle_request(&req.method, req.params, &mut linker, &mut manager); + let response_value = + handle_request(&req.method, req.params, &mut linker, &mut manager); let result = response_value.unwrap(); let response = lsp_server::Response { diff --git a/src/dev_aid/lsp/tree_walk.rs b/src/dev_aid/lsp/tree_walk.rs index 59d1b17..a372908 100644 --- a/src/dev_aid/lsp/tree_walk.rs +++ b/src/dev_aid/lsp/tree_walk.rs @@ -3,11 +3,11 @@ use std::ops::Deref; use crate::flattening::*; use crate::prelude::*; -use crate::linker::{FileData, LinkInfo, GlobalUUID}; +use crate::linker::{FileData, GlobalUUID, LinkInfo}; use crate::typing::template::{ - GenerativeParameterKind, GlobalReference, TemplateArgKind, Parameter, - ParameterKind, TypeParameterKind, + GenerativeParameterKind, GlobalReference, Parameter, ParameterKind, TemplateArgKind, + TypeParameterKind, }; /// See [LocationInfo] @@ -18,7 +18,7 @@ pub enum InGlobal<'linker> { Temporary(&'linker Expression), } -/// Information about an object in the source code. Used for hovering, completions, syntax highlighting etc. +/// Information about an object in the source code. Used for hovering, completions, syntax highlighting etc. #[derive(Clone, Copy, Debug)] pub enum LocationInfo<'linker> { InGlobal(GlobalUUID, &'linker LinkInfo, FlatID, InGlobal<'linker>), @@ -61,7 +61,7 @@ impl<'linker> From> for RefersTo { let decl = link_info.instructions[flat_id].unwrap_declaration(); match decl.decl_kind { DeclarationKind::NotPort => {} - DeclarationKind::StructField { field_id:_ } => {} + DeclarationKind::StructField { field_id: _ } => {} DeclarationKind::RegularPort { is_input: _, port_id, @@ -96,7 +96,10 @@ impl<'linker> From> for RefersTo { result.global = Some(name_elem); } LocationInfo::Port(sm, md, p_id) => { - result.local = Some((GlobalUUID::Module(sm.module_ref.id), md.ports[p_id].declaration_instruction)); + result.local = Some(( + GlobalUUID::Module(sm.module_ref.id), + md.ports[p_id].declaration_instruction, + )); result.port = Some((sm.module_ref.id, p_id)) } LocationInfo::Interface(md_id, _md, i_id, _interface) => { @@ -257,7 +260,8 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b } WireReferenceRoot::SubModulePort(port) => { if let Some(span) = port.port_name_span { - let sm_instruction = link_info.instructions[port.submodule_decl].unwrap_submodule(); + let sm_instruction = + link_info.instructions[port.submodule_decl].unwrap_submodule(); let submodule = &self.linker.modules[sm_instruction.module_ref.id]; self.visit( span, @@ -351,24 +355,18 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b } } - fn walk_name_and_template_arguments(&mut self, name_elem : GlobalUUID, link_info: &'linker LinkInfo) { - self.visit( - link_info.name_span, - LocationInfo::Global(name_elem), - ); + fn walk_name_and_template_arguments( + &mut self, + name_elem: GlobalUUID, + link_info: &'linker LinkInfo, + ) { + self.visit(link_info.name_span, LocationInfo::Global(name_elem)); for (template_id, template_arg) in &link_info.template_parameters { - if let ParameterKind::Type(TypeParameterKind {}) = - &template_arg.kind - { + if let ParameterKind::Type(TypeParameterKind {}) = &template_arg.kind { self.visit( template_arg.name_span, - LocationInfo::Parameter( - name_elem, - &link_info, - template_id, - template_arg, - ), + LocationInfo::Parameter(name_elem, &link_info, template_id, template_arg), ); } } @@ -382,15 +380,16 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b for (id, inst) in &link_info.instructions { match inst { Instruction::SubModule(sm) => { - self.walk_global_reference( - obj_id, - &link_info, - &sm.module_ref, - ); + self.walk_global_reference(obj_id, &link_info, &sm.module_ref); if let Some((_sm_name, sm_name_span)) = &sm.name { self.visit( *sm_name_span, - LocationInfo::InGlobal(obj_id, link_info, id, InGlobal::NamedSubmodule(sm)), + LocationInfo::InGlobal( + obj_id, + link_info, + id, + InGlobal::NamedSubmodule(sm), + ), ); } } @@ -399,7 +398,12 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b if decl.declaration_itself_is_not_written_to { self.visit( decl.name_span, - LocationInfo::InGlobal(obj_id, link_info, id, InGlobal::NamedLocal(decl)), + LocationInfo::InGlobal( + obj_id, + link_info, + id, + InGlobal::NamedLocal(decl), + ), ); } } @@ -409,7 +413,12 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b } else { self.visit( wire.span, - LocationInfo::InGlobal(obj_id, link_info, id, InGlobal::Temporary(wire)), + LocationInfo::InGlobal( + obj_id, + link_info, + id, + InGlobal::Temporary(wire), + ), ); }; } @@ -435,7 +444,7 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b interface.name_span, LocationInfo::Interface(md_id, md, interface_id, interface), ); - } + } } GlobalUUID::Type(_typ_id) => {} // These cases are covered by walk_link_info GlobalUUID::Constant(_cst_id) => {} // These cases are covered by walk_link_info diff --git a/src/errors.rs b/src/errors.rs index 61fb3e3..44d7503 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -5,7 +5,9 @@ use std::thread::panicking; use crate::{alloc::ArenaAllocator, typing::template::Parameter}; -use crate::flattening::{Declaration, DomainInfo, Instruction, Interface, Module, Port, SubModuleInstance}; +use crate::flattening::{ + Declaration, DomainInfo, Instruction, Interface, Module, Port, SubModuleInstance, +}; use crate::linker::{checkpoint::ErrorCheckpoint, FileData, LinkInfo}; #[derive(Debug, Clone, PartialEq, Eq)] @@ -15,7 +17,7 @@ pub enum ErrorLevel { } /// Represents a comment about a location in the source code. -/// +/// /// Multiple infos can be attached to a single [CompileError] #[derive(Debug, Clone)] pub struct ErrorInfo { @@ -25,7 +27,7 @@ pub struct ErrorInfo { } /// Represents an error or warning that the compiler produced. They can be shown in the IDE, or on the CLI -/// +/// /// All errors for a single file are stored together, which is why this struct does not contain a FileUUID #[derive(Debug, Clone)] pub struct CompileError { @@ -113,7 +115,11 @@ impl<'linker> ErrorCollector<'linker> { self.error_store.replace(ErrorStore::new()) } /// Turn an [ErrorStore] into [ErrorCollector] - pub fn from_storage(error_store: ErrorStore, file: FileUUID, files: &'linker ArenaAllocator) -> Self { + pub fn from_storage( + error_store: ErrorStore, + file: FileUUID, + files: &'linker ArenaAllocator, + ) -> Self { Self { error_store: RefCell::new(error_store), file, @@ -122,7 +128,10 @@ impl<'linker> ErrorCollector<'linker> { } } /// To re-attach this [ErrorCollector] to a new [Linker]. Mostly to get around the borrow checker - pub fn re_attach<'new_linker>(self, files: &'new_linker ArenaAllocator) -> ErrorCollector<'new_linker> { + pub fn re_attach<'new_linker>( + self, + files: &'new_linker ArenaAllocator, + ) -> ErrorCollector<'new_linker> { ErrorCollector { error_store: RefCell::new(self.error_store.replace(ErrorStore::new())), file: self.file, @@ -191,10 +200,10 @@ impl<'l> Drop for ErrorCollector<'l> { } } -/// Intermediary struct to make adding infos far easier. -/// +/// Intermediary struct to make adding infos far easier. +/// /// Use as: -/// +/// /// errors.warn(span, "Unused Variable").info(span2, file2, "In module").info(blablabla) pub struct ErrorReference<'ec> { err_collector: &'ec ErrorCollector<'ec>, @@ -242,7 +251,9 @@ impl<'ec> ErrorReference<'ec> { self } pub fn add_info_list(&self, mut info_list: Vec) { - self.err_collector.error_store.borrow_mut().errors[self.pos].infos.append(&mut info_list); + self.err_collector.error_store.borrow_mut().errors[self.pos] + .infos + .append(&mut info_list); } pub fn suggest_replace>(&self, replace_span: Span, replace_with: S) -> &Self { self.info_same_file( @@ -262,10 +273,7 @@ pub trait ErrorInfoObject { /// This represents objects that can be given as info to an error in a straight-forward way. pub trait FileKnowingErrorInfoObject { - fn make_global_info( - &self, - files: &ArenaAllocator, - ) -> ErrorInfo; + fn make_global_info(&self, files: &ArenaAllocator) -> ErrorInfo; } // Trait implementations in the compiler @@ -336,10 +344,7 @@ impl ErrorInfoObject for Port { } impl FileKnowingErrorInfoObject for LinkInfo { - fn make_global_info( - &self, - _files: &ArenaAllocator, - ) -> ErrorInfo { + fn make_global_info(&self, _files: &ArenaAllocator) -> ErrorInfo { ErrorInfo { position: self.name_span, file: self.file, @@ -350,10 +355,7 @@ impl FileKnowingErrorInfoObject for LinkInfo { /// For interfaces of this module impl FileKnowingErrorInfoObject for (&'_ Module, &'_ Interface) { - fn make_global_info( - &self, - _files: &ArenaAllocator, - ) -> ErrorInfo { + fn make_global_info(&self, _files: &ArenaAllocator) -> ErrorInfo { let (md, interface) = *self; ErrorInfo { position: interface.name_span, @@ -364,11 +366,9 @@ impl FileKnowingErrorInfoObject for (&'_ Module, &'_ Interface) { } impl FileKnowingErrorInfoObject for Module { - fn make_global_info( - &self, - files: &ArenaAllocator, - ) -> ErrorInfo { - let ports_str = self.make_all_ports_info_string(&files[self.link_info.file].file_text, None); + fn make_global_info(&self, files: &ArenaAllocator) -> ErrorInfo { + let ports_str = + self.make_all_ports_info_string(&files[self.link_info.file].file_text, None); ErrorInfo { position: self.link_info.name_span, diff --git a/src/file_position.rs b/src/file_position.rs index fd94e17..528dceb 100644 --- a/src/file_position.rs +++ b/src/file_position.rs @@ -76,8 +76,8 @@ impl Display for Span { } } -/// A span for something that is between brackets. The assumption is that the brackets are 1 byte each. -/// +/// A span for something that is between brackets. The assumption is that the brackets are 1 byte each. +/// /// This struct is provided to improve readability on using these spans #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct BracketSpan(Span); diff --git a/src/flattening/flatten.rs b/src/flattening/flatten.rs index 1625fbc..b7b6822 100644 --- a/src/flattening/flatten.rs +++ b/src/flattening/flatten.rs @@ -13,7 +13,7 @@ use super::parser::Cursor; use super::*; use crate::typing::template::{ - GenerativeParameterKind, ParameterKind, TVec, TemplateArg, TemplateArgKind + GenerativeParameterKind, ParameterKind, TVec, TemplateArg, TemplateArgKind, }; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -21,7 +21,7 @@ enum NamedLocal { Declaration(FlatID), SubModule(FlatID), TemplateType(TemplateID), - DomainDecl(DomainID) + DomainDecl(DomainID), } enum LocalOrGlobal { @@ -193,23 +193,23 @@ impl core::fmt::Display for BinaryOperator { #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum GenerativeKind { PlainGenerative, - ForLoopGenerative + ForLoopGenerative, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum DeclarationContext { - IO{is_input : bool}, + IO { is_input: bool }, Generative(GenerativeKind), TemplateGenerative(TemplateID), PlainWire, - StructField + StructField, } #[derive(Debug, Clone, Copy)] enum DomainAllocOption { Generative, NonGenerativeUnknown, - NonGenerativeKnown(DomainID) + NonGenerativeKnown(DomainID), } #[derive(Debug)] @@ -224,9 +224,11 @@ impl TypingAllocator { typ: AbstractType::Unknown(self.type_variable_alloc.alloc()), domain: match domain { DomainAllocOption::Generative => DomainType::Generative, - DomainAllocOption::NonGenerativeUnknown => DomainType::Unknown(self.domain_variable_alloc.alloc()), + DomainAllocOption::NonGenerativeUnknown => { + DomainType::Unknown(self.domain_variable_alloc.alloc()) + } DomainAllocOption::NonGenerativeKnown(domain_id) => DomainType::Physical(domain_id), - } + }, } } } @@ -246,12 +248,16 @@ struct FlatteningContext<'l, 'errs> { local_variable_context: LocalVariableContext<'l, NamedLocal>, - default_declaration_context: DeclarationContext + default_declaration_context: DeclarationContext, } impl<'l, 'errs> FlatteningContext<'l, 'errs> { fn flatten_parameters(&mut self, cursor: &mut Cursor) { - let mut parameters_to_visit = self.working_on_link_info.template_parameters.id_range().into_iter(); + let mut parameters_to_visit = self + .working_on_link_info + .template_parameters + .id_range() + .into_iter(); if cursor.optional_field(field!("template_declaration_arguments")) { cursor.list(kind!("template_declaration_arguments"), |cursor| { let claimed_type_id = parameters_to_visit.next().unwrap(); @@ -259,17 +265,23 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { kind!("template_declaration_type") => cursor.go_down_no_check(|cursor| { // Already covered in initialization cursor.field(field!("name")); - - let selected_arg = &self.working_on_link_info.template_parameters[claimed_type_id]; - + + let selected_arg = + &self.working_on_link_info.template_parameters[claimed_type_id]; + let name_span = selected_arg.name_span; - + self.alloc_local_name(name_span, NamedLocal::TemplateType(claimed_type_id)); }), kind!("declaration") => { - let _ = self.flatten_declaration::(DeclarationContext::TemplateGenerative(claimed_type_id), true, true, cursor); + let _ = self.flatten_declaration::( + DeclarationContext::TemplateGenerative(claimed_type_id), + true, + true, + cursor, + ); } - _other => cursor.could_not_match() + _other => cursor.could_not_match(), } }) } @@ -278,17 +290,26 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { fn must_be_generative(&self, is_generative: bool, context: &str, span: Span) { if !is_generative { - self.errors.error(span, format!("{context} must be a compile-time expression")); + self.errors + .error(span, format!("{context} must be a compile-time expression")); } } - fn flatten_template_args(&mut self, found_global: GlobalUUID, has_template_args: bool, cursor: &mut Cursor) -> TVec> { + fn flatten_template_args( + &mut self, + found_global: GlobalUUID, + has_template_args: bool, + cursor: &mut Cursor, + ) -> TVec> { let link_info = self.globals.get_link_info(found_global); let full_object_name = link_info.get_full_name(); - let mut template_arg_map : FlatAlloc, TemplateIDMarker> = link_info.template_parameters.map(|_| None); - - if !has_template_args {return template_arg_map;} + let mut template_arg_map: FlatAlloc, TemplateIDMarker> = + link_info.template_parameters.map(|_| None); + + if !has_template_args { + return template_arg_map; + } cursor.list(kind!("template_args"), |cursor| { cursor.go_down(kind!("template_arg"), |cursor| { @@ -318,10 +339,10 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { (match self.local_variable_context.get_declaration_for(name) { Some(NamedLocal::TemplateType(t)) => TemplateArgKind::Type(WrittenType::TemplateVariable(name_span, t)), Some(NamedLocal::Declaration(decl_id)) => { - let wire_read_id = self.instructions.alloc(Instruction::Expression(Expression { + let wire_read_id = self.instructions.alloc(Instruction::Expression(Expression { typ: self.type_alloc.alloc_unset_type(DomainAllocOption::Generative), span: name_span, - source: ExpressionSource::WireRef(WireReference::simple_var_read(decl_id, true, name_span)) + source: ExpressionSource::WireRef(WireReference::simple_var_read(decl_id, true, name_span)) })); TemplateArgKind::Value(wire_read_id) } @@ -344,7 +365,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { if let Some((id, parameter)) = name_found { match (¶meter.kind, &template_arg) { - (ParameterKind::Type(_), TemplateArgKind::Type(_)) + (ParameterKind::Type(_), TemplateArgKind::Type(_)) | (ParameterKind::Generative(_), TemplateArgKind::Value(_)) => { // Correct pairing let elem = &mut template_arg_map[id]; @@ -412,11 +433,14 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { }; if let Some(global_id) = self.globals.resolve_global(name_span) { // MUST Still be at field!("template_args") - let template_span = template_args_used.then(|| BracketSpan::from_outer(cursor.span())); + let template_span = + template_args_used.then(|| BracketSpan::from_outer(cursor.span())); - let template_args = self.flatten_template_args(global_id, template_args_used, cursor); + let template_args = + self.flatten_template_args(global_id, template_args_used, cursor); - let template_arg_types = template_args.map(|_| AbstractType::Unknown(self.type_alloc.type_variable_alloc.alloc())); + let template_arg_types = template_args + .map(|_| AbstractType::Unknown(self.type_alloc.type_variable_alloc.alloc())); match global_id { GlobalUUID::Module(id) => LocalOrGlobal::Module(GlobalReference { @@ -453,7 +477,8 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { let array_element_type = self.flatten_type(cursor); cursor.field(field!("arr_idx")); - let (array_size_wire_id, is_generative, bracket_span) = self.flatten_array_bracket(cursor); + let (array_size_wire_id, is_generative, bracket_span) = + self.flatten_array_bracket(cursor); self.must_be_generative(is_generative, "Array Size", span); WrittenType::Array( @@ -501,25 +526,32 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { self.errors .error( span, - format!( - "This is not a {accepted_text}, it is a domain instead!" - ), + format!("This is not a {accepted_text}, it is a domain instead!"), ) .info_obj_same_file(&self.domains[domain_id]); ModuleOrWrittenType::WrittenType(WrittenType::Error(span)) } LocalOrGlobal::Local(span, NamedLocal::TemplateType(template_id)) => { - ModuleOrWrittenType::WrittenType(WrittenType::TemplateVariable(span, template_id)) + ModuleOrWrittenType::WrittenType(WrittenType::TemplateVariable( + span, + template_id, + )) + } + LocalOrGlobal::Type(type_ref) => { + ModuleOrWrittenType::WrittenType(WrittenType::Named(type_ref)) + } + LocalOrGlobal::Module(module_ref) if ALLOW_MODULES => { + ModuleOrWrittenType::Module(module_ref) } - LocalOrGlobal::Type(type_ref) => ModuleOrWrittenType::WrittenType(WrittenType::Named(type_ref)), - LocalOrGlobal::Module(module_ref) if ALLOW_MODULES => ModuleOrWrittenType::Module(module_ref), LocalOrGlobal::Module(module_ref) => { - self.globals.not_expected_global_error(&module_ref, accepted_text); + self.globals + .not_expected_global_error(&module_ref, accepted_text); ModuleOrWrittenType::WrittenType(WrittenType::Error(module_ref.name_span)) } LocalOrGlobal::Constant(constant_ref) => { - self.globals.not_expected_global_error(&constant_ref, accepted_text); + self.globals + .not_expected_global_error(&constant_ref, accepted_text); ModuleOrWrittenType::WrittenType(WrittenType::Error(constant_ref.name_span)) } LocalOrGlobal::NotFound(name_span) => { @@ -545,14 +577,10 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { match conflict { NamedLocal::Declaration(decl_id) => { - err_ref.info_obj_same_file( - self.instructions[decl_id].unwrap_declaration(), - ); + err_ref.info_obj_same_file(self.instructions[decl_id].unwrap_declaration()); } NamedLocal::SubModule(submod_id) => { - err_ref.info_obj_same_file( - self.instructions[submod_id].unwrap_submodule(), - ); + err_ref.info_obj_same_file(self.instructions[submod_id].unwrap_submodule()); } NamedLocal::TemplateType(template_id) => { err_ref.info_obj_same_file( @@ -560,26 +588,30 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { ); } NamedLocal::DomainDecl(domain_id) => { - err_ref.info_obj_same_file( - &self.domains[domain_id], - ); + err_ref.info_obj_same_file(&self.domains[domain_id]); } } } } - fn alloc_submodule_instruction(&mut self, module_ref: GlobalReference, name: Option<(String, Span)>, documentation: Documentation) -> FlatID { + fn alloc_submodule_instruction( + &mut self, + module_ref: GlobalReference, + name: Option<(String, Span)>, + documentation: Documentation, + ) -> FlatID { let md = &self.globals[module_ref.id]; let local_interface_domains = md .domains .map(|_| DomainType::Unknown(self.type_alloc.domain_variable_alloc.alloc())); - self.instructions.alloc(Instruction::SubModule(SubModuleInstance{ - name, - module_ref, - local_interface_domains, - documentation - })) + self.instructions + .alloc(Instruction::SubModule(SubModuleInstance { + name, + module_ref, + local_interface_domains, + documentation, + })) } fn flatten_declaration( @@ -746,7 +778,10 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { }) } - fn flatten_array_bracket(&mut self, cursor: &mut Cursor) -> (FlatID, bool/*Is generative */, BracketSpan) { + fn flatten_array_bracket( + &mut self, + cursor: &mut Cursor, + ) -> (FlatID, bool /*Is generative */, BracketSpan) { let bracket_span = BracketSpan::from_outer(cursor.span()); cursor.go_down_content(kind!("array_bracket_expression"), |cursor| { let (expr, is_generative) = self.flatten_expr(cursor); @@ -756,7 +791,9 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { fn alloc_error(&mut self, span: Span) -> FlatID { self.instructions.alloc(Instruction::Expression(Expression { - typ: self.type_alloc.alloc_unset_type(DomainAllocOption::NonGenerativeUnknown), + typ: self + .type_alloc + .alloc_unset_type(DomainAllocOption::NonGenerativeUnknown), span, source: ExpressionSource::new_error(), })) @@ -822,7 +859,11 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { }) } - fn get_main_interface(&self, submodule_decl: FlatID, span: Span) -> Option<(InterfaceID, &Interface)> { + fn get_main_interface( + &self, + submodule_decl: FlatID, + span: Span, + ) -> Option<(InterfaceID, &Interface)> { let sm = self.instructions[submodule_decl].unwrap_submodule(); let md = &self.globals[sm.module_ref.id]; @@ -846,7 +887,8 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { PartialWireReference::GlobalModuleName(module_ref) => { let documentation = cursor.extract_gathered_comments(); let interface_span = module_ref.get_total_span(); - let submodule_decl = self.alloc_submodule_instruction(module_ref, None, documentation); + let submodule_decl = + self.alloc_submodule_instruction(module_ref, None, documentation); Some(ModuleInterfaceReference { submodule_decl, submodule_interface: self.get_main_interface(submodule_decl, interface_span)?.0, @@ -887,8 +929,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { &self, interface_reference: &ModuleInterfaceReference, ) -> (&Module, &Interface) { - let submodule = - self.instructions[interface_reference.submodule_decl].unwrap_submodule(); + let submodule = self.instructions[interface_reference.submodule_decl].unwrap_submodule(); let md = &self.globals[submodule.module_ref.id]; let interface = &md.interfaces[interface_reference.submodule_interface]; (md, interface) @@ -900,8 +941,11 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { let (source, is_generative) = if kind == kind!("number") { let text = &self.globals.file_data.file_text[expr_span]; - use std::str::FromStr; - (ExpressionSource::Constant(Value::Integer(BigInt::from_str(text).unwrap())), true) + use std::str::FromStr; + ( + ExpressionSource::Constant(Value::Integer(BigInt::from_str(text).unwrap())), + true, + ) } else if kind == kind!("unary_op") { cursor.go_down_no_check(|cursor| { cursor.field(field!("operator")); @@ -923,34 +967,40 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { cursor.field(field!("right")); let (right, right_gen) = self.flatten_expr(cursor); - (ExpressionSource::BinaryOp { op, left, right }, left_gen & right_gen) + ( + ExpressionSource::BinaryOp { op, left, right }, + left_gen & right_gen, + ) }) } else if kind == kind!("func_call") { - (if let Some(fc_id) = self.flatten_func_call(cursor) { - let fc = self.instructions[fc_id].unwrap_func_call(); - let (md, interface) = self.get_interface_reference(&fc.interface_reference); - if interface.func_call_outputs.len() != 1 { - self.errors + ( + if let Some(fc_id) = self.flatten_func_call(cursor) { + let fc = self.instructions[fc_id].unwrap_func_call(); + let (md, interface) = self.get_interface_reference(&fc.interface_reference); + if interface.func_call_outputs.len() != 1 { + self.errors .error(expr_span, "A function called in this context may only return one result. Split this function call into a separate line instead.") .info_obj(&(md, interface)); - } + } - if interface.func_call_outputs.len() >= 1 { - ExpressionSource::WireRef(WireReference::simple_port(PortReference { - submodule_name_span: fc.interface_reference.name_span, - submodule_decl: fc.interface_reference.submodule_decl, - port: interface.func_call_outputs.0, - port_name_span: None, - is_input: false, - })) + if interface.func_call_outputs.len() >= 1 { + ExpressionSource::WireRef(WireReference::simple_port(PortReference { + submodule_name_span: fc.interface_reference.name_span, + submodule_decl: fc.interface_reference.submodule_decl, + port: interface.func_call_outputs.0, + port_name_span: None, + is_input: false, + })) + } else { + // Function desugaring or using threw an error + ExpressionSource::new_error() + } } else { // Function desugaring or using threw an error ExpressionSource::new_error() - } - } else { - // Function desugaring or using threw an error - ExpressionSource::new_error() - }, false) // TODO add compile-time functions https://github.com/pc2/sus-compiler/issues/10 + }, + false, + ) // TODO add compile-time functions https://github.com/pc2/sus-compiler/issues/10 } else if kind == kind!("parenthesis_expression") { // Explicitly return so we don't alloc another WireInstance Instruction return cursor.go_down_content(kind!("parenthesis_expression"), |cursor| { @@ -959,15 +1009,25 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { } else { if let Some(wr) = self.flatten_wire_reference(cursor).expect_wireref(self) { let mut is_comptime = match wr.root { - WireReferenceRoot::LocalDecl(uuid, _span) => self.instructions[uuid].unwrap_declaration().identifier_type.is_generative(), + WireReferenceRoot::LocalDecl(uuid, _span) => self.instructions[uuid] + .unwrap_declaration() + .identifier_type + .is_generative(), WireReferenceRoot::NamedConstant(_) => true, WireReferenceRoot::SubModulePort(_) => false, }; for elem in &wr.path { match elem { - WireReferencePathElement::ArrayAccess { idx, bracket_span:_ } => { - is_comptime &= self.instructions[*idx].unwrap_expression().typ.domain.is_generative() + WireReferencePathElement::ArrayAccess { + idx, + bracket_span: _, + } => { + is_comptime &= self.instructions[*idx] + .unwrap_expression() + .typ + .domain + .is_generative() } } } @@ -978,12 +1038,19 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { }; let wire_instance = Expression { - typ: self.type_alloc.alloc_unset_type(if is_generative {DomainAllocOption::Generative} else {DomainAllocOption::NonGenerativeUnknown}), + typ: self.type_alloc.alloc_unset_type(if is_generative { + DomainAllocOption::Generative + } else { + DomainAllocOption::NonGenerativeUnknown + }), span: expr_span, source, }; - (self.instructions - .alloc(Instruction::Expression(wire_instance)), is_generative) + ( + self.instructions + .alloc(Instruction::Expression(wire_instance)), + is_generative, + ) } fn flatten_wire_reference(&mut self, cursor: &mut Cursor) -> PartialWireReference { @@ -995,7 +1062,10 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { let root = WireReferenceRoot::LocalDecl(decl_id, expr_span); PartialWireReference::WireReference(WireReference { root, - is_generative: self.instructions[decl_id].unwrap_declaration().identifier_type.is_generative(), + is_generative: self.instructions[decl_id] + .unwrap_declaration() + .identifier_type + .is_generative(), path: Vec::new(), }) } @@ -1003,24 +1073,30 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { PartialWireReference::ModuleButNoPort(submod_id, expr_span) } NamedLocal::TemplateType(template_id) => { - self.errors.error( - span, - format!( - "Expected a value, but instead found template type '{}'", - self.working_on_link_info.template_parameters[template_id].name - ), - ).info_obj_same_file(&self.working_on_link_info.template_parameters[template_id]); + self.errors + .error( + span, + format!( + "Expected a value, but instead found template type '{}'", + self.working_on_link_info.template_parameters[template_id].name + ), + ) + .info_obj_same_file( + &self.working_on_link_info.template_parameters[template_id], + ); PartialWireReference::Error } NamedLocal::DomainDecl(domain_id) => { let domain = &self.domains[domain_id]; - self.errors.error( - span, - format!( - "Expected a value, but instead found domain '{}'", - domain.name - ), - ).info_same_file(span, format!("Domain {} declared here", domain.name)); + self.errors + .error( + span, + format!( + "Expected a value, but instead found domain '{}'", + domain.name + ), + ) + .info_same_file(span, format!("Domain {} declared here", domain.name)); PartialWireReference::Error } }, @@ -1032,14 +1108,13 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { path: Vec::new(), }) } - LocalOrGlobal::Module(md_ref) => { - PartialWireReference::GlobalModuleName(md_ref) - } + LocalOrGlobal::Module(md_ref) => PartialWireReference::GlobalModuleName(md_ref), LocalOrGlobal::Type(type_ref) => { - self.globals.not_expected_global_error(&type_ref, "named wire: local or constant"); + self.globals + .not_expected_global_error(&type_ref, "named wire: local or constant"); PartialWireReference::Error } - LocalOrGlobal::NotFound(_) => PartialWireReference::Error + LocalOrGlobal::NotFound(_) => PartialWireReference::Error, } } else if kind == kind!("array_op") { cursor.go_down_no_check(|cursor| { @@ -1064,7 +1139,8 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { } PartialWireReference::Error => {} PartialWireReference::WireReference(wr) => { - wr.path.push(WireReferencePathElement::ArrayAccess { idx, bracket_span }); + wr.path + .push(WireReferencePathElement::ArrayAccess { idx, bracket_span }); } } @@ -1159,23 +1235,31 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { let position_statement_keyword = cursor.span(); cursor.field(field!("condition")); let (condition, condition_is_generative) = self.flatten_expr(cursor); - match(keyword_is_if, condition_is_generative){ + match (keyword_is_if, condition_is_generative) { (true, false) => { - self.errors.warn(position_statement_keyword, "Used 'if' in a non generative context, use 'when' instead"); - }, + self.errors.warn( + position_statement_keyword, + "Used 'if' in a non generative context, use 'when' instead", + ); + } (false, true) => { - self.errors.error(position_statement_keyword, "Used 'when' in a generative context, use 'if' instead"); - }, - (_, _) => () + self.errors.error( + position_statement_keyword, + "Used 'when' in a generative context, use 'if' instead", + ); + } + (_, _) => (), } - let if_id = self.instructions.alloc(Instruction::IfStatement(IfStatement { - condition, - is_generative: keyword_is_if, - then_start: FlatID::PLACEHOLDER, - then_end_else_start: FlatID::PLACEHOLDER, - else_end: FlatID::PLACEHOLDER, - })); + let if_id = self + .instructions + .alloc(Instruction::IfStatement(IfStatement { + condition, + is_generative: keyword_is_if, + then_start: FlatID::PLACEHOLDER, + then_end_else_start: FlatID::PLACEHOLDER, + else_end: FlatID::PLACEHOLDER, + })); let then_start = self.instructions.get_next_alloc_id(); cursor.field(field!("then_block")); @@ -1243,23 +1327,28 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { let mut to_iter = to.into_iter(); for port in outputs { if let Some((Some((to, write_modifiers)), to_span)) = to_iter.next() { - let from = - self.instructions.alloc(Instruction::Expression(Expression { - typ: self.type_alloc.alloc_unset_type(DomainAllocOption::NonGenerativeUnknown), // TODO Generative Function Calls https://github.com/pc2/sus-compiler/issues/10 - span: func_call_span, - source: ExpressionSource::WireRef(WireReference::simple_port(PortReference { + let from = self.instructions.alloc(Instruction::Expression(Expression { + typ: self + .type_alloc + .alloc_unset_type(DomainAllocOption::NonGenerativeUnknown), // TODO Generative Function Calls https://github.com/pc2/sus-compiler/issues/10 + span: func_call_span, + source: ExpressionSource::WireRef(WireReference::simple_port( + PortReference { port, port_name_span: None, is_input: false, submodule_name_span, submodule_decl, - })), - })); + }, + )), + })); self.instructions.alloc(Instruction::Write(Write { from, to, to_span, - to_type: self.type_alloc.alloc_unset_type(DomainAllocOption::NonGenerativeUnknown), // Module ports are always non-generative + to_type: self + .type_alloc + .alloc_unset_type(DomainAllocOption::NonGenerativeUnknown), // Module ports are always non-generative write_modifiers, })); } @@ -1271,7 +1360,9 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { for leftover_to in to_iter { if let (Some((to, write_modifiers)), to_span) = leftover_to { let err_id = self.instructions.alloc(Instruction::Expression(Expression { - typ: self.type_alloc.alloc_unset_type(DomainAllocOption::NonGenerativeUnknown), + typ: self + .type_alloc + .alloc_unset_type(DomainAllocOption::NonGenerativeUnknown), span: func_call_span, source: ExpressionSource::new_error(), })); @@ -1279,7 +1370,9 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { from: err_id, to, to_span, - to_type: self.type_alloc.alloc_unset_type(DomainAllocOption::NonGenerativeUnknown), // Even non-existing Module ports are non-generative + to_type: self + .type_alloc + .alloc_unset_type(DomainAllocOption::NonGenerativeUnknown), // Even non-existing Module ports are non-generative write_modifiers, })); } @@ -1447,7 +1540,9 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { )) } else { // It's _expression - if let Some(wire_ref) = self.flatten_wire_reference(cursor).expect_wireref(self) { + if let Some(wire_ref) = + self.flatten_wire_reference(cursor).expect_wireref(self) + { Some((wire_ref, write_modifiers)) } else { None @@ -1505,24 +1600,32 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { fn flatten_interface_ports(&mut self, cursor: &mut Cursor) { cursor.go_down(kind!("interface_ports"), |cursor| { if cursor.optional_field(field!("inputs")) { - self.flatten_declaration_list(DeclarationContext::IO{is_input:true}, true, cursor) + self.flatten_declaration_list( + DeclarationContext::IO { is_input: true }, + true, + cursor, + ) } if cursor.optional_field(field!("outputs")) { - self.flatten_declaration_list(DeclarationContext::IO{is_input:false}, false, cursor) + self.flatten_declaration_list( + DeclarationContext::IO { is_input: false }, + false, + cursor, + ) } }) } fn flatten_global(&mut self, cursor: &mut Cursor) { - // Skip because we covered it in initialization. + // Skip because we covered it in initialization. let _ = cursor.optional_field(field!("extern_marker")); - // Skip because we know this from initialization. + // Skip because we know this from initialization. cursor.field(field!("object_type")); // We parse this one a bit strangely. Just because visually it looks nicer to have the template arguments after // const int[SIZE] range #(int SIZE) {} let const_type_cursor = (cursor.kind() == kind!("const_and_type")).then(|| cursor.clone()); - + let name_span = cursor.field_span(field!("name"), kind!("identifier")); self.flatten_parameters(cursor); let module_name = &self.globals.file_data.file_text[name_span]; @@ -1533,20 +1636,24 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { const_type_cursor.go_down(kind!("const_and_type"), |const_type_cursor| { const_type_cursor.field(field!("const_type")); let typ_expr = self.flatten_type(const_type_cursor); - let module_output_decl = self.instructions.alloc(Instruction::Declaration(Declaration{ - typ_expr, - typ: self.type_alloc.alloc_unset_type(DomainAllocOption::Generative), - decl_span, - name_span, - name: module_name.to_string(), - declaration_runtime_depth: OnceCell::new(), - read_only: false, - declaration_itself_is_not_written_to: true, - decl_kind: DeclarationKind::NotPort, - identifier_type: IdentifierType::Generative, - latency_specifier: None, - documentation: const_type_cursor.extract_gathered_comments(), - })); + let module_output_decl = + self.instructions + .alloc(Instruction::Declaration(Declaration { + typ_expr, + typ: self + .type_alloc + .alloc_unset_type(DomainAllocOption::Generative), + decl_span, + name_span, + name: module_name.to_string(), + declaration_runtime_depth: OnceCell::new(), + read_only: false, + declaration_itself_is_not_written_to: true, + decl_kind: DeclarationKind::NotPort, + identifier_type: IdentifierType::Generative, + latency_specifier: None, + documentation: const_type_cursor.extract_gathered_comments(), + })); self.alloc_local_name(name_span, NamedLocal::Declaration(module_output_decl)); }); @@ -1561,9 +1668,9 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { /// /// Requires that first, all globals have been initialized. pub fn flatten_all_globals(linker: &mut Linker) { - let linker_files : *const ArenaAllocator = &linker.files; - // SAFETY we won't be touching the files anywere. This is just to get the compiler to stop complaining about linker going into the closure. - for (_file_id, file) in unsafe{&*linker_files} { + let linker_files: *const ArenaAllocator = &linker.files; + // SAFETY we won't be touching the files anywere. This is just to get the compiler to stop complaining about linker going into the closure. + for (_file_id, file) in unsafe { &*linker_files } { let mut span_debugger = SpanDebugger::new("flatten_all_globals", file); let mut associated_value_iter = file.associated_values.iter(); @@ -1571,7 +1678,9 @@ pub fn flatten_all_globals(linker: &mut Linker) { cursor.list(kind!("source_file"), |cursor| { cursor.go_down(kind!("global_object"), |cursor| { - let global_obj = *associated_value_iter.next().expect("Iterator cannot be exhausted"); + let global_obj = *associated_value_iter + .next() + .expect("Iterator cannot be exhausted"); flatten_global(linker, global_obj, cursor); }); @@ -1580,7 +1689,7 @@ pub fn flatten_all_globals(linker: &mut Linker) { } } -fn flatten_global(linker: &mut Linker, global_obj : GlobalUUID, cursor: &mut Cursor<'_>) { +fn flatten_global(linker: &mut Linker, global_obj: GlobalUUID, cursor: &mut Cursor<'_>) { let errors_globals = GlobalResolver::take_errors_globals(linker, global_obj); let obj_link_info = linker.get_link_info(global_obj); let globals = GlobalResolver::new(linker, obj_link_info, errors_globals); @@ -1592,27 +1701,44 @@ fn flatten_global(linker: &mut Linker, global_obj : GlobalUUID, cursor: &mut Cur let md = &globals[module_uuid]; for (id, domain) in &md.domains { - if let Err(conflict) = local_variable_context.add_declaration(&domain.name, NamedLocal::DomainDecl(id)) { - let NamedLocal::DomainDecl(conflict) = conflict else {unreachable!()}; + if let Err(conflict) = + local_variable_context.add_declaration(&domain.name, NamedLocal::DomainDecl(id)) + { + let NamedLocal::DomainDecl(conflict) = conflict else { + unreachable!() + }; globals.errors.error(domain.name_span.unwrap(), format!("Conflicting domain declaration. Domain '{}' was already declared earlier", domain.name)) .info_obj_same_file(&md.domains[conflict]); } } - (md.ports.id_range().into_iter(), UUIDRange::empty().into_iter(), DeclarationContext::PlainWire, &md.domains) + ( + md.ports.id_range().into_iter(), + UUIDRange::empty().into_iter(), + DeclarationContext::PlainWire, + &md.domains, + ) } GlobalUUID::Type(type_uuid) => { let typ = &globals[type_uuid]; - (UUIDRange::empty().into_iter(), typ.fields.id_range().into_iter(), DeclarationContext::StructField, &FlatAlloc::EMPTY_FLAT_ALLOC) - } - GlobalUUID::Constant(_const_uuid) => { - (UUIDRange::empty().into_iter(), UUIDRange::empty().into_iter(), DeclarationContext::Generative(GenerativeKind::PlainGenerative), &FlatAlloc::EMPTY_FLAT_ALLOC) + ( + UUIDRange::empty().into_iter(), + typ.fields.id_range().into_iter(), + DeclarationContext::StructField, + &FlatAlloc::EMPTY_FLAT_ALLOC, + ) } + GlobalUUID::Constant(_const_uuid) => ( + UUIDRange::empty().into_iter(), + UUIDRange::empty().into_iter(), + DeclarationContext::Generative(GenerativeKind::PlainGenerative), + &FlatAlloc::EMPTY_FLAT_ALLOC, + ), }; let mut context = FlatteningContext { - globals : &globals, + globals: &globals, ports_to_visit, fields_to_visit, domains, @@ -1620,13 +1746,16 @@ fn flatten_global(linker: &mut Linker, global_obj : GlobalUUID, cursor: &mut Cur errors: &globals.errors, working_on_link_info: linker.get_link_info(global_obj), instructions: FlatAlloc::new(), - type_alloc: TypingAllocator { type_variable_alloc: UUIDAllocator::new(), domain_variable_alloc: UUIDAllocator::new() }, + type_alloc: TypingAllocator { + type_variable_alloc: UUIDAllocator::new(), + domain_variable_alloc: UUIDAllocator::new(), + }, named_domain_alloc: UUIDAllocator::new(), local_variable_context, }; context.flatten_global(cursor); - + // Make sure all ports have been visited assert!(context.ports_to_visit.is_empty()); @@ -1635,21 +1764,26 @@ fn flatten_global(linker: &mut Linker, global_obj : GlobalUUID, cursor: &mut Cur let errors_globals = globals.decommission(&linker.files); - let link_info : &mut LinkInfo = match global_obj { + let link_info: &mut LinkInfo = match global_obj { GlobalUUID::Module(module_uuid) => { let md = &mut linker.modules[module_uuid]; // Set all declaration_instruction values for (decl_id, instr) in &instructions { if let Instruction::Declaration(decl) = instr { match decl.decl_kind { - DeclarationKind::NotPort => {}, - DeclarationKind::RegularPort { is_input:_, port_id } => { + DeclarationKind::NotPort => {} + DeclarationKind::RegularPort { + is_input: _, + port_id, + } => { let port = &mut md.ports[port_id]; assert_eq!(port.name_span, decl.name_span); port.declaration_instruction = decl_id; } DeclarationKind::GenerativeInput(_) => {} - DeclarationKind::StructField { field_id:_ } => unreachable!("No Struct fields in Modules") + DeclarationKind::StructField { field_id: _ } => { + unreachable!("No Struct fields in Modules") + } } } } @@ -1666,18 +1800,28 @@ fn flatten_global(linker: &mut Linker, global_obj : GlobalUUID, cursor: &mut Cur } GlobalUUID::Type(type_uuid) => { let typ = &mut linker.types[type_uuid]; - + // Set all declaration_instruction values for (decl_id, instr) in &instructions { if let Instruction::Declaration(decl) = instr { match decl.decl_kind { - DeclarationKind::NotPort => {assert!(decl.identifier_type == IdentifierType::Generative, "If a variable isn't generative, then it MUST be a struct field")} + DeclarationKind::NotPort => { + assert!( + decl.identifier_type == IdentifierType::Generative, + "If a variable isn't generative, then it MUST be a struct field" + ) + } DeclarationKind::StructField { field_id } => { let field = &mut typ.fields[field_id]; assert_eq!(field.name_span, decl.name_span); field.declaration_instruction = decl_id; } - DeclarationKind::RegularPort { is_input:_, port_id:_ } => {unreachable!("No ports in structs")} + DeclarationKind::RegularPort { + is_input: _, + port_id: _, + } => { + unreachable!("No ports in structs") + } DeclarationKind::GenerativeInput(_) => {} } } @@ -1687,11 +1831,17 @@ fn flatten_global(linker: &mut Linker, global_obj : GlobalUUID, cursor: &mut Cur GlobalUUID::Constant(const_uuid) => { let cst = &mut linker.constants[const_uuid]; - cst.output_decl = instructions.iter().find(|(_decl_id, instr)| { - if let Instruction::Declaration(decl) = instr { - decl.name_span == cst.link_info.name_span - } else {false} - }).unwrap().0; + cst.output_decl = instructions + .iter() + .find(|(_decl_id, instr)| { + if let Instruction::Declaration(decl) = instr { + decl.name_span == cst.link_info.name_span + } else { + false + } + }) + .unwrap() + .0; &mut cst.link_info } @@ -1701,8 +1851,13 @@ fn flatten_global(linker: &mut Linker, global_obj : GlobalUUID, cursor: &mut Cur for (decl_id, instr) in &mut instructions { if let Instruction::Declaration(decl) = instr { if let DeclarationKind::GenerativeInput(this_template_id) = decl.decl_kind { - let ParameterKind::Generative(GenerativeParameterKind { decl_span:_, declaration_instruction }) = - &mut link_info.template_parameters[this_template_id].kind else {unreachable!()}; + let ParameterKind::Generative(GenerativeParameterKind { + decl_span: _, + declaration_instruction, + }) = &mut link_info.template_parameters[this_template_id].kind + else { + unreachable!() + }; *declaration_instruction = decl_id; } diff --git a/src/flattening/initialization.rs b/src/flattening/initialization.rs index f4e96b6..17151b6 100644 --- a/src/flattening/initialization.rs +++ b/src/flattening/initialization.rs @@ -9,7 +9,7 @@ use crate::linker::{FileBuilder, LinkInfo, ResolvedGlobals}; use crate::{file_position::FileText, flattening::Module, instantiation::InstantiationCache}; use crate::typing::template::{ - GenerativeParameterKind, Parameter, ParameterKind, TVec, TypeParameterKind + GenerativeParameterKind, Parameter, ParameterKind, TVec, TypeParameterKind, }; use super::parser::Cursor; @@ -22,9 +22,9 @@ struct InitializationContext<'linker> { ports: FlatAlloc, interfaces: FlatAlloc, domains: FlatAlloc, - /// This is initially true, but when the first `domain xyz` statement is encountered this is set to false. + /// This is initially true, but when the first `domain xyz` statement is encountered this is set to false. implicit_clk_domain: bool, - + // struct-only stuff fields: FlatAlloc, @@ -37,7 +37,10 @@ impl<'linker> InitializationContext<'linker> { fn gather_initial_global_object(&mut self, cursor: &mut Cursor) -> (Span, String) { let name_span = cursor.field_span(field!("name"), kind!("identifier")); let name = self.file_text[name_span].to_owned(); - self.domains.alloc(DomainInfo { name: "clk".to_string(), name_span: None }); + self.domains.alloc(DomainInfo { + name: "clk".to_string(), + name_span: None, + }); if cursor.optional_field(field!("template_declaration_arguments")) { cursor.list(kind!("template_declaration_arguments"), |cursor| { let (kind, decl_span) = cursor.kind_span(); @@ -57,7 +60,7 @@ impl<'linker> InitializationContext<'linker> { cursor.field(field!("type")); let name_span = cursor.field_span(field!("name"), kind!("identifier")); let name = self.file_text[name_span].to_owned(); - + self.parameters.alloc(Parameter { name, name_span, @@ -67,9 +70,8 @@ impl<'linker> InitializationContext<'linker> { }), }); }), - _other => cursor.could_not_match() + _other => cursor.could_not_match(), } - }); } @@ -108,13 +110,13 @@ impl<'linker> InitializationContext<'linker> { if cursor.kind() == kind!("declaration") { let whole_decl_span = cursor.span(); cursor.go_down_no_check(|cursor| { - let is_input = cursor.optional_field(field!("io_port_modifiers")).then(|| { - match cursor.kind() { + let is_input = cursor.optional_field(field!("io_port_modifiers")).then( + || match cursor.kind() { kw!("input") => true, kw!("output") => false, _ => cursor.could_not_match(), - } - }); + }, + ); self.finish_gather_decl(is_input, whole_decl_span, cursor); }); } @@ -228,7 +230,12 @@ impl<'linker> InitializationContext<'linker> { self.ports.range_since(list_start_at) } - fn finish_gather_decl(&mut self, is_input: Option, whole_decl_span: Span, cursor: &mut Cursor) { + fn finish_gather_decl( + &mut self, + is_input: Option, + whole_decl_span: Span, + cursor: &mut Cursor, + ) { // If generative input it's a template arg let is_generative = if cursor.optional_field(field!("declaration_modifiers")) { cursor.kind() == kw!("gen") @@ -254,11 +261,11 @@ impl<'linker> InitializationContext<'linker> { }); } (false, None) => { - self.fields.alloc(StructField{ + self.fields.alloc(StructField { name: name.clone(), name_span, decl_span, - declaration_instruction: FlatID::PLACEHOLDER + declaration_instruction: FlatID::PLACEHOLDER, }); } _other => {} @@ -283,35 +290,36 @@ pub fn gather_initial_file_data(mut builder: FileBuilder) { ); } - enum GlobalObjectKind { Module, Const, - Struct + Struct, } -fn initialize_global_object(builder: &mut FileBuilder, parsing_errors: ErrorCollector, span: Span, cursor: &mut Cursor) { - let is_extern = match cursor.optional_field(field!("extern_marker")).then(|| cursor.kind()) { +fn initialize_global_object( + builder: &mut FileBuilder, + parsing_errors: ErrorCollector, + span: Span, + cursor: &mut Cursor, +) { + let is_extern = match cursor + .optional_field(field!("extern_marker")) + .then(|| cursor.kind()) + { None => IsExtern::Normal, Some(kw!("extern")) => IsExtern::Extern, Some(kw!("__builtin__")) => IsExtern::Builtin, - Some(_) => cursor.could_not_match() + Some(_) => cursor.could_not_match(), }; - + cursor.field(field!("object_type")); let global_obj_kind = match cursor.kind() { - kw!("module") => { - GlobalObjectKind::Module - } - kind!("const_and_type") => { - GlobalObjectKind::Const - } - kw!("struct") => { - GlobalObjectKind::Struct - } - _other => cursor.could_not_match() + kw!("module") => GlobalObjectKind::Module, + kind!("const_and_type") => GlobalObjectKind::Const, + kw!("struct") => GlobalObjectKind::Struct, + _other => cursor.could_not_match(), }; - + let mut ctx = InitializationContext { ports: FlatAlloc::new(), interfaces: FlatAlloc::new(), @@ -326,7 +334,10 @@ fn initialize_global_object(builder: &mut FileBuilder, parsing_errors: ErrorColl let (name_span, name) = ctx.gather_initial_global_object(cursor); let mut link_info = LinkInfo { - type_variable_alloc: TypingAllocator{domain_variable_alloc: UUIDAllocator::new(), type_variable_alloc: UUIDAllocator::new()}, + type_variable_alloc: TypingAllocator { + domain_variable_alloc: UUIDAllocator::new(), + type_variable_alloc: UUIDAllocator::new(), + }, template_parameters: ctx.parameters, instructions: FlatAlloc::new(), documentation: cursor.extract_gathered_comments(), @@ -337,10 +348,13 @@ fn initialize_global_object(builder: &mut FileBuilder, parsing_errors: ErrorColl errors: ErrorStore::new(), is_extern, resolved_globals: ResolvedGlobals::empty(), - checkpoints: ArrayVec::new() + checkpoints: ArrayVec::new(), }; - link_info.reabsorb_errors_globals((ctx.errors, ResolvedGlobals::empty()), AFTER_INITIAL_PARSE_CP); + link_info.reabsorb_errors_globals( + (ctx.errors, ResolvedGlobals::empty()), + AFTER_INITIAL_PARSE_CP, + ); match global_obj_kind { GlobalObjectKind::Module => { @@ -356,13 +370,13 @@ fn initialize_global_object(builder: &mut FileBuilder, parsing_errors: ErrorColl GlobalObjectKind::Struct => { builder.add_type(StructType { link_info, - fields: ctx.fields + fields: ctx.fields, }); } GlobalObjectKind::Const => { builder.add_const(NamedConstant { link_info, - output_decl: FlatID::PLACEHOLDER + output_decl: FlatID::PLACEHOLDER, }); } } diff --git a/src/flattening/lints.rs b/src/flattening/lints.rs index 0b97f64..a320d73 100644 --- a/src/flattening/lints.rs +++ b/src/flattening/lints.rs @@ -8,14 +8,18 @@ use super::walk::for_each_generative_input_in_template_args; use super::{ExpressionSource, Instruction, Module, WireReferencePathElement, WireReferenceRoot}; - pub fn perform_lints(linker: &mut Linker) { for (_, md) in &mut linker.modules { - let errors = ErrorCollector::from_storage(md.link_info.errors.take(), md.link_info.file, &linker.files); + let errors = ErrorCollector::from_storage( + md.link_info.errors.take(), + md.link_info.file, + &linker.files, + ); let resolved_globals = md.link_info.resolved_globals.take(); find_unused_variables(md, &errors); extern_objects_may_not_have_type_template_args(&md.link_info, &errors); - md.link_info.reabsorb_errors_globals((errors, resolved_globals), AFTER_LINTS_CP); + md.link_info + .reabsorb_errors_globals((errors, resolved_globals), AFTER_LINTS_CP); } } @@ -26,7 +30,10 @@ fn extern_objects_may_not_have_type_template_args(link_info: &LinkInfo, errors: if link_info.is_extern == IsExtern::Extern { for (_id, arg) in &link_info.template_parameters { if let ParameterKind::Type(..) = &arg.kind { - errors.error(arg.name_span, "'extern' modules may not have 'type' arguments. Convert to bool[] first"); + errors.error( + arg.name_span, + "'extern' modules may not have 'type' arguments. Convert to bool[] first", + ); } } } @@ -38,7 +45,7 @@ fn extern_objects_may_not_have_type_template_args(link_info: &LinkInfo, errors: fn find_unused_variables(md: &Module, errors: &ErrorCollector) { match md.link_info.is_extern { IsExtern::Normal => {} - IsExtern::Extern | IsExtern::Builtin => {return} // Don't report unused variables for extern modules. + IsExtern::Extern | IsExtern::Builtin => return, // Don't report unused variables for extern modules. } let instruction_fanins = make_fanins(&md.link_info.instructions); @@ -89,13 +96,17 @@ fn find_unused_variables(md: &Module, errors: &ErrorCollector) { } } -fn make_fanins(instructions: &FlatAlloc) -> FlatAlloc, FlatIDMarker> { +fn make_fanins( + instructions: &FlatAlloc, +) -> FlatAlloc, FlatIDMarker> { // Setup Wire Fanouts List for faster processing let mut instruction_fanins: FlatAlloc, FlatIDMarker> = instructions.map(|_| Vec::new()); for (inst_id, inst) in instructions.iter() { - let mut collector_func = |id| {instruction_fanins[inst_id].push(id);}; + let mut collector_func = |id| { + instruction_fanins[inst_id].push(id); + }; match inst { Instruction::Write(conn) => { if let Some(flat_root) = conn.to.root.get_root_flat() { diff --git a/src/flattening/mod.rs b/src/flattening/mod.rs index 3069978..b06c7b3 100644 --- a/src/flattening/mod.rs +++ b/src/flattening/mod.rs @@ -1,10 +1,10 @@ mod flatten; mod initialization; +mod lints; mod name_context; mod parser; mod typechecking; mod walk; -mod lints; use crate::alloc::UUIDAllocator; use crate::prelude::*; @@ -16,16 +16,13 @@ use std::ops::Deref; pub use flatten::flatten_all_globals; pub use initialization::gather_initial_file_data; -pub use typechecking::typecheck_all_modules; pub use lints::perform_lints; +pub use typechecking::typecheck_all_modules; use crate::linker::{Documentation, LinkInfo}; use crate::{file_position::FileText, instantiation::InstantiationCache, value::Value}; -use crate::typing::{ - abstract_type::FullType, - template::GlobalReference, -}; +use crate::typing::{abstract_type::FullType, template::GlobalReference}; /// Modules are compiled in 4 stages. All modules must pass through each stage before advancing to the next stage. /// @@ -42,7 +39,7 @@ use crate::typing::{ /// 3.1: Execution /// /// 3.2: Concrete Typecheck, Latency Counting -/// +/// /// All Modules are stored in [Linker::modules] and indexed by [ModuleUUID] #[derive(Debug)] pub struct Module { @@ -125,42 +122,42 @@ impl Module { } /// Temporary upgrade such that we can name the singular clock of the module, such that weirdly-named external module clocks can be used - /// + /// /// See #7 pub fn get_clock_name(&self) -> &str { &self.domains.iter().next().unwrap().1.name } } -/// Represents an opaque type in the compiler, like `int` or `bool`. -/// +/// Represents an opaque type in the compiler, like `int` or `bool`. +/// /// TODO: Structs #8 -/// +/// /// All Types are stored in [Linker::types] and indexed by [TypeUUID] #[derive(Debug)] pub struct StructType { /// Created in Stage 1: Initialization - pub link_info : LinkInfo, - + pub link_info: LinkInfo, + /// Created in Stage 1: Initialization /// /// [StructField::declaration_instruction] are set in Stage 2: Flattening - fields: FlatAlloc + fields: FlatAlloc, } /// Global constant, like `true`, `false`, or user-defined constants (TODO #19) -/// +/// /// All Constants are stored in [Linker::constants] and indexed by [ConstantUUID] #[derive(Debug)] pub struct NamedConstant { pub link_info: LinkInfo, - pub output_decl: FlatID + pub output_decl: FlatID, } /// Represents a field in a struct -/// +/// /// UNFINISHED -/// +/// /// TODO: Structs #8 #[derive(Debug)] pub struct StructField { @@ -173,8 +170,8 @@ pub struct StructField { pub declaration_instruction: FlatID, } -/// In SUS, when you write `my_submodule.abc`, `abc` could refer to an interface or to a port. -/// +/// In SUS, when you write `my_submodule.abc`, `abc` could refer to an interface or to a port. +/// /// See [Module::get_port_or_interface_by_name] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PortOrInterface { @@ -182,14 +179,14 @@ pub enum PortOrInterface { Interface(InterfaceID), } -/// Information about a (clock) domain. -/// -/// Right now this only contains the domain name, but when actual clock domains are implemented (#7), -/// this will contain information about the Clock. +/// Information about a (clock) domain. +/// +/// Right now this only contains the domain name, but when actual clock domains are implemented (#7), +/// this will contain information about the Clock. #[derive(Debug, Clone)] pub struct DomainInfo { pub name: String, - pub name_span: Option + pub name_span: Option, } /// With this struct, we convert the domains of a submodule, to their connecting domains in the containing module @@ -206,8 +203,8 @@ impl<'linker> InterfaceToDomainMap<'linker> { } } -/// What kind of wire/value does this identifier represent? -/// +/// What kind of wire/value does this identifier represent? +/// /// We already know it's not a submodule #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum IdentifierType { @@ -239,22 +236,22 @@ impl IdentifierType { } } -/// A port of a module. Not to be confused with [PortReference], which is a reference to a submodule port. -/// +/// A port of a module. Not to be confused with [PortReference], which is a reference to a submodule port. +/// /// All ports must have a name -/// +/// /// ```sus /// module md { /// interface beep : int a -> bool b, int[3] c -/// +/// /// output int d /// } /// ``` -/// -/// Creates four ports: a, b, c, and d. -/// +/// +/// Creates four ports: a, b, c, and d. +/// /// Ports can be part of interfaces, as is the case above, or are standalone, like d -/// +/// /// ```sus /// module md { /// interface beep : int a -> bool b, int[3] c @@ -272,19 +269,19 @@ pub struct Port { } /// An interface, like: -/// +/// /// ```sus /// module md { /// interface beep : int a -> bool b, int[3] c /// } /// ``` -/// +/// /// So this struct represents an interface, which always can be called with a method-call notation: -/// +/// /// ```sus /// module use_md { /// md x -/// +/// /// bool xyz, int[3] pqr = x.beep(3) /// } /// ``` @@ -306,7 +303,7 @@ impl Interface { } /// An element in a [WireReference] path. Could be array accesses, slice accesses, field accesses, etc -/// +/// /// When executing, this turns into [crate::instantiation::RealWirePathElem] #[derive(Debug, Clone, Copy)] pub enum WireReferencePathElement { @@ -316,9 +313,9 @@ pub enum WireReferencePathElement { }, } -/// The root of a [WireReference]. Basically where the wire reference starts. -/// -/// This can be a local declaration, a global constant, the port of a submodule. +/// The root of a [WireReference]. Basically where the wire reference starts. +/// +/// This can be a local declaration, a global constant, the port of a submodule. #[derive(Debug)] pub enum WireReferenceRoot { /// ```sus @@ -354,11 +351,11 @@ impl WireReferenceRoot { } } -/// References to wires or generative variables. -/// -/// Basically, this struct encapsulates all expressions that can be written to, like field and array accesses. -/// -/// [Expression] covers anything that can not be written to. +/// References to wires or generative variables. +/// +/// Basically, this struct encapsulates all expressions that can be written to, like field and array accesses. +/// +/// [Expression] covers anything that can not be written to. /// /// Example: `myModule.port[a][b:c]`. (`myModule.port` is the [Self::root], `[a][b:c]` are two parts of the [Self::path]) #[derive(Debug)] @@ -377,10 +374,10 @@ impl WireReference { } } fn simple_var_read(id: FlatID, is_generative: bool, name_span: Span) -> WireReference { - WireReference{ + WireReference { root: WireReferenceRoot::LocalDecl(id, name_span), is_generative, - path: Vec::new() + path: Vec::new(), } } } @@ -406,17 +403,17 @@ impl WriteModifiers { pub fn requires_generative(&self) -> bool { match self { Self::Connection { .. } => false, - Self::Initial { .. } => true + Self::Initial { .. } => true, } } } /// An [Instruction] that refers to an assignment -/// +/// /// ```sus /// module md { /// int x = 3 // first write -/// +/// /// int b, int c = someFunc(3) // Two writes, one to b, one to c /// } /// ``` @@ -425,18 +422,18 @@ pub struct Write { pub from: FlatID, pub to: WireReference, pub to_span: Span, - /// The type and domain to which will be written. - /// + /// The type and domain to which will be written. + /// /// The output_typ domain should be generative when to.root is generative, or a generative value is required such as with "initial" /// When this is not the case, it should be initialized with an unknown Domain Variable - /// - /// In short, this should be the type and domain *to which* the read type must be unified. + /// + /// In short, this should be the type and domain *to which* the read type must be unified. pub to_type: FullType, pub write_modifiers: WriteModifiers, } /// -x -/// +/// /// See [crate::value::compute_unary_op] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum UnaryOperator { @@ -457,7 +454,7 @@ pub enum UnaryOperator { } /// x * y -/// +/// /// See [crate::value::compute_binary_op] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BinaryOperator { @@ -479,7 +476,7 @@ pub enum BinaryOperator { LesserEq, } -/// A reference to a port within a submodule. +/// A reference to a port within a submodule. /// Not to be confused with [Port], which is the declaration of the port itself in the [Module] #[derive(Debug, Clone, Copy)] pub struct PortReference { @@ -495,9 +492,9 @@ pub struct PortReference { } /// An [Instruction] that represents a single expression in the program. Like ((3) + (x)) -/// +/// /// See [ExpressionSource] -/// +/// /// On instantiation, creates [crate::instantiation::RealWire] when non-generative #[derive(Debug)] pub struct Expression { @@ -528,10 +525,10 @@ impl ExpressionSource { } } -/// The textual representation of a type expression in the source code. -/// -/// Not to be confused with [crate::typing::abstract_type::AbstractType] which is for working with types in the flattening stage, -/// or [crate::typing::concrete_type::ConcreteType], which is for working with types post instantiation. +/// The textual representation of a type expression in the source code. +/// +/// Not to be confused with [crate::typing::abstract_type::AbstractType] which is for working with types in the flattening stage, +/// or [crate::typing::concrete_type::ConcreteType], which is for working with types post instantiation. #[derive(Debug)] pub enum WrittenType { Error(Span), @@ -546,23 +543,23 @@ impl WrittenType { WrittenType::Error(total_span) | WrittenType::TemplateVariable(total_span, ..) | WrittenType::Array(total_span, _) => *total_span, - WrittenType::Named(global_ref) => global_ref.get_total_span() + WrittenType::Named(global_ref) => global_ref.get_total_span(), } } } -/// Little helper struct that tells us what kind of declaration it is. -/// Is it a Port, Template argument, A struct field, or just a regular temporary? +/// Little helper struct that tells us what kind of declaration it is. +/// Is it a Port, Template argument, A struct field, or just a regular temporary? #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DeclarationKind { NotPort, - StructField { field_id : FieldID }, + StructField { field_id: FieldID }, RegularPort { is_input: bool, port_id: PortID }, GenerativeInput(TemplateID), } impl DeclarationKind { - /// Basically an unwrap to see if this [Declaration] refers to a [Port], and returns `Some(is_input)` if so. + /// Basically an unwrap to see if this [Declaration] refers to a [Port], and returns `Some(is_input)` if so. pub fn is_io_port(&self) -> Option { if let DeclarationKind::RegularPort { is_input, @@ -577,7 +574,7 @@ impl DeclarationKind { pub fn implies_read_only(&self) -> bool { match self { DeclarationKind::NotPort => false, - DeclarationKind::StructField { field_id:_ } => false, + DeclarationKind::StructField { field_id: _ } => false, DeclarationKind::RegularPort { is_input, port_id: _, @@ -587,11 +584,11 @@ impl DeclarationKind { } } -/// An [Instruction] that represents a declaration of a new local variable. -/// +/// An [Instruction] that represents a declaration of a new local variable. +/// /// It can be referenced by a [WireReferenceRoot::LocalDecl] -/// -/// A Declaration Instruction always corresponds to a new entry in the [self::name_context::LocalVariableContext]. +/// +/// A Declaration Instruction always corresponds to a new entry in the [self::name_context::LocalVariableContext]. #[derive(Debug)] pub struct Declaration { pub typ_expr: WrittenType, @@ -612,12 +609,12 @@ pub struct Declaration { pub documentation: Documentation, } -/// An [Instruction] that represents a instantiation of a submodule. -/// +/// An [Instruction] that represents a instantiation of a submodule. +/// /// It can be referenced by a [WireReferenceRoot::SubModulePort] -/// -/// A SubModuleInstance Instruction always corresponds to a new entry in the [self::name_context::LocalVariableContext]. -/// +/// +/// A SubModuleInstance Instruction always corresponds to a new entry in the [self::name_context::LocalVariableContext]. +/// /// When instantiating, creates a [crate::instantiation::SubModule] #[derive(Debug)] pub struct SubModuleInstance { @@ -625,7 +622,7 @@ pub struct SubModuleInstance { /// Name is not always present in source code. Such as in inline function call syntax: my_mod(a, b, c) pub name: Option<(String, Span)>, /// Maps each of the module's local domains to the domain that it is used in. - /// + /// /// These are *always* [DomainType::Physical] (of course, start out as [DomainType::DomainVariable] before typing) pub local_interface_domains: FlatAlloc, pub documentation: Documentation, @@ -664,43 +661,43 @@ pub struct ModuleInterfaceReference { pub interface_span: Span, } -/// An [Instruction] that represents the calling on an interface of a [SubModuleInstance]. -/// It is the connecting of multiple input ports, and output ports on a submodule in one statement. -/// -/// One may ask, why is this not simply part of [Expression]? +/// An [Instruction] that represents the calling on an interface of a [SubModuleInstance]. +/// It is the connecting of multiple input ports, and output ports on a submodule in one statement. +/// +/// One may ask, why is this not simply part of [Expression]? /// That is because an Expression can only represent one output. Workarounds like putting multiple outputs /// together in a tuple would not work, because: -/// - The function call syntax is just a convenient syntax sugar for connecting multiple inputs and outputs simultaneously. -/// We want to conceptually keep the signals separate. Both input and output signals, while keeping the function call syntax that programmers are used to. +/// - The function call syntax is just a convenient syntax sugar for connecting multiple inputs and outputs simultaneously. +/// We want to conceptually keep the signals separate. Both input and output signals, while keeping the function call syntax that programmers are used to. /// - Forcing all outputs together into one type would bind them together for latency counting, which we don't want /// - We don't have tuple types -/// +/// /// The outputs of a function call are collected with [Write] instructions over the outputs of the underlying [SubModuleInstance] -/// +/// /// Function calls can come in three forms: -/// +/// /// ```sus /// module xor { /// interface xor : bool a, bool b -> bool c /// } -/// +/// /// module fifo #(T) { /// interface push : bool push, T data /// interface pop : bool pop -> bool valid, T data /// } -/// +/// /// module use_modules { /// // We can use functions inline /// bool x = xor(true, false) -/// +/// /// // Declare the submodule explicitly /// xor xor_inst /// bool y = xor_inst(true, false) -/// +/// /// // Or access interfaces explicitly /// fifo my_fifo /// bool z, int data = my_fifo.pop() -/// +/// /// // Finally, if a function returns a single argument, we can call it inline in an expression: /// bool w = true | xor(true, false) /// } @@ -724,7 +721,7 @@ impl FuncCallInstruction { } } -/// A control-flow altering [Instruction] to represent compiletime and runtime if & when statements. +/// A control-flow altering [Instruction] to represent compiletime and runtime if & when statements. #[derive(Debug)] pub struct IfStatement { pub condition: FlatID, @@ -743,16 +740,16 @@ pub struct ForStatement { pub loop_body: FlatIDRange, } -/// When a module has been parsed and flattened, it is turned into a large list of instructions, +/// When a module has been parsed and flattened, it is turned into a large list of instructions, /// These are stored in [LinkInfo::instructions]`: FlatAlloc` -/// +/// /// Instructions are indexed with [FlatID] -/// -/// One may ask: Why have [Expression], [WrittenType], etc refer to others by [FlatID], instead of a recursive datastructure? +/// +/// One may ask: Why have [Expression], [WrittenType], etc refer to others by [FlatID], instead of a recursive datastructure? /// The reason is that later representations, such as [crate::instantiation::RealWire] and other structures can still refer to intermediate parts of expressions -/// They can simply refer to the [FlatID] of these instructions, instead of some convoluted other representation. -/// -/// When executing, the instructions are processed in order. Control flow instructions like [IfStatement] and [ForStatement] can cause the executor to repeat or skip sections. +/// They can simply refer to the [FlatID] of these instructions, instead of some convoluted other representation. +/// +/// When executing, the instructions are processed in order. Control flow instructions like [IfStatement] and [ForStatement] can cause the executor to repeat or skip sections. #[derive(Debug)] pub enum Instruction { SubModule(SubModuleInstance), @@ -797,10 +794,10 @@ impl Instruction { /// Small wrapper struct for allocating the Hindley-Milner variables /// required for [crate::typing::abstract_type::AbstractType::Unknown] and [DomainType::DomainVariable] -/// +/// /// See [crate::typing::type_inference::HindleyMilner] #[derive(Debug, Clone)] pub struct TypingAllocator { pub type_variable_alloc: UUIDAllocator, - pub domain_variable_alloc: UUIDAllocator + pub domain_variable_alloc: UUIDAllocator, } diff --git a/src/flattening/name_context.rs b/src/flattening/name_context.rs index b053d0b..2be9683 100644 --- a/src/flattening/name_context.rs +++ b/src/flattening/name_context.rs @@ -1,9 +1,8 @@ - -/// This keeps track of the variables that are in the current scope. -/// +/// This keeps track of the variables that are in the current scope. +/// /// Each [super::Declaration] and [super::SubModuleInstance] should be added here at some point -/// -/// Must be maintained manually. +/// +/// Must be maintained manually. /// When a new scope is entered, call [Self::new_frame], /// when exiting a scope call [Self::pop_frame] pub struct LocalVariableContext<'file, Obj: Copy> { diff --git a/src/flattening/parser.rs b/src/flattening/parser.rs index 3a2e9ff..942e5af 100644 --- a/src/flattening/parser.rs +++ b/src/flattening/parser.rs @@ -31,10 +31,10 @@ fn print_current_node_indented<'ft>(file_text: &'ft FileText, cursor: &TreeCurso node_name } -/// Wraps the tree-sitter [TreeCursor] for a more functional-style interface. -/// -/// Especially with regards to going up and down the syntax tree, this module provides [Self::go_down] and friends. -/// +/// Wraps the tree-sitter [TreeCursor] for a more functional-style interface. +/// +/// Especially with regards to going up and down the syntax tree, this module provides [Self::go_down] and friends. +/// /// This module also handles documentation comment gathering #[derive(Clone)] pub struct Cursor<'t> { diff --git a/src/flattening/typechecking.rs b/src/flattening/typechecking.rs index 0d70b5e..a12a5c3 100644 --- a/src/flattening/typechecking.rs +++ b/src/flattening/typechecking.rs @@ -6,9 +6,7 @@ use crate::typing::template::ParameterKind; use crate::typing::type_inference::{FailedUnification, HindleyMilner}; use crate::debug::SpanDebugger; -use crate::linker::{ - GlobalResolver, GlobalUUID, AFTER_TYPECHECK_CP -}; +use crate::linker::{GlobalResolver, GlobalUUID, AFTER_TYPECHECK_CP}; use crate::typing::{ abstract_type::{DomainType, TypeUnifier, BOOL_TYPE, INT_TYPE}, @@ -18,7 +16,7 @@ use crate::typing::{ use super::*; pub fn typecheck_all_modules(linker: &mut Linker) { - let module_uuids : Vec = linker.modules.iter().map(|(id, _md)| id).collect(); + let module_uuids: Vec = linker.modules.iter().map(|(id, _md)| id).collect(); for module_uuid in module_uuids { let global_id = GlobalUUID::Module(module_uuid); let errs_globals = GlobalResolver::take_errors_globals(linker, global_id); @@ -28,17 +26,15 @@ pub fn typecheck_all_modules(linker: &mut Linker) { let ctx_info_string = format!("Typechecking {}", &working_on.link_info.name); println!("{ctx_info_string}"); - let mut span_debugger = SpanDebugger::new( - &ctx_info_string, - &linker.files[working_on.link_info.file], - ); + let mut span_debugger = + SpanDebugger::new(&ctx_info_string, &linker.files[working_on.link_info.file]); let mut context = TypeCheckingContext { - globals : &globals, + globals: &globals, errors: &globals.errors, type_checker: TypeUnifier::new( &working_on.link_info.template_parameters, - working_on.link_info.type_variable_alloc.clone() + working_on.link_info.type_variable_alloc.clone(), ), runtime_condition_stack: Vec::new(), working_on: &working_on.link_info, @@ -51,10 +47,17 @@ pub fn typecheck_all_modules(linker: &mut Linker) { // Grab another mutable copy of md so it doesn't force a borrow conflict let working_on_mut = &mut linker.modules[module_uuid]; - apply_types(type_checker, working_on_mut, &errs_and_globals.0, &linker.types); + apply_types( + type_checker, + working_on_mut, + &errs_and_globals.0, + &linker.types, + ); + + working_on_mut + .link_info + .reabsorb_errors_globals(errs_and_globals, AFTER_TYPECHECK_CP); - working_on_mut.link_info.reabsorb_errors_globals(errs_and_globals, AFTER_TYPECHECK_CP); - span_debugger.defuse(); } } @@ -95,17 +98,19 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { let port_interface = submodule_module.ports[port].domain; let port_local_domain = submodule_inst.local_interface_domains[port_interface]; let typ = AbstractType::Unknown(self.type_checker.alloc_typ_variable()); - self.type_checker.unify_with_written_type_substitute_templates_must_succeed(&decl.typ_expr, &typ, &submodule_inst.module_ref.template_arg_types); + self.type_checker + .unify_with_written_type_substitute_templates_must_succeed( + &decl.typ_expr, + &typ, + &submodule_inst.module_ref.template_arg_types, + ); FullType { typ, domain: port_local_domain.clone(), } } - fn get_wire_ref_info( - &self, - wire_ref_root: &WireReferenceRoot, - ) -> ErrorInfo { + fn get_wire_ref_info(&self, wire_ref_root: &WireReferenceRoot) -> ErrorInfo { match wire_ref_root { WireReferenceRoot::LocalDecl(id, _) => { let decl_root = self.working_on.instructions[*id].unwrap_declaration(); @@ -122,22 +127,27 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { } } - /// Wire references are used in two contexts: + /// Wire references are used in two contexts: /// - Reading from a wire /// - Writing to a wire - /// + /// /// The AbstractTypes just get unified - /// - /// But the domains behave differently. - /// - Reading: - /// The domains combine to form the lowest common denominator. + /// + /// But the domains behave differently. + /// - Reading: + /// The domains combine to form the lowest common denominator. /// If all are generative this becomes generative /// At least one non-generative domain makes the whole thing non-generative /// It should be supplied with a generative output_typ domain when generative, and an unknown domain variable otherwise - /// - Writing: + /// - Writing: /// The output_typ domain should be generative when wire_ref.root is generative, or a generative value is required such as with "initial" /// When wire_ref.root is not generative, it should be an unknown domain variable - fn typecheck_wire_reference(&self, wire_ref: &WireReference, whole_span: Span, output_typ: &FullType) { + fn typecheck_wire_reference( + &self, + wire_ref: &WireReference, + whole_span: Span, + output_typ: &FullType, + ) { let root_type = match &wire_ref.root { WireReferenceRoot::LocalDecl(id, _) => { let decl_root = self.working_on.instructions[*id].unwrap_declaration(); @@ -145,45 +155,67 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { } WireReferenceRoot::NamedConstant(cst) => { self.typecheck_template_global(cst); - + let linker_cst = &self.globals[cst.id]; - let decl = linker_cst.link_info.instructions[linker_cst.output_decl].unwrap_declaration(); + let decl = + linker_cst.link_info.instructions[linker_cst.output_decl].unwrap_declaration(); let typ = AbstractType::Unknown(self.type_checker.alloc_typ_variable()); - self.type_checker.unify_with_written_type_substitute_templates_must_succeed(&decl.typ_expr, &typ, &cst.template_arg_types); + self.type_checker + .unify_with_written_type_substitute_templates_must_succeed( + &decl.typ_expr, + &typ, + &cst.template_arg_types, + ); FullType { typ, - domain: DomainType::Generative + domain: DomainType::Generative, } } WireReferenceRoot::SubModulePort(port) => { self.get_type_of_port(port.port, port.submodule_decl) } }; - self.type_checker.unify_domains(&root_type.domain, &output_typ.domain, whole_span, "wire reference root with root type"); - + self.type_checker.unify_domains( + &root_type.domain, + &output_typ.domain, + whole_span, + "wire reference root with root type", + ); + let mut current_type_in_progress = root_type.typ; for p in &wire_ref.path { match p { &WireReferencePathElement::ArrayAccess { idx, bracket_span } => { let idx_expr = self.working_on.instructions[idx].unwrap_expression(); - let new_resulting_variable = AbstractType::Unknown(self.type_checker.alloc_typ_variable()); + let new_resulting_variable = + AbstractType::Unknown(self.type_checker.alloc_typ_variable()); let arr_span = bracket_span.outer_span(); self.type_checker.typecheck_array_access( ¤t_type_in_progress, &idx_expr.typ.typ, arr_span, idx_expr.span, - &new_resulting_variable + &new_resulting_variable, ); - self.type_checker.unify_domains(&idx_expr.typ.domain, &output_typ.domain, idx_expr.span, "array access index"); + self.type_checker.unify_domains( + &idx_expr.typ.domain, + &output_typ.domain, + idx_expr.span, + "array access index", + ); current_type_in_progress = new_resulting_variable; } } } - self.type_checker.type_substitutor.unify_report_error(¤t_type_in_progress, &output_typ.typ, whole_span, "variable reference"); + self.type_checker.type_substitutor.unify_report_error( + ¤t_type_in_progress, + &output_typ.typ, + whole_span, + "variable reference", + ); } fn control_flow_visit_instruction(&mut self, inst_id: FlatID) { @@ -199,8 +231,10 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { } Instruction::FuncCall(_) => {} Instruction::Declaration(decl) => { - // For both runtime, and compiletime declarations. - decl.declaration_runtime_depth.set(self.runtime_condition_stack.len()).unwrap(); + // For both runtime, and compiletime declarations. + decl.declaration_runtime_depth + .set(self.runtime_condition_stack.len()) + .unwrap(); } Instruction::Expression(_) => {} Instruction::Write(conn) => { @@ -215,11 +249,13 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { (decl, self.errors.file) } WireReferenceRoot::NamedConstant(cst) => { - self.errors.error(cst.name_span, "Cannot assign to a global"); + self.errors + .error(cst.name_span, "Cannot assign to a global"); return; } WireReferenceRoot::SubModulePort(port) => { - let module_port_decl = self.get_decl_of_module_port(port.port, port.submodule_decl); + let module_port_decl = + self.get_decl_of_module_port(port.port, port.submodule_decl); if !module_port_decl.0.decl_kind.is_io_port().unwrap() { self.errors @@ -239,17 +275,15 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { if decl.identifier_type.is_generative() { // Check that this generative declaration isn't used in a non-compiletime if if let Some(root_flat) = conn.to.root.get_root_flat() { - let to_decl = self.working_on.instructions[root_flat] - .unwrap_declaration(); + let to_decl = + self.working_on.instructions[root_flat].unwrap_declaration(); - let found_decl_depth = *to_decl.declaration_runtime_depth.get().unwrap(); - if self.runtime_condition_stack.len() > found_decl_depth - { + let found_decl_depth = + *to_decl.declaration_runtime_depth.get().unwrap(); + if self.runtime_condition_stack.len() > found_decl_depth { let err_ref = self.errors.error(conn.to_span, "Cannot write to generative variables in runtime conditional block"); err_ref.info_obj_different_file(decl, file); - for elem in &self.runtime_condition_stack - [found_decl_depth..] - { + for elem in &self.runtime_condition_stack[found_decl_depth..] { err_ref.info((elem.span, file), "Runtime condition here"); } } @@ -269,7 +303,8 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { } } Instruction::IfStatement(if_stmt) => { - let condition_expr = self.working_on.instructions[if_stmt.condition].unwrap_expression(); + let condition_expr = + self.working_on.instructions[if_stmt.condition].unwrap_expression(); if !condition_expr.typ.domain.is_generative() { self.runtime_condition_stack.push(ConditionStackElem { ends_at: if_stmt.else_end, @@ -292,17 +327,17 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { for (parameter_id, argument_type) in &global_ref.template_arg_types { let parameter = &target_link_info.template_parameters[parameter_id]; match ¶meter.kind { - ParameterKind::Type(_) => {} // Do nothing, nothing to unify with. Maybe in the future traits? + ParameterKind::Type(_) => {} // Do nothing, nothing to unify with. Maybe in the future traits? ParameterKind::Generative(parameter) => { - let decl = target_link_info.instructions[parameter.declaration_instruction].unwrap_declaration(); - - self.type_checker.unify_with_written_type_substitute_templates_must_succeed( - &decl.typ_expr, - &argument_type, - &global_ref.template_arg_types // Yes that's right. We already must substitute the templates for type variables here - ); - + let decl = target_link_info.instructions[parameter.declaration_instruction] + .unwrap_declaration(); + self.type_checker + .unify_with_written_type_substitute_templates_must_succeed( + &decl.typ_expr, + &argument_type, + &global_ref.template_arg_types, // Yes that's right. We already must substitute the templates for type variables here + ); } } @@ -311,7 +346,8 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { TemplateArgKind::Type(wr_typ) => { self.typecheck_written_type(wr_typ); // This slot will not have been filled out yet - self.type_checker.unify_with_written_type_must_succeed(wr_typ, argument_type); + self.type_checker + .unify_with_written_type_must_succeed(wr_typ, argument_type); } TemplateArgKind::Value(val) => { let argument_expr = self.working_on.instructions[*val].unwrap_expression(); @@ -320,7 +356,7 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { &argument_expr.typ.typ, &argument_type, argument_expr.span, - "generative template argument" + "generative template argument", ); } } @@ -328,10 +364,10 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { } } - /// Critically, this is different from [TypeUnifier::unify_with_written_type]. - /// That one unifies a given typ with the written type, without checking the written type. - /// - /// This function checks the written type itself. + /// Critically, this is different from [TypeUnifier::unify_with_written_type]. + /// That one unifies a given typ with the written type, without checking the written type. + /// + /// This function checks the written type itself. fn typecheck_written_type(&self, wr_typ: &WrittenType) { match wr_typ { WrittenType::Error(_) => {} @@ -349,7 +385,7 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { &idx_expr.typ.typ, &INT_TYPE, idx_expr.span, - "array size" + "array size", ); } } @@ -365,7 +401,12 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { /// outside of a condition block fn join_with_condition(&self, ref_domain: &DomainType, span: Span) { if let Some(condition_domain) = self.get_current_condition_domain() { - self.type_checker.unify_domains(ref_domain, &condition_domain.0, span, "condition join"); + self.type_checker.unify_domains( + ref_domain, + &condition_domain.0, + span, + "condition join", + ); } } @@ -382,22 +423,24 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { &latency_specifier_expr.typ.typ, &INT_TYPE, latency_specifier_expr.span, - "latency specifier" + "latency specifier", ); } - + self.typecheck_written_type(&decl.typ_expr); // Unify with the type written in the source code - self.type_checker.unify_with_written_type_must_succeed(&decl.typ_expr, &decl.typ.typ); + self.type_checker + .unify_with_written_type_must_succeed(&decl.typ_expr, &decl.typ.typ); } Instruction::IfStatement(stm) => { - let condition_expr = &self.working_on.instructions[stm.condition].unwrap_expression(); + let condition_expr = + &self.working_on.instructions[stm.condition].unwrap_expression(); self.type_checker.typecheck_write_to_abstract( &condition_expr.typ.typ, &BOOL_TYPE, condition_expr.span, - "if statement condition" + "if statement condition", ); } Instruction::ForStatement(stm) => { @@ -409,13 +452,13 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { &start.typ.typ, &loop_var.typ.typ, start.span, - "for loop start" + "for loop start", ); self.type_checker.typecheck_write_to_abstract( &end.typ.typ, &loop_var.typ.typ, end.span, - "for loop end" + "for loop end", ); } Instruction::Expression(expr) => { @@ -429,7 +472,7 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { op, &right_expr.typ, &expr.typ, - right_expr.span + right_expr.span, ); } &ExpressionSource::BinaryOp { op, left, right } => { @@ -441,10 +484,13 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { &right_expr.typ, left_expr.span, right_expr.span, - &expr.typ + &expr.typ, ) } - ExpressionSource::Constant(value) => self.type_checker.unify_with_constant(&expr.typ.typ, value, expr.span), + ExpressionSource::Constant(value) => { + self.type_checker + .unify_with_constant(&expr.typ.typ, value, expr.span) + } }; } Instruction::FuncCall(fc) => { @@ -464,8 +510,11 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { &write_to_type, from_expr.span, || { - ("function argument".to_string(), vec![decl.make_info(file).unwrap()]) - } + ( + "function argument".to_string(), + vec![decl.make_info(file).unwrap()], + ) + }, ); } } @@ -484,12 +533,12 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { from_expr.span, || { let write_context = match conn.write_modifiers { - WriteModifiers::Connection {..} => "connection", - WriteModifiers::Initial { initial_kw_span: _ } => "initial value" + WriteModifiers::Connection { .. } => "connection", + WriteModifiers::Initial { initial_kw_span: _ } => "initial value", }; let declared_here = self.get_wire_ref_info(&conn.to.root); (write_context.to_string(), vec![declared_here]) - } + }, ); } } @@ -500,7 +549,7 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { Some((last.domain, last.span)) } - /// Should be followed up by a [apply_types] call to actually apply all the checked types. + /// Should be followed up by a [apply_types] call to actually apply all the checked types. fn typecheck(&mut self) { for elem_id in self.working_on.instructions.id_range() { self.control_flow_visit_instruction(elem_id); @@ -509,21 +558,23 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { } } - // ====== Free functions for actually applying the result of type checking ====== pub fn apply_types( mut type_checker: TypeUnifier, working_on: &mut Module, errors: &ErrorCollector, - types: &ArenaAllocator + types: &ArenaAllocator, ) { - // Set the remaining domain variables that aren't associated with a module port. - // We just find domain IDs that haven't been - let mut leftover_domain_alloc = UUIDAllocator::new_start_from(working_on.domains.get_next_alloc_id()); + // Set the remaining domain variables that aren't associated with a module port. + // We just find domain IDs that haven't been + let mut leftover_domain_alloc = + UUIDAllocator::new_start_from(working_on.domains.get_next_alloc_id()); for d in type_checker.domain_substitutor.iter() { if d.get().is_none() { - assert!(d.set(DomainType::Physical(leftover_domain_alloc.alloc())).is_ok()); + assert!(d + .set(DomainType::Physical(leftover_domain_alloc.alloc())) + .is_ok()); } } @@ -532,7 +583,10 @@ pub fn apply_types( if let Some(work_on_domain) = working_on.domains.get(id) { work_on_domain.clone() } else { - DomainInfo {name: format!("domain_{}", id.get_hidden_value()), name_span: None} + DomainInfo { + name: format!("domain_{}", id.get_hidden_value()), + name_span: None, + } } }); @@ -547,16 +601,25 @@ pub fn apply_types( } } } - Instruction::Declaration(decl) => type_checker.finalize_type(types, &mut decl.typ, decl.name_span, errors), - Instruction::Write(Write { to_type, to_span, to, .. }) => { + Instruction::Declaration(decl) => { + type_checker.finalize_type(types, &mut decl.typ, decl.name_span, errors) + } + Instruction::Write(Write { + to_type, + to_span, + to, + .. + }) => { type_checker.finalize_type(types, to_type, *to_span, errors); if let WireReferenceRoot::NamedConstant(cst) = &mut to.root { type_checker.finalize_global_ref(types, cst, errors); } } - // TODO Submodule domains may not be crossed either? + // TODO Submodule domains may not be crossed either? Instruction::SubModule(sm) => { - for (_domain_id_in_submodule, domain_assigned_to_it_here) in &mut sm.local_interface_domains { + for (_domain_id_in_submodule, domain_assigned_to_it_here) in + &mut sm.local_interface_domains + { type_checker.finalize_domain_type(domain_assigned_to_it_here); } type_checker.finalize_global_ref(types, &mut sm.module_ref, errors); @@ -566,13 +629,24 @@ pub fn apply_types( } // Print all errors - for FailedUnification{mut found, mut expected, span, context, infos} in type_checker.type_substitutor.extract_errors() { + for FailedUnification { + mut found, + mut expected, + span, + context, + infos, + } in type_checker.type_substitutor.extract_errors() + { // Not being able to fully substitute is not an issue. We just display partial types let _ = found.fully_substitute(&type_checker.type_substitutor); let _ = expected.fully_substitute(&type_checker.type_substitutor); - let expected_name = expected.display(types, &type_checker.template_type_names).to_string(); - let found_name = found.display(types, &type_checker.template_type_names).to_string(); + let expected_name = expected + .display(types, &type_checker.template_type_names) + .to_string(); + let found_name = found + .display(types, &type_checker.template_type_names) + .to_string(); errors .error(span, format!("Typing Error: {context} expects a {expected_name} but was given a {found_name}")) .add_info_list(infos); @@ -582,7 +656,14 @@ pub fn apply_types( "{expected_name} != {found_name}" ); } - for FailedUnification{mut found, mut expected, span, context, infos} in type_checker.domain_substitutor.extract_errors() { + for FailedUnification { + mut found, + mut expected, + span, + context, + infos, + } in type_checker.domain_substitutor.extract_errors() + { assert!(found.fully_substitute(&type_checker.domain_substitutor)); assert!(expected.fully_substitute(&type_checker.domain_substitutor)); diff --git a/src/flattening/walk.rs b/src/flattening/walk.rs index 4416dd7..b049359 100644 --- a/src/flattening/walk.rs +++ b/src/flattening/walk.rs @@ -2,7 +2,7 @@ use crate::typing::template::{TVec, TemplateArg, TemplateArgKind}; use crate::prelude::*; -use super::{WireReferencePathElement, WireReferenceRoot, ExpressionSource, WrittenType}; +use super::{ExpressionSource, WireReferencePathElement, WireReferenceRoot, WrittenType}; impl ExpressionSource { /// Enumerates all instructions that this instruction depends on. This includes (maybe compiletime) wires, and submodules. @@ -13,10 +13,12 @@ impl ExpressionSource { WireReferenceRoot::LocalDecl(decl_id, _) => func(*decl_id), WireReferenceRoot::NamedConstant(cst) => { for (_id, arg) in &cst.template_args { - let Some(arg) = arg else {continue}; + let Some(arg) = arg else { continue }; match &arg.kind { - TemplateArgKind::Type(written_type) => written_type.for_each_generative_input(func), - TemplateArgKind::Value(uuid) => {func(*uuid)} + TemplateArgKind::Type(written_type) => { + written_type.for_each_generative_input(func) + } + TemplateArgKind::Value(uuid) => func(*uuid), } } } diff --git a/src/instantiation/concrete_typecheck.rs b/src/instantiation/concrete_typecheck.rs index 4f9f94d..d1e49b0 100644 --- a/src/instantiation/concrete_typecheck.rs +++ b/src/instantiation/concrete_typecheck.rs @@ -1,4 +1,3 @@ - use std::ops::Deref; use crate::errors::ErrorInfoObject; @@ -8,7 +7,9 @@ use crate::typing::concrete_type::ConcreteGlobalReference; use crate::typing::template::TemplateArgKind; use crate::typing::{ concrete_type::{ConcreteType, BOOL_CONCRETE_TYPE, INT_CONCRETE_TYPE}, - type_inference::{FailedUnification, DelayedConstraint, DelayedConstraintStatus, DelayedConstraintsList}, + type_inference::{ + DelayedConstraint, DelayedConstraintStatus, DelayedConstraintsList, FailedUnification, + }, }; use super::*; @@ -19,15 +20,22 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { fn walk_type_along_path( &self, mut current_type_in_progress: ConcreteType, - path: &[RealWirePathElem] + path: &[RealWirePathElem], ) -> ConcreteType { for p in path { let typ_after_applying_array = ConcreteType::Unknown(self.type_substitutor.alloc()); match p { - RealWirePathElem::ArrayAccess {span: _, idx_wire: _} => { // TODO #28 integer size <-> array bound check + RealWirePathElem::ArrayAccess { + span: _, + idx_wire: _, + } => { + // TODO #28 integer size <-> array bound check let arr_size = ConcreteType::Unknown(self.type_substitutor.alloc()); let arr_box = Box::new((typ_after_applying_array.clone(), arr_size)); - self.type_substitutor.unify_must_succeed(¤t_type_in_progress, &ConcreteType::Array(arr_box)); + self.type_substitutor.unify_must_succeed( + ¤t_type_in_progress, + &ConcreteType::Array(arr_box), + ); current_type_in_progress = typ_after_applying_array; } } @@ -37,7 +45,10 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { } fn make_array_of(&self, concrete_typ: ConcreteType) -> ConcreteType { - ConcreteType::Array(Box::new((concrete_typ, ConcreteType::Unknown(self.type_substitutor.alloc())))) + ConcreteType::Array(Box::new(( + concrete_typ, + ConcreteType::Unknown(self.type_substitutor.alloc()), + ))) } fn typecheck_all_wires(&self) { @@ -54,8 +65,14 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { } for s in sources { let source_typ = &self.wires[s.from].typ; - let destination_typ = self.walk_type_along_path(self.wires[this_wire_id].typ.clone(), &s.to_path); - self.type_substitutor.unify_report_error(&destination_typ, &source_typ, span, "write wire access"); + let destination_typ = self + .walk_type_along_path(self.wires[this_wire_id].typ.clone(), &s.to_path); + self.type_substitutor.unify_report_error( + &destination_typ, + &source_typ, + span, + "write wire access", + ); } } &RealWireDataSource::UnaryOp { op, right } => { @@ -63,38 +80,100 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { let (input_typ, output_typ) = match op { UnaryOperator::Not => (BOOL_CONCRETE_TYPE, BOOL_CONCRETE_TYPE), UnaryOperator::Negate => (INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), - UnaryOperator::And | UnaryOperator::Or | UnaryOperator::Xor => (self.make_array_of(BOOL_CONCRETE_TYPE), BOOL_CONCRETE_TYPE), - UnaryOperator::Sum | UnaryOperator::Product => (self.make_array_of(INT_CONCRETE_TYPE), INT_CONCRETE_TYPE), + UnaryOperator::And | UnaryOperator::Or | UnaryOperator::Xor => { + (self.make_array_of(BOOL_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) + } + UnaryOperator::Sum | UnaryOperator::Product => { + (self.make_array_of(INT_CONCRETE_TYPE), INT_CONCRETE_TYPE) + } }; - self.type_substitutor.unify_report_error(&self.wires[right].typ, &input_typ, span, "unary input"); - self.type_substitutor.unify_report_error(&self.wires[this_wire_id].typ, &output_typ, span, "unary output"); + self.type_substitutor.unify_report_error( + &self.wires[right].typ, + &input_typ, + span, + "unary input", + ); + self.type_substitutor.unify_report_error( + &self.wires[this_wire_id].typ, + &output_typ, + span, + "unary output", + ); } &RealWireDataSource::BinaryOp { op, left, right } => { // TODO overloading let ((in_left, in_right), out) = match op { - BinaryOperator::And => ((BOOL_CONCRETE_TYPE, BOOL_CONCRETE_TYPE), BOOL_CONCRETE_TYPE), - BinaryOperator::Or => ((BOOL_CONCRETE_TYPE, BOOL_CONCRETE_TYPE), BOOL_CONCRETE_TYPE), - BinaryOperator::Xor => ((BOOL_CONCRETE_TYPE, BOOL_CONCRETE_TYPE), BOOL_CONCRETE_TYPE), - BinaryOperator::Add => ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), INT_CONCRETE_TYPE), - BinaryOperator::Subtract => ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), INT_CONCRETE_TYPE), - BinaryOperator::Multiply => ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), INT_CONCRETE_TYPE), - BinaryOperator::Divide => ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), INT_CONCRETE_TYPE), - BinaryOperator::Modulo => ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), INT_CONCRETE_TYPE), - BinaryOperator::Equals => ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE), - BinaryOperator::NotEquals => ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE), - BinaryOperator::GreaterEq => ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE), - BinaryOperator::Greater => ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE), - BinaryOperator::LesserEq => ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE), - BinaryOperator::Lesser => ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE), + BinaryOperator::And => { + ((BOOL_CONCRETE_TYPE, BOOL_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) + } + BinaryOperator::Or => { + ((BOOL_CONCRETE_TYPE, BOOL_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) + } + BinaryOperator::Xor => { + ((BOOL_CONCRETE_TYPE, BOOL_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) + } + BinaryOperator::Add => { + ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), INT_CONCRETE_TYPE) + } + BinaryOperator::Subtract => { + ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), INT_CONCRETE_TYPE) + } + BinaryOperator::Multiply => { + ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), INT_CONCRETE_TYPE) + } + BinaryOperator::Divide => { + ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), INT_CONCRETE_TYPE) + } + BinaryOperator::Modulo => { + ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), INT_CONCRETE_TYPE) + } + BinaryOperator::Equals => { + ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) + } + BinaryOperator::NotEquals => { + ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) + } + BinaryOperator::GreaterEq => { + ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) + } + BinaryOperator::Greater => { + ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) + } + BinaryOperator::LesserEq => { + ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) + } + BinaryOperator::Lesser => { + ((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) + } }; - self.type_substitutor.unify_report_error(&self.wires[this_wire_id].typ, &out, span, "binary output"); - self.type_substitutor.unify_report_error(&self.wires[left].typ, &in_left, span, "binary left"); - self.type_substitutor.unify_report_error(&self.wires[right].typ, &in_right, span, "binary right"); + self.type_substitutor.unify_report_error( + &self.wires[this_wire_id].typ, + &out, + span, + "binary output", + ); + self.type_substitutor.unify_report_error( + &self.wires[left].typ, + &in_left, + span, + "binary left", + ); + self.type_substitutor.unify_report_error( + &self.wires[right].typ, + &in_right, + span, + "binary right", + ); } RealWireDataSource::Select { root, path } => { let found_typ = self.walk_type_along_path(self.wires[*root].typ.clone(), path); - self.type_substitutor.unify_report_error(&found_typ, &self.wires[this_wire_id].typ, span, "wire access"); + self.type_substitutor.unify_report_error( + &found_typ, + &self.wires[this_wire_id].typ, + span, + "wire access", + ); } RealWireDataSource::Constant { value } => { assert!( @@ -110,7 +189,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { for (_id, w) in &mut self.wires { if w.typ.fully_substitute(&self.type_substitutor) == false { let typ_as_str = w.typ.display(&self.linker.types); - + let span = self.md.get_instruction_span(w.original_instruction); span.debug(); self.errors.error(span, format!("Could not finalize this type, some parameters were still unknown: {typ_as_str}")); @@ -118,11 +197,18 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { } // Print all errors - for FailedUnification{mut found, mut expected, span, context, infos} in self.type_substitutor.extract_errors() { + for FailedUnification { + mut found, + mut expected, + span, + context, + infos, + } in self.type_substitutor.extract_errors() + { // Not being able to fully substitute is not an issue. We just display partial types let _ = found.fully_substitute(&self.type_substitutor); let _ = expected.fully_substitute(&self.type_substitutor); - + let expected_name = expected.display(&self.linker.types).to_string(); let found_name = found.display(&self.linker.types).to_string(); self.errors @@ -137,7 +223,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { } pub fn typecheck(&mut self) { - let mut delayed_constraints : DelayedConstraintsList = DelayedConstraintsList::new(); + let mut delayed_constraints: DelayedConstraintsList = DelayedConstraintsList::new(); for (sm_id, sm) in &self.submodules { let sub_module = &self.linker.modules[sm.module_uuid]; @@ -145,14 +231,21 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { let wire = &self.wires[p.maps_to_wire]; let port_decl_instr = sub_module.ports[port_id].declaration_instruction; - let port_decl = sub_module.link_info.instructions[port_decl_instr].unwrap_declaration(); - - let typ_for_inference = concretize_written_type_with_possible_template_args(&port_decl.typ_expr, &sm.template_args, &sub_module.link_info, &self.type_substitutor); - - self.type_substitutor.unify_must_succeed(&wire.typ, &typ_for_inference); + let port_decl = + sub_module.link_info.instructions[port_decl_instr].unwrap_declaration(); + + let typ_for_inference = concretize_written_type_with_possible_template_args( + &port_decl.typ_expr, + &sm.template_args, + &sub_module.link_info, + &self.type_substitutor, + ); + + self.type_substitutor + .unify_must_succeed(&wire.typ, &typ_for_inference); } - - delayed_constraints.push(SubmoduleTypecheckConstraint {sm_id}); + + delayed_constraints.push(SubmoduleTypecheckConstraint { sm_id }); } self.typecheck_all_wires(); @@ -164,13 +257,13 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { } struct SubmoduleTypecheckConstraint { - sm_id: SubModuleID + sm_id: SubModuleID, } -/// Part of Template Value Inference. -/// +/// Part of Template Value Inference. +/// /// Specifically, for code like this: -/// +/// /// ```sus /// module add_all #(int Size) { /// input int[Size] arr // We're targeting the 'Size' within the array size @@ -179,11 +272,19 @@ struct SubmoduleTypecheckConstraint { /// ``` fn can_expression_be_value_inferred(link_info: &LinkInfo, expr_id: FlatID) -> Option { let expr = link_info.instructions[expr_id].unwrap_expression(); - let ExpressionSource::WireRef(wr) = &expr.source else {return None}; - if !wr.path.is_empty() {return None} // Must be a plain, no fuss reference to a de - let WireReferenceRoot::LocalDecl(wire_declaration, _span) = &wr.root else {return None}; + let ExpressionSource::WireRef(wr) = &expr.source else { + return None; + }; + if !wr.path.is_empty() { + return None; + } // Must be a plain, no fuss reference to a de + let WireReferenceRoot::LocalDecl(wire_declaration, _span) = &wr.root else { + return None; + }; let template_arg_decl = link_info.instructions[*wire_declaration].unwrap_declaration(); - let DeclarationKind::GenerativeInput(template_id) = &template_arg_decl.decl_kind else {return None}; + let DeclarationKind::GenerativeInput(template_id) = &template_arg_decl.decl_kind else { + return None; + }; Some(*template_id) } @@ -191,41 +292,58 @@ fn concretize_written_type_with_possible_template_args( written_typ: &WrittenType, template_args: &TVec, link_info: &LinkInfo, - type_substitutor: &TypeSubstitutor + type_substitutor: &TypeSubstitutor, ) -> ConcreteType { match written_typ { WrittenType::Error(_span) => ConcreteType::Unknown(type_substitutor.alloc()), WrittenType::TemplateVariable(_span, uuid) => template_args[*uuid].clone(), WrittenType::Named(global_reference) => { - let object_template_args : TVec = global_reference.template_args.map(|(_arg_id, arg)| -> ConcreteType { - if let Some(arg) = arg { - match &arg.kind { - TemplateArgKind::Type(arg_wr_typ) => { - concretize_written_type_with_possible_template_args(arg_wr_typ, template_args, link_info, type_substitutor) - } - TemplateArgKind::Value(uuid) => { - if let Some(found_template_arg) = can_expression_be_value_inferred(link_info, *uuid) { - template_args[found_template_arg].clone() - } else { - ConcreteType::Unknown(type_substitutor.alloc()) + let object_template_args: TVec = + global_reference + .template_args + .map(|(_arg_id, arg)| -> ConcreteType { + if let Some(arg) = arg { + match &arg.kind { + TemplateArgKind::Type(arg_wr_typ) => { + concretize_written_type_with_possible_template_args( + arg_wr_typ, + template_args, + link_info, + type_substitutor, + ) + } + TemplateArgKind::Value(uuid) => { + if let Some(found_template_arg) = + can_expression_be_value_inferred(link_info, *uuid) + { + template_args[found_template_arg].clone() + } else { + ConcreteType::Unknown(type_substitutor.alloc()) + } + } } + } else { + ConcreteType::Unknown(type_substitutor.alloc()) } - } - } else { - ConcreteType::Unknown(type_substitutor.alloc()) - } - }); + }); - ConcreteType::Named(ConcreteGlobalReference{ + ConcreteType::Named(ConcreteGlobalReference { id: global_reference.id, - template_args: object_template_args + template_args: object_template_args, }) } WrittenType::Array(_span, arr_box) => { let (arr_content_wr, arr_idx_id, _arr_brackets) = arr_box.deref(); - let arr_content_concrete = concretize_written_type_with_possible_template_args(arr_content_wr, template_args, link_info, type_substitutor); - let arr_idx_concrete = if let Some(found_template_arg) = can_expression_be_value_inferred(link_info, *arr_idx_id) { + let arr_content_concrete = concretize_written_type_with_possible_template_args( + arr_content_wr, + template_args, + link_info, + type_substitutor, + ); + let arr_idx_concrete = if let Some(found_template_arg) = + can_expression_be_value_inferred(link_info, *arr_idx_id) + { template_args[found_template_arg].clone() } else { ConcreteType::Unknown(type_substitutor.alloc()) @@ -244,18 +362,20 @@ impl SubmoduleTypecheckConstraint { } impl DelayedConstraint> for SubmoduleTypecheckConstraint { - fn try_apply(&mut self, context : &mut InstantiationContext) -> DelayedConstraintStatus { - // Try to infer template arguments based on the connections to the ports of the module. + fn try_apply(&mut self, context: &mut InstantiationContext) -> DelayedConstraintStatus { + // Try to infer template arguments based on the connections to the ports of the module. self.try_infer_latency_counts(context); let sm = &mut context.submodules[self.sm_id]; - let submod_instr = context.md.link_info.instructions[sm.original_instruction].unwrap_submodule(); + let submod_instr = + context.md.link_info.instructions[sm.original_instruction].unwrap_submodule(); let sub_module = &context.linker.modules[sm.module_uuid]; // Check if there's any argument that isn't known for (_id, arg) in &mut sm.template_args { - if !arg.fully_substitute(&context.type_substitutor) { // We don't actually *need* to already fully_substitute here, but it's convenient and saves some work + if !arg.fully_substitute(&context.type_substitutor) { + // We don't actually *need* to already fully_substitute here, but it's convenient and saves some work return DelayedConstraintStatus::NoProgress; } } @@ -285,25 +405,32 @@ impl DelayedConstraint> for SubmoduleTypecheckConst (Some(_concrete_port), None) => { // Port is enabled, but not used let source_code_port = &sub_module.ports[port_id]; - context.errors + context + .errors .warn( submod_instr.module_ref.get_total_span(), format!("Unused port '{}'", source_code_port.name), ) - .info_obj_different_file( - source_code_port, - sub_module.link_info.file, - ) + .info_obj_different_file(source_code_port, sub_module.link_info.file) .info_obj_same_file(submod_instr); } (Some(concrete_port), Some(connecting_wire)) => { let wire = &context.wires[connecting_wire.maps_to_wire]; - context.type_substitutor.unify_report_error(&wire.typ, &concrete_port.typ, submod_instr.module_ref.get_total_span(), || { - let abstract_port = &sub_module.ports[port_id]; - let port_declared_here = abstract_port.make_info(sub_module.link_info.file).unwrap(); - - (format!("Port '{}'", abstract_port.name), vec![port_declared_here]) - }); + context.type_substitutor.unify_report_error( + &wire.typ, + &concrete_port.typ, + submod_instr.module_ref.get_total_span(), + || { + let abstract_port = &sub_module.ports[port_id]; + let port_declared_here = + abstract_port.make_info(sub_module.link_info.file).unwrap(); + + ( + format!("Port '{}'", abstract_port.name), + vec![port_declared_here], + ) + }, + ); } } } @@ -341,7 +468,9 @@ impl DelayedConstraint> for SubmoduleTypecheckConst } } - sm.instance.set(instance).expect("Can only set the instance of a submodule once"); + sm.instance + .set(instance) + .expect("Can only set the instance of a submodule once"); DelayedConstraintStatus::Resolved } else { context.errors.error( @@ -352,15 +481,22 @@ impl DelayedConstraint> for SubmoduleTypecheckConst } } - fn report_could_not_resolve_error(&self, context : &InstantiationContext) { + fn report_could_not_resolve_error(&self, context: &InstantiationContext) { let sm = &context.submodules[self.sm_id]; - let submod_instr = context.md.link_info.instructions[sm.original_instruction].unwrap_submodule(); + let submod_instr = + context.md.link_info.instructions[sm.original_instruction].unwrap_submodule(); let sub_module = &context.linker.modules[sm.module_uuid]; - let submodule_template_args_string = pretty_print_concrete_instance(&sub_module.link_info, &sm.template_args, &context.linker.types); + let submodule_template_args_string = pretty_print_concrete_instance( + &sub_module.link_info, + &sm.template_args, + &context.linker.types, + ); let message = format!("Could not fully instantiate {submodule_template_args_string}"); - context.errors.error(submod_instr.get_most_relevant_span(), message); + context + .errors + .error(submod_instr.get_most_relevant_span(), message); } } diff --git a/src/instantiation/execute.rs b/src/instantiation/execute.rs index 7ff23e1..ec7b799 100644 --- a/src/instantiation/execute.rs +++ b/src/instantiation/execute.rs @@ -214,14 +214,23 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { } } - fn get_first_template_argument_value(&self, cst_ref: &GlobalReference) -> (&Value, Span) { + fn get_first_template_argument_value( + &self, + cst_ref: &GlobalReference, + ) -> (&Value, Span) { let first_arg = cst_ref.unwrap_first_template_argument(); let value_instruction = first_arg.kind.unwrap_value(); - (self.generation_state[value_instruction].unwrap_generation_value(), first_arg.value_span) + ( + self.generation_state[value_instruction].unwrap_generation_value(), + first_arg.value_span, + ) } /// TODO make builtins that depend on parameters - fn get_named_constant_value(&self, cst_ref: &GlobalReference) -> ExecutionResult { + fn get_named_constant_value( + &self, + cst_ref: &GlobalReference, + ) -> ExecutionResult { let linker_cst = &self.linker.constants[cst_ref.id]; Ok(if linker_cst.link_info.is_extern == IsExtern::Builtin { @@ -232,11 +241,11 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { let (val, span) = self.get_first_template_argument_value(cst_ref); let int_val = val.unwrap_integer(); if *int_val > BigInt::ZERO { - let int_val_minus_one : BigInt = int_val - 1; + let int_val_minus_one: BigInt = int_val - 1; Value::Integer(BigInt::from(int_val_minus_one.bits())) } else { - return Err((span, format!("clog2 argument must be > 0, found {int_val}"))) + return Err((span, format!("clog2 argument must be > 0, found {int_val}"))); } } "assert" => { @@ -245,7 +254,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { if condition.unwrap_bool() { Value::Bool(true) } else { - return Err((span, "Assertion failed".into())) + return Err((span, "Assertion failed".into())); } } "sizeof" => { @@ -255,7 +264,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { let concrete_typ = self.concretize_type(wr_typ)?; let Some(typ_sz) = concrete_typ.sizeof() else { - return Err((first_arg.value_span, "This is an incomplete type".into())) + return Err((first_arg.value_span, "This is an incomplete type".into())); }; Value::Integer(typ_sz) @@ -272,7 +281,10 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { } // Points to the wire in the hardware that corresponds to the root of this. - fn determine_wire_ref_root(&mut self, wire_ref_root: &WireReferenceRoot) -> ExecutionResult { + fn determine_wire_ref_root( + &mut self, + wire_ref_root: &WireReferenceRoot, + ) -> ExecutionResult { Ok(match wire_ref_root { &WireReferenceRoot::LocalDecl(decl_id, _) => match &self.generation_state[decl_id] { SubModuleOrWire::Wire(w) => RealWireRefRoot::Wire { @@ -432,9 +444,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { &WireReferenceRoot::LocalDecl(decl_id, _span) => { self.generation_state.get_generation_value(decl_id)?.clone() } - WireReferenceRoot::NamedConstant(cst) => { - self.get_named_constant_value(cst)? - } + WireReferenceRoot::NamedConstant(cst) => self.get_named_constant_value(cst)?, &WireReferenceRoot::SubModulePort(_) => { todo!("Don't yet support compile time functions") } @@ -718,8 +728,9 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { template_args.alloc(match v { Some(arg) => match &arg.kind { TemplateArgKind::Type(typ) => self.concretize_type(typ)?, - TemplateArgKind::Value(v) => - ConcreteType::Value(self.generation_state.get_generation_value(*v)?.clone()), + TemplateArgKind::Value(v) => ConcreteType::Value( + self.generation_state.get_generation_value(*v)?.clone(), + ), }, None => ConcreteType::Unknown(self.type_substitutor.alloc()), }); diff --git a/src/instantiation/latency_algorithm.rs b/src/instantiation/latency_algorithm.rs index 99f1894..264630c 100644 --- a/src/instantiation/latency_algorithm.rs +++ b/src/instantiation/latency_algorithm.rs @@ -2,9 +2,9 @@ use crate::config::config; use super::list_of_lists::ListOfLists; -/// A wire for which a latency has been specified. -/// -/// Provided as a list to [solve_latencies]. +/// A wire for which a latency has been specified. +/// +/// Provided as a list to [solve_latencies]. #[derive(Debug, Clone, Copy)] pub struct SpecifiedLatency { pub wire: usize, @@ -26,7 +26,7 @@ pub enum LatencyCountingError { }, } -/// A graph connection from (resp to) another wire, which specifies the minimal (resp maximal) difference in latency between them. +/// A graph connection from (resp to) another wire, which specifies the minimal (resp maximal) difference in latency between them. #[derive(Debug, Clone, Copy)] pub struct FanInOut { pub other: usize, @@ -62,7 +62,7 @@ struct LatencyStackElem<'d> { } /// The node for the latency-counting graph. See [solve_latencies] -/// +/// /// TODO make this only take up 8 bytes with bitfield #[derive(Clone, Copy)] struct LatencyNode { diff --git a/src/instantiation/latency_count.rs b/src/instantiation/latency_count.rs index f54f9ed..7782cf2 100644 --- a/src/instantiation/latency_count.rs +++ b/src/instantiation/latency_count.rs @@ -70,9 +70,7 @@ fn filter_unique_write_flats<'w>( ) -> Vec<&'w crate::flattening::Write> { let mut result: Vec<&'w crate::flattening::Write> = Vec::new(); for w in writes { - if let Instruction::Write(original_write) = - &instructions[w.mux_input.original_connection] - { + if let Instruction::Write(original_write) = &instructions[w.mux_input.original_connection] { if !result .iter() .any(|found_write| std::ptr::eq(*found_write, original_write)) @@ -136,7 +134,7 @@ impl InstantiatedModule { /// If needed only the same cycle it is generated, then this is equal to [RealWire::absolute_latency]. pub fn compute_needed_untils(&self) -> FlatAlloc { let mut result = self.wires.map(|(_id, w)| w.absolute_latency); - + for (_id, w) in &self.wires { w.source.iter_sources_with_min_latency(|other, _| { let nu = &mut result[other]; @@ -290,7 +288,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { fanins } - + // Returns a proper interface if all ports involved did not produce an error. If a port did produce an error then returns None. // Computes all latencies involved pub fn compute_latencies(&mut self) { @@ -476,12 +474,13 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { &self.wires[latency_node_meanings[conflict_path.first().unwrap().wire]]; let end_wire = &self.wires[latency_node_meanings[conflict_path.last().unwrap().wire]]; - let start_decl = - self.md.link_info.instructions[start_wire.original_instruction].unwrap_declaration(); - let end_decl = - self.md.link_info.instructions[end_wire.original_instruction].unwrap_declaration(); - let end_latency_decl = - self.md.link_info.instructions[end_decl.latency_specifier.unwrap()].unwrap_expression(); + let start_decl = self.md.link_info.instructions[start_wire.original_instruction] + .unwrap_declaration(); + let end_decl = self.md.link_info.instructions[end_wire.original_instruction] + .unwrap_declaration(); + let end_latency_decl = self.md.link_info.instructions + [end_decl.latency_specifier.unwrap()] + .unwrap_expression(); let writes_involved = self.gather_all_mux_inputs(latency_node_meanings, &conflict_path); diff --git a/src/instantiation/list_of_lists.rs b/src/instantiation/list_of_lists.rs index 295c6a4..714abc8 100644 --- a/src/instantiation/list_of_lists.rs +++ b/src/instantiation/list_of_lists.rs @@ -3,7 +3,7 @@ use std::{ ops::{Index, IndexMut}, }; -/// Basically `Vec>`, but reduces pointer chasing by laying the nested vectors all out sequentially. Read-only. +/// Basically `Vec>`, but reduces pointer chasing by laying the nested vectors all out sequentially. Read-only. #[derive(Debug, Clone)] pub struct ListOfLists { buf: Vec, diff --git a/src/instantiation/mod.rs b/src/instantiation/mod.rs index c85cd62..2aefb86 100644 --- a/src/instantiation/mod.rs +++ b/src/instantiation/mod.rs @@ -1,8 +1,8 @@ +mod concrete_typecheck; mod execute; mod latency_algorithm; mod latency_count; mod list_of_lists; -mod concrete_typecheck; mod unique_names; use unique_names::UniqueNames; @@ -30,7 +30,7 @@ use self::latency_algorithm::SpecifiedLatency; pub const CALCULATE_LATENCY_LATER: i64 = i64::MIN; /// See [MultiplexerSource] -/// +/// /// This is the post-instantiation equivalent of [crate::flattening::WireReferencePathElement] #[derive(Debug, Clone)] pub enum RealWirePathElem { @@ -49,8 +49,8 @@ impl RealWirePathElem { } } -/// One arm of a multiplexer. Each arm has an attached condition that is also stored here. -/// +/// One arm of a multiplexer. Each arm has an attached condition that is also stored here. +/// /// See [RealWireDataSource::Multiplexer] #[derive(Debug)] pub struct MultiplexerSource { @@ -61,8 +61,8 @@ pub struct MultiplexerSource { pub original_connection: FlatID, } -/// Where a [RealWire] gets its data, be it an operator, read-only value, constant, etc. -/// +/// Where a [RealWire] gets its data, be it an operator, read-only value, constant, etc. +/// /// This is the post-instantiation equivalent of [crate::flattening::ExpressionSource] #[derive(Debug)] pub enum RealWireDataSource { @@ -90,9 +90,9 @@ pub enum RealWireDataSource { } /// An actual instantiated wire of an [InstantiatedModule] (See [InstantiatedModule::wires]) -/// +/// /// It can have a latency count and domain. All wires have a name, either the name they were given by the user, or a generated name like _1, _13 -/// +/// /// Generated from a [crate::flattening::Expression] instruction #[derive(Debug)] pub struct RealWire { @@ -109,7 +109,7 @@ pub struct RealWire { } /// See [SubModule] -/// +/// /// This represents a port of such a submodule #[derive(Debug)] pub struct SubModulePort { @@ -118,11 +118,11 @@ pub struct SubModulePort { } /// An actual instantiated submodule of an [InstantiatedModule] (See [InstantiatedModule::submodules]) -/// +/// /// All submodules have a name, either the name they were given by the user, or a generated name like _1, _13 -/// +/// /// When generating RTL code, one submodule object generates a single submodule instantiation -/// +/// /// Generated from a [crate::flattening::SubModuleInstance] instruction #[derive(Debug)] pub struct SubModule { @@ -145,11 +145,11 @@ pub struct InstantiatedPort { pub domain: DomainID, } -/// [InstantiatedModule] are the final product we're trying to produce with the compiler. -/// They amount to little more than a collection of wires, multiplexers and submodules. -/// -/// With the submodules, they form a tree structure, of nested [InstantiatedModule] references. -/// +/// [InstantiatedModule] are the final product we're trying to produce with the compiler. +/// They amount to little more than a collection of wires, multiplexers and submodules. +/// +/// With the submodules, they form a tree structure, of nested [InstantiatedModule] references. +/// /// Generated when instantiating a [Module] #[derive(Debug)] pub struct InstantiatedModule { @@ -200,10 +200,10 @@ impl SubModuleOrWire { } } -/// Stored per module [Module]. -/// With this you can instantiate a module for different sets of template arguments. -/// It caches the instantiations that have been made, such that they need not be repeated. -/// +/// Stored per module [Module]. +/// With this you can instantiate a module for different sets of template arguments. +/// It caches the instantiations that have been made, such that they need not be repeated. +/// /// Also, with incremental builds (#49) this will be a prime area for investigation #[derive(Debug)] pub struct InstantiationCache { @@ -285,9 +285,9 @@ impl InstantiationCache { } } -/// Every [crate::flattening::Instruction] has an associated value (See [SubModuleOrWire]). -/// They are either what this local name is currently referencing (either a wire instance or a submodule instance). -/// Or in the case of Generative values, the current value in the generative variable. +/// Every [crate::flattening::Instruction] has an associated value (See [SubModuleOrWire]). +/// They are either what this local name is currently referencing (either a wire instance or a submodule instance). +/// Or in the case of Generative values, the current value in the generative variable. #[derive(Debug)] struct GenerationState<'fl> { generation_state: FlatAlloc, @@ -295,7 +295,7 @@ struct GenerationState<'fl> { } /// Runtime conditions applied to a [crate::flattening::Write] -/// +/// /// ```sus /// state int a /// when x { @@ -306,12 +306,12 @@ struct GenerationState<'fl> { /// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ConditionStackElem { - pub condition_wire : WireID, + pub condition_wire: WireID, /// When this is an else-branch - pub inverse : bool + pub inverse: bool, } -/// As with other contexts, this is the shared state we're lugging around while executing & typechecking a module. +/// As with other contexts, this is the shared state we're lugging around while executing & typechecking a module. struct InstantiationContext<'fl, 'l> { name: String, generation_state: GenerationState<'fl>, @@ -322,7 +322,7 @@ struct InstantiationContext<'fl, 'l> { // Used for Execution unique_name_producer: UniqueNames, - condition_stack : Vec, + condition_stack: Vec, interface_ports: FlatAlloc, PortIDMarker>, errors: ErrorCollector<'l>, @@ -367,7 +367,10 @@ fn perform_instantiation( name: pretty_print_concrete_instance(&md.link_info, template_args, &linker.types), generation_state: GenerationState { md, - generation_state: md.link_info.instructions.map(|(_, _)| SubModuleOrWire::Unnasigned), + generation_state: md + .link_info + .instructions + .map(|(_, _)| SubModuleOrWire::Unnasigned), }, type_substitutor: TypeSubstitutor::new(), condition_stack: Vec::new(), diff --git a/src/instantiation/unique_names.rs b/src/instantiation/unique_names.rs index ae84dbe..1e4d8ff 100644 --- a/src/instantiation/unique_names.rs +++ b/src/instantiation/unique_names.rs @@ -1,32 +1,30 @@ use std::collections::HashMap; -/// Generates ascending IDs for locals, while keeping the name information as much as possible. -/// +/// Generates ascending IDs for locals, while keeping the name information as much as possible. +/// /// For example, when generating multiple names for the string "beep" it returns: /// - beep /// - beep_2 /// - beep_3 /// - ... pub struct UniqueNames { - name_map : HashMap + name_map: HashMap, } impl UniqueNames { pub fn new() -> Self { - let mut name_map : HashMap = HashMap::new(); + let mut name_map: HashMap = HashMap::new(); name_map.insert(String::new(), 1); - Self { - name_map - } + Self { name_map } } - pub fn get_unique_name + AsRef>(&mut self, name : S) -> String { + pub fn get_unique_name + AsRef>(&mut self, name: S) -> String { let name_ref = name.as_ref(); if let Some(found_id) = self.name_map.get_mut(name_ref) { let result = format!("{name_ref}_{found_id}"); *found_id += 1; result } else { - let result : String = name.into(); + let result: String = name.into(); self.name_map.insert(result.clone(), 2); result } diff --git a/src/linker/checkpoint.rs b/src/linker/checkpoint.rs index 45494c3..d907b5f 100644 --- a/src/linker/checkpoint.rs +++ b/src/linker/checkpoint.rs @@ -3,19 +3,19 @@ use crate::errors::ErrorStore; use super::{LinkInfo, ResolvedGlobals}; /// Checkpoints [LinkInfo::errors] -/// +/// /// For incremental builds (#49) #[derive(Debug, Clone, Copy)] pub struct ErrorCheckpoint(pub usize, pub bool); /// Checkpoints [LinkInfo::resolved_globals] -/// +/// /// For incremental builds (#49) #[derive(Debug, Clone, Copy)] pub struct ResolvedGlobalsCheckpoint(pub usize, pub bool); /// See [LinkInfo::checkpoints] -/// +/// /// For incremental builds (#49) #[derive(Debug, Clone, Copy)] pub struct CheckPoint { diff --git a/src/linker/mod.rs b/src/linker/mod.rs index 646a56e..88b5e30 100644 --- a/src/linker/mod.rs +++ b/src/linker/mod.rs @@ -1,4 +1,10 @@ -use crate::{flattening::{Instruction, NamedConstant}, prelude::*, typing::template::{GenerativeParameterKind, Parameter, ParameterKind, TVec, TypeParameterKind}}; +use crate::{ + flattening::{Instruction, NamedConstant}, + prelude::*, + typing::template::{ + GenerativeParameterKind, Parameter, ParameterKind, TVec, TypeParameterKind, + }, +}; pub mod checkpoint; mod resolver; @@ -12,18 +18,12 @@ use std::{ use tree_sitter::Tree; -use crate::{ - alloc::ArenaAllocator, - file_position::FileText, - flattening::Module -}; +use crate::{alloc::ArenaAllocator, file_position::FileText, flattening::Module}; use crate::errors::{CompileError, ErrorInfo, ErrorLevel, ErrorStore}; use crate::flattening::{StructType, TypingAllocator}; - - use self::checkpoint::CheckPoint; /// Documentation can be attached to [Module], [StructType], [NamedConstant], [crate::flattening::Declaration] @@ -47,36 +47,36 @@ impl Documentation { } } -/// [Module], [StructType], or [NamedConstant] annotation that specifies exceptions to code generation. +/// [Module], [StructType], or [NamedConstant] annotation that specifies exceptions to code generation. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum IsExtern { /// Code is generated for this through the regular channel (See [crate::codegen]) - /// + /// /// ```sus /// module md {} /// ``` Normal, /// Modules that are provided externally, and thus no code should be generated for these - /// + /// /// ```sus /// extern module md {} /// ``` Extern, /// Builtins, like escape hatches for Latency Counting & domains - /// + /// /// ```sus /// __builtin__ module md {} /// ``` - Builtin + Builtin, } -pub const AFTER_INITIAL_PARSE_CP : usize = 0; -pub const AFTER_FLATTEN_CP : usize = 1; -pub const AFTER_TYPECHECK_CP : usize = 2; -pub const AFTER_LINTS_CP : usize = 3; +pub const AFTER_INITIAL_PARSE_CP: usize = 0; +pub const AFTER_FLATTEN_CP: usize = 1; +pub const AFTER_TYPECHECK_CP: usize = 2; +pub const AFTER_LINTS_CP: usize = 3; /// Represents any global. Stored in [Linker] and each is uniquely indexed by [GlobalUUID] -/// +/// /// Base class for [Module], [StructType], [NamedConstant] #[derive(Debug)] pub struct LinkInfo { @@ -87,10 +87,10 @@ pub struct LinkInfo { pub documentation: Documentation, pub errors: ErrorStore, pub resolved_globals: ResolvedGlobals, - pub is_extern : IsExtern, + pub is_extern: IsExtern, /// Created in Stage 2: Flattening - /// + /// /// Is only temporary. It's used during typechecking to allocate the type unification block pub type_variable_alloc: TypingAllocator, @@ -99,12 +99,12 @@ pub struct LinkInfo { /// Created in Stage 2: Flattening. type data is filled out during Typechecking pub instructions: FlatAlloc, - /// Reset checkpoints. These are to reset errors and resolved_globals for incremental compilation. - /// + /// Reset checkpoints. These are to reset errors and resolved_globals for incremental compilation. + /// /// TODO the system is there, just need to actually do incremental compilation (#49) - /// + /// /// Right now it already functions as a sanity check, to make sure no steps in building modules/types are skipped - pub checkpoints : ArrayVec + pub checkpoints: ArrayVec, } impl LinkInfo { @@ -118,26 +118,20 @@ impl LinkInfo { let mut template_args: Vec<&str> = Vec::new(); for (_id, t) in &self.template_parameters { match &t.kind { - ParameterKind::Type(TypeParameterKind { }) => { - template_args.push(&t.name) - } + ParameterKind::Type(TypeParameterKind {}) => template_args.push(&t.name), ParameterKind::Generative(GenerativeParameterKind { decl_span, declaration_instruction: _, - }) => template_args.push(&file_text[*decl_span]) + }) => template_args.push(&file_text[*decl_span]), } } - format!( - "{} #({})", - self.get_full_name(), - template_args.join(", ") - ) + format!("{} #({})", self.get_full_name(), template_args.join(", ")) } } -/// Data associated with a file. Such as the text, the parse tree, and all [Module]s, [StructType]s, or [NamedConstant]s. -/// +/// Data associated with a file. Such as the text, the parse tree, and all [Module]s, [StructType]s, or [NamedConstant]s. +/// /// All FileDatas are stored in [Linker::files], and indexed by [FileUUID] pub struct FileData { pub file_identifier: String, @@ -159,17 +153,23 @@ pub enum GlobalUUID { impl GlobalUUID { #[track_caller] pub fn unwrap_module(&self) -> ModuleUUID { - let GlobalUUID::Module(id) = self else {unreachable!("Not a ModuleUUID!")}; + let GlobalUUID::Module(id) = self else { + unreachable!("Not a ModuleUUID!") + }; *id } #[track_caller] pub fn unwrap_type(&self) -> TypeUUID { - let GlobalUUID::Type(id) = self else {unreachable!("Not a TypeUUID!")}; + let GlobalUUID::Type(id) = self else { + unreachable!("Not a TypeUUID!") + }; *id } #[track_caller] pub fn unwrap_const(&self) -> ConstantUUID { - let GlobalUUID::Constant(id) = self else {unreachable!("Not a ConstantUUID!")}; + let GlobalUUID::Constant(id) = self else { + unreachable!("Not a ConstantUUID!") + }; *id } } @@ -197,14 +197,14 @@ enum NamespaceElement { Colission(Box<[GlobalUUID]>), } -/// The global singleton object that collects all [Module]s, [StructType]s, and [NamedConstant]s that are in the current SUS codebase. -/// -/// There should only be one [Linker] globally. -/// -/// See [LinkInfo], this contains shared data between all global objects in the whole progam. -/// -/// It also keeps track of the global namespace. -/// +/// The global singleton object that collects all [Module]s, [StructType]s, and [NamedConstant]s that are in the current SUS codebase. +/// +/// There should only be one [Linker] globally. +/// +/// See [LinkInfo], this contains shared data between all global objects in the whole progam. +/// +/// It also keeps track of the global namespace. +/// /// Incremental operations such as adding and removing files can be performed on this pub struct Linker { pub types: ArenaAllocator, @@ -229,22 +229,26 @@ impl Linker { match global { GlobalUUID::Module(md_id) => &self.modules[md_id].link_info, GlobalUUID::Type(typ_id) => &self.types[typ_id].link_info, - GlobalUUID::Constant(cst_id) => &self.constants[cst_id].link_info + GlobalUUID::Constant(cst_id) => &self.constants[cst_id].link_info, } } pub fn get_link_info_mut<'l>( modules: &'l mut ArenaAllocator, types: &'l mut ArenaAllocator, constants: &'l mut ArenaAllocator, - global: GlobalUUID + global: GlobalUUID, ) -> &'l mut LinkInfo { match global { GlobalUUID::Module(md_id) => &mut modules[md_id].link_info, GlobalUUID::Type(typ_id) => &mut types[typ_id].link_info, - GlobalUUID::Constant(cst_id) => &mut constants[cst_id].link_info + GlobalUUID::Constant(cst_id) => &mut constants[cst_id].link_info, } } - fn for_all_duplicate_declaration_errors(&self, file_uuid: FileUUID, f: &mut impl FnMut(&CompileError)) { + fn for_all_duplicate_declaration_errors( + &self, + file_uuid: FileUUID, + f: &mut impl FnMut(&CompileError), + ) { // Conflicting Declarations for item in &self.global_namespace { let NamespaceElement::Colission(colission) = &item.1 else { @@ -254,7 +258,9 @@ impl Linker { colission.iter().map(|id| self.get_link_info(*id)).collect(); for (idx, info) in infos.iter().enumerate() { - if info.file != file_uuid {continue} + if info.file != file_uuid { + continue; + } let mut conflict_infos = Vec::new(); for (idx_2, conflicts_with) in infos.iter().enumerate() { if idx_2 == idx { @@ -273,7 +279,7 @@ impl Linker { .collect(); let reason = format!("'{this_object_name}' conflicts with other declarations:"); - + f(&CompileError { position: info.name_span, reason, @@ -360,7 +366,8 @@ impl Linker { let mut parsing_errors = std::mem::replace(&mut self.files[file_id].parsing_errors, ErrorStore::new()); let file_data = &self.files[file_id]; - let other_parsing_errors = ErrorCollector::from_storage(parsing_errors.take(), file_id, &self.files); + let other_parsing_errors = + ErrorCollector::from_storage(parsing_errors.take(), file_id, &self.files); f(FileBuilder { file_id, diff --git a/src/linker/resolver.rs b/src/linker/resolver.rs index 4f524cd..26da620 100644 --- a/src/linker/resolver.rs +++ b/src/linker/resolver.rs @@ -50,30 +50,49 @@ pub struct GlobalResolver<'linker> { pub file_data: &'linker FileData, pub errors: ErrorCollector<'linker>, - resolved_globals: RefCell + resolved_globals: RefCell, } impl<'linker> GlobalResolver<'linker> { - pub fn take_errors_globals(linker: &mut Linker, global_obj: GlobalUUID) -> (ErrorStore, ResolvedGlobals) { - let obj_link_info = Linker::get_link_info_mut(&mut linker.modules, &mut linker.types, &mut linker.constants, global_obj); + pub fn take_errors_globals( + linker: &mut Linker, + global_obj: GlobalUUID, + ) -> (ErrorStore, ResolvedGlobals) { + let obj_link_info = Linker::get_link_info_mut( + &mut linker.modules, + &mut linker.types, + &mut linker.constants, + global_obj, + ); let errors = obj_link_info.errors.take(); let resolved_globals = obj_link_info.resolved_globals.take(); (errors, resolved_globals) } - pub fn new(linker: &'linker Linker, obj_link_info: &'linker LinkInfo, errors_globals: (ErrorStore, ResolvedGlobals)) -> Self { + pub fn new( + linker: &'linker Linker, + obj_link_info: &'linker LinkInfo, + errors_globals: (ErrorStore, ResolvedGlobals), + ) -> Self { let file_data = &linker.files[obj_link_info.file]; GlobalResolver { linker, file_data, - errors: ErrorCollector::from_storage(errors_globals.0, obj_link_info.file, &linker.files), + errors: ErrorCollector::from_storage( + errors_globals.0, + obj_link_info.file, + &linker.files, + ), resolved_globals: RefCell::new(errors_globals.1), } } /// Get the [ErrorCollector] and [ResolvedGlobals] out of this - pub fn decommission<'linker_files>(self, linker_files: &'linker_files ArenaAllocator) -> (ErrorCollector<'linker_files>, ResolvedGlobals) { + pub fn decommission<'linker_files>( + self, + linker_files: &'linker_files ArenaAllocator, + ) -> (ErrorCollector<'linker_files>, ResolvedGlobals) { let errors = self.errors.re_attach(linker_files); let resolved_globals = self.resolved_globals.into_inner(); (errors, resolved_globals) @@ -83,7 +102,7 @@ impl<'linker> GlobalResolver<'linker> { let named_type = match global { GlobalUUID::Module(_) => "Module", GlobalUUID::Type(_) => "Struct", - GlobalUUID::Constant(_) => "Constant" + GlobalUUID::Constant(_) => "Constant", }; let link_info = self.linker.get_link_info(global); LinkingErrorLocation { @@ -133,7 +152,13 @@ impl<'linker> GlobalResolver<'linker> { } } - pub fn not_expected_global_error(&self, global_ref: &GlobalReference, expected: &str) where GlobalUUID: From { + pub fn not_expected_global_error( + &self, + global_ref: &GlobalReference, + expected: &str, + ) where + GlobalUUID: From, + { // SAFETY: The allocated linker objects aren't going to change. let info = self.get_linking_error_location(GlobalUUID::from(global_ref.id)); let name = &info.full_name; @@ -146,7 +171,10 @@ impl<'linker> GlobalResolver<'linker> { } pub fn get_link_info(&self, id: GlobalUUID) -> &LinkInfo { - self.resolved_globals.borrow_mut().referenced_globals.push(id); + self.resolved_globals + .borrow_mut() + .referenced_globals + .push(id); self.linker.get_link_info(id) } } @@ -155,7 +183,8 @@ impl<'l> Index for GlobalResolver<'l> { type Output = Module; fn index(&self, index: ModuleUUID) -> &Self::Output { - self.resolved_globals.borrow_mut() + self.resolved_globals + .borrow_mut() .referenced_globals .push(GlobalUUID::Module(index)); @@ -166,7 +195,8 @@ impl<'l> Index for GlobalResolver<'l> { type Output = StructType; fn index(&self, index: TypeUUID) -> &Self::Output { - self.resolved_globals.borrow_mut() + self.resolved_globals + .borrow_mut() .referenced_globals .push(GlobalUUID::Type(index)); @@ -177,7 +207,8 @@ impl<'l> Index for GlobalResolver<'l> { type Output = NamedConstant; fn index(&self, index: ConstantUUID) -> &Self::Output { - self.resolved_globals.borrow_mut() + self.resolved_globals + .borrow_mut() .referenced_globals .push(GlobalUUID::Constant(index)); @@ -186,18 +217,20 @@ impl<'l> Index for GlobalResolver<'l> { } impl LinkInfo { - pub fn reabsorb_errors_globals(&mut self, (errors, resolved_globals): (ErrorCollector, ResolvedGlobals), checkpoint_id: usize) { + pub fn reabsorb_errors_globals( + &mut self, + (errors, resolved_globals): (ErrorCollector, ResolvedGlobals), + checkpoint_id: usize, + ) { // Store errors and resolved_globals back into module assert!(self.resolved_globals.is_untouched()); assert!(self.errors.is_untouched()); let expected_checkpoint = self.checkpoints.len(); assert_eq!(expected_checkpoint, checkpoint_id, "The new checkpoint is not what was expected. The new checkpoint was {checkpoint_id}, whereas the expected next checkpoint is {expected_checkpoint}"); - + self.resolved_globals = resolved_globals; self.errors = errors.into_storage(); - self.checkpoints.push(CheckPoint::checkpoint( - &self.errors, - &self.resolved_globals, - )); + self.checkpoints + .push(CheckPoint::checkpoint(&self.errors, &self.resolved_globals)); } } diff --git a/src/main.rs b/src/main.rs index f24166b..090503f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,8 +21,8 @@ mod linker; mod compiler_top; -use std::io::Write; use std::error::Error; +use std::io::Write; use prelude::*; @@ -38,7 +38,9 @@ fn main() -> Result<(), Box> { let file_paths = config.files.clone(); let codegen_backend = match config.target_language { - config::TargetLanguage::SystemVerilog => Box::new(VerilogCodegenBackend) as Box, + config::TargetLanguage::SystemVerilog => { + Box::new(VerilogCodegenBackend) as Box + } config::TargetLanguage::VHDL => Box::new(VHDLCodegenBackend) as Box, }; diff --git a/src/prelude.rs b/src/prelude.rs index 666ad11..f687744 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -75,7 +75,6 @@ impl UUIDMarker for FieldIDMarker { } pub type FieldID = UUID; - pub struct TemplateIDMarker; impl UUIDMarker for TemplateIDMarker { const DISPLAY_NAME: &'static str = "template_arg_"; diff --git a/src/to_string.rs b/src/to_string.rs index 80cd0b9..a311af1 100644 --- a/src/to_string.rs +++ b/src/to_string.rs @@ -91,11 +91,7 @@ impl WrittenType { } #[derive(Debug)] -pub struct AbstractTypeDisplay< - 'a, - TypVec: , - TemplateVec: TemplateNameGetter, -> { +pub struct AbstractTypeDisplay<'a, TypVec, TemplateVec: TemplateNameGetter> { inner: &'a AbstractType, linker_types: &'a TypVec, template_names: &'a TemplateVec, @@ -313,8 +309,7 @@ pub fn pretty_print_concrete_instance( write!(result, " {}: ", arg_in_target.name).unwrap(); match arg { ConcreteType::Named(_) | ConcreteType::Array(_) => { - writeln!(result, "type {},", arg.display(linker_types)) - .unwrap(); + writeln!(result, "type {},", arg.display(linker_types)).unwrap(); } ConcreteType::Value(value) => { writeln!(result, "{value},").unwrap(); diff --git a/src/typing/abstract_type.rs b/src/typing/abstract_type.rs index 7dcaa4d..4348047 100644 --- a/src/typing/abstract_type.rs +++ b/src/typing/abstract_type.rs @@ -6,7 +6,10 @@ use crate::value::Value; use std::ops::Deref; use super::template::{GlobalReference, Parameter, TVec}; -use super::type_inference::{DomainVariableID, DomainVariableIDMarker, TypeSubstitutor, TypeVariableID, TypeVariableIDMarker, UnifyErrorReport}; +use super::type_inference::{ + DomainVariableID, DomainVariableIDMarker, TypeSubstitutor, TypeVariableID, + TypeVariableIDMarker, UnifyErrorReport, +}; use crate::flattening::{BinaryOperator, StructType, TypingAllocator, UnaryOperator, WrittenType}; use crate::to_string::map_to_type_names; @@ -15,24 +18,24 @@ use crate::to_string::map_to_type_names; /// Its most important components are the names and structure of types. /// /// What isn't included are the parameters of types. So Array Sizes for example. -/// -/// This is such that useful information can still be given for modules that haven't been instantiated. -/// -/// Not to be confused with [WrittenType], which is the in-source text representation. -/// +/// +/// This is such that useful information can still be given for modules that haven't been instantiated. +/// +/// Not to be confused with [WrittenType], which is the in-source text representation. +/// /// Not to be confused with [crate::typing::concrete_type::ConcreteType], which is the -/// post-instantiation type. -/// -/// [AbstractType]s don't actually get converted to [crate::typing::concrete_type::ConcreteType]s. -/// Instead [crate::typing::concrete_type::ConcreteType] gets created from [WrittenType] directly. +/// post-instantiation type. +/// +/// [AbstractType]s don't actually get converted to [crate::typing::concrete_type::ConcreteType]s. +/// Instead [crate::typing::concrete_type::ConcreteType] gets created from [WrittenType] directly. #[derive(Debug, Clone)] pub enum AbstractType { Template(TemplateID), Named(TypeUUID), Array(Box), - /// Referencing [AbstractType::Unknown] is a strong code smell. + /// Referencing [AbstractType::Unknown] is a strong code smell. /// It is likely you should use [TypeSubstitutor::unify_must_succeed] or [TypeSubstitutor::unify_report_error] instead - /// + /// /// It should only occur in creation `AbstractType::Unknown(self.type_substitutor.alloc())` Unknown(TypeVariableID), } @@ -40,15 +43,15 @@ pub enum AbstractType { pub const BOOL_TYPE: AbstractType = AbstractType::Named(get_builtin_type!("bool")); pub const INT_TYPE: AbstractType = AbstractType::Named(get_builtin_type!("int")); -/// These represent (clock) domains. While clock domains are included under this umbrella, domains can use the same clock. -/// The use case for non-clock-domains is to separate Latency Counting domains. So different pipelines where it doesn't -/// necessarily make sense that their values are related by a fixed number of clock cycles. -/// -/// Domains are resolved pre-instantiation, because dynamic domain merging doesn't seem like a valuable use case. -/// -/// As a convenience, we make [DomainType::Generative] a special case for a domain. -/// -/// The fun thing is that we can now use this domain info for syntax highlighting, giving wires in different domains a different color. +/// These represent (clock) domains. While clock domains are included under this umbrella, domains can use the same clock. +/// The use case for non-clock-domains is to separate Latency Counting domains. So different pipelines where it doesn't +/// necessarily make sense that their values are related by a fixed number of clock cycles. +/// +/// Domains are resolved pre-instantiation, because dynamic domain merging doesn't seem like a valuable use case. +/// +/// As a convenience, we make [DomainType::Generative] a special case for a domain. +/// +/// The fun thing is that we can now use this domain info for syntax highlighting, giving wires in different domains a different color. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DomainType { /// Generative conflicts with nothing @@ -57,14 +60,14 @@ pub enum DomainType { Physical(DomainID), /// These are unified by Hindley-Milner unification - /// - /// They always point to non-generative domains. - /// - /// Referencing [DomainType::Unknown] is a strong code smell. + /// + /// They always point to non-generative domains. + /// + /// Referencing [DomainType::Unknown] is a strong code smell. /// It is likely you should use [TypeSubstitutor::unify_must_succeed] or [TypeSubstitutor::unify_report_error] instead - /// + /// /// It should only occur in creation `DomainType::Unknown(self.domain_substitutor.alloc())` - Unknown(DomainVariableID) + Unknown(DomainVariableID), } impl DomainType { @@ -83,10 +86,10 @@ impl DomainType { } } -/// Represents all typing information needed in the Flattening Stage. -/// +/// Represents all typing information needed in the Flattening Stage. +/// /// At the time being, this consists of the structural type ([AbstractType]), IE, if it's an `int`, `bool`, or `int[]` -/// And the domain ([DomainType]), which tracks part of what (clock) domain this wire is. +/// And the domain ([DomainType]), which tracks part of what (clock) domain this wire is. #[derive(Debug, Clone)] pub struct FullType { pub typ: AbstractType, @@ -94,7 +97,7 @@ pub struct FullType { } /// Performs Hindley-Milner typing during Flattening. (See [TypeSubstitutor]) -/// +/// /// 'A U 'x -> Substitute 'x = 'A /// /// 'x U 'y -> Substitute 'x = 'y @@ -105,14 +108,11 @@ pub struct TypeUnifier { } impl TypeUnifier { - pub fn new( - parameters: &TVec, - typing_alloc: TypingAllocator - ) -> Self { + pub fn new(parameters: &TVec, typing_alloc: TypingAllocator) -> Self { Self { template_type_names: map_to_type_names(parameters), type_substitutor: TypeSubstitutor::init(&typing_alloc.type_variable_alloc), - domain_substitutor: TypeSubstitutor::init(&typing_alloc.domain_variable_alloc) + domain_substitutor: TypeSubstitutor::init(&typing_alloc.domain_variable_alloc), } } @@ -125,54 +125,78 @@ impl TypeUnifier { self.domain_substitutor.alloc() } - /// This should always be what happens first to a given variable. - /// + /// This should always be what happens first to a given variable. + /// /// Therefore it should be impossible that one of the internal unifications ever fails pub fn unify_with_written_type_must_succeed(&self, wr_typ: &WrittenType, typ: &AbstractType) { match wr_typ { WrittenType::Error(_span) => {} // Already an error, don't unify WrittenType::TemplateVariable(_span, argument_id) => { - self.type_substitutor.unify_must_succeed(&typ, &AbstractType::Template(*argument_id)); + self.type_substitutor + .unify_must_succeed(&typ, &AbstractType::Template(*argument_id)); } WrittenType::Named(global_reference) => { - self.type_substitutor.unify_must_succeed(&typ, &AbstractType::Named(global_reference.id)); + self.type_substitutor + .unify_must_succeed(&typ, &AbstractType::Named(global_reference.id)); } - WrittenType::Array(_span, array_content_and_size) => { + WrittenType::Array(_span, array_content_and_size) => { let (arr_content, _size_flat, _array_bracket_span) = array_content_and_size.deref(); let arr_content_variable = AbstractType::Unknown(self.alloc_typ_variable()); - self.type_substitutor.unify_must_succeed(typ, &AbstractType::Array(Box::new(arr_content_variable.clone()))); + self.type_substitutor.unify_must_succeed( + typ, + &AbstractType::Array(Box::new(arr_content_variable.clone())), + ); - Self::unify_with_written_type_must_succeed(self, arr_content, &arr_content_variable); + Self::unify_with_written_type_must_succeed( + self, + arr_content, + &arr_content_variable, + ); } } } - /// This should always be what happens first to a given variable. - /// + /// This should always be what happens first to a given variable. + /// /// Therefore it should be impossible that one of the internal unifications ever fails - /// + /// /// template_type_args applies to both Template Type args and Template Value args. /// /// For Types this is the Type, for Values this is unified with the parameter declaration type - pub fn unify_with_written_type_substitute_templates_must_succeed(&self, wr_typ: &WrittenType, typ: &AbstractType, template_type_args: &TVec) { + pub fn unify_with_written_type_substitute_templates_must_succeed( + &self, + wr_typ: &WrittenType, + typ: &AbstractType, + template_type_args: &TVec, + ) { match wr_typ { WrittenType::Error(_span) => {} // Already an error, don't unify WrittenType::TemplateVariable(_span, argument_id) => { - self.type_substitutor.unify_must_succeed(&typ, &template_type_args[*argument_id]); + self.type_substitutor + .unify_must_succeed(&typ, &template_type_args[*argument_id]); } WrittenType::Named(global_reference) => { - self.type_substitutor.unify_must_succeed(&typ, &AbstractType::Named(global_reference.id)); + self.type_substitutor + .unify_must_succeed(&typ, &AbstractType::Named(global_reference.id)); } - WrittenType::Array(_span, array_content_and_size) => { + WrittenType::Array(_span, array_content_and_size) => { let (arr_content, _size_flat, _array_bracket_span) = array_content_and_size.deref(); let arr_content_variable = AbstractType::Unknown(self.alloc_typ_variable()); - self.type_substitutor.unify_must_succeed(typ, &AbstractType::Array(Box::new(arr_content_variable.clone()))); - - Self::unify_with_written_type_substitute_templates_must_succeed(self, arr_content, &arr_content_variable, template_type_args); + self.type_substitutor.unify_must_succeed( + typ, + &AbstractType::Array(Box::new(arr_content_variable.clone())), + ); + + Self::unify_with_written_type_substitute_templates_must_succeed( + self, + arr_content, + &arr_content_variable, + template_type_args, + ); } } } @@ -180,12 +204,25 @@ impl TypeUnifier { /// TODO make WrittenValue compared to Value to encode Spans pub fn unify_with_constant(&mut self, typ: &AbstractType, value: &Value, value_span: Span) { match value { - Value::Bool(_) => self.type_substitutor.unify_report_error(typ, &BOOL_TYPE, value_span, "bool constant"), - Value::Integer(_big_int) => self.type_substitutor.unify_report_error(typ, &INT_TYPE, value_span, "int constant"), + Value::Bool(_) => self.type_substitutor.unify_report_error( + typ, + &BOOL_TYPE, + value_span, + "bool constant", + ), + Value::Integer(_big_int) => { + self.type_substitutor + .unify_report_error(typ, &INT_TYPE, value_span, "int constant") + } Value::Array(arr) => { let arr_content_variable = AbstractType::Unknown(self.alloc_typ_variable()); - self.type_substitutor.unify_report_error(typ, &AbstractType::Array(Box::new(arr_content_variable.clone())), value_span, "array constant"); - + self.type_substitutor.unify_report_error( + typ, + &AbstractType::Array(Box::new(arr_content_variable.clone())), + value_span, + "array constant", + ); + for v in arr.deref() { self.unify_with_constant(&arr_content_variable, v, value_span); } @@ -201,7 +238,12 @@ impl TypeUnifier { output_typ: AbstractType, arr_span: Span, ) { - self.type_substitutor.unify_report_error(arr_type, &AbstractType::Array(Box::new(output_typ)), arr_span, "array access"); + self.type_substitutor.unify_report_error( + arr_type, + &AbstractType::Array(Box::new(output_typ)), + arr_span, + "array access", + ); } pub fn typecheck_unary_operator_abstr( @@ -212,11 +254,15 @@ impl TypeUnifier { output_typ: &AbstractType, ) { if op == UnaryOperator::Not { - self.type_substitutor.unify_report_error(input_typ, &BOOL_TYPE, span, "! input"); - self.type_substitutor.unify_report_error(output_typ, &BOOL_TYPE, span, "! output"); + self.type_substitutor + .unify_report_error(input_typ, &BOOL_TYPE, span, "! input"); + self.type_substitutor + .unify_report_error(output_typ, &BOOL_TYPE, span, "! output"); } else if op == UnaryOperator::Negate { - self.type_substitutor.unify_report_error(input_typ, &INT_TYPE, span, "unary - input"); - self.type_substitutor.unify_report_error(output_typ, &INT_TYPE, span, "unary - output"); + self.type_substitutor + .unify_report_error(input_typ, &INT_TYPE, span, "unary - input"); + self.type_substitutor + .unify_report_error(output_typ, &INT_TYPE, span, "unary - output"); } else { let reduction_type = match op { UnaryOperator::And => BOOL_TYPE, @@ -226,7 +272,12 @@ impl TypeUnifier { UnaryOperator::Product => INT_TYPE, _ => unreachable!(), }; - self.type_substitutor.unify_report_error(output_typ, &reduction_type, span, "array reduction"); + self.type_substitutor.unify_report_error( + output_typ, + &reduction_type, + span, + "array reduction", + ); self.unify_with_array_of(input_typ, output_typ.clone(), span); } } @@ -257,23 +308,19 @@ impl TypeUnifier { BinaryOperator::Lesser => (INT_TYPE, INT_TYPE, BOOL_TYPE), }; - self.type_substitutor.unify_report_error( - left_typ, - &exp_left, - left_span, - "binop left side" - ); + self.type_substitutor + .unify_report_error(left_typ, &exp_left, left_span, "binop left side"); self.type_substitutor.unify_report_error( right_typ, &exp_right, right_span, - "binop right side" + "binop right side", ); self.type_substitutor.unify_report_error( output_typ, &out_typ, Span::new_overarching(left_span, right_span), - "binop output" + "binop output", ); } @@ -284,11 +331,12 @@ impl TypeUnifier { from_domain: &DomainType, to_domain: &DomainType, span: Span, - context: Context + context: Context, ) { // The case of writes to generatives from non-generatives should be fully covered by flattening if !from_domain.is_generative() && !to_domain.is_generative() { - self.domain_substitutor.unify_report_error(&from_domain, &to_domain, span, context); + self.domain_substitutor + .unify_report_error(&from_domain, &to_domain, span, context); } } @@ -312,9 +360,26 @@ impl TypeUnifier { right_span: Span, output_typ: &FullType, ) { - self.typecheck_binary_operator_abstr(op, &left_typ.typ, &right_typ.typ, left_span, right_span, &output_typ.typ); - self.unify_domains(&left_typ.domain, &output_typ.domain, left_span, "binop left"); - self.unify_domains(&right_typ.domain, &output_typ.domain, right_span, "binop right"); + self.typecheck_binary_operator_abstr( + op, + &left_typ.typ, + &right_typ.typ, + left_span, + right_span, + &output_typ.typ, + ); + self.unify_domains( + &left_typ.domain, + &output_typ.domain, + left_span, + "binop left", + ); + self.unify_domains( + &right_typ.domain, + &output_typ.domain, + right_span, + "binop right", + ); } pub fn typecheck_array_access( @@ -325,7 +390,8 @@ impl TypeUnifier { idx_span: Span, output_typ: &AbstractType, ) { - self.type_substitutor.unify_report_error(&idx_type, &INT_TYPE, idx_span, "array index"); + self.type_substitutor + .unify_report_error(&idx_type, &INT_TYPE, idx_span, "array index"); self.unify_with_array_of(&arr_type, output_typ.clone(), arr_span); } @@ -334,17 +400,18 @@ impl TypeUnifier { found: &AbstractType, expected: &AbstractType, span: Span, - context: Context + context: Context, ) { - self.type_substitutor.unify_report_error(&found, &expected, span, context); + self.type_substitutor + .unify_report_error(&found, &expected, span, context); } - pub fn typecheck_write_to( + pub fn typecheck_write_to( &self, found: &FullType, expected: &FullType, span: Span, - context: Context + context: Context, ) { self.typecheck_write_to_abstract(&found.typ, &expected.typ, span, context.clone()); self.unify_domains(&found.domain, &expected.domain, span, context); @@ -355,20 +422,40 @@ impl TypeUnifier { assert!(typ_domain.fully_substitute(&self.domain_substitutor) == true); } - pub fn finalize_abstract_type(&mut self, types: &ArenaAllocator, typ: &mut AbstractType, span: Span, errors: &ErrorCollector) { + pub fn finalize_abstract_type( + &mut self, + types: &ArenaAllocator, + typ: &mut AbstractType, + span: Span, + errors: &ErrorCollector, + ) { use super::type_inference::HindleyMilner; if typ.fully_substitute(&self.type_substitutor) == false { let typ_as_string = typ.display(types, &self.template_type_names); - errors.error(span, format!("Could not fully figure out the type of this object. {typ_as_string}")); + errors.error( + span, + format!("Could not fully figure out the type of this object. {typ_as_string}"), + ); } } - pub fn finalize_type(&mut self, types: &ArenaAllocator, typ: &mut FullType, span: Span, errors: &ErrorCollector) { + pub fn finalize_type( + &mut self, + types: &ArenaAllocator, + typ: &mut FullType, + span: Span, + errors: &ErrorCollector, + ) { self.finalize_domain_type(&mut typ.domain); self.finalize_abstract_type(types, &mut typ.typ, span, errors); } - pub fn finalize_global_ref(&mut self, types: &ArenaAllocator, global_ref: &mut GlobalReference, errors: &ErrorCollector) { + pub fn finalize_global_ref( + &mut self, + types: &ArenaAllocator, + global_ref: &mut GlobalReference, + errors: &ErrorCollector, + ) { let global_ref_span = global_ref.get_total_span(); for (_template_id, template_type) in &mut global_ref.template_arg_types { self.finalize_abstract_type(types, template_type, global_ref_span, errors); diff --git a/src/typing/concrete_type.rs b/src/typing/concrete_type.rs index 6df4ad8..e3861d1 100644 --- a/src/typing/concrete_type.rs +++ b/src/typing/concrete_type.rs @@ -26,19 +26,19 @@ pub struct ConcreteGlobalReference { pub template_args: TVec, } -/// A post-instantiation type. These fully define what wires should be generated for a given object. -/// So as opposed to [crate::typing::abstract_type::AbstractType], type parameters are filled out with concrete values. -/// +/// A post-instantiation type. These fully define what wires should be generated for a given object. +/// So as opposed to [crate::typing::abstract_type::AbstractType], type parameters are filled out with concrete values. +/// /// Examples: `bool[3]`, `int #(MAX: 20)` -/// +/// /// Not to be confused with [crate::typing::abstract_type::AbstractType] which represents pre-instantiation types, -/// or [crate::flattening::WrittenType] which represents the textual in-editor data. +/// or [crate::flattening::WrittenType] which represents the textual in-editor data. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ConcreteType { Named(ConcreteGlobalReference), Value(Value), Array(Box<(ConcreteType, ConcreteType)>), - /// Referencing [ConcreteType::Unknown] is a strong code smell. + /// Referencing [ConcreteType::Unknown] is a strong code smell. /// It is likely you should use [crate::typing::type_inference::TypeSubstitutor::unify_must_succeed] /// or [crate::typing::type_inference::TypeSubstitutor::unify_report_error] instead /// @@ -56,12 +56,10 @@ impl ConcreteType { } pub fn contains_unknown(&self) -> bool { match self { - ConcreteType::Named(global_ref) => { - global_ref - .template_args - .iter() - .any(|concrete_template_arg| concrete_template_arg.1.contains_unknown()) - } + ConcreteType::Named(global_ref) => global_ref + .template_args + .iter() + .any(|concrete_template_arg| concrete_template_arg.1.contains_unknown()), ConcreteType::Value(_) => false, ConcreteType::Array(arr_box) => { let (arr_arr, arr_size) = arr_box.deref(); @@ -71,7 +69,7 @@ impl ConcreteType { } } /// Returns the size of this type in *wires*. So int #(MAX: 255) would return '8' - /// + /// /// If it contains any Unknowns, then returns None pub fn sizeof(&self) -> Option { match self { @@ -82,13 +80,15 @@ impl ConcreteType { let mut typ_sz = typ.sizeof()?; - let ConcreteType::Value(arr_sz) = size else {return None}; + let ConcreteType::Value(arr_sz) = size else { + return None; + }; typ_sz *= arr_sz.unwrap_integer(); Some(typ_sz) } - ConcreteType::Unknown(_uuid) => None + ConcreteType::Unknown(_uuid) => None, } } diff --git a/src/typing/template.rs b/src/typing/template.rs index 34b6552..c25271f 100644 --- a/src/typing/template.rs +++ b/src/typing/template.rs @@ -1,7 +1,6 @@ - -use crate::{alloc::UUID, prelude::*}; use super::abstract_type::AbstractType; use crate::flattening::WrittenType; +use crate::{alloc::UUID, prelude::*}; /// References any [crate::flattening::Module], [crate::flattening::StructType], or [crate::flattening::NamedConstant], /// and includes any template arguments. @@ -29,7 +28,9 @@ impl GlobalReference { } /// Used for builtins, like clog2, assert, sizeof, etc pub fn unwrap_first_template_argument(&self) -> &TemplateArg { - self.template_args[UUID::from_hidden_value(0)].as_ref().unwrap() + self.template_args[UUID::from_hidden_value(0)] + .as_ref() + .unwrap() } } diff --git a/src/typing/type_inference.rs b/src/typing/type_inference.rs index ddc893a..88cae4d 100644 --- a/src/typing/type_inference.rs +++ b/src/typing/type_inference.rs @@ -1,4 +1,4 @@ -//! Implements the Hindley-Milner algorithm for Type Inference. +//! Implements the Hindley-Milner algorithm for Type Inference. use std::cell::{OnceCell, RefCell}; use std::fmt::Debug; @@ -40,24 +40,26 @@ pub struct FailedUnification { pub expected: MyType, pub span: Span, pub context: String, - pub infos: Vec + pub infos: Vec, } /// Pretty big block size so for most typing needs we only need one -const BLOCK_SIZE : usize = 512; +const BLOCK_SIZE: usize = 512; /// Implements Hindley-Milner type inference -/// +/// /// It actually already does eager inference where possible (through [Self::unify]) -/// +/// /// When eager inference is not possible, [DelayedConstraintsList] should be used -pub struct TypeSubstitutor, VariableIDMarker : UUIDMarker> { +pub struct TypeSubstitutor, VariableIDMarker: UUIDMarker> { substitution_map: BlockVec, BLOCK_SIZE>, failed_unifications: RefCell>>, - _ph: PhantomData + _ph: PhantomData, } -impl<'v, MyType: HindleyMilner + 'v, VariableIDMarker: UUIDMarker> IntoIterator for &'v TypeSubstitutor { +impl<'v, MyType: HindleyMilner + 'v, VariableIDMarker: UUIDMarker> IntoIterator + for &'v TypeSubstitutor +{ type Item = &'v OnceCell; type IntoIter = BlockVecIter<'v, OnceCell, BLOCK_SIZE>; @@ -67,7 +69,9 @@ impl<'v, MyType: HindleyMilner + 'v, VariableIDMarker: UUIDMar } } -impl, VariableIDMarker : UUIDMarker> Index> for TypeSubstitutor { +impl, VariableIDMarker: UUIDMarker> + Index> for TypeSubstitutor +{ type Output = OnceCell; fn index(&self, index: UUID) -> &Self::Output { @@ -84,7 +88,7 @@ impl<'s> UnifyErrorReport for &'s str { (self.to_string(), Vec::new()) } } -impl (String, Vec)> UnifyErrorReport for F { +impl (String, Vec)> UnifyErrorReport for F { fn report(self) -> (String, Vec) { self() } @@ -94,7 +98,7 @@ impl (String, Vec)> UnifyErrorReport for F { pub enum UnifyResult { Success, NoMatchingTypeFunc, - NoInfiniteTypes + NoInfiniteTypes, } impl BitAnd for UnifyResult { type Output = UnifyResult; @@ -108,20 +112,25 @@ impl BitAnd for UnifyResult { } } -impl+Clone+Debug, VariableIDMarker : UUIDMarker> TypeSubstitutor { +impl + Clone + Debug, VariableIDMarker: UUIDMarker> + TypeSubstitutor +{ pub fn new() -> Self { Self { substitution_map: BlockVec::new(), failed_unifications: RefCell::new(Vec::new()), - _ph: PhantomData + _ph: PhantomData, } } - - pub fn init(variable_alloc : &UUIDAllocator) -> Self { + + pub fn init(variable_alloc: &UUIDAllocator) -> Self { Self { - substitution_map: variable_alloc.into_iter().map(|_| OnceCell::new()).collect(), + substitution_map: variable_alloc + .into_iter() + .map(|_| OnceCell::new()) + .collect(), failed_unifications: RefCell::new(Vec::new()), - _ph: PhantomData + _ph: PhantomData, } } @@ -133,19 +142,30 @@ impl+Clone+Debug, VariableIDMarker : UU UUIDRange::new_with_length(self.substitution_map.len()) } - fn does_typ_reference_var_recurse_with_substitution(&self, does_this: &MyType, reference_this: UUID) -> bool { + fn does_typ_reference_var_recurse_with_substitution( + &self, + does_this: &MyType, + reference_this: UUID, + ) -> bool { let mut does_it_reference_it = false; does_this.for_each_unknown(&mut |v: UUID| { if v == reference_this { does_it_reference_it = true; } else if let Some(found_substitution) = self[v].get() { - does_it_reference_it |= self.does_typ_reference_var_recurse_with_substitution(found_substitution, reference_this); + does_it_reference_it |= self.does_typ_reference_var_recurse_with_substitution( + found_substitution, + reference_this, + ); } }); does_it_reference_it } - fn try_fill_empty_var<'s>(&'s self, empty_var: UUID, mut replace_with: &'s MyType) -> UnifyResult { + fn try_fill_empty_var<'s>( + &'s self, + empty_var: UUID, + mut replace_with: &'s MyType, + ) -> UnifyResult { assert!(self[empty_var].get().is_none()); // 1-deep Unknowns should be dug out, becuase they don't create infinite types @@ -172,8 +192,8 @@ impl+Clone+Debug, VariableIDMarker : UU /// Returns false if the types couldn't be unified /// Unification is loosely based on this video: https://www.youtube.com/watch?v=KNbRLTLniZI - /// - /// The main change is that I don't keep a substitution list, + /// + /// The main change is that I don't keep a substitution list, /// but immediately apply substitutions to [Self::substitution_map] #[must_use] fn unify(&self, a: &MyType, b: &MyType) -> UnifyResult { @@ -189,7 +209,7 @@ impl+Clone+Debug, VariableIDMarker : UU } (None, Some(subs_b)) => self.try_fill_empty_var(a_var, subs_b), (Some(subs_a), None) => self.try_fill_empty_var(b_var, subs_a), - (Some(subs_a), Some(subs_b)) => self.unify(subs_a, subs_b) + (Some(subs_a), Some(subs_b)) => self.unify(subs_a, subs_b), } } } @@ -197,9 +217,7 @@ impl+Clone+Debug, VariableIDMarker : UU if tf_a != tf_b { UnifyResult::NoMatchingTypeFunc } else { - MyType::unify_all_args(a, b, &mut |arg_a, arg_b| { - self.unify(arg_a, arg_b) - }) + MyType::unify_all_args(a, b, &mut |arg_a, arg_b| self.unify(arg_a, arg_b)) } } (HindleyMilnerInfo::TypeFunc(_), HindleyMilnerInfo::TypeVar(v), tf, _) @@ -219,22 +237,33 @@ impl+Clone+Debug, VariableIDMarker : UU result } pub fn unify_must_succeed(&self, a: &MyType, b: &MyType) { - assert!(self.unify(a, b) == UnifyResult::Success, "This unification cannot fail. Usually because we're unifying with a Written Type"); - } - pub fn unify_report_error(&self, found: &MyType, expected: &MyType, span: Span, reporter: Report) { + assert!( + self.unify(a, b) == UnifyResult::Success, + "This unification cannot fail. Usually because we're unifying with a Written Type" + ); + } + pub fn unify_report_error( + &self, + found: &MyType, + expected: &MyType, + span: Span, + reporter: Report, + ) { let unify_result = self.unify(found, expected); if unify_result != UnifyResult::Success { let (mut context, infos) = reporter.report(); if unify_result == UnifyResult::NoInfiniteTypes { context.push_str(": Creating Infinite Types is Forbidden!"); } - self.failed_unifications.borrow_mut().push(FailedUnification { - found: found.clone(), - expected: expected.clone(), - span, - context, - infos - }); + self.failed_unifications + .borrow_mut() + .push(FailedUnification { + found: found.clone(), + expected: expected.clone(), + span, + context, + infos, + }); } } pub fn extract_errors(&mut self) -> Vec> { @@ -246,24 +275,28 @@ impl+Clone+Debug, VariableIDMarker : UU } /// Used for sanity-checking. The graph of Unknown nodes must be non-cyclical, such that we don't create infinite types - /// + /// /// Implements https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm pub fn check_no_unknown_loop(&self) { #[derive(Clone, Copy)] struct NodeInfo { is_not_part_of_loop: bool, - is_part_of_stack: bool + is_part_of_stack: bool, } - fn is_node_infinite_loop+Clone+Debug, VariableIDMarker : UUIDMarker>( - slf : &TypeSubstitutor, - node_in_path : &mut FlatAlloc, - unknown_id: UUID + fn is_node_infinite_loop< + MyType: HindleyMilner + Clone + Debug, + VariableIDMarker: UUIDMarker, + >( + slf: &TypeSubstitutor, + node_in_path: &mut FlatAlloc, + unknown_id: UUID, ) -> bool { // This is the core check we're doing. If this triggers then we have an infinite loop - if node_in_path[unknown_id].is_not_part_of_loop { // Early exit, so we don't do the same thing over and over + if node_in_path[unknown_id].is_not_part_of_loop { + // Early exit, so we don't do the same thing over and over return false; } - + let mut is_infinite_loop = false; if let Some(substitutes_to) = slf[unknown_id].get() { @@ -289,73 +322,92 @@ impl+Clone+Debug, VariableIDMarker : UU is_infinite_loop } - let mut node_in_path : FlatAlloc = FlatAlloc::with_size(self.substitution_map.len(), NodeInfo{ - is_not_part_of_loop: false, - is_part_of_stack: false, - }); - + let mut node_in_path: FlatAlloc = FlatAlloc::with_size( + self.substitution_map.len(), + NodeInfo { + is_not_part_of_loop: false, + is_part_of_stack: false, + }, + ); + for id in self.id_range() { if !node_in_path[id].is_not_part_of_loop { if is_node_infinite_loop(self, &mut node_in_path, id) { - panic!("Cyclic Type Substitution Found! See Above. On node {id:?} => {:?}", self[id]) + panic!( + "Cyclic Type Substitution Found! See Above. On node {id:?} => {:?}", + self[id] + ) } } } } } -impl, VariableIDMarker: UUIDMarker> Drop for TypeSubstitutor { +impl, VariableIDMarker: UUIDMarker> Drop + for TypeSubstitutor +{ fn drop(&mut self) { if !panicking() { - assert!(self.failed_unifications.borrow().is_empty(), "Errors were not extracted before dropping!"); + assert!( + self.failed_unifications.borrow().is_empty(), + "Errors were not extracted before dropping!" + ); } } } /// See [HindleyMilner] -/// -/// `TypeFuncIdent` is a value object, that is a "terminal". Basically, it's an atom that can either be equal or not. -/// -/// Usually this is type names: `int` `bool`, or "array of" without the containing type. -/// +/// +/// `TypeFuncIdent` is a value object, that is a "terminal". Basically, it's an atom that can either be equal or not. +/// +/// Usually this is type names: `int` `bool`, or "array of" without the containing type. +/// /// Basically, when unifying, `int` isn't equal to "array of", and thus a type error is generated -/// +/// /// This enum itself then is either such a terminal, or a type variable that can be unified (IE substituted) #[derive(Debug, Clone, Copy)] -pub enum HindleyMilnerInfo { +pub enum HindleyMilnerInfo { /// Just a marker. Use [HindleyMilner::unify_all_args] TypeFunc(TypeFuncIdent), - TypeVar(UUID) + TypeVar(UUID), } /// Implements Hindley-Milner type unification for various types in the SUS language -/// +/// /// Unification is roughly based on this video: https://www.youtube.com/watch?v=KNbRLTLniZI /// The other HM videos are also highly recommended to understand this -/// +/// /// Though this implementation does eager unification as much as possible, while unifications that cannot -/// be performed eagerly are handled by [DelayedConstraintsList]. -pub trait HindleyMilner : Sized { - type TypeFuncIdent<'slf> : Eq where Self : 'slf; +/// be performed eagerly are handled by [DelayedConstraintsList]. +pub trait HindleyMilner: Sized { + type TypeFuncIdent<'slf>: Eq + where + Self: 'slf; - fn get_hm_info<'slf>(&'slf self) -> HindleyMilnerInfo, VariableIDMarker>; + fn get_hm_info<'slf>( + &'slf self, + ) -> HindleyMilnerInfo, VariableIDMarker>; /// Iterate through all arguments and unify them - /// + /// /// If any pair couldn't be unified, return false - /// + /// /// This is never called by the user, only by [TypeSubstitutor::unify] - fn unify_all_args UnifyResult>(left : &Self, right : &Self, unify : &mut F) -> UnifyResult; + fn unify_all_args UnifyResult>( + left: &Self, + right: &Self, + unify: &mut F, + ) -> UnifyResult; /// Has to be implemented separately per type - /// + /// /// Returns true when no Unknowns remain fn fully_substitute(&mut self, substitutor: &TypeSubstitutor) -> bool; /// Recursively called for each Unknown that is part of this. Used by [TypeSubstitutor::check_no_unknown_loop] - fn for_each_unknown(&self, f : &mut impl FnMut(UUID)); + fn for_each_unknown(&self, f: &mut impl FnMut(UUID)); - fn contains_unknown(&self, var : UUID) -> bool { + fn contains_unknown(&self, var: UUID) -> bool { let mut contains_var = false; self.for_each_unknown(&mut |v: UUID| { if v == var { @@ -371,7 +423,7 @@ pub trait HindleyMilner : Sized { pub enum AbstractTypeHMInfo { Template(TemplateID), Named(TypeUUID), - Array + Array, } impl HindleyMilner for AbstractType { @@ -380,29 +432,49 @@ impl HindleyMilner for AbstractType { fn get_hm_info(&self) -> HindleyMilnerInfo { match self { AbstractType::Unknown(var_id) => HindleyMilnerInfo::TypeVar(*var_id), - AbstractType::Template(template_id) => HindleyMilnerInfo::TypeFunc(AbstractTypeHMInfo::Template(*template_id)), - AbstractType::Named(named_id) => HindleyMilnerInfo::TypeFunc(AbstractTypeHMInfo::Named(*named_id)), + AbstractType::Template(template_id) => { + HindleyMilnerInfo::TypeFunc(AbstractTypeHMInfo::Template(*template_id)) + } + AbstractType::Named(named_id) => { + HindleyMilnerInfo::TypeFunc(AbstractTypeHMInfo::Named(*named_id)) + } AbstractType::Array(_) => HindleyMilnerInfo::TypeFunc(AbstractTypeHMInfo::Array), } } - fn unify_all_args UnifyResult>(left : &Self, right : &Self, unify : &mut F) -> UnifyResult { + fn unify_all_args UnifyResult>( + left: &Self, + right: &Self, + unify: &mut F, + ) -> UnifyResult { match (left, right) { - (AbstractType::Template(na), AbstractType::Template(nb)) => {assert!(*na == *nb); UnifyResult::Success}, // Already covered by get_hm_info - (AbstractType::Named(na), AbstractType::Named(nb)) => {assert!(*na == *nb); UnifyResult::Success}, // Already covered by get_hm_info - (AbstractType::Array(arr_typ), AbstractType::Array(arr_typ_2)) => unify(arr_typ, arr_typ_2), - (_, _) => unreachable!("All others should have been eliminated by get_hm_info check") + (AbstractType::Template(na), AbstractType::Template(nb)) => { + assert!(*na == *nb); + UnifyResult::Success + } // Already covered by get_hm_info + (AbstractType::Named(na), AbstractType::Named(nb)) => { + assert!(*na == *nb); + UnifyResult::Success + } // Already covered by get_hm_info + (AbstractType::Array(arr_typ), AbstractType::Array(arr_typ_2)) => { + unify(arr_typ, arr_typ_2) + } + (_, _) => unreachable!("All others should have been eliminated by get_hm_info check"), } } - fn fully_substitute(&mut self, substitutor: &TypeSubstitutor) -> bool { + fn fully_substitute( + &mut self, + substitutor: &TypeSubstitutor, + ) -> bool { match self { AbstractType::Named(_) | AbstractType::Template(_) => true, // Template Name & Name is included in get_hm_info - AbstractType::Array(arr_typ) => { - arr_typ.fully_substitute(substitutor) - }, + AbstractType::Array(arr_typ) => arr_typ.fully_substitute(substitutor), AbstractType::Unknown(var) => { - let Some(replacement) = substitutor.substitution_map[var.get_hidden_value()].get() else {return false}; + let Some(replacement) = substitutor.substitution_map[var.get_hidden_value()].get() + else { + return false; + }; assert!(!std::ptr::eq(self, replacement)); *self = replacement.clone(); self.fully_substitute(substitutor) @@ -410,11 +482,11 @@ impl HindleyMilner for AbstractType { } } - fn for_each_unknown(&self, f : &mut impl FnMut(TypeVariableID)) { + fn for_each_unknown(&self, f: &mut impl FnMut(TypeVariableID)) { match self { AbstractType::Template(_) | AbstractType::Named(_) => {} AbstractType::Array(array_content) => array_content.for_each_unknown(f), - AbstractType::Unknown(uuid) => f(*uuid) + AbstractType::Unknown(uuid) => f(*uuid), } } } @@ -430,13 +502,20 @@ impl HindleyMilner for DomainType { } } - fn unify_all_args UnifyResult>(_left : &Self, _right : &Self, _unify : &mut F) -> UnifyResult { + fn unify_all_args UnifyResult>( + _left: &Self, + _right: &Self, + _unify: &mut F, + ) -> UnifyResult { // No sub-args UnifyResult::Success } /// For domains, always returns true. Or rather it should, since any leftover unconnected domains should be assigned an ID of their own by the type checker - fn fully_substitute(&mut self, substitutor: &TypeSubstitutor) -> bool { + fn fully_substitute( + &mut self, + substitutor: &TypeSubstitutor, + ) -> bool { match self { DomainType::Generative | DomainType::Physical(_) => true, // Do nothing, These are done already DomainType::Unknown(var) => { @@ -446,66 +525,81 @@ impl HindleyMilner for DomainType { } } - fn for_each_unknown(&self, f : &mut impl FnMut(DomainVariableID)) { + fn for_each_unknown(&self, f: &mut impl FnMut(DomainVariableID)) { match self { DomainType::Generative | DomainType::Physical(_) => {} - DomainType::Unknown(uuid) => f(*uuid) + DomainType::Unknown(uuid) => f(*uuid), } } } - /// [HindleyMilnerInfo] `TypeFuncIdent` for [ConcreteType] #[derive(Debug, Clone, PartialEq, Eq)] pub enum ConcreteTypeHMInfo<'slf> { Named(TypeUUID), Value(&'slf Value), - Array + Array, } - impl HindleyMilner for ConcreteType { type TypeFuncIdent<'slf> = ConcreteTypeHMInfo<'slf>; fn get_hm_info(&self) -> HindleyMilnerInfo { match self { ConcreteType::Unknown(var_id) => HindleyMilnerInfo::TypeVar(*var_id), - ConcreteType::Named(named_id) => HindleyMilnerInfo::TypeFunc(ConcreteTypeHMInfo::Named(named_id.id)), + ConcreteType::Named(named_id) => { + HindleyMilnerInfo::TypeFunc(ConcreteTypeHMInfo::Named(named_id.id)) + } ConcreteType::Value(v) => HindleyMilnerInfo::TypeFunc(ConcreteTypeHMInfo::Value(v)), ConcreteType::Array(_) => HindleyMilnerInfo::TypeFunc(ConcreteTypeHMInfo::Array), } } - fn unify_all_args UnifyResult>(left : &Self, right : &Self, unify : &mut F) -> UnifyResult { + fn unify_all_args UnifyResult>( + left: &Self, + right: &Self, + unify: &mut F, + ) -> UnifyResult { match (left, right) { - (ConcreteType::Named(na), ConcreteType::Named(nb)) => {assert!(*na == *nb); UnifyResult::Success} // Already covered by get_hm_info - (ConcreteType::Value(v_1), ConcreteType::Value(v_2)) => {assert!(*v_1 == *v_2); UnifyResult::Success} // Already covered by get_hm_info + (ConcreteType::Named(na), ConcreteType::Named(nb)) => { + assert!(*na == *nb); + UnifyResult::Success + } // Already covered by get_hm_info + (ConcreteType::Value(v_1), ConcreteType::Value(v_2)) => { + assert!(*v_1 == *v_2); + UnifyResult::Success + } // Already covered by get_hm_info (ConcreteType::Array(arr_typ_1), ConcreteType::Array(arr_typ_2)) => { let (arr_typ_1_arr, arr_typ_1_sz) = arr_typ_1.deref(); let (arr_typ_2_arr, arr_typ_2_sz) = arr_typ_2.deref(); unify(arr_typ_1_arr, arr_typ_2_arr) & unify(arr_typ_1_sz, arr_typ_2_sz) } - (_, _) => unreachable!("All others should have been eliminated by get_hm_info check") + (_, _) => unreachable!("All others should have been eliminated by get_hm_info check"), } } - fn fully_substitute(&mut self, substitutor: &TypeSubstitutor) -> bool { + fn fully_substitute( + &mut self, + substitutor: &TypeSubstitutor, + ) -> bool { match self { ConcreteType::Named(_) | ConcreteType::Value(_) => true, // Don't need to do anything, this is already final ConcreteType::Array(arr_typ) => { let (arr_typ, arr_sz) = arr_typ.deref_mut(); - arr_typ.fully_substitute(substitutor) && - arr_sz.fully_substitute(substitutor) - }, + arr_typ.fully_substitute(substitutor) && arr_sz.fully_substitute(substitutor) + } ConcreteType::Unknown(var) => { - let Some(replacement) = substitutor.substitution_map[var.get_hidden_value()].get() else {return false}; + let Some(replacement) = substitutor.substitution_map[var.get_hidden_value()].get() + else { + return false; + }; *self = replacement.clone(); self.fully_substitute(substitutor) } } } - fn for_each_unknown(&self, f : &mut impl FnMut(ConcreteTypeVariableID)) { + fn for_each_unknown(&self, f: &mut impl FnMut(ConcreteTypeVariableID)) { match self { ConcreteType::Named(_) | ConcreteType::Value(_) => {} ConcreteType::Unknown(uuid) => f(*uuid), @@ -513,7 +607,7 @@ impl HindleyMilner for ConcreteType { let (arr_typ, arr_sz) = arr_typ.deref(); arr_typ.for_each_unknown(f); arr_sz.for_each_unknown(f); - }, + } } } } @@ -526,26 +620,26 @@ pub enum DelayedConstraintStatus { /// Progress was made, (potentially enabling other parts to continue), but the constraint cannot be removed #[allow(unused)] Progress, - /// No progress was made, if all constraints return [DelayedConstraintStatus::NoProgress] then type resolution deadlocked and cannot finish. - NoProgress + /// No progress was made, if all constraints return [DelayedConstraintStatus::NoProgress] then type resolution deadlocked and cannot finish. + NoProgress, } -/// Implement this for any typing constraints that can't be resolved immediately. -/// +/// Implement this for any typing constraints that can't be resolved immediately. +/// /// See [DelayedConstraintsList] pub trait DelayedConstraint { - fn try_apply(&mut self, shared_object : &mut T) -> DelayedConstraintStatus; - fn report_could_not_resolve_error(&self, shared_object : &T); + fn try_apply(&mut self, shared_object: &mut T) -> DelayedConstraintStatus; + fn report_could_not_resolve_error(&self, shared_object: &T); } /// This is for unification of constraints that may not be resolveable right away -/// +/// /// Such as struct field access. vec.x cannot resolve the type of x before the type of vec has been resolved -/// +/// /// The given function should only make changes when it can be successfully resolved -/// +/// /// When the constraint has been resolved, it should return 'true' -/// +/// /// For convenience, a &mut T is provided such that a shared mutable object can be used pub struct DelayedConstraintsList(Vec>>); @@ -555,23 +649,28 @@ impl DelayedConstraintsList { } /// Add a constraint - pub fn push + 'static>(&mut self, constraint: C) { + pub fn push + 'static>(&mut self, constraint: C) { self.0.push(Box::new(constraint)); } - /// Will keep looping over the list of constraints, and try to apply them. - /// + /// Will keep looping over the list of constraints, and try to apply them. + /// /// Calls [DelayedConstraint::report_could_not_resolve_error] on all constraints that weren't resolved pub fn resolve_delayed_constraints(mut self, shared_object: &mut T) { while self.0.len() > 0 { let mut progress_made = false; - self.0.retain_mut(|constraint| { - match constraint.try_apply(shared_object) { - DelayedConstraintStatus::Resolved => {progress_made = true; false} - DelayedConstraintStatus::Progress => {progress_made = true; true} - DelayedConstraintStatus::NoProgress => true - } - }); + self.0 + .retain_mut(|constraint| match constraint.try_apply(shared_object) { + DelayedConstraintStatus::Resolved => { + progress_made = true; + false + } + DelayedConstraintStatus::Progress => { + progress_made = true; + true + } + DelayedConstraintStatus::NoProgress => true, + }); if !progress_made { for constraint in std::mem::replace(&mut self.0, Vec::new()) { constraint.report_could_not_resolve_error(shared_object); @@ -589,4 +688,3 @@ impl Drop for DelayedConstraintsList { } } } - diff --git a/src/value.rs b/src/value.rs index 0e9ff8f..36b1a56 100644 --- a/src/value.rs +++ b/src/value.rs @@ -6,11 +6,11 @@ use crate::flattening::{BinaryOperator, UnaryOperator}; use crate::typing::{ concrete_type::{ConcreteType, BOOL_CONCRETE_TYPE, INT_CONCRETE_TYPE}, - type_inference::{ConcreteTypeVariableIDMarker, TypeSubstitutor} + type_inference::{ConcreteTypeVariableIDMarker, TypeSubstitutor}, }; -/// Top type for any kind of compiletime value while executing. -/// +/// Top type for any kind of compiletime value while executing. +/// /// These are used during execution ([crate::instantiation::execute]) #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Value { @@ -23,18 +23,23 @@ pub enum Value { } impl Value { - /// Traverses the Value, to create a best-effort [ConcreteType] for it. - /// So '1' becomes [INT_CONCRETE_TYPE], + /// Traverses the Value, to create a best-effort [ConcreteType] for it. + /// So '1' becomes [INT_CONCRETE_TYPE], /// but `Value::Array([])` becomes `ConcreteType::Array(ConcreteType::Unknown)` - /// + /// /// Panics when arrays contain mutually incompatible types - pub fn get_type_best_effort(&self, type_substitutor: &mut TypeSubstitutor) -> ConcreteType { + pub fn get_type_best_effort( + &self, + type_substitutor: &mut TypeSubstitutor, + ) -> ConcreteType { match self { Value::Bool(_) => BOOL_CONCRETE_TYPE, Value::Integer(_) => INT_CONCRETE_TYPE, Value::Array(arr) => { let mut arr_iter = arr.iter(); - let Some(fst) = arr_iter.next() else {return ConcreteType::Unknown(type_substitutor.alloc())}; + let Some(fst) = arr_iter.next() else { + return ConcreteType::Unknown(type_substitutor.alloc()); + }; let typ = fst.get_type_best_effort(type_substitutor); for other in arr_iter { @@ -42,7 +47,10 @@ impl Value { assert!(other.is_of_type(&typ)); } - ConcreteType::Array(Box::new((typ, ConcreteType::Value(Value::Integer(arr.len().into()))))) + ConcreteType::Array(Box::new(( + typ, + ConcreteType::Value(Value::Integer(arr.len().into())), + ))) } Value::Unset | Value::Error => unreachable!(), } @@ -123,9 +131,7 @@ pub fn compute_unary_op(op: UnaryOperator, v: &Value) -> Value { todo!("Array Values") } UnaryOperator::Negate => { - let Value::Integer(v) = v else { - panic!() - }; + let Value::Integer(v) = v else { panic!() }; Value::Integer(-v) } } @@ -139,27 +145,15 @@ pub fn compute_binary_op(left: &Value, op: BinaryOperator, right: &Value) -> Val match op { BinaryOperator::Equals => Value::Bool(left == right), BinaryOperator::NotEquals => Value::Bool(left != right), - BinaryOperator::GreaterEq => { - Value::Bool(left.unwrap_integer() >= right.unwrap_integer()) - } + BinaryOperator::GreaterEq => Value::Bool(left.unwrap_integer() >= right.unwrap_integer()), BinaryOperator::Greater => Value::Bool(left.unwrap_integer() > right.unwrap_integer()), - BinaryOperator::LesserEq => { - Value::Bool(left.unwrap_integer() <= right.unwrap_integer()) - } + BinaryOperator::LesserEq => Value::Bool(left.unwrap_integer() <= right.unwrap_integer()), BinaryOperator::Lesser => Value::Bool(left.unwrap_integer() < right.unwrap_integer()), BinaryOperator::Add => Value::Integer(left.unwrap_integer() + right.unwrap_integer()), - BinaryOperator::Subtract => { - Value::Integer(left.unwrap_integer() - right.unwrap_integer()) - } - BinaryOperator::Multiply => { - Value::Integer(left.unwrap_integer() * right.unwrap_integer()) - } - BinaryOperator::Divide => { - Value::Integer(left.unwrap_integer() / right.unwrap_integer()) - } - BinaryOperator::Modulo => { - Value::Integer(left.unwrap_integer() % right.unwrap_integer()) - } + BinaryOperator::Subtract => Value::Integer(left.unwrap_integer() - right.unwrap_integer()), + BinaryOperator::Multiply => Value::Integer(left.unwrap_integer() * right.unwrap_integer()), + BinaryOperator::Divide => Value::Integer(left.unwrap_integer() / right.unwrap_integer()), + BinaryOperator::Modulo => Value::Integer(left.unwrap_integer() % right.unwrap_integer()), BinaryOperator::And => Value::Bool(left.unwrap_bool() & right.unwrap_bool()), BinaryOperator::Or => Value::Bool(left.unwrap_bool() & right.unwrap_bool()), BinaryOperator::Xor => Value::Bool(left.unwrap_bool() & right.unwrap_bool()), diff --git a/sus-proc-macro/src/lib.rs b/sus-proc-macro/src/lib.rs index 3fc7f68..0379f09 100644 --- a/sus-proc-macro/src/lib.rs +++ b/sus-proc-macro/src/lib.rs @@ -1,4 +1,3 @@ - use proc_macro::TokenStream; use quote::{quote, quote_spanned}; @@ -87,14 +86,16 @@ pub fn get_builtin_type(token_stream: TokenStream) -> TokenStream { if found_name == object_name { return quote! { crate::prelude::TypeUUID::from_hidden_value(#idx) - }.into(); + } + .into(); } } - + quote_spanned!( string_literal.span() => compile_error!("Unknown builtin type was not found in std/core.sus") - ).into() + ) + .into() } #[proc_macro] @@ -112,12 +113,14 @@ pub fn get_builtin_const(token_stream: TokenStream) -> TokenStream { if found_name == object_name { return quote! { crate::prelude::ConstantUUID::from_hidden_value(#idx) - }.into(); + } + .into(); } } - + quote_spanned!( string_literal.span() => compile_error!("Unknown builtin const was not found in std/core.sus") - ).into() + ) + .into() } From d1728ee09f26fe24a92ae87a9ea429700703fed9 Mon Sep 17 00:00:00 2001 From: Tobias Tom Hodapp Date: Thu, 30 Jan 2025 19:39:47 +0100 Subject: [PATCH 2/6] Clippy auto fixes --- src/alloc.rs | 49 +++++++++++++------ src/block_vector.rs | 14 +++--- src/codegen/mod.rs | 2 +- src/codegen/system_verilog.rs | 16 +++---- src/codegen/vhdl.rs | 8 ++-- src/compiler_top.rs | 4 +- src/debug.rs | 6 +-- src/dev_aid/ariadne_interface.rs | 4 +- src/dev_aid/lsp/hover_info.rs | 13 +++--- src/dev_aid/lsp/mod.rs | 20 ++++---- src/dev_aid/lsp/semantic_tokens.rs | 2 +- src/dev_aid/lsp/tree_walk.rs | 10 ++-- src/errors.rs | 17 ++++--- src/flattening/flatten.rs | 62 +++++++++++-------------- src/flattening/initialization.rs | 4 +- src/flattening/mod.rs | 2 +- src/flattening/parser.rs | 16 +++---- src/flattening/typechecking.rs | 12 ++--- src/instantiation/concrete_typecheck.rs | 6 +-- src/instantiation/execute.rs | 8 ++-- src/instantiation/latency_algorithm.rs | 19 +++----- src/instantiation/latency_count.rs | 10 ++-- src/instantiation/list_of_lists.rs | 18 ++++--- src/instantiation/mod.rs | 8 +++- src/linker/mod.rs | 10 +++- src/linker/resolver.rs | 14 +++--- src/typing/abstract_type.rs | 20 ++++---- src/typing/type_inference.rs | 50 ++++++++++---------- 28 files changed, 224 insertions(+), 200 deletions(-) diff --git a/src/alloc.rs b/src/alloc.rs index 0e5810a..2e08ef2 100644 --- a/src/alloc.rs +++ b/src/alloc.rs @@ -64,9 +64,13 @@ pub struct UUIDAllocator { impl Clone for UUIDAllocator { fn clone(&self) -> Self { - Self { - cur: self.cur.clone(), - } + Self { cur: self.cur } + } +} + +impl Default for UUIDAllocator { + fn default() -> Self { + Self::new() } } @@ -289,7 +293,7 @@ impl ArenaAllocator { } pub fn free(&mut self, UUID(uuid, _): UUID) -> T { self.free_slots.push(uuid); - std::mem::replace(&mut self.data[uuid], None).unwrap() + self.data[uuid].take().unwrap() } pub fn clear(&mut self) { self.data.clear(); @@ -298,10 +302,10 @@ impl ArenaAllocator { pub fn is_empty(&self) -> bool { self.data.len() == self.free_slots.len() } - pub fn iter<'a>(&'a self) -> FlatOptionIterator<'a, T, IndexMarker> { + pub fn iter(&self) -> FlatOptionIterator<'_, T, IndexMarker> { self.into_iter() } - pub fn iter_mut<'a>(&'a mut self) -> FlatOptionIteratorMut<'a, T, IndexMarker> { + pub fn iter_mut(&mut self) -> FlatOptionIteratorMut<'_, T, IndexMarker> { self.into_iter() } pub fn find( @@ -407,6 +411,12 @@ pub struct ArenaVector { _ph: PhantomData, } +impl Default for ArenaVector { + fn default() -> Self { + Self::new() + } +} + impl ArenaVector { pub fn new() -> Self { Self { @@ -424,10 +434,10 @@ impl ArenaVector { pub fn remove(&mut self, UUID(uuid, _): UUID) { self.data[uuid] = None; } - pub fn iter<'a>(&'a self) -> FlatOptionIterator<'a, T, IndexMarker> { + pub fn iter(&self) -> FlatOptionIterator<'_, T, IndexMarker> { self.into_iter() } - pub fn iter_mut<'a>(&'a mut self) -> FlatOptionIteratorMut<'a, T, IndexMarker> { + pub fn iter_mut(&mut self) -> FlatOptionIteratorMut<'_, T, IndexMarker> { self.into_iter() } pub fn find( @@ -485,6 +495,12 @@ pub struct FlatAlloc { _ph: PhantomData, } +impl Default for FlatAlloc { + fn default() -> Self { + Self::new() + } +} + impl FlatAlloc { pub const EMPTY_FLAT_ALLOC: Self = Self::new(); @@ -516,7 +532,10 @@ impl FlatAlloc { UUID(uuid, PhantomData) } pub fn last_id(&self) -> UUID { - assert!(self.data.len() >= 1, "Can't get last_id on empty FlatAlloc"); + assert!( + !self.data.is_empty(), + "Can't get last_id on empty FlatAlloc" + ); UUID(self.data.len() - 1, PhantomData) } pub fn alloc(&mut self, value: T) -> UUID { @@ -536,10 +555,10 @@ impl FlatAlloc { pub fn clear(&mut self) { self.data.clear(); } - pub fn iter<'a>(&'a self) -> FlatAllocIter<'a, T, IndexMarker> { + pub fn iter(&self) -> FlatAllocIter<'_, T, IndexMarker> { self.into_iter() } - pub fn iter_mut<'a>(&'a mut self) -> FlatAllocIterMut<'a, T, IndexMarker> { + pub fn iter_mut(&mut self) -> FlatAllocIterMut<'_, T, IndexMarker> { self.into_iter() } pub fn map( @@ -589,13 +608,13 @@ impl FlatAlloc { } impl FlatAlloc, IndexMarker> { - pub fn iter_valids<'a>(&'a self) -> FlatOptionIterator<'a, T, IndexMarker> { + pub fn iter_valids(&self) -> FlatOptionIterator<'_, T, IndexMarker> { FlatOptionIterator { it: self.data.iter().enumerate(), _ph: PhantomData, } } - pub fn iter_valids_mut<'a>(&'a mut self) -> FlatOptionIteratorMut<'a, T, IndexMarker> { + pub fn iter_valids_mut(&mut self) -> FlatOptionIteratorMut<'_, T, IndexMarker> { FlatOptionIteratorMut { it: self.data.iter_mut().enumerate(), _ph: PhantomData, @@ -661,7 +680,7 @@ impl<'a, T, IndexMarker> Iterator for FlatAllocIter<'a, T, IndexMarker> { self.iter.size_hint() } } -impl<'a, T, IndexMarker> ExactSizeIterator for FlatAllocIter<'a, T, IndexMarker> { +impl ExactSizeIterator for FlatAllocIter<'_, T, IndexMarker> { fn len(&self) -> usize { self.iter.len() } @@ -696,7 +715,7 @@ impl<'a, T, IndexMarker> Iterator for FlatAllocIterMut<'a, T, IndexMarker> { self.iter.size_hint() } } -impl<'a, T, IndexMarker> ExactSizeIterator for FlatAllocIterMut<'a, T, IndexMarker> { +impl ExactSizeIterator for FlatAllocIterMut<'_, T, IndexMarker> { fn len(&self) -> usize { self.iter.len() } diff --git a/src/block_vector.rs b/src/block_vector.rs index fd9626d..70fafd9 100644 --- a/src/block_vector.rs +++ b/src/block_vector.rs @@ -67,11 +67,11 @@ impl BlockVec { /// Critically, since appending to [BlockVec] is non-mutable, it is possible to do so while holding a [BlockVecIter]. /// BlockVecIter only iterates up to the size the BlockVec had when [BlockVec::iter] was called - pub fn iter<'s>(&'s self) -> BlockVecIter<'s, T, BLOCK_SIZE> { + pub fn iter(&self) -> BlockVecIter<'_, T, BLOCK_SIZE> { self.into_iter() } - pub fn iter_mut<'s>(&'s mut self) -> BlockVecIterMut<'s, T, BLOCK_SIZE> { + pub fn iter_mut(&mut self) -> BlockVecIterMut<'_, T, BLOCK_SIZE> { self.into_iter() } } @@ -159,7 +159,7 @@ impl<'bv, T, const BLOCK_SIZE: usize> Iterator for BlockVecIter<'bv, T, BLOCK_SI Some(self.block_vec.index(selected_idx)) } else { - return None; + None } } } @@ -196,7 +196,7 @@ impl<'bv, T, const BLOCK_SIZE: usize> Iterator for BlockVecIterMut<'bv, T, BLOCK let original_ref: *mut T = self.block_vec.index_mut(selected_idx); Some(unsafe { &mut *original_ref }) } else { - return None; + None } } } @@ -236,7 +236,7 @@ impl Iterator for BlockVecConsumingIter IntoIterator for BlockVec { fn into_iter(mut self) -> Self::IntoIter { let total_vec_size = self.length.get(); self.length.set(0); - let block_vec = std::mem::replace(self.blocks.get_mut(), Vec::new()); + let block_vec = std::mem::take(self.blocks.get_mut()); let block_vec_iter = block_vec.into_iter(); BlockVecConsumingIter { block_vec_iter, @@ -262,7 +262,7 @@ impl IntoIterator for BlockVec { impl Drop for BlockVecConsumingIter { fn drop(&mut self) { - while let Some(_) = self.next() {} // Automatically drops all remaining elements of the iterator + for _ in self.by_ref() {} // Automatically drops all remaining elements of the iterator } } diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 3aee9b0..2117011 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -58,7 +58,7 @@ pub trait CodeGenBackend { return; // Continue } println!("Instantiating success: {inst_name}"); - let code = self.codegen(md, &inst, linker, true); // hardcode use_latency = true for now. Maybe forever, we'll see + let code = self.codegen(md, inst, linker, true); // hardcode use_latency = true for now. Maybe forever, we'll see write!(out_file, "{code}").unwrap(); } diff --git a/src/codegen/system_verilog.rs b/src/codegen/system_verilog.rs index d9587c4..a55c5c5 100644 --- a/src/codegen/system_verilog.rs +++ b/src/codegen/system_verilog.rs @@ -142,13 +142,13 @@ impl<'g> CodeGenerationContext<'g> { } fn comment_out(&mut self, f: impl FnOnce(&mut Self)) { - let store_program_text_temporary = std::mem::replace(&mut self.program_text, String::new()); + let store_program_text_temporary = std::mem::take(&mut self.program_text); f(self); let added_text = std::mem::replace(&mut self.program_text, store_program_text_temporary); - write!( + writeln!( self.program_text, - "// {}\n", + "// {}", added_text.replace("\n", "\n// ") ) .unwrap(); @@ -218,7 +218,7 @@ impl<'g> CodeGenerationContext<'g> { match value { Value::Bool(_) | Value::Integer(_) | Value::Unset => { let v_str = value.inline_constant_to_string(); - write!(self.program_text, "{to} = {v_str};\n").unwrap(); + writeln!(self.program_text, "{to} = {v_str};").unwrap(); } Value::Array(arr) => { for (idx, v) in arr.iter().enumerate() { @@ -254,7 +254,7 @@ impl<'g> CodeGenerationContext<'g> { match &w.source { RealWireDataSource::Select { root, path } => { let wire_name = self.wire_name(*root, w.absolute_latency); - let path = self.wire_ref_path_to_string(&path, w.absolute_latency); + let path = self.wire_ref_path_to_string(path, w.absolute_latency); writeln!(self.program_text, " = {wire_name}{path};").unwrap(); } RealWireDataSource::UnaryOp { op, right } => { @@ -362,7 +362,7 @@ impl<'g> CodeGenerationContext<'g> { first = false; } self.program_text.write_char('.').unwrap(); - self.program_text.write_str(&arg_name).unwrap(); + self.program_text.write_str(arg_name).unwrap(); self.program_text.write_char('(').unwrap(); self.program_text.write_str(&arg_value).unwrap(); self.program_text.write_char(')').unwrap(); @@ -447,7 +447,7 @@ impl<'g> CodeGenerationContext<'g> { .md .unwrap_port(PortID::from_hidden_value(1), false, "bits"); for i in 0..32 { - write!(self.program_text, "\tassign bits[{i}] = value[{i}];\n").unwrap(); + writeln!(self.program_text, "\tassign bits[{i}] = value[{i}];").unwrap(); } } "BitsToInt" => { @@ -458,7 +458,7 @@ impl<'g> CodeGenerationContext<'g> { .md .unwrap_port(PortID::from_hidden_value(1), false, "value"); for i in 0..32 { - write!(self.program_text, "\tassign value[{i}] = bits[{i}];\n").unwrap(); + writeln!(self.program_text, "\tassign value[{i}] = bits[{i}];").unwrap(); } } other => { diff --git a/src/codegen/vhdl.rs b/src/codegen/vhdl.rs index 1cc63e5..8cdee1f 100644 --- a/src/codegen/vhdl.rs +++ b/src/codegen/vhdl.rs @@ -60,7 +60,7 @@ fn typ_to_declaration(mut typ: &ConcreteType) -> String { } } -impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> { +impl CodeGenerationContext<'_, '_, Stream> { fn write_vhdl_code(&mut self) { match self.md.link_info.is_extern { IsExtern::Normal => { @@ -104,9 +104,9 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> let port_direction = if port.is_input { "in" } else { "out" }; let port_type = typ_to_declaration(&port_wire.typ); let end = if it.peek().is_some() { ";" } else { "" }; - write!( + writeln!( self.program_text, - "{comment_text} {port_name} : {port_direction} {port_type}{end}\n" + "{comment_text} {port_name} : {port_direction} {port_type}{end}" ) .unwrap(); } @@ -143,7 +143,7 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> return false; } } - return true; + true }) .map(|(_, wire)| { let signal_name = wire_name_self_latency(wire, self.use_latency); diff --git a/src/compiler_top.rs b/src/compiler_top.rs index 9ebe939..2163b0c 100644 --- a/src/compiler_top.rs +++ b/src/compiler_top.rs @@ -240,8 +240,6 @@ impl Linker { } span_debugger.defuse(); } - if config().early_exit == EarlyExitUpTo::Instantiate { - return; - } + if config().early_exit == EarlyExitUpTo::Instantiate {} } } diff --git a/src/debug.rs b/src/debug.rs index b81e438..d8543fa 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -33,11 +33,11 @@ struct TouchedSpansHistory { thread_local! { static SPANS_HISTORY : RefCell = - RefCell::new(TouchedSpansHistory{ + const { RefCell::new(TouchedSpansHistory{ span_history : [DEFAULT_RANGE; SPAN_TOUCH_HISTORY_SIZE], num_spans : 0, in_use : false - }); + }) }; } fn print_most_recent_spans(file_data: &FileData) { @@ -111,7 +111,7 @@ impl<'text> SpanDebugger<'text> { } } -impl<'text> Drop for SpanDebugger<'text> { +impl Drop for SpanDebugger<'_> { fn drop(&mut self) { if !self.defused { println!("Panic happened in Span-guarded context: {}", self.context); diff --git a/src/dev_aid/ariadne_interface.rs b/src/dev_aid/ariadne_interface.rs index 8a5c3c8..bba9e42 100644 --- a/src/dev_aid/ariadne_interface.rs +++ b/src/dev_aid/ariadne_interface.rs @@ -201,14 +201,14 @@ pub fn pretty_print_many_spans(file_data: &FileData, spans: &[(String, Range> = Report::build(ReportKind::Advice, (), spans[0].1.start).with_config(config); - for (text, span) in spans.into_iter().rev() { + for (text, span) in spans.iter().rev() { // If span not in file, just don't print it. This happens. if span.end > text_len { println!( diff --git a/src/dev_aid/lsp/hover_info.rs b/src/dev_aid/lsp/hover_info.rs index 2debf13..02e7f49 100644 --- a/src/dev_aid/lsp/hover_info.rs +++ b/src/dev_aid/lsp/hover_info.rs @@ -23,7 +23,7 @@ struct HoverCollector<'l> { file_data: &'l FileData, } -impl<'l> HoverCollector<'l> { +impl HoverCollector<'_> { fn documentation(&mut self, d: &Documentation) { self.list .push(MarkedString::String(d.to_string(&self.file_data.file_text))) @@ -56,7 +56,7 @@ impl<'l> HoverCollector<'l> { let value_str = match &inst.generation_state[id] { SubModuleOrWire::SubModule(_) | SubModuleOrWire::Wire(_) => unreachable!(), SubModuleOrWire::CompileTimeValue(v) => format!(" = {}", v), - SubModuleOrWire::Unnasigned => format!("never assigned to"), + SubModuleOrWire::Unnasigned => "never assigned to".to_string(), }; self.monospace(value_str); } else { @@ -241,10 +241,11 @@ pub fn hover(info: LocationInfo, linker: &Linker, file_data: &FileData) -> Vec { let md = &linker.modules[md_uuid]; diff --git a/src/dev_aid/lsp/mod.rs b/src/dev_aid/lsp/mod.rs index 6c33a89..d535239 100644 --- a/src/dev_aid/lsp/mod.rs +++ b/src/dev_aid/lsp/mod.rs @@ -168,7 +168,7 @@ fn push_all_errors( let mut diag_vec: Vec = Vec::new(); linker.for_all_errors_in_file(file_id, |err| { - diag_vec.push(convert_diagnostic(err, &file_data.file_text, &linker)); + diag_vec.push(convert_diagnostic(err, &file_data.file_text, linker)); }); let params = &PublishDiagnosticsParams { @@ -289,9 +289,9 @@ fn gather_all_references_in_one_file(linker: &Linker, file_id: FileUUID, pos: us if let Some((_location, hover_info)) = get_selected_object(linker, file_id, pos) { let refers_to = RefersTo::from(hover_info); if refers_to.is_global() { - gather_references_in_file(&linker, &linker.files[file_id], refers_to) + gather_references_in_file(linker, &linker.files[file_id], refers_to) } else if let Some(local) = refers_to.local { - for_each_local_reference_in_global(&linker, local.0, local.1) + for_each_local_reference_in_global(linker, local.0, local.1) } else { Vec::new() } @@ -311,20 +311,20 @@ fn gather_all_references_across_all_files( let refers_to = RefersTo::from(hover_info); if refers_to.is_global() { for (other_file_id, other_file) in &linker.files { - let found_refs = gather_references_in_file(&linker, other_file, refers_to); + let found_refs = gather_references_in_file(linker, other_file, refers_to); for r in &found_refs { assert!(location.size() == r.size()) } - if found_refs.len() > 0 { + if !found_refs.is_empty() { ref_locations.push((other_file_id, found_refs)) } } } else if let Some(local) = refers_to.local { - let found_refs = for_each_local_reference_in_global(&linker, local.0, local.1); + let found_refs = for_each_local_reference_in_global(linker, local.0, local.1); for r in &found_refs { assert!(location.size() == r.size()) } - if found_refs.len() > 0 { + if !found_refs.is_empty() { ref_locations.push((file_id, found_refs)) } } @@ -499,7 +499,7 @@ fn handle_request( let (file_uuid, position) = linker.location_in_file(¶ms.text_document_position, manager); - serde_json::to_value(&CompletionResponse::Array(gather_completions( + serde_json::to_value(CompletionResponse::Array(gather_completions( linker, file_uuid, position, ))) } @@ -529,13 +529,13 @@ fn handle_notification( assert!(only_change.range.is_none()); linker.update_text(¶ms.text_document.uri, only_change.text, manager); - push_all_errors(connection, &linker)?; + push_all_errors(connection, linker)?; } notification::DidChangeWatchedFiles::METHOD => { println!("Workspace Files modified"); (*linker, *manager) = initialize_all_files(initialize_params); - push_all_errors(&connection, &linker)?; + push_all_errors(connection, linker)?; } other => { println!("got other notification: {other:?}"); diff --git a/src/dev_aid/lsp/semantic_tokens.rs b/src/dev_aid/lsp/semantic_tokens.rs index 0421465..8649d3b 100644 --- a/src/dev_aid/lsp/semantic_tokens.rs +++ b/src/dev_aid/lsp/semantic_tokens.rs @@ -83,7 +83,7 @@ fn convert_to_semantic_tokens( }; ide_tokens - .into_iter() + .iter_mut() .map(|(span, ide_kind)| { let typ = get_semantic_token_type_from_ide_token(*ide_kind); let mod_bits = get_modifiers_for_token(*ide_kind); diff --git a/src/dev_aid/lsp/tree_walk.rs b/src/dev_aid/lsp/tree_walk.rs index a372908..a9adad8 100644 --- a/src/dev_aid/lsp/tree_walk.rs +++ b/src/dev_aid/lsp/tree_walk.rs @@ -46,7 +46,7 @@ pub struct RefersTo { pub parameter: Option<(GlobalUUID, TemplateID)>, } -impl<'linker> From> for RefersTo { +impl From> for RefersTo { fn from(info: LocationInfo) -> Self { let mut result = RefersTo { local: None, @@ -366,7 +366,7 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b if let ParameterKind::Type(TypeParameterKind {}) = &template_arg.kind { self.visit( template_arg.name_span, - LocationInfo::Parameter(name_elem, &link_info, template_id, template_arg), + LocationInfo::Parameter(name_elem, link_info, template_id, template_arg), ); } } @@ -375,12 +375,12 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b fn walk_link_info(&mut self, obj_id: GlobalUUID) { let link_info = self.linker.get_link_info(obj_id); if !(self.should_prune)(link_info.span) { - self.walk_name_and_template_arguments(obj_id, &link_info); + self.walk_name_and_template_arguments(obj_id, link_info); for (id, inst) in &link_info.instructions { match inst { Instruction::SubModule(sm) => { - self.walk_global_reference(obj_id, &link_info, &sm.module_ref); + self.walk_global_reference(obj_id, link_info, &sm.module_ref); if let Some((_sm_name, sm_name_span)) = &sm.name { self.visit( *sm_name_span, @@ -394,7 +394,7 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b } } Instruction::Declaration(decl) => { - self.walk_type(obj_id, &link_info, &decl.typ_expr); + self.walk_type(obj_id, link_info, &decl.typ_expr); if decl.declaration_itself_is_not_written_to { self.visit( decl.name_span, diff --git a/src/errors.rs b/src/errors.rs index 44d7503..fcfcd60 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -46,6 +46,12 @@ pub struct ErrorStore { pub did_error: bool, } +impl Default for ErrorStore { + fn default() -> Self { + Self::new() + } +} + impl ErrorStore { pub fn new() -> ErrorStore { ErrorStore { @@ -128,10 +134,7 @@ impl<'linker> ErrorCollector<'linker> { } } /// To re-attach this [ErrorCollector] to a new [Linker]. Mostly to get around the borrow checker - pub fn re_attach<'new_linker>( - self, - files: &'new_linker ArenaAllocator, - ) -> ErrorCollector<'new_linker> { + pub fn re_attach(self, files: &ArenaAllocator) -> ErrorCollector<'_> { ErrorCollector { error_store: RefCell::new(self.error_store.replace(ErrorStore::new())), file: self.file, @@ -192,7 +195,7 @@ impl<'linker> ErrorCollector<'linker> { } } -impl<'l> Drop for ErrorCollector<'l> { +impl Drop for ErrorCollector<'_> { fn drop(&mut self) { if !self.error_store.borrow().is_untouched() && !panicking() { panic!("ErrorCollector should have been emptied!"); @@ -210,7 +213,7 @@ pub struct ErrorReference<'ec> { pos: usize, } -impl<'ec> ErrorReference<'ec> { +impl ErrorReference<'_> { pub fn existing_info(&self, error_info: ErrorInfo) -> &Self { assert!( error_info.position.debug().into_range().end @@ -232,7 +235,7 @@ impl<'ec> ErrorReference<'ec> { self.info((span, self.err_collector.file), reason) } pub fn info_obj(&self, obj: &Obj) -> &Self { - self.existing_info(obj.make_global_info(&self.err_collector.files)) + self.existing_info(obj.make_global_info(self.err_collector.files)) } pub fn info_obj_same_file(&self, obj: &Obj) -> &Self { if let Some(info) = obj.make_info(self.err_collector.file) { diff --git a/src/flattening/flatten.rs b/src/flattening/flatten.rs index b7b6822..286c350 100644 --- a/src/flattening/flatten.rs +++ b/src/flattening/flatten.rs @@ -251,7 +251,7 @@ struct FlatteningContext<'l, 'errs> { default_declaration_context: DeclarationContext, } -impl<'l, 'errs> FlatteningContext<'l, 'errs> { +impl FlatteningContext<'_, '_> { fn flatten_parameters(&mut self, cursor: &mut Cursor) { let mut parameters_to_visit = self .working_on_link_info @@ -983,7 +983,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { .info_obj(&(md, interface)); } - if interface.func_call_outputs.len() >= 1 { + if !interface.func_call_outputs.is_empty() { ExpressionSource::WireRef(WireReference::simple_port(PortReference { submodule_name_span: fc.interface_reference.name_span, submodule_decl: fc.interface_reference.submodule_decl, @@ -1006,35 +1006,33 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { return cursor.go_down_content(kind!("parenthesis_expression"), |cursor| { self.flatten_expr(cursor) }); - } else { - if let Some(wr) = self.flatten_wire_reference(cursor).expect_wireref(self) { - let mut is_comptime = match wr.root { - WireReferenceRoot::LocalDecl(uuid, _span) => self.instructions[uuid] - .unwrap_declaration() - .identifier_type - .is_generative(), - WireReferenceRoot::NamedConstant(_) => true, - WireReferenceRoot::SubModulePort(_) => false, - }; + } else if let Some(wr) = self.flatten_wire_reference(cursor).expect_wireref(self) { + let mut is_comptime = match wr.root { + WireReferenceRoot::LocalDecl(uuid, _span) => self.instructions[uuid] + .unwrap_declaration() + .identifier_type + .is_generative(), + WireReferenceRoot::NamedConstant(_) => true, + WireReferenceRoot::SubModulePort(_) => false, + }; - for elem in &wr.path { - match elem { - WireReferencePathElement::ArrayAccess { - idx, - bracket_span: _, - } => { - is_comptime &= self.instructions[*idx] - .unwrap_expression() - .typ - .domain - .is_generative() - } + for elem in &wr.path { + match elem { + WireReferencePathElement::ArrayAccess { + idx, + bracket_span: _, + } => { + is_comptime &= self.instructions[*idx] + .unwrap_expression() + .typ + .domain + .is_generative() } } - (ExpressionSource::WireRef(wr), is_comptime) - } else { - (ExpressionSource::new_error(), false) } + (ExpressionSource::WireRef(wr), is_comptime) + } else { + (ExpressionSource::new_error(), false) }; let wire_instance = Expression { @@ -1540,13 +1538,9 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { )) } else { // It's _expression - if let Some(wire_ref) = - self.flatten_wire_reference(cursor).expect_wireref(self) - { - Some((wire_ref, write_modifiers)) - } else { - None - } + self.flatten_wire_reference(cursor) + .expect_wireref(self) + .map(|wire_ref| (wire_ref, write_modifiers)) }, span, ) diff --git a/src/flattening/initialization.rs b/src/flattening/initialization.rs index 17151b6..96f3719 100644 --- a/src/flattening/initialization.rs +++ b/src/flattening/initialization.rs @@ -33,7 +33,7 @@ struct InitializationContext<'linker> { file_text: &'linker FileText, } -impl<'linker> InitializationContext<'linker> { +impl InitializationContext<'_> { fn gather_initial_global_object(&mut self, cursor: &mut Cursor) -> (Span, String) { let name_span = cursor.field_span(field!("name"), kind!("identifier")); let name = self.file_text[name_span].to_owned(); @@ -277,7 +277,7 @@ pub fn gather_initial_file_data(mut builder: FileBuilder) { let mut cursor = Cursor::new_at_root(builder.tree, &builder.file_data.file_text); cursor.list_and_report_errors( kind!("source_file"), - &builder.other_parsing_errors, + builder.other_parsing_errors, |cursor| { let parsing_errors = ErrorCollector::new_empty(builder.file_id, builder.files); cursor.report_all_decendant_errors(&parsing_errors); diff --git a/src/flattening/mod.rs b/src/flattening/mod.rs index b06c7b3..92b4380 100644 --- a/src/flattening/mod.rs +++ b/src/flattening/mod.rs @@ -104,7 +104,7 @@ impl Module { ), ) .info_obj(self); - return None; + None } pub fn get_instruction_span(&self, instr_id: FlatID) -> Span { diff --git a/src/flattening/parser.rs b/src/flattening/parser.rs index 942e5af..c0e7e47 100644 --- a/src/flattening/parser.rs +++ b/src/flattening/parser.rs @@ -97,11 +97,9 @@ impl<'t> Cursor<'t> { #[must_use] pub fn optional_field(&mut self, field_id: NonZeroU16) -> bool { // If a previous call to field already found this field, then we must immediately skip it. - if self.current_field_was_already_consumed { - if !self.cursor.goto_next_sibling() { - self.current_field_was_already_consumed = false; - return false; - } + if self.current_field_was_already_consumed && !self.cursor.goto_next_sibling() { + self.current_field_was_already_consumed = false; + return false; } loop { if let Some(found) = self.cursor.field_id() { @@ -342,11 +340,9 @@ impl<'t> Cursor<'t> { let mut depth = 0; assert!(self.cursor.goto_first_child()); loop { - if !self.push_potential_node_error(errors) { - if self.cursor.goto_first_child() { - depth += 1; - continue; - } + if !self.push_potential_node_error(errors) && self.cursor.goto_first_child() { + depth += 1; + continue; } while !self.cursor.goto_next_sibling() { assert!(self.cursor.goto_parent()); diff --git a/src/flattening/typechecking.rs b/src/flattening/typechecking.rs index a12a5c3..d050b84 100644 --- a/src/flattening/typechecking.rs +++ b/src/flattening/typechecking.rs @@ -76,7 +76,7 @@ struct TypeCheckingContext<'l, 'errs> { runtime_condition_stack: Vec, } -impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { +impl TypeCheckingContext<'_, '_> { fn get_decl_of_module_port( &self, port: PortID, @@ -106,7 +106,7 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { ); FullType { typ, - domain: port_local_domain.clone(), + domain: port_local_domain, } } @@ -118,7 +118,7 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { } WireReferenceRoot::NamedConstant(cst) => { let linker_cst = &self.globals[cst.id]; - linker_cst.link_info.make_global_info(&self.errors.files) + linker_cst.link_info.make_global_info(self.errors.files) } WireReferenceRoot::SubModulePort(port) => { let (decl, file) = self.get_decl_of_module_port(port.port, port.submodule_decl); @@ -309,7 +309,7 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { self.runtime_condition_stack.push(ConditionStackElem { ends_at: if_stmt.else_end, span: condition_expr.span, - domain: condition_expr.typ.domain.clone(), + domain: condition_expr.typ.domain, }); } } @@ -335,7 +335,7 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { self.type_checker .unify_with_written_type_substitute_templates_must_succeed( &decl.typ_expr, - &argument_type, + argument_type, &global_ref.template_arg_types, // Yes that's right. We already must substitute the templates for type variables here ); } @@ -354,7 +354,7 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { self.type_checker.typecheck_write_to_abstract( &argument_expr.typ.typ, - &argument_type, + argument_type, argument_expr.span, "generative template argument", ); diff --git a/src/instantiation/concrete_typecheck.rs b/src/instantiation/concrete_typecheck.rs index d1e49b0..54e3bc3 100644 --- a/src/instantiation/concrete_typecheck.rs +++ b/src/instantiation/concrete_typecheck.rs @@ -16,7 +16,7 @@ use super::*; use crate::typing::type_inference::HindleyMilner; -impl<'fl, 'l> InstantiationContext<'fl, 'l> { +impl InstantiationContext<'_, '_> { fn walk_type_along_path( &self, mut current_type_in_progress: ConcreteType, @@ -69,7 +69,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { .walk_type_along_path(self.wires[this_wire_id].typ.clone(), &s.to_path); self.type_substitutor.unify_report_error( &destination_typ, - &source_typ, + source_typ, span, "write wire access", ); @@ -187,7 +187,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { fn finalize(&mut self) { for (_id, w) in &mut self.wires { - if w.typ.fully_substitute(&self.type_substitutor) == false { + if !w.typ.fully_substitute(&self.type_substitutor) { let typ_as_str = w.typ.display(&self.linker.types); let span = self.md.get_instruction_span(w.original_instruction); diff --git a/src/instantiation/execute.rs b/src/instantiation/execute.rs index ec7b799..26581c0 100644 --- a/src/instantiation/execute.rs +++ b/src/instantiation/execute.rs @@ -34,7 +34,7 @@ macro_rules! caught_by_typecheck { pub type ExecutionResult = Result; -impl<'fl> GenerationState<'fl> { +impl GenerationState<'_> { fn span_of(&self, v: FlatID) -> Span { let instr = &self.md.link_info.instructions[v]; match instr { @@ -114,7 +114,7 @@ impl<'fl> GenerationState<'fl> { } } -impl<'fl> Index for GenerationState<'fl> { +impl Index for GenerationState<'_> { type Output = SubModuleOrWire; fn index(&self, index: FlatID) -> &Self::Output { @@ -122,7 +122,7 @@ impl<'fl> Index for GenerationState<'fl> { } } -impl<'fl> IndexMut for GenerationState<'fl> { +impl IndexMut for GenerationState<'_> { fn index_mut(&mut self, index: FlatID) -> &mut Self::Output { &mut self.generation_state[index] } @@ -170,7 +170,7 @@ enum RealWireRefRoot { Constant(Value), } -impl<'fl, 'l> InstantiationContext<'fl, 'l> { +impl InstantiationContext<'_, '_> { /// Uses the current context to turn a [WrittenType] into a [ConcreteType]. /// /// Failures are fatal. diff --git a/src/instantiation/latency_algorithm.rs b/src/instantiation/latency_algorithm.rs index 264630c..6286247 100644 --- a/src/instantiation/latency_algorithm.rs +++ b/src/instantiation/latency_algorithm.rs @@ -339,7 +339,7 @@ pub fn solve_latencies( let mut ports_to_place = Vec::with_capacity(inputs.len() + outputs.len()); // If no latencies are given, we have to initialize an arbitrary one ourselves. Prefer input ports over output ports over regular wires - if specified_latencies.len() == 0 { + if specified_latencies.is_empty() { let wire = *inputs.first().unwrap_or(outputs.first().unwrap_or(&0)); specified_latencies.push(SpecifiedLatency { wire, latency: 0 }); } @@ -371,7 +371,7 @@ pub fn solve_latencies( // First forward run from the initial latency assignment to discover other ports count_latency_all_in_list::( &mut working_latencies, - &fanouts, + fanouts, &specified_latencies, &mut stack, )?; @@ -381,7 +381,7 @@ pub fn solve_latencies( // Then backward run count_latency_all_in_list::( &mut working_latencies, - &fanins, + fanins, &specified_latencies, &mut stack, )?; @@ -395,17 +395,12 @@ pub fn solve_latencies( if chosen_port.is_input { count_latency::( &mut working_latencies, - &fanouts, + fanouts, chosen_port.wire, &mut stack, )?; } else { - count_latency::( - &mut working_latencies, - &fanins, - chosen_port.wire, - &mut stack, - )?; + count_latency::(&mut working_latencies, fanins, chosen_port.wire, &mut stack)?; } inform_all_ports(&mut ports_to_place, &working_latencies)?; clear_unpinned_latencies(&mut working_latencies); @@ -417,7 +412,7 @@ pub fn solve_latencies( for idx in 0..working_latencies.len() { if working_latencies[idx].is_pinned() { // it's a defined latency! - count_latency::(&mut working_latencies, &fanouts, idx, &mut stack)?; + count_latency::(&mut working_latencies, fanouts, idx, &mut stack)?; } } @@ -435,7 +430,7 @@ pub fn solve_latencies( // Finally we add in the backwards latencies. TODO maybe be more conservative here? for idx in 0..working_latencies.len() { if working_latencies[idx].is_pinned() { - count_latency::(&mut working_latencies, &fanins, idx, &mut stack)?; + count_latency::(&mut working_latencies, fanins, idx, &mut stack)?; } } diff --git a/src/instantiation/latency_count.rs b/src/instantiation/latency_count.rs index 7782cf2..f13aa97 100644 --- a/src/instantiation/latency_count.rs +++ b/src/instantiation/latency_count.rs @@ -53,7 +53,7 @@ fn make_path_info_string( write_path_elem_to_string( &mut result, - &decl_name, + decl_name, to_absolute_latency, prev_decl_absolute_latency, ); @@ -147,7 +147,7 @@ impl InstantiatedModule { } } -impl<'fl, 'l> InstantiationContext<'fl, 'l> { +impl InstantiationContext<'_, '_> { fn make_wire_to_latency_map(&self) -> WireToLatencyMap { const PLACEHOLDER: usize = usize::MAX; @@ -334,8 +334,8 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { domain_info.initial_values.clone(), ) { Ok(latencies) => { - for (_id, (node, lat)) in - zip(domain_info.latency_node_meanings.iter(), latencies.iter()).enumerate() + for (node, lat) in + zip(domain_info.latency_node_meanings.iter(), latencies.iter()) { let wire = &mut self.wires[*node]; wire.absolute_latency = *lat; @@ -344,7 +344,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { self.md.get_instruction_span(wire.original_instruction); self.errors.error( source_location, - format!("Latency Counting couldn't reach this node"), + "Latency Counting couldn't reach this node".to_string(), ); } } diff --git a/src/instantiation/list_of_lists.rs b/src/instantiation/list_of_lists.rs index 714abc8..d60d6b1 100644 --- a/src/instantiation/list_of_lists.rs +++ b/src/instantiation/list_of_lists.rs @@ -11,6 +11,12 @@ pub struct ListOfLists { start_ends: Vec, } +impl Default for ListOfLists { + fn default() -> Self { + Self::new() + } +} + impl ListOfLists { pub fn new() -> Self { Self::new_with_groups_capacity(0) @@ -99,10 +105,8 @@ impl ListOfLists { cumulative_sum += found_value; } - let mut partially_initialize_buf: Vec> = (0..cumulative_sum) - .into_iter() - .map(|_| MaybeUninit::uninit()) - .collect(); + let mut partially_initialize_buf: Vec> = + (0..cumulative_sum).map(|_| MaybeUninit::uninit()).collect(); for (to_idx, data) in iter { let found_idx = &mut start_ends[to_idx + 1]; @@ -148,7 +152,7 @@ impl ListOfLists { pub fn from_slice_slice(slice_slice: &[&[T]]) -> Self { slice_slice .iter() - .map(|sub_slice| sub_slice.into_iter().cloned()) + .map(|sub_slice| sub_slice.iter().cloned()) .collect() } } @@ -264,7 +268,7 @@ impl<'a, T> IntoIterator for &'a ListOfLists { ListOfListsIter { buf: &self.buf, start: 0, - ends_iter: self.start_ends[1..].into_iter(), + ends_iter: self.start_ends[1..].iter(), } } } @@ -278,7 +282,7 @@ impl<'a, T> IntoIterator for &'a mut ListOfLists { ListOfListsIterMut { buf: &mut self.buf, start: 0, - ends_iter: self.start_ends[1..].into_iter(), + ends_iter: self.start_ends[1..].iter(), } } } diff --git a/src/instantiation/mod.rs b/src/instantiation/mod.rs index 2aefb86..7797dd3 100644 --- a/src/instantiation/mod.rs +++ b/src/instantiation/mod.rs @@ -210,6 +210,12 @@ pub struct InstantiationCache { cache: RefCell, Rc>>, } +impl Default for InstantiationCache { + fn default() -> Self { + Self::new() + } +} + impl InstantiationCache { pub fn new() -> Self { Self { @@ -344,7 +350,7 @@ fn mangle_name(str: &str) -> String { result } -impl<'fl, 'l> InstantiationContext<'fl, 'l> { +impl InstantiationContext<'_, '_> { fn extract(self) -> InstantiatedModule { InstantiatedModule { mangled_name: mangle_name(&self.name), diff --git a/src/linker/mod.rs b/src/linker/mod.rs index 88b5e30..4ccc04c 100644 --- a/src/linker/mod.rs +++ b/src/linker/mod.rs @@ -214,6 +214,12 @@ pub struct Linker { global_namespace: HashMap, } +impl Default for Linker { + fn default() -> Self { + Self::new() + } +} + impl Linker { pub fn new() -> Linker { Linker { @@ -372,7 +378,7 @@ impl Linker { f(FileBuilder { file_id, tree: &file_data.tree, - file_data: &file_data, + file_data, files: &self.files, other_parsing_errors: &other_parsing_errors, associated_values: &mut associated_values, @@ -403,7 +409,7 @@ pub struct FileBuilder<'linker> { constants: &'linker mut ArenaAllocator, } -impl<'linker> FileBuilder<'linker> { +impl FileBuilder<'_> { fn add_name(&mut self, name: String, new_obj_id: GlobalUUID) { match self.global_namespace.entry(name) { std::collections::hash_map::Entry::Occupied(mut occ) => { diff --git a/src/linker/resolver.rs b/src/linker/resolver.rs index 26da620..3abb353 100644 --- a/src/linker/resolver.rs +++ b/src/linker/resolver.rs @@ -89,10 +89,10 @@ impl<'linker> GlobalResolver<'linker> { } } /// Get the [ErrorCollector] and [ResolvedGlobals] out of this - pub fn decommission<'linker_files>( + pub fn decommission( self, - linker_files: &'linker_files ArenaAllocator, - ) -> (ErrorCollector<'linker_files>, ResolvedGlobals) { + linker_files: &ArenaAllocator, + ) -> (ErrorCollector<'_>, ResolvedGlobals) { let errors = self.errors.re_attach(linker_files); let resolved_globals = self.resolved_globals.into_inner(); (errors, resolved_globals) @@ -113,7 +113,7 @@ impl<'linker> GlobalResolver<'linker> { } /// SAFETY: Files are never touched, and as long as this object is managed properly linker will also exist long enough. - pub fn resolve_global<'slf>(&'slf self, name_span: Span) -> Option { + pub fn resolve_global(&self, name_span: Span) -> Option { let name = &self.file_data.file_text[name_span]; let mut resolved_globals = self.resolved_globals.borrow_mut(); @@ -179,7 +179,7 @@ impl<'linker> GlobalResolver<'linker> { } } -impl<'l> Index for GlobalResolver<'l> { +impl Index for GlobalResolver<'_> { type Output = Module; fn index(&self, index: ModuleUUID) -> &Self::Output { @@ -191,7 +191,7 @@ impl<'l> Index for GlobalResolver<'l> { &self.linker.modules[index] } } -impl<'l> Index for GlobalResolver<'l> { +impl Index for GlobalResolver<'_> { type Output = StructType; fn index(&self, index: TypeUUID) -> &Self::Output { @@ -203,7 +203,7 @@ impl<'l> Index for GlobalResolver<'l> { &self.linker.types[index] } } -impl<'l> Index for GlobalResolver<'l> { +impl Index for GlobalResolver<'_> { type Output = NamedConstant; fn index(&self, index: ConstantUUID) -> &Self::Output { diff --git a/src/typing/abstract_type.rs b/src/typing/abstract_type.rs index 4348047..6a88cb3 100644 --- a/src/typing/abstract_type.rs +++ b/src/typing/abstract_type.rs @@ -133,11 +133,11 @@ impl TypeUnifier { WrittenType::Error(_span) => {} // Already an error, don't unify WrittenType::TemplateVariable(_span, argument_id) => { self.type_substitutor - .unify_must_succeed(&typ, &AbstractType::Template(*argument_id)); + .unify_must_succeed(typ, &AbstractType::Template(*argument_id)); } WrittenType::Named(global_reference) => { self.type_substitutor - .unify_must_succeed(&typ, &AbstractType::Named(global_reference.id)); + .unify_must_succeed(typ, &AbstractType::Named(global_reference.id)); } WrittenType::Array(_span, array_content_and_size) => { let (arr_content, _size_flat, _array_bracket_span) = array_content_and_size.deref(); @@ -175,11 +175,11 @@ impl TypeUnifier { WrittenType::Error(_span) => {} // Already an error, don't unify WrittenType::TemplateVariable(_span, argument_id) => { self.type_substitutor - .unify_must_succeed(&typ, &template_type_args[*argument_id]); + .unify_must_succeed(typ, &template_type_args[*argument_id]); } WrittenType::Named(global_reference) => { self.type_substitutor - .unify_must_succeed(&typ, &AbstractType::Named(global_reference.id)); + .unify_must_succeed(typ, &AbstractType::Named(global_reference.id)); } WrittenType::Array(_span, array_content_and_size) => { let (arr_content, _size_flat, _array_bracket_span) = array_content_and_size.deref(); @@ -336,7 +336,7 @@ impl TypeUnifier { // The case of writes to generatives from non-generatives should be fully covered by flattening if !from_domain.is_generative() && !to_domain.is_generative() { self.domain_substitutor - .unify_report_error(&from_domain, &to_domain, span, context); + .unify_report_error(from_domain, to_domain, span, context); } } @@ -391,8 +391,8 @@ impl TypeUnifier { output_typ: &AbstractType, ) { self.type_substitutor - .unify_report_error(&idx_type, &INT_TYPE, idx_span, "array index"); - self.unify_with_array_of(&arr_type, output_typ.clone(), arr_span); + .unify_report_error(idx_type, &INT_TYPE, idx_span, "array index"); + self.unify_with_array_of(arr_type, output_typ.clone(), arr_span); } pub fn typecheck_write_to_abstract( @@ -403,7 +403,7 @@ impl TypeUnifier { context: Context, ) { self.type_substitutor - .unify_report_error(&found, &expected, span, context); + .unify_report_error(found, expected, span, context); } pub fn typecheck_write_to( @@ -419,7 +419,7 @@ impl TypeUnifier { pub fn finalize_domain_type(&mut self, typ_domain: &mut DomainType) { use super::type_inference::HindleyMilner; - assert!(typ_domain.fully_substitute(&self.domain_substitutor) == true); + assert!(typ_domain.fully_substitute(&self.domain_substitutor)); } pub fn finalize_abstract_type( @@ -430,7 +430,7 @@ impl TypeUnifier { errors: &ErrorCollector, ) { use super::type_inference::HindleyMilner; - if typ.fully_substitute(&self.type_substitutor) == false { + if !typ.fully_substitute(&self.type_substitutor) { let typ_as_string = typ.display(types, &self.template_type_names); errors.error( span, diff --git a/src/typing/type_inference.rs b/src/typing/type_inference.rs index 88cae4d..d50bc14 100644 --- a/src/typing/type_inference.rs +++ b/src/typing/type_inference.rs @@ -83,7 +83,7 @@ impl, VariableIDMarker: UUIDMarker> pub trait UnifyErrorReport { fn report(self) -> (String, Vec); } -impl<'s> UnifyErrorReport for &'s str { +impl UnifyErrorReport for &str { fn report(self) -> (String, Vec) { (self.to_string(), Vec::new()) } @@ -112,6 +112,14 @@ impl BitAnd for UnifyResult { } } +impl + Clone + Debug, VariableIDMarker: UUIDMarker> Default + for TypeSubstitutor +{ + fn default() -> Self { + Self::new() + } +} + impl + Clone + Debug, VariableIDMarker: UUIDMarker> TypeSubstitutor { @@ -172,13 +180,11 @@ impl + Clone + Debug, VariableIDMarker: while let HindleyMilnerInfo::TypeVar(unknown_synonym) = replace_with.get_hm_info() { if let Some(found_subst) = self[unknown_synonym].get() { replace_with = found_subst; + } else if unknown_synonym == empty_var { + return UnifyResult::Success; } else { - if unknown_synonym == empty_var { - return UnifyResult::Success; - } else { - assert!(self[empty_var].set(replace_with.clone()).is_ok()); - return UnifyResult::Success; - } + assert!(self[empty_var].set(replace_with.clone()).is_ok()); + return UnifyResult::Success; } } @@ -305,10 +311,8 @@ impl + Clone + Debug, VariableIDMarker: } else { node_in_path[unknown_id].is_part_of_stack = true; substitutes_to.for_each_unknown(&mut |id| { - if !is_infinite_loop { - if is_node_infinite_loop(slf, node_in_path, id) { - is_infinite_loop = true; - } + if !is_infinite_loop && is_node_infinite_loop(slf, node_in_path, id) { + is_infinite_loop = true; } }); node_in_path[unknown_id].is_part_of_stack = false; @@ -331,13 +335,13 @@ impl + Clone + Debug, VariableIDMarker: ); for id in self.id_range() { - if !node_in_path[id].is_not_part_of_loop { - if is_node_infinite_loop(self, &mut node_in_path, id) { - panic!( - "Cyclic Type Substitution Found! See Above. On node {id:?} => {:?}", - self[id] - ) - } + if !node_in_path[id].is_not_part_of_loop + && is_node_infinite_loop(self, &mut node_in_path, id) + { + panic!( + "Cyclic Type Substitution Found! See Above. On node {id:?} => {:?}", + self[id] + ) } } } @@ -384,9 +388,7 @@ pub trait HindleyMilner: Sized { where Self: 'slf; - fn get_hm_info<'slf>( - &'slf self, - ) -> HindleyMilnerInfo, VariableIDMarker>; + fn get_hm_info(&self) -> HindleyMilnerInfo, VariableIDMarker>; /// Iterate through all arguments and unify them /// @@ -519,7 +521,7 @@ impl HindleyMilner for DomainType { match self { DomainType::Generative | DomainType::Physical(_) => true, // Do nothing, These are done already DomainType::Unknown(var) => { - *self = substitutor.substitution_map[var.get_hidden_value()].get().expect("It's impossible for domain variables to remain, as any unset domain variable would have been replaced with a new physical domain").clone(); + *self = *substitutor.substitution_map[var.get_hidden_value()].get().expect("It's impossible for domain variables to remain, as any unset domain variable would have been replaced with a new physical domain"); self.fully_substitute(substitutor) } } @@ -657,7 +659,7 @@ impl DelayedConstraintsList { /// /// Calls [DelayedConstraint::report_could_not_resolve_error] on all constraints that weren't resolved pub fn resolve_delayed_constraints(mut self, shared_object: &mut T) { - while self.0.len() > 0 { + while !self.0.is_empty() { let mut progress_made = false; self.0 .retain_mut(|constraint| match constraint.try_apply(shared_object) { @@ -672,7 +674,7 @@ impl DelayedConstraintsList { DelayedConstraintStatus::NoProgress => true, }); if !progress_made { - for constraint in std::mem::replace(&mut self.0, Vec::new()) { + for constraint in std::mem::take(&mut self.0) { constraint.report_could_not_resolve_error(shared_object); } return; // Exit From 2fd3c72132bc834f59f52bffff45c7fba004c97e Mon Sep 17 00:00:00 2001 From: Tobias Tom Hodapp Date: Thu, 30 Jan 2025 20:38:19 +0100 Subject: [PATCH 3/6] Fixed all clippy lints --- build.rs | 7 +++++-- src/alloc.rs | 7 ++++--- src/block_vector.rs | 10 +++++----- src/codegen/system_verilog.rs | 7 +++---- src/codegen/vhdl.rs | 16 +++++++++------- src/compiler_top.rs | 4 ++-- src/config.rs | 18 +++++++++--------- src/dev_aid/ariadne_interface.rs | 7 ++++--- src/dev_aid/lsp/mod.rs | 4 ++-- src/errors.rs | 6 +++--- src/file_position.rs | 16 +++++++--------- src/flattening/flatten.rs | 8 +------- src/flattening/typechecking.rs | 2 +- src/instantiation/concrete_typecheck.rs | 2 +- src/instantiation/latency_algorithm.rs | 11 +++++------ src/instantiation/list_of_lists.rs | 12 ++++-------- src/linker/checkpoint.rs | 2 +- src/linker/resolver.rs | 2 +- src/main.rs | 2 +- src/to_string.rs | 2 +- tree-sitter-sus/bindings/rust/build.rs | 2 +- tree-sitter-sus/bindings/rust/lib.rs | 2 +- 22 files changed, 71 insertions(+), 78 deletions(-) diff --git a/build.rs b/build.rs index c792420..21d280c 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,7 @@ -use std::{fs, path::PathBuf}; +use std::{ + fs, + path::{Path, PathBuf}, +}; fn main() { let mut install_dir = get_sus_dir(); @@ -29,7 +32,7 @@ fn get_sus_dir() -> PathBuf { } // Helper function to copy a directory and its contents recursively -fn copy_dir(src: &str, dst: &PathBuf) -> std::io::Result<()> { +fn copy_dir(src: &str, dst: &Path) -> std::io::Result<()> { for entry in fs::read_dir(src)? { let entry = entry?; let path = entry.path(); diff --git a/src/alloc.rs b/src/alloc.rs index 2e08ef2..90a19d7 100644 --- a/src/alloc.rs +++ b/src/alloc.rs @@ -13,11 +13,12 @@ use std::{ /// /// TODO add custom niche for more efficient Options, wait until custom niches are stabilized (https://internals.rust-lang.org/t/nonmaxusize-and-niche-value-optimisation/19661) /// Maybe use NonZeroUsize (https://doc.rust-lang.org/std/num/struct.NonZeroUsize.html) +#[allow(clippy::upper_case_acronyms)] pub struct UUID(usize, PhantomData); impl Clone for UUID { fn clone(&self) -> Self { - Self(self.0, PhantomData) + *self } } impl Copy for UUID {} @@ -98,7 +99,7 @@ impl UUIDAllocator { } result } - pub fn into_range(&self) -> UUIDRange { + pub fn as_range(&self) -> UUIDRange { UUIDRange(UUID::from_hidden_value(0), self.cur) } } @@ -172,7 +173,7 @@ impl Debug for UUIDRange { impl Clone for UUIDRange { fn clone(&self) -> Self { - Self(self.0, self.1) + *self } } impl Copy for UUIDRange {} diff --git a/src/block_vector.rs b/src/block_vector.rs index 70fafd9..c3ad9a5 100644 --- a/src/block_vector.rs +++ b/src/block_vector.rs @@ -82,8 +82,8 @@ impl Drop for BlockVec { let num_remaining = self.length.get() % BLOCK_SIZE; let block_vec = self.blocks.get_mut(); - for i in 0..num_full_blocks { - for v in block_vec[i].deref_mut() { + for i in block_vec.iter_mut() { + for v in i.deref_mut() { unsafe { v.assume_init_drop(); } @@ -92,8 +92,8 @@ impl Drop for BlockVec { if num_remaining > 0 { let last_block = block_vec[num_full_blocks].deref_mut(); - for i in 0..num_remaining { - unsafe { last_block[i].assume_init_drop() }; + for element in last_block.iter_mut().take(num_remaining) { + unsafe { element.assume_init_drop() }; } } } @@ -266,7 +266,7 @@ impl Drop for BlockVecConsumingIter { } } -impl<'bv, T, const BLOCK_SIZE: usize> FromIterator for BlockVec { +impl FromIterator for BlockVec { fn from_iter>(iter: Iter) -> Self { let new_coll = BlockVec::new(); for v in iter { diff --git a/src/codegen/system_verilog.rs b/src/codegen/system_verilog.rs index a55c5c5..3ee56b2 100644 --- a/src/codegen/system_verilog.rs +++ b/src/codegen/system_verilog.rs @@ -78,10 +78,9 @@ impl<'g> CodeGenerationContext<'g> { /// This is for making the resulting Verilog a little nicer to read fn can_inline(&self, wire: &RealWire) -> bool { match &wire.source { - RealWireDataSource::Constant { value } => match value { - Value::Bool(_) | Value::Integer(_) => true, - _other => false, - }, + RealWireDataSource::Constant { + value: Value::Bool(_) | Value::Integer(_), + } => true, _other => false, } } diff --git a/src/codegen/vhdl.rs b/src/codegen/vhdl.rs index 8cdee1f..39ee8d1 100644 --- a/src/codegen/vhdl.rs +++ b/src/codegen/vhdl.rs @@ -23,7 +23,7 @@ impl super::CodeGenBackend for VHDLCodegenBackend { &self, md: &Module, instance: &InstantiatedModule, - linker: &Linker, + _linker: &Linker, use_latency: bool, ) -> String { gen_vhdl_code(md, instance, use_latency) @@ -35,7 +35,7 @@ struct CodeGenerationContext<'g, 'out, Stream: std::fmt::Write> { instance: &'g InstantiatedModule, program_text: &'out mut Stream, use_latency: bool, - needed_untils: FlatAlloc, + _needed_untils: FlatAlloc, } fn typ_to_declaration(mut typ: &ConcreteType) -> String { @@ -163,16 +163,18 @@ impl CodeGenerationContext<'_, '_, Stream> { } } -fn gen_vhdl_code(md: &Module, instance: &InstantiatedModule, use_latency: bool) -> String { +// TODO This should be removed as soon as this feature is usable +#[allow(unreachable_code)] +fn gen_vhdl_code(_md: &Module, _instance: &InstantiatedModule, _use_latency: bool) -> String { todo!("VHDl codegen is unfinshed"); let mut program_text = String::new(); let mut ctx = CodeGenerationContext { - md, - instance, - use_latency, + md: _md, + instance: _instance, + use_latency: _use_latency, program_text: &mut program_text, - needed_untils: instance.compute_needed_untils(), + _needed_untils: _instance.compute_needed_untils(), }; ctx.write_vhdl_code(); diff --git a/src/compiler_top.rs b/src/compiler_top.rs index 2163b0c..5821e83 100644 --- a/src/compiler_top.rs +++ b/src/compiler_top.rs @@ -1,5 +1,5 @@ use std::ffi::OsStr; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::str::FromStr; use crate::config::EarlyExitUpTo; @@ -23,7 +23,7 @@ const STD_LIB_PATH: &str = env!("SUS_COMPILER_STD_LIB_PATH"); /// Any extra operations that should happen when files are added or removed from the linker. Such as caching line offsets. pub trait LinkerExtraFileInfoManager { /// This is there to give an acceptable identifier that can be printed - fn convert_filename(&self, path: &PathBuf) -> String { + fn convert_filename(&self, path: &Path) -> String { path.to_string_lossy().into_owned() } fn on_file_added(&mut self, _file_id: FileUUID, _linker: &Linker) {} diff --git a/src/config.rs b/src/config.rs index ce20e8e..f2ce211 100644 --- a/src/config.rs +++ b/src/config.rs @@ -24,7 +24,7 @@ pub enum EarlyExitUpTo { #[derive(Clone, Copy, Debug, PartialEq, Eq, ValueEnum)] pub enum TargetLanguage { SystemVerilog, - VHDL, + Vhdl, } /// All command-line flags are converted to this struct, of which the singleton instance can be acquired using [crate::config::config] @@ -55,7 +55,7 @@ fn command_builder() -> Command { .default_value("25000") .help("Set the LSP TCP socket port") .value_parser(|socket_int : &str| { - match u16::from_str_radix(socket_int, 10) { + match socket_int.parse::() { Ok(port) => Ok(port), Err(_) => Err("Must be a valid port 0-65535") } @@ -192,7 +192,7 @@ mod tests { #[test] fn test_socket_invalid_port() { - let config = parse_args(&["", "--lsp", "--socket", "1234567890"]); + let config = parse_args(["", "--lsp", "--socket", "1234567890"]); assert!(config.is_err()); let err = config.unwrap_err(); assert_eq!(err.kind(), clap::error::ErrorKind::ValueValidation); @@ -200,7 +200,7 @@ mod tests { #[test] fn test_socket_require_lsp() { - let config = parse_args(&["", "--socket", "1500"]); + let config = parse_args(["", "--socket", "1500"]); assert!(config.is_err()); let err = config.unwrap_err(); assert_eq!(err.kind(), clap::error::ErrorKind::MissingRequiredArgument); @@ -208,7 +208,7 @@ mod tests { #[test] fn test_lsp_debug_require_lsp() { - let config = parse_args(&["", "--lsp-debug"]); + let config = parse_args(["", "--lsp-debug"]); assert!(config.is_err()); let err = config.unwrap_err(); assert_eq!(err.kind(), clap::error::ErrorKind::MissingRequiredArgument); @@ -216,13 +216,13 @@ mod tests { #[test] fn test_lsp_no_color() { - let config = parse_args(&["", "--lsp"]).unwrap(); - assert_eq!(config.use_color, false) + let config = parse_args(["", "--lsp"]).unwrap(); + assert!(!config.use_color) } #[test] fn test_automatic_codegen() { - let config = parse_args(&[""]).unwrap(); - assert_eq!(config.codegen, true) + let config = parse_args([""]).unwrap(); + assert!(config.codegen) } } diff --git a/src/dev_aid/ariadne_interface.rs b/src/dev_aid/ariadne_interface.rs index bba9e42..d73a124 100644 --- a/src/dev_aid/ariadne_interface.rs +++ b/src/dev_aid/ariadne_interface.rs @@ -1,3 +1,4 @@ +use std::path::Path; use std::{ops::Range, path::PathBuf}; use crate::compiler_top::LinkerExtraFileInfoManager; @@ -53,7 +54,7 @@ pub struct FileSourcesManager { } impl LinkerExtraFileInfoManager for FileSourcesManager { - fn convert_filename(&self, path: &PathBuf) -> String { + fn convert_filename(&self, path: &Path) -> String { path.to_string_lossy().into_owned() } @@ -124,7 +125,7 @@ pub fn pretty_print_error>( // Assert that span is in file let _ = &linker.files[file].file_text[error.position]; - let error_span = error.position.into_range(); + let error_span = error.position.as_range(); let config = ariadne_config(); let mut report: ReportBuilder<'_, (FileUUID, Range)> = @@ -136,7 +137,7 @@ pub fn pretty_print_error>( ); for info in &error.infos { - let info_span = info.position.into_range(); + let info_span = info.position.as_range(); // Assert that span is in file let _ = &linker.files[info.file].file_text[info.position]; report = report.with_label( diff --git a/src/dev_aid/lsp/mod.rs b/src/dev_aid/lsp/mod.rs index d535239..90d6f47 100644 --- a/src/dev_aid/lsp/mod.rs +++ b/src/dev_aid/lsp/mod.rs @@ -7,7 +7,7 @@ use crate::{compiler_top::LinkerExtraFileInfoManager, linker::GlobalUUID, prelud use hover_info::hover; use lsp_types::{notification::*, request::Request, *}; use semantic_tokens::{make_semantic_tokens, semantic_token_capabilities}; -use std::{collections::HashMap, error::Error, net::SocketAddr, path::PathBuf}; +use std::{collections::HashMap, error::Error, net::SocketAddr, path::Path}; use crate::{ config::config, @@ -191,7 +191,7 @@ fn push_all_errors( struct LSPFileManager {} impl LinkerExtraFileInfoManager for LSPFileManager { - fn convert_filename(&self, path: &PathBuf) -> String { + fn convert_filename(&self, path: &Path) -> String { Url::from_file_path(path).unwrap().into() } } diff --git a/src/errors.rs b/src/errors.rs index fcfcd60..a9092e8 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -60,7 +60,7 @@ impl ErrorStore { } } - pub fn take<'linker>(&mut self) -> Self { + pub fn take(&mut self) -> Self { std::mem::replace(self, ErrorStore::new()) } @@ -145,7 +145,7 @@ impl<'linker> ErrorCollector<'linker> { fn assert_span_good(&self, span: Span) { span.debug(); - let rng = span.into_range(); + let rng = span.as_range(); assert!(rng.end <= self.file_len); // Don't need to verify start, since Span already enforces start <= end } fn push_diagnostic( @@ -216,7 +216,7 @@ pub struct ErrorReference<'ec> { impl ErrorReference<'_> { pub fn existing_info(&self, error_info: ErrorInfo) -> &Self { assert!( - error_info.position.debug().into_range().end + error_info.position.debug().as_range().end <= self.err_collector.files[error_info.file].file_text.len() ); self.err_collector.error_store.borrow_mut().errors[self.pos] diff --git a/src/file_position.rs b/src/file_position.rs index 528dceb..caec2fa 100644 --- a/src/file_position.rs +++ b/src/file_position.rs @@ -27,7 +27,7 @@ impl Span { /// Only really used for having a span with the maximum size. pub const MAX_POSSIBLE_SPAN: Span = Span(0, usize::MAX); - pub fn into_range(&self) -> Range { + pub fn as_range(&self) -> Range { self.debug(); self.0..self.1 } @@ -60,7 +60,7 @@ impl Span { impl PartialOrd for Span { fn partial_cmp(&self, other: &Self) -> Option { - self.0.partial_cmp(&other.0) + Some(self.cmp(other)) } } impl Ord for Span { @@ -159,12 +159,10 @@ impl FileText { } /// Clamps the linecol to be within the file, so cannot error. pub fn linecol_to_byte_clamp(&self, linecol: LineCol) -> usize { - let line_end = if linecol.line + 1 < self.lines_start_at.len() { - self.lines_start_at[linecol.line + 1] - 1 - } else if linecol.line + 1 == self.lines_start_at.len() { - self.file_text.len() - } else { - return self.file_text.len(); + let line_end = match (linecol.line + 1).cmp(&self.lines_start_at.len()) { + std::cmp::Ordering::Less => self.lines_start_at[linecol.line + 1] - 1, + std::cmp::Ordering::Equal => self.file_text.len(), + std::cmp::Ordering::Greater => return self.file_text.len(), }; let line_start = self.lines_start_at[linecol.line]; let line_text = &self.file_text[line_start..line_end]; @@ -199,6 +197,6 @@ impl Index for FileText { fn index(&self, index: Span) -> &str { index.debug(); - &self.file_text[index.into_range()] + &self.file_text[index.as_range()] } } diff --git a/src/flattening/flatten.rs b/src/flattening/flatten.rs index 286c350..27b3173 100644 --- a/src/flattening/flatten.rs +++ b/src/flattening/flatten.rs @@ -1199,13 +1199,7 @@ impl FlatteningContext<'_, '_> { self.errors .error(expr_span, "A constant is not a wire reference"); PartialWireReference::Error - } else if kind == kind!("unary_op") { - self.errors.error( - expr_span, - "The result of an operator is not a wire reference", - ); - PartialWireReference::Error - } else if kind == kind!("binary_op") { + } else if kind == kind!("unary_op") || kind == kind!("binary_op") { self.errors.error( expr_span, "The result of an operator is not a wire reference", diff --git a/src/flattening/typechecking.rs b/src/flattening/typechecking.rs index d050b84..afd6845 100644 --- a/src/flattening/typechecking.rs +++ b/src/flattening/typechecking.rs @@ -579,7 +579,7 @@ pub fn apply_types( } // Assign names to all of the domains in this module - working_on.domains = leftover_domain_alloc.into_range().map(|id| { + working_on.domains = leftover_domain_alloc.as_range().map(|id| { if let Some(work_on_domain) = working_on.domains.get(id) { work_on_domain.clone() } else { diff --git a/src/instantiation/concrete_typecheck.rs b/src/instantiation/concrete_typecheck.rs index 54e3bc3..2eb146b 100644 --- a/src/instantiation/concrete_typecheck.rs +++ b/src/instantiation/concrete_typecheck.rs @@ -356,7 +356,7 @@ fn concretize_written_type_with_possible_template_args( impl SubmoduleTypecheckConstraint { /// Directly named type and value parameters are immediately unified, but latency count deltas can only be computed from the latency counting graph - fn try_infer_latency_counts(&mut self, context: &mut InstantiationContext) { + fn try_infer_latency_counts(&mut self, _context: &mut InstantiationContext) { // TODO } } diff --git a/src/instantiation/latency_algorithm.rs b/src/instantiation/latency_algorithm.rs index 6286247..f5e5c17 100644 --- a/src/instantiation/latency_algorithm.rs +++ b/src/instantiation/latency_algorithm.rs @@ -417,12 +417,12 @@ pub fn solve_latencies( } // First pin all these latencies - for idx in 0..working_latencies.len() { - if working_latencies[idx].is_set() { + for latency in working_latencies.iter_mut() { + if latency.is_set() { // it's a defined latency! - if !working_latencies[idx].is_pinned() { + if !latency.is_pinned() { // Just to avoid the is_pinned check in pin() - working_latencies[idx].pin(); + latency.pin(); } } } @@ -496,7 +496,6 @@ mod tests { fanins: &ListOfLists, specified_latencies: Vec, ) -> Result, LatencyCountingError> { - let fanins = fanins.into(); let fanouts = convert_fanin_to_fanout(fanins); let inputs = infer_ports(fanins); @@ -515,7 +514,7 @@ mod tests { return false; } } - return true; + true } #[test] diff --git a/src/instantiation/list_of_lists.rs b/src/instantiation/list_of_lists.rs index d60d6b1..04b853d 100644 --- a/src/instantiation/list_of_lists.rs +++ b/src/instantiation/list_of_lists.rs @@ -157,7 +157,7 @@ impl ListOfLists { } } -impl<'a, T> Index for ListOfLists { +impl Index for ListOfLists { type Output = [T]; fn index(&self, index: usize) -> &[T] { @@ -166,7 +166,7 @@ impl<'a, T> Index for ListOfLists { } } -impl<'a, T> IndexMut for ListOfLists { +impl IndexMut for ListOfLists { fn index_mut(&mut self, index: usize) -> &mut [T] { assert!(index < self.len()); &mut self.buf[self.start_ends[index]..self.start_ends[index + 1]] @@ -184,9 +184,7 @@ impl<'a, T> Iterator for ListOfListsFlatOriginIter<'a, T> { type Item = (usize, &'a T); fn next(&mut self) -> Option<(usize, &'a T)> { - let Some((idx, item)) = self.buf_iter.next() else { - return None; - }; + let (idx, item) = self.buf_iter.next()?; // Skip through blocks of 0 size while idx == self.ends[self.cur_slice_idx] { @@ -207,9 +205,7 @@ impl<'a, T> Iterator for ListOfListsFlatOriginIterMut<'a, T> { type Item = (usize, &'a mut T); fn next(&mut self) -> Option<(usize, &'a mut T)> { - let Some((idx, item)) = self.buf_iter.next() else { - return None; - }; + let (idx, item) = self.buf_iter.next()?; // Skip through blocks of 0 size while idx == self.ends[self.cur_slice_idx] { diff --git a/src/linker/checkpoint.rs b/src/linker/checkpoint.rs index d907b5f..820f8eb 100644 --- a/src/linker/checkpoint.rs +++ b/src/linker/checkpoint.rs @@ -24,7 +24,7 @@ pub struct CheckPoint { } impl CheckPoint { - pub fn checkpoint(errors: &ErrorStore, resolved_globals: &ResolvedGlobals) -> CheckPoint { + pub fn new(errors: &ErrorStore, resolved_globals: &ResolvedGlobals) -> CheckPoint { CheckPoint { errors_cp: errors.checkpoint(), resolved_globals_cp: resolved_globals.checkpoint(), diff --git a/src/linker/resolver.rs b/src/linker/resolver.rs index 3abb353..8e4eb40 100644 --- a/src/linker/resolver.rs +++ b/src/linker/resolver.rs @@ -231,6 +231,6 @@ impl LinkInfo { self.resolved_globals = resolved_globals; self.errors = errors.into_storage(); self.checkpoints - .push(CheckPoint::checkpoint(&self.errors, &self.resolved_globals)); + .push(CheckPoint::new(&self.errors, &self.resolved_globals)); } } diff --git a/src/main.rs b/src/main.rs index 090503f..f9ac723 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,7 +41,7 @@ fn main() -> Result<(), Box> { config::TargetLanguage::SystemVerilog => { Box::new(VerilogCodegenBackend) as Box } - config::TargetLanguage::VHDL => Box::new(VHDLCodegenBackend) as Box, + config::TargetLanguage::Vhdl => Box::new(VHDLCodegenBackend) as Box, }; if config.use_lsp { diff --git a/src/to_string.rs b/src/to_string.rs index a311af1..132f8f2 100644 --- a/src/to_string.rs +++ b/src/to_string.rs @@ -286,7 +286,7 @@ impl Module { for (id, inst) in &self.link_info.instructions { println!(" {id:?}: {inst:?}"); let span = self.get_instruction_span(id); - spans_print.push((format!("{id:?}"), span.into_range())); + spans_print.push((format!("{id:?}"), span.as_range())); } pretty_print_many_spans(file_data, &spans_print); } diff --git a/tree-sitter-sus/bindings/rust/build.rs b/tree-sitter-sus/bindings/rust/build.rs index c6061f0..cd9230d 100644 --- a/tree-sitter-sus/bindings/rust/build.rs +++ b/tree-sitter-sus/bindings/rust/build.rs @@ -2,7 +2,7 @@ fn main() { let src_dir = std::path::Path::new("src"); let mut c_config = cc::Build::new(); - c_config.include(&src_dir); + c_config.include(src_dir); c_config .flag_if_supported("-Wno-unused-parameter") .flag_if_supported("-Wno-unused-but-set-variable") diff --git a/tree-sitter-sus/bindings/rust/lib.rs b/tree-sitter-sus/bindings/rust/lib.rs index 375ac6f..8e3ffbb 100644 --- a/tree-sitter-sus/bindings/rust/lib.rs +++ b/tree-sitter-sus/bindings/rust/lib.rs @@ -31,7 +31,7 @@ pub fn language() -> Language { /// The content of the [`node-types.json`][] file for this grammar. /// /// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types -pub const NODE_TYPES: &'static str = include_str!("../../src/node-types.json"); +pub const NODE_TYPES: &str = include_str!("../../src/node-types.json"); // Uncomment these to include any queries that this grammar contains From fb86a7d699cdb43473b776823f5e2ddd911f41d4 Mon Sep 17 00:00:00 2001 From: Tobias Tom Hodapp Date: Thu, 30 Jan 2025 23:41:03 +0100 Subject: [PATCH 4/6] Added ci --- .github/workflows/ci.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1db8763..94af8ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,18 +19,19 @@ jobs: with: submodules: recursive - name: Build - # Don't try to build codegen, as it needs to link against LLVM run: cargo build --verbose --all-features - name: Run tests run: cargo test --verbose --all-features - name: Run regression test run: ./target/debug/sus_compiler test.sus --ci --nocolor 1> test.sus_output_ci.txt 2> test.sus_errors_ci.txt || true && diff test.sus_output_ci.txt test.sus_output.txt && diff test.sus_errors_ci.txt test.sus_errors.txt - - # check-fmt: - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v4 - # with: - # submodules: recursive - # - name: cargo fmt --check - # run: cargo fmt --check + lint: + runs-on: ubuntu-latest + env: + CARGO_INCREMENTAL: 0 + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: format + run: cargo fmt --check + - name: clippy + run: cargo clippy --check From 80adf88a85a5ea4d1e28f7a4b8764a2edde15ece Mon Sep 17 00:00:00 2001 From: Tobias Tom Hodapp Date: Thu, 30 Jan 2025 23:49:19 +0100 Subject: [PATCH 5/6] Fixed clippy command --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 94af8ef..eba3006 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,10 +28,11 @@ jobs: runs-on: ubuntu-latest env: CARGO_INCREMENTAL: 0 + steps: - uses: actions/checkout@v4 with: submodules: recursive - name: format run: cargo fmt --check - name: clippy - run: cargo clippy --check + run: cargo clippy -- -Dwarnings From cfea6127c9bf36e39987a0e7c3474f5f3db49362 Mon Sep 17 00:00:00 2001 From: Tobias Tom Hodapp Date: Fri, 31 Jan 2025 00:03:10 +0100 Subject: [PATCH 6/6] Added missing take --- src/block_vector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/block_vector.rs b/src/block_vector.rs index c3ad9a5..2b3cd98 100644 --- a/src/block_vector.rs +++ b/src/block_vector.rs @@ -82,7 +82,7 @@ impl Drop for BlockVec { let num_remaining = self.length.get() % BLOCK_SIZE; let block_vec = self.blocks.get_mut(); - for i in block_vec.iter_mut() { + for i in block_vec.iter_mut().take(num_full_blocks) { for v in i.deref_mut() { unsafe { v.assume_init_drop();