diff --git a/src/codegen/system_verilog.rs b/src/codegen/system_verilog.rs index c363ee1..1beb673 100644 --- a/src/codegen/system_verilog.rs +++ b/src/codegen/system_verilog.rs @@ -322,7 +322,7 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> self.program_text.write_str(" #(").unwrap(); let mut first = true; concrete_template_args.iter().for_each(|(arg_id, arg)| { - let arg_name = &link_info.template_arguments[arg_id].name; + let arg_name = &link_info.template_parameters[arg_id].name; let arg_value = match arg { ConcreteTemplateArg::Type(..) => { unreachable!("No extern module type arguments. Should have been caught by Lint") diff --git a/src/compiler_top.rs b/src/compiler_top.rs index 3d50d6e..948717f 100644 --- a/src/compiler_top.rs +++ b/src/compiler_top.rs @@ -173,7 +173,7 @@ impl Linker { &self.files[md.link_info.file], ); // Can immediately instantiate modules that have no template args - if md.link_info.template_arguments.is_empty() { + if md.link_info.template_parameters.is_empty() { let _inst = md.instantiations.instantiate(md, self, FlatAlloc::new()); } span_debugger.defuse(); diff --git a/src/dev_aid/lsp/hover_info.rs b/src/dev_aid/lsp/hover_info.rs index 5a9071b..cd20a0c 100644 --- a/src/dev_aid/lsp/hover_info.rs +++ b/src/dev_aid/lsp/hover_info.rs @@ -7,11 +7,11 @@ 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, NameElem}; +use crate::linker::{Documentation, FileData, LinkInfo, GlobalUUID}; use crate::typing::{ abstract_type::DomainType, - template::{GenerativeTemplateInputKind, TemplateInputKind, TypeTemplateInputKind}, + template::{GenerativeParameterKind, ParameterKind, TypeParameterKind}, }; use super::tree_walk::{InModule, LocationInfo}; @@ -126,7 +126,7 @@ pub fn hover(info: LocationInfo, linker: &Linker, file_data: &FileData) -> 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, &md.link_info.template_arguments).to_string(), + .display(&linker.types, &md.link_info.template_parameters).to_string(), )); hover.sus_code(details_vec.join(" ")); hover.gather_hover_infos(md, id, wire.typ.domain.is_generative()); } LocationInfo::Type(typ, link_info) => { hover.sus_code( - typ.display(&linker.types, &link_info.template_arguments).to_string(), + typ.display(&linker.types, &link_info.template_parameters).to_string(), ); } - LocationInfo::TemplateInput(in_obj, link_info, _template_id, template_arg) => { + LocationInfo::Parameter(in_obj, link_info, _template_id, template_arg) => { match &template_arg.kind { - TemplateInputKind::Type(TypeTemplateInputKind { }) => { + ParameterKind::Type(TypeParameterKind { }) => { hover.monospace(format!("type {}", template_arg.name)); } - TemplateInputKind::Generative(GenerativeTemplateInputKind { + ParameterKind::Generative(GenerativeParameterKind { decl_span: _, declaration_instruction, }) => { - let NameElem::Module(md_id) = in_obj else { + let GlobalUUID::Module(md_id) = in_obj else { todo!("Non-module template args") }; let md = &linker.modules[md_id]; @@ -207,7 +207,7 @@ pub fn hover(info: LocationInfo, linker: &Linker, file_data: &FileData) -> Vec Vec { + GlobalUUID::Module(md_uuid) => { let md = &linker.modules[md_uuid]; hover.sus_code(md.make_all_ports_info_string( &linker.files[md.link_info.file].file_text, None, )); } - NameElem::Type(_) => {} - NameElem::Constant(_) => {} + GlobalUUID::Type(_) => {} + GlobalUUID::Constant(_) => {} } } LocationInfo::Port(_sm, md, port_id) => { diff --git a/src/dev_aid/lsp/mod.rs b/src/dev_aid/lsp/mod.rs index a9957af..46816f8 100644 --- a/src/dev_aid/lsp/mod.rs +++ b/src/dev_aid/lsp/mod.rs @@ -392,7 +392,7 @@ fn handle_request( .push((submod_decl.name.as_ref().unwrap().1, md.link_info.file)), LocationInfo::InModule(_, _, _, InModule::Temporary(_)) => {} LocationInfo::Type(_, _) => {} - LocationInfo::TemplateInput(_, link_info, _, template_arg) => { + LocationInfo::Parameter(_, link_info, _, template_arg) => { goto_definition_list.push((template_arg.name_span, link_info.file)) } LocationInfo::Global(id) => { diff --git a/src/dev_aid/lsp/semantic_tokens.rs b/src/dev_aid/lsp/semantic_tokens.rs index 73dade5..747a4f3 100644 --- a/src/dev_aid/lsp/semantic_tokens.rs +++ b/src/dev_aid/lsp/semantic_tokens.rs @@ -9,10 +9,10 @@ use lsp_types::{ use crate::{ dev_aid::lsp::to_position, flattening::IdentifierType, - linker::{FileData, NameElem}, + linker::{FileData, GlobalUUID}, }; -use crate::typing::{abstract_type::DomainType, template::TemplateInputKind}; +use crate::typing::{abstract_type::DomainType, template::ParameterKind}; use super::tree_walk::{self, InModule, LocationInfo}; @@ -154,16 +154,16 @@ fn walk_name_color(file: &FileData, linker: &Linker) -> Vec<(Span, IDEIdentifier } LocationInfo::InModule(_md_id, _, _, InModule::Temporary(_)) => return, LocationInfo::Type(_, _) => return, - LocationInfo::TemplateInput(_id, _link_info, _, template_arg) => { + LocationInfo::Parameter(_id, _link_info, _, template_arg) => { match &template_arg.kind { - TemplateInputKind::Type(_) => IDEIdentifierType::Type, - TemplateInputKind::Generative(_) => IDEIdentifierType::Generative, + ParameterKind::Type(_) => IDEIdentifierType::Type, + ParameterKind::Generative(_) => IDEIdentifierType::Generative, } } LocationInfo::Global(g) => match g { - NameElem::Module(_) => IDEIdentifierType::Interface, - NameElem::Type(_) => IDEIdentifierType::Type, - NameElem::Constant(_) => IDEIdentifierType::Constant, + GlobalUUID::Module(_) => IDEIdentifierType::Interface, + GlobalUUID::Type(_) => IDEIdentifierType::Type, + GlobalUUID::Constant(_) => IDEIdentifierType::Constant, }, LocationInfo::Port(_, md, port_id) => { let interface = md.ports[port_id].domain; diff --git a/src/dev_aid/lsp/tree_walk.rs b/src/dev_aid/lsp/tree_walk.rs index ffd713b..4c86c4b 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, NameElem}; +use crate::linker::{FileData, LinkInfo, GlobalUUID}; use crate::typing::template::{ - GenerativeTemplateInputKind, GlobalReference, TemplateArgKind, TemplateInput, - TemplateInputKind, TypeTemplateInputKind, + GenerativeParameterKind, GlobalReference, TemplateArgKind, Parameter, + ParameterKind, TypeParameterKind, }; #[derive(Clone, Copy, Debug)] @@ -20,14 +20,14 @@ pub enum InModule<'linker> { #[derive(Clone, Copy, Debug)] pub enum LocationInfo<'linker> { InModule(ModuleUUID, &'linker Module, FlatID, InModule<'linker>), - TemplateInput( - NameElem, + Parameter( + GlobalUUID, &'linker LinkInfo, TemplateID, - &'linker TemplateInput, + &'linker Parameter, ), Type(&'linker WrittenType, &'linker LinkInfo), - Global(NameElem), + Global(GlobalUUID), /// The contained module only refers to the module on which the port is defined /// No reference to the module in which the reference was found is provided Port(&'linker SubModuleInstance, &'linker Module, PortID), @@ -38,10 +38,10 @@ pub enum LocationInfo<'linker> { #[derive(Clone, Copy, Debug)] pub struct RefersTo { pub local: Option<(ModuleUUID, FlatID)>, - pub global: Option, + pub global: Option, pub port: Option<(ModuleUUID, PortID)>, pub interface: Option<(ModuleUUID, InterfaceID)>, - pub template_input: Option<(NameElem, TemplateID)>, + pub parameter: Option<(GlobalUUID, TemplateID)>, } impl<'linker> From> for RefersTo { @@ -51,7 +51,7 @@ impl<'linker> From> for RefersTo { global: None, port: None, interface: None, - template_input: None, + parameter: None, }; match info { LocationInfo::InModule(md_id, md, flat_id, flat_obj) => match flat_obj { @@ -67,7 +67,7 @@ impl<'linker> From> for RefersTo { result.port = Some((md_id, port_id)); } DeclarationKind::GenerativeInput(template_id) => { - result.template_input = Some((NameElem::Module(md_id), template_id)) + result.parameter = Some((GlobalUUID::Module(md_id), template_id)) } } result.local = Some((md_id, flat_id)); @@ -78,20 +78,20 @@ impl<'linker> From> for RefersTo { InModule::Temporary(_) => {} }, LocationInfo::Type(_, _) => {} - LocationInfo::TemplateInput(obj, _link_info, template_id, template_arg) => { + LocationInfo::Parameter(obj, _link_info, template_id, template_arg) => { match &template_arg.kind { - TemplateInputKind::Type(TypeTemplateInputKind {}) => {} - TemplateInputKind::Generative(GenerativeTemplateInputKind { + ParameterKind::Type(TypeParameterKind {}) => {} + ParameterKind::Generative(GenerativeParameterKind { decl_span: _, declaration_instruction, }) => { - let NameElem::Module(md_id) = obj else { + let GlobalUUID::Module(md_id) = obj else { unreachable!() }; // TODO, local names in types? result.local = Some((md_id, *declaration_instruction)); } } - result.template_input = Some((obj, template_id)) + result.parameter = Some((obj, template_id)) } LocationInfo::Global(name_elem) => { result.global = Some(name_elem); @@ -112,8 +112,8 @@ impl RefersTo { pub fn refers_to_same_as(&self, info: LocationInfo) -> bool { match info { LocationInfo::InModule(md_id, _, obj, _) => self.local == Some((md_id, obj)), - LocationInfo::TemplateInput(parent, _, template_id, _) => { - self.template_input == Some((parent, template_id)) + LocationInfo::Parameter(parent, _, template_id, _) => { + self.parameter == Some((parent, template_id)) } LocationInfo::Type(_, _) => false, LocationInfo::Global(ne) => self.global == Some(ne), @@ -125,7 +125,7 @@ impl RefersTo { self.global.is_some() | self.port.is_some() | self.interface.is_some() - | self.template_input.is_some() + | self.parameter.is_some() } } @@ -207,23 +207,23 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b fn walk_global_reference( &mut self, - parent: NameElem, + parent: GlobalUUID, link_info: &'linker LinkInfo, global: &'linker GlobalReference, ) where - NameElem: From, + GlobalUUID: From, { - let target_name_elem = NameElem::from(global.id); + let target_name_elem = GlobalUUID::from(global.id); self.visit(global.name_span, LocationInfo::Global(target_name_elem)); for (id, template_arg) in global.template_args.iter_valids() { let target_link_info = self.linker.get_link_info(target_name_elem); self.visit( template_arg.name_span, - LocationInfo::TemplateInput( + LocationInfo::Parameter( target_name_elem, target_link_info, id, - &target_link_info.template_arguments[id], + &target_link_info.template_parameters[id], ), ); match &template_arg.kind { @@ -254,7 +254,7 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b ); } WireReferenceRoot::NamedConstant(cst) => { - self.walk_global_reference(NameElem::Module(md_id), &md.link_info, cst); + self.walk_global_reference(GlobalUUID::Module(md_id), &md.link_info, cst); } WireReferenceRoot::SubModulePort(port) => { if let Some(span) = port.port_name_span { @@ -286,7 +286,7 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b fn walk_type( &mut self, - parent: NameElem, + parent: GlobalUUID, link_info: &'linker LinkInfo, typ_expr: &'linker WrittenType, ) { @@ -298,11 +298,11 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b WrittenType::TemplateVariable(span, template_id) => { self.visit( *span, - LocationInfo::TemplateInput( + LocationInfo::Parameter( parent, link_info, *template_id, - &link_info.template_arguments[*template_id], + &link_info.template_parameters[*template_id], ), ); } @@ -352,19 +352,19 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b } } - fn walk_name_and_template_arguments(&mut self, name_elem : NameElem, link_info: &'linker LinkInfo) { + 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_arguments { - if let TemplateInputKind::Type(TypeTemplateInputKind {}) = + for (template_id, template_arg) in &link_info.template_parameters { + if let ParameterKind::Type(TypeParameterKind {}) = &template_arg.kind { self.visit( template_arg.name_span, - LocationInfo::TemplateInput( + LocationInfo::Parameter( name_elem, &link_info, template_id, @@ -378,7 +378,7 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b fn walk_module(&mut self, md_id: ModuleUUID) { let md = &self.linker.modules[md_id]; if !(self.should_prune)(md.link_info.span) { - self.walk_name_and_template_arguments(NameElem::Module(md_id), &md.link_info); + self.walk_name_and_template_arguments(GlobalUUID::Module(md_id), &md.link_info); for (interface_id, interface) in &md.interfaces { self.visit( @@ -391,7 +391,7 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b match inst { Instruction::SubModule(sm) => { self.walk_global_reference( - NameElem::Module(md_id), + GlobalUUID::Module(md_id), &md.link_info, &sm.module_ref, ); @@ -403,7 +403,7 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b } } Instruction::Declaration(decl) => { - self.walk_type(NameElem::Module(md_id), &md.link_info, &decl.typ_expr); + self.walk_type(GlobalUUID::Module(md_id), &md.link_info, &decl.typ_expr); if decl.declaration_itself_is_not_written_to { self.visit( decl.name_span, @@ -436,7 +436,7 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b fn walk_struct(&mut self, typ_id: TypeUUID) { let typ = &self.linker.types[typ_id]; if !(self.should_prune)(typ.link_info.span) { - self.walk_name_and_template_arguments(NameElem::Type(typ_id), &typ.link_info); + self.walk_name_and_template_arguments(GlobalUUID::Type(typ_id), &typ.link_info); println!("TODO struct instructions") } @@ -445,7 +445,7 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b fn walk_constant(&mut self, cst_id: ConstantUUID) { let cst = &self.linker.constants[cst_id]; if !(self.should_prune)(cst.link_info.span) { - self.walk_name_and_template_arguments(NameElem::Constant(cst_id), &cst.link_info); + self.walk_name_and_template_arguments(GlobalUUID::Constant(cst_id), &cst.link_info); println!("TODO constant instructions") } @@ -454,13 +454,13 @@ impl<'linker, Visitor: FnMut(Span, LocationInfo<'linker>), Pruner: Fn(Span) -> b fn walk_file(&mut self, file: &'linker FileData) { for global in &file.associated_values { match *global { - NameElem::Module(md_id) => { + GlobalUUID::Module(md_id) => { self.walk_module(md_id); } - NameElem::Type(typ_id) => { + GlobalUUID::Type(typ_id) => { self.walk_struct(typ_id); } - NameElem::Constant(cst_id) => { + GlobalUUID::Constant(cst_id) => { self.walk_constant(cst_id); } } diff --git a/src/errors.rs b/src/errors.rs index 9cb1faa..0a56bec 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -3,7 +3,7 @@ use crate::prelude::*; use std::cell::RefCell; use std::thread::panicking; -use crate::{alloc::ArenaAllocator, typing::template::TemplateInput}; +use crate::{alloc::ArenaAllocator, typing::template::Parameter}; use crate::flattening::{Declaration, Instruction, Interface, Module, Port, SubModuleInstance}; use crate::linker::{checkpoint::ErrorCheckpoint, FileData, LinkInfo}; @@ -298,7 +298,7 @@ impl ErrorInfoObject for Instruction { } } -impl ErrorInfoObject for TemplateInput { +impl ErrorInfoObject for Parameter { fn make_info(&self, file: FileUUID) -> ErrorInfo { ErrorInfo { position: self.name_span, diff --git a/src/flattening/flatten.rs b/src/flattening/flatten.rs index 24489d2..3409568 100644 --- a/src/flattening/flatten.rs +++ b/src/flattening/flatten.rs @@ -5,7 +5,7 @@ use crate::{alloc::UUIDRangeIter, prelude::*}; use num::BigInt; use sus_proc_macro::{field, kind, kw}; -use crate::linker::{FileData, GlobalResolver, NameElem, AFTER_FLATTEN_CP}; +use crate::linker::{FileData, GlobalResolver, GlobalUUID, AFTER_FLATTEN_CP}; use crate::{debug::SpanDebugger, value::Value}; use super::name_context::LocalVariableContext; @@ -13,7 +13,7 @@ use super::parser::Cursor; use super::*; use crate::typing::template::{ - GenerativeTemplateInputKind, TemplateArg, TemplateArgKind, TemplateArgs, TemplateInputKind + GenerativeParameterKind, TemplateArg, TemplateArgKind, TemplateArgs, ParameterKind }; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -223,7 +223,7 @@ impl TypingAllocator { typ: AbstractType::Unknown(self.type_variable_alloc.alloc()), domain: match domain { DomainAllocOption::Generative => DomainType::Generative, - DomainAllocOption::NonGenerativeUnknown => DomainType::DomainVariable(self.domain_variable_alloc.alloc()), + DomainAllocOption::NonGenerativeUnknown => DomainType::Unknown(self.domain_variable_alloc.alloc()), DomainAllocOption::NonGenerativeKnown(domain_id) => DomainType::Physical(domain_id), } } @@ -248,17 +248,17 @@ struct FlatteningContext<'l, 'errs> { } impl<'l, 'errs> FlatteningContext<'l, 'errs> { - fn flatten_template_inputs(&mut self, cursor: &mut Cursor) { - let mut template_inputs_to_visit = self.working_on_link_info.template_arguments.id_range().into_iter(); + fn flatten_parameters(&mut self, cursor: &mut Cursor) { + 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 = template_inputs_to_visit.next().unwrap(); + let claimed_type_id = parameters_to_visit.next().unwrap(); match cursor.kind() { 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_arguments[claimed_type_id]; + let selected_arg = &self.working_on_link_info.template_parameters[claimed_type_id]; let name_span = selected_arg.name_span; @@ -271,7 +271,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { } }) } - assert!(template_inputs_to_visit.is_empty()); + assert!(parameters_to_visit.is_empty()); } fn must_be_generative(&self, is_generative: bool, context: &str, span: Span) { @@ -280,11 +280,11 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { } } - fn flatten_template_args(&mut self, found_global: NameElem, has_template_args: bool, cursor: &mut Cursor) -> TemplateArgs { + fn flatten_template_args(&mut self, found_global: GlobalUUID, has_template_args: bool, cursor: &mut Cursor) -> TemplateArgs { 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_arguments.map(|_| None); + let mut template_arg_map : FlatAlloc, TemplateIDMarker> = link_info.template_parameters.map(|_| None); if !has_template_args {return template_arg_map;} @@ -295,7 +295,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { let name = &self.globals.file_data.file_text[name_span]; - let name_found = link_info.template_arguments.iter().find(|(_id, arg)| arg.name == name); + let name_found = link_info.template_parameters.iter().find(|(_id, arg)| arg.name == name); if name_found.is_none() { self.errors.error(name_span, format!("{name} is not a valid template argument of {full_object_name}")) .info_obj(link_info); @@ -334,10 +334,10 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { }, name_span) }; - if let Some((id, template_input)) = name_found { - match (&template_input.kind, &template_arg) { - (TemplateInputKind::Type(_), TemplateArgKind::Type(_)) - | (TemplateInputKind::Generative(_), TemplateArgKind::Value(_)) => { + if let Some((id, parameter)) = name_found { + match (¶meter.kind, &template_arg) { + (ParameterKind::Type(_), TemplateArgKind::Type(_)) + | (ParameterKind::Generative(_), TemplateArgKind::Value(_)) => { // Correct pairing let elem = &mut template_arg_map[id]; if let Some(prev) = elem { @@ -351,13 +351,13 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { }); } } - (TemplateInputKind::Type(_), TemplateArgKind::Value(_)) => { + (ParameterKind::Type(_), TemplateArgKind::Value(_)) => { self.errors.error(name_span, format!("'{name}' is not a value. `type` keyword cannot be used for values")) - .info((template_input.name_span, link_info.file), "Declared here"); + .info((parameter.name_span, link_info.file), "Declared here"); } - (TemplateInputKind::Generative(_), TemplateArgKind::Type(_)) => { + (ParameterKind::Generative(_), TemplateArgKind::Type(_)) => { self.errors.error(name_span, format!("'{name}' is not a type. To use template type arguments use the `type` keyword like `T: type int[123]`")) - .info((template_input.name_span, link_info.file), "Declared here"); + .info((parameter.name_span, link_info.file), "Declared here"); } } } @@ -411,21 +411,21 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { let template_arg_types = template_args.map(|_| AbstractType::Unknown(self.type_alloc.type_variable_alloc.alloc())); match global_id { - NameElem::Module(id) => LocalOrGlobal::Module(GlobalReference { + GlobalUUID::Module(id) => LocalOrGlobal::Module(GlobalReference { id, name_span, template_args, template_arg_types, template_span, }), - NameElem::Type(id) => LocalOrGlobal::Type(GlobalReference { + GlobalUUID::Type(id) => LocalOrGlobal::Type(GlobalReference { id, name_span, template_args, template_arg_types, template_span, }), - NameElem::Constant(id) => LocalOrGlobal::Constant(GlobalReference { + GlobalUUID::Constant(id) => LocalOrGlobal::Constant(GlobalReference { id, name_span, template_args, @@ -536,7 +536,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { } NamedLocal::TemplateType(template_id) => { err_ref.info_obj_same_file( - &self.working_on_link_info.template_arguments[template_id], + &self.working_on_link_info.template_parameters[template_id], ); } } @@ -547,7 +547,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { let md = &self.globals[module_ref.id]; let local_interface_domains = md .domain_names - .map(|_| DomainType::DomainVariable(self.type_alloc.domain_variable_alloc.alloc())); + .map(|_| DomainType::Unknown(self.type_alloc.domain_variable_alloc.alloc())); self.instructions.alloc(Instruction::SubModule(SubModuleInstance{ name, @@ -982,7 +982,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { span, format!( "Expected a value, but instead found template type '{}'", - self.working_on_link_info.template_arguments[template_id].name + self.working_on_link_info.template_parameters[template_id].name ), ); PartialWireReference::Error @@ -1477,7 +1477,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> { 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_template_inputs(cursor); + self.flatten_parameters(cursor); let module_name = &self.globals.file_data.file_text[name_span]; println!("TREE SITTER module! {module_name}"); @@ -1530,15 +1530,15 @@ pub fn flatten_all_modules(linker: &mut Linker) { let globals = GlobalResolver::new(linker, global_obj, errors_globals); let (ports_to_visit, fields_to_visit, default_declaration_context) = match global_obj { - NameElem::Module(module_uuid) => { + GlobalUUID::Module(module_uuid) => { let md = &globals[module_uuid]; (md.ports.id_range().into_iter(), UUIDRange::empty().into_iter(), DeclarationContext::PlainWire) } - NameElem::Type(type_uuid) => { + GlobalUUID::Type(type_uuid) => { let typ = &globals[type_uuid]; (UUIDRange::empty().into_iter(), typ.fields.id_range().into_iter(), DeclarationContext::StructField) } - NameElem::Constant(const_uuid) => { + GlobalUUID::Constant(const_uuid) => { (UUIDRange::empty().into_iter(), UUIDRange::empty().into_iter(), DeclarationContext::Generative(GenerativeKind::PlainGenerative)) } }; @@ -1567,7 +1567,7 @@ pub fn flatten_all_modules(linker: &mut Linker) { let errors_globals = globals.decommission(&linker.files); let link_info : &mut LinkInfo = match global_obj { - NameElem::Module(module_uuid) => { + GlobalUUID::Module(module_uuid) => { let md = &mut linker.modules[module_uuid]; // Set all declaration_instruction values for (decl_id, instr) in &instructions { @@ -1580,8 +1580,8 @@ pub fn flatten_all_modules(linker: &mut Linker) { port.declaration_instruction = decl_id; } DeclarationKind::GenerativeInput(this_template_id) => { - let TemplateInputKind::Generative(GenerativeTemplateInputKind { decl_span:_, declaration_instruction }) = - &mut md.link_info.template_arguments[this_template_id].kind else {unreachable!()}; + let ParameterKind::Generative(GenerativeParameterKind { decl_span:_, declaration_instruction }) = + &mut md.link_info.template_parameters[this_template_id].kind else {unreachable!()}; *declaration_instruction = decl_id; } @@ -1600,7 +1600,7 @@ pub fn flatten_all_modules(linker: &mut Linker) { &mut md.link_info } - NameElem::Type(type_uuid) => { + GlobalUUID::Type(type_uuid) => { let typ = &mut linker.types[type_uuid]; // Set all declaration_instruction values @@ -1615,8 +1615,8 @@ pub fn flatten_all_modules(linker: &mut Linker) { } DeclarationKind::RegularPort { is_input:_, port_id:_ } => {unreachable!("No ports in structs")} DeclarationKind::GenerativeInput(this_template_id) => { - let TemplateInputKind::Generative(GenerativeTemplateInputKind { decl_span:_, declaration_instruction }) = - &mut typ.link_info.template_arguments[this_template_id].kind else {unreachable!()}; + let ParameterKind::Generative(GenerativeParameterKind { decl_span:_, declaration_instruction }) = + &mut typ.link_info.template_parameters[this_template_id].kind else {unreachable!()}; *declaration_instruction = decl_id; } @@ -1625,7 +1625,7 @@ pub fn flatten_all_modules(linker: &mut Linker) { } &mut typ.link_info } - NameElem::Constant(const_uuid) => { + GlobalUUID::Constant(const_uuid) => { let cst = &mut linker.constants[const_uuid]; cst.output_decl = instructions.iter().find(|(_decl_id, instr)| { diff --git a/src/flattening/initialization.rs b/src/flattening/initialization.rs index 99298e2..2effe46 100644 --- a/src/flattening/initialization.rs +++ b/src/flattening/initialization.rs @@ -2,22 +2,22 @@ use arrayvec::ArrayVec; use sus_proc_macro::{field, kind, kw}; use crate::errors::ErrorStore; -use crate::linker::{IsExtern, NamedConstant, AFTER_INITIAL_PARSE_CP}; +use crate::linker::{IsExtern, AFTER_INITIAL_PARSE_CP}; use crate::prelude::*; use crate::linker::{FileBuilder, LinkInfo, ResolvedGlobals}; -use crate::{file_position::FileText, flattening::Module, instantiation::InstantiationList}; +use crate::{file_position::FileText, flattening::Module, instantiation::InstantiationCache}; use crate::typing::template::{ - GenerativeTemplateInputKind, TemplateInput, TemplateInputKind, TemplateInputs, - TypeTemplateInputKind, + GenerativeParameterKind, Parameter, ParameterKind, Parameters, + TypeParameterKind, }; use super::parser::Cursor; use super::*; struct InitializationContext<'linker> { - template_inputs: TemplateInputs, + parameters: Parameters, // module-only stuff ports: FlatAlloc, @@ -42,10 +42,10 @@ impl<'linker> InitializationContext<'linker> { kind!("template_declaration_type") => cursor.go_down_no_check(|cursor| { let name_span = cursor.field_span(field!("name"), kind!("identifier")); let name = self.file_text[name_span].to_owned(); - self.template_inputs.alloc(TemplateInput { + self.parameters.alloc(Parameter { name, name_span, - kind: TemplateInputKind::Type(TypeTemplateInputKind {}), + kind: ParameterKind::Type(TypeParameterKind {}), }); }), kind!("declaration") => cursor.go_down_no_check(|cursor| { @@ -55,10 +55,10 @@ impl<'linker> InitializationContext<'linker> { let name_span = cursor.field_span(field!("name"), kind!("identifier")); let name = self.file_text[name_span].to_owned(); - self.template_inputs.alloc(TemplateInput { + self.parameters.alloc(Parameter { name, name_span, - kind: TemplateInputKind::Generative(GenerativeTemplateInputKind { + kind: ParameterKind::Generative(GenerativeParameterKind { decl_span, declaration_instruction: FlatID::PLACEHOLDER, }), @@ -291,7 +291,7 @@ fn initialize_global_object(builder: &mut FileBuilder, parsing_errors: ErrorColl ports: FlatAlloc::new(), interfaces: FlatAlloc::new(), domains: FlatAlloc::new(), - template_inputs: FlatAlloc::new(), + parameters: FlatAlloc::new(), fields: FlatAlloc::new(), file_text: &builder.file_data.file_text, }; @@ -300,7 +300,7 @@ fn initialize_global_object(builder: &mut FileBuilder, parsing_errors: ErrorColl let mut link_info = LinkInfo { type_variable_alloc: TypingAllocator{domain_variable_alloc: UUIDAllocator::new(), type_variable_alloc: UUIDAllocator::new()}, - template_arguments: ctx.template_inputs, + template_parameters: ctx.parameters, instructions: FlatAlloc::new(), documentation: cursor.extract_gathered_comments(), file: builder.file_id, @@ -323,7 +323,7 @@ fn initialize_global_object(builder: &mut FileBuilder, parsing_errors: ErrorColl domain_names: ctx.domains, domains: FlatAlloc::new(), interfaces: ctx.interfaces, - instantiations: InstantiationList::new(), + instantiations: InstantiationCache::new(), }); } GlobalObjectKind::Struct => { diff --git a/src/flattening/lints.rs b/src/flattening/lints.rs index 9657560..e26be15 100644 --- a/src/flattening/lints.rs +++ b/src/flattening/lints.rs @@ -1,6 +1,6 @@ use crate::linker::{IsExtern, LinkInfo, AFTER_LINTS_CP}; use crate::prelude::*; -use crate::typing::template::TemplateInputKind; +use crate::typing::template::ParameterKind; use super::walk::for_each_generative_input_in_template_args; @@ -22,8 +22,8 @@ pub fn perform_lints(linker: &mut Linker) { */ fn extern_objects_may_not_have_type_template_args(link_info: &LinkInfo, errors: &ErrorCollector) { if link_info.is_extern == IsExtern::Extern { - for (_id, arg) in &link_info.template_arguments { - if let TemplateInputKind::Type(..) = &arg.kind { + 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"); } } diff --git a/src/flattening/mod.rs b/src/flattening/mod.rs index 2988876..4abc91d 100644 --- a/src/flattening/mod.rs +++ b/src/flattening/mod.rs @@ -20,7 +20,7 @@ pub use typechecking::typecheck_all_modules; pub use lints::perform_lints; use crate::linker::{Documentation, LinkInfo}; -use crate::{file_position::FileText, instantiation::InstantiationList, value::Value}; +use crate::{file_position::FileText, instantiation::InstantiationCache, value::Value}; use crate::typing::{ abstract_type::FullType, @@ -42,13 +42,15 @@ pub enum GlobalObjectKind { /// /// 2.1: Parsing: Parse source code to create instruction list. /// -/// 2.2: Typecheck: Add typ variables to everything. [Declaration::typ], [WireInstance::typ] and [SubModuleInstance::local_interface_domains] are set in this stage. +/// 2.2: Typecheck: Add typ variables to everything. [Declaration::typ], [Expression::typ] and [SubModuleInstance::local_interface_domains] are set in this stage. /// /// 3. Instantiation: Actually run generative code and instantiate modules. /// /// 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 { /// Created in Stage 1: Initialization @@ -69,7 +71,7 @@ pub struct Module { pub domains: FlatAlloc, /// Created in Stage 3: Instantiation - pub instantiations: InstantiationList, + pub instantiations: InstantiationCache, } impl Module { @@ -139,6 +141,8 @@ impl Module { /// 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 @@ -150,6 +154,20 @@ pub struct StructType { 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 +} + +/// Represents a field in a struct +/// +/// UNFINISHED +/// +/// TODO: Structs #8 #[derive(Debug)] pub struct StructField { pub name: String, @@ -159,13 +177,19 @@ 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. +/// +/// See [Module::get_port_or_interface_by_name] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PortOrInterface { Port(PortID), 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. #[derive(Debug)] pub struct DomainInfo { pub name: String, @@ -185,10 +209,23 @@ impl<'linker> InterfaceToDomainMap<'linker> { } } +/// 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 { + /// Local temporary + /// ```sus + /// int v = val + /// ``` Local, + /// ```sus + /// state int v + /// ``` State, + /// ```sus + /// gen int V = 3 + /// ``` Generative, } @@ -271,6 +308,7 @@ impl Interface { } } +/// An element in a [WireReference] path. Could be array accesses, slice accesses, field accesses, etc #[derive(Debug, Clone, Copy)] pub enum WireReferencePathElement { ArrayAccess { @@ -292,11 +330,24 @@ impl 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. #[derive(Debug)] pub enum WireReferenceRoot { + /// ```sus + /// int local_var + /// local_var = 3 + /// ``` LocalDecl(FlatID, Span), + /// ```sus + /// bool b = true // root is global constant `true` + /// ``` NamedConstant(GlobalReference), + /// ```sus + /// FIFO local_submodule + /// local_submodule.data_in = 3 // root is local_submodule.data_in (yes, both) + /// ``` SubModulePort(PortReference), } @@ -317,9 +368,13 @@ impl WireReferenceRoot { } } -/// References to wires +/// 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]` +/// Example: `myModule.port[a][b:c]`. (`myModule.port` is the [Self::root], `[a][b:c]` are two parts of the [Self::path]) #[derive(Debug)] pub struct WireReference { pub root: WireReferenceRoot, @@ -344,9 +399,20 @@ impl WireReference { } } +/// In a [Write], this represents what kind of write it is, based on keywords `reg` or `initial` #[derive(Debug)] pub enum WriteModifiers { + /// A regular write to a local wire (can include latency registers) or generative variable + /// ```sus + /// int v + /// reg reg v = a * 3 + /// ``` Connection { num_regs: i64, regs_span: Span }, + /// Set the initial value of a `state` register + /// ```sus + /// state int count + /// initial count = 3 // Must be generative + /// ``` Initial { initial_kw_span: Span }, } @@ -383,17 +449,30 @@ pub struct Write { pub write_modifiers: WriteModifiers, } +/// -x +/// +/// See [crate::value::compute_unary_op] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum UnaryOperator { + /// Horizontal & on arrays And, + /// Horizontal | on arrays Or, + /// Horizontal ^ on arrays Xor, + /// ! on booleans Not, + /// Horizontal + on arrays Sum, + /// Horizontal * on arrays Product, + /// - on integers Negate, } +/// x * y +/// +/// See [crate::value::compute_binary_op] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BinaryOperator { And, @@ -414,7 +493,8 @@ pub enum BinaryOperator { LesserEq, } -/// 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] +/// 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 { pub submodule_decl: FlatID, @@ -429,6 +509,10 @@ 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 { pub typ: FullType, @@ -436,6 +520,7 @@ pub struct Expression { pub source: ExpressionSource, } +/// See [Expression] #[derive(Debug)] pub enum ExpressionSource { WireRef(WireReference), // Used to add a span to the reference of a wire. @@ -480,7 +565,8 @@ impl WrittenType { } } -/// 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, @@ -545,6 +631,8 @@ pub struct Declaration { /// It can be referenced by a [WireReferenceRoot::SubModulePort] /// /// 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 { pub module_ref: GlobalReference, diff --git a/src/flattening/typechecking.rs b/src/flattening/typechecking.rs index 3dbfd9e..5b4e2cc 100644 --- a/src/flattening/typechecking.rs +++ b/src/flattening/typechecking.rs @@ -2,12 +2,12 @@ use crate::alloc::ArenaAllocator; use crate::errors::{ErrorInfo, ErrorInfoObject, FileKnowingErrorInfoObject}; use crate::prelude::*; use crate::typing::abstract_type::AbstractType; -use crate::typing::template::TemplateInputKind; +use crate::typing::template::ParameterKind; use crate::typing::type_inference::{FailedUnification, HindleyMilner}; use crate::debug::SpanDebugger; use crate::linker::{ - GlobalResolver, NameElem, AFTER_TYPECHECK_CP + GlobalResolver, GlobalUUID, AFTER_TYPECHECK_CP }; use crate::typing::{ @@ -20,7 +20,7 @@ use super::*; pub fn typecheck_all_modules(linker: &mut Linker) { let module_uuids : Vec = linker.modules.iter().map(|(id, _md)| id).collect(); for module_uuid in module_uuids { - let global_id = NameElem::Module(module_uuid); + let global_id = GlobalUUID::Module(module_uuid); let errs_globals = GlobalResolver::take_errors_globals(linker, global_id); let globals = GlobalResolver::new(linker, global_id, errs_globals); @@ -37,7 +37,7 @@ pub fn typecheck_all_modules(linker: &mut Linker) { globals : &globals, errors: &globals.errors, type_checker: TypeUnifier::new( - &working_on.link_info.template_arguments, + &working_on.link_info.template_parameters, working_on.link_info.type_variable_alloc.clone() ), runtime_condition_stack: Vec::new(), @@ -280,19 +280,19 @@ impl<'l, 'errs> TypeCheckingContext<'l, 'errs> { } } - fn typecheck_template_global>( + fn typecheck_template_global>( &self, global_ref: &GlobalReference, ) { - let global_obj: NameElem = global_ref.id.into(); + let global_obj: GlobalUUID = global_ref.id.into(); let target_link_info = self.globals.get_link_info(global_obj); for (parameter_id, argument_type) in &global_ref.template_arg_types { - let parameter = &target_link_info.template_arguments[parameter_id]; + let parameter = &target_link_info.template_parameters[parameter_id]; match ¶meter.kind { - TemplateInputKind::Type(_) => {} // Do nothing, nothing to unify with. Maybe in the future traits? - TemplateInputKind::Generative(template_input) => { - let decl = target_link_info.instructions[template_input.declaration_instruction].unwrap_declaration(); + 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, diff --git a/src/instantiation/concrete_typecheck.rs b/src/instantiation/concrete_typecheck.rs index aa83137..b74aaf9 100644 --- a/src/instantiation/concrete_typecheck.rs +++ b/src/instantiation/concrete_typecheck.rs @@ -7,8 +7,7 @@ use crate::linker::LinkInfo; use crate::typing::template::{ConcreteTemplateArg, HowDoWeKnowTheTemplateArg}; use crate::typing::{ concrete_type::{ConcreteType, BOOL_CONCRETE_TYPE, INT_CONCRETE_TYPE}, - delayed_constraint::{DelayedConstraint, DelayedConstraintStatus, DelayedConstraintsList}, - type_inference::FailedUnification + type_inference::{FailedUnification, DelayedConstraint, DelayedConstraintStatus, DelayedConstraintsList}, }; use super::*; diff --git a/src/instantiation/execute.rs b/src/instantiation/execute.rs index 47f3294..983501c 100644 --- a/src/instantiation/execute.rs +++ b/src/instantiation/execute.rs @@ -8,7 +8,6 @@ use std::ops::{Deref, Index, IndexMut}; use crate::linker::IsExtern; use crate::prelude::*; -use crate::typing::concrete_type::BOOL_CONCRETE_TYPE; use crate::typing::template::{GlobalReference, HowDoWeKnowTheTemplateArg}; use num::BigInt; @@ -148,6 +147,20 @@ fn array_access<'v>(arr_val: &'v Value, idx: &BigInt, span: BracketSpan) -> Exec } } +/// Temporary intermediary struct +/// +/// See [WireReferenceRoot] +#[derive(Debug, Clone)] +enum RealWireRefRoot { + /// The preamble isn't really used yet, but it's there for when we have submodule arrays (soon) + Wire { + wire_id: WireID, + preamble: Vec, + }, + Generative(FlatID), + Constant(Value), +} + impl<'fl, 'l> InstantiationContext<'fl, 'l> { /// Uses the current context to turn a [WrittenType] into a [ConcreteType]. /// @@ -679,7 +692,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { let wire_found = self.expression_to_real_wire(expr, original_instruction, domain)?; SubModuleOrWire::Wire(wire_found) } - DomainType::DomainVariable(_) => unreachable!("Domain variables have been eliminated by type checking") + DomainType::Unknown(_) => unreachable!("Domain variables have been eliminated by type checking") }, Instruction::Write(conn) => { self.instantiate_connection( @@ -751,7 +764,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { // Get rid of the condition let _ = self.condition_stack.pop().unwrap(); } - DomainType::DomainVariable(_) => unreachable!("Domain variables have been eliminated by type checking") + DomainType::Unknown(_) => unreachable!("Domain variables have been eliminated by type checking") } instruction_range.skip_to(stm.else_end); continue; diff --git a/src/instantiation/mod.rs b/src/instantiation/mod.rs index e797a72..3dfeb8a 100644 --- a/src/instantiation/mod.rs +++ b/src/instantiation/mod.rs @@ -91,6 +91,8 @@ 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 { pub source: RealWireDataSource, @@ -119,6 +121,8 @@ pub struct SubModulePort { /// 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 { pub original_instruction: FlatID, @@ -130,6 +134,7 @@ pub struct SubModule { pub template_args: ConcreteTemplateArgs, } +/// Generated from [Module::ports] #[derive(Debug)] pub struct InstantiatedPort { pub wire: WireID, @@ -139,18 +144,26 @@ 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. +/// +/// Generated when instantiating a [Module] #[derive(Debug)] pub struct InstantiatedModule { /// Unique name involving all template arguments pub name: String, pub errors: ErrorStore, - /// This matches the ports in [Module::module_ports]. Ports are not None when they are not part of this instantiation. + /// This matches the ports in [Module::ports]. Ports are not `None` when they are not part of this instantiation. pub interface_ports: FlatAlloc, PortIDMarker>, pub wires: FlatAlloc, pub submodules: FlatAlloc, + /// See [GenerationState] pub generation_state: FlatAlloc, } +/// See [GenerationState] #[derive(Debug, Clone)] pub enum SubModuleOrWire { SubModule(SubModuleID), @@ -184,23 +197,17 @@ impl SubModuleOrWire { } } -#[derive(Debug, Clone)] -pub enum RealWireRefRoot { - /// The preamble isn't really used yet, but it's there for when we have submodule arrays (soon) - Wire { - wire_id: WireID, - preamble: Vec, - }, - Generative(FlatID), - Constant(Value), -} - +/// 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 InstantiationList { +pub struct InstantiationCache { cache: RefCell>>, } -impl InstantiationList { +impl InstantiationCache { pub fn new() -> Self { Self { cache: RefCell::new(HashMap::new()), @@ -264,29 +271,44 @@ impl InstantiationList { // Also passes over invalid instances. Instance validity should not be assumed! // Only used for things like syntax highlighting - pub fn for_each_instance<'s, F: FnMut(&ConcreteTemplateArgs, &Rc)>( + pub fn for_each_instance)>( &self, mut f: F, ) { let borrow = self.cache.borrow(); for (k, v) in borrow.iter() { - f(k, &v) + f(k, v) } } } +/// 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, md: &'fl Module, } +/// Runtime conditions applied to a [crate::flattening::Write] +/// +/// ```sus +/// state int a +/// when x { +/// a = 3 +/// } else { +/// a = 2 +/// } +/// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ConditionStackElem { pub condition_wire : WireID, + /// When this is an else-branch pub inverse : bool } +/// 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>, diff --git a/src/instantiation/unique_names.rs b/src/instantiation/unique_names.rs index b6fc7d2..ae84dbe 100644 --- a/src/instantiation/unique_names.rs +++ b/src/instantiation/unique_names.rs @@ -1,6 +1,12 @@ use std::collections::HashMap; - +/// 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 } diff --git a/src/linker/checkpoint.rs b/src/linker/checkpoint.rs index a7fdb9d..45494c3 100644 --- a/src/linker/checkpoint.rs +++ b/src/linker/checkpoint.rs @@ -2,12 +2,21 @@ 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 { errors_cp: ErrorCheckpoint, diff --git a/src/linker/mod.rs b/src/linker/mod.rs index 79ea4b6..19c59c5 100644 --- a/src/linker/mod.rs +++ b/src/linker/mod.rs @@ -1,4 +1,4 @@ -use crate::{flattening::Instruction, prelude::*, typing::template::{GenerativeTemplateInputKind, TemplateInputKind, TypeTemplateInputKind}}; +use crate::{flattening::{Instruction, NamedConstant}, prelude::*, typing::template::{GenerativeParameterKind, ParameterKind, TypeParameterKind}}; pub mod checkpoint; mod resolver; @@ -23,7 +23,7 @@ use crate::errors::{CompileError, ErrorInfo, ErrorLevel, ErrorStore}; use crate::flattening::{StructType, TypingAllocator}; -use crate::typing::template::TemplateInputs; +use crate::typing::template::Parameters; use self::checkpoint::CheckPoint; @@ -37,6 +37,7 @@ pub const fn get_builtin_type(name: &'static str) -> TypeUUID { } } +/// Documentation can be attached to [Module], [StructType], [NamedConstant], [crate::flattening::Declaration] #[derive(Debug, Clone)] pub struct Documentation { pub gathered: Box<[Span]>, @@ -59,8 +60,17 @@ impl Documentation { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum IsExtern { + /// ```sus + /// module md {} + /// ``` Normal, + /// ```sus + /// extern module md {} + /// ``` Extern, + /// ```sus + /// __builtin__ module md {} + /// ``` Builtin } @@ -69,7 +79,9 @@ 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 { pub file: FileUUID, @@ -86,14 +98,14 @@ pub struct LinkInfo { /// Is only temporary. It's used during typechecking to allocate the type unification block pub type_variable_alloc: TypingAllocator, - pub template_arguments: TemplateInputs, + pub template_parameters: Parameters, /// 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. /// - /// TODO the system is there, just need to actually do 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 @@ -108,12 +120,12 @@ impl LinkInfo { } pub fn get_full_name_and_template_args(&self, file_text: &FileText) -> String { let mut template_args: Vec<&str> = Vec::new(); - for (_id, t) in &self.template_arguments { + for (_id, t) in &self.template_parameters { match &t.kind { - TemplateInputKind::Type(TypeTemplateInputKind { }) => { + ParameterKind::Type(TypeParameterKind { }) => { template_args.push(&t.name) } - TemplateInputKind::Generative(GenerativeTemplateInputKind { + ParameterKind::Generative(GenerativeParameterKind { decl_span, declaration_instruction: _, }) => template_args.push(&file_text[*decl_span]) @@ -128,58 +140,56 @@ impl LinkInfo { } } -pub struct LinkingErrorLocation { - pub named_type: &'static str, - pub full_name: String, - pub location: SpanFile, -} - -#[derive(Debug)] -pub struct NamedConstant { - pub link_info: LinkInfo, - pub output_decl: FlatID -} - +/// 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, pub file_text: FileText, pub parsing_errors: ErrorStore, /// In source file order - pub associated_values: Vec, + pub associated_values: Vec, pub tree: tree_sitter::Tree, } +/// Globally references any [Module], [StructType], or [NamedConstant] in [Linker] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum NameElem { +pub enum GlobalUUID { Module(ModuleUUID), Type(TypeUUID), Constant(ConstantUUID), } -impl From for NameElem { +impl From for GlobalUUID { fn from(value: ModuleUUID) -> Self { - NameElem::Module(value) + GlobalUUID::Module(value) } } -impl From for NameElem { +impl From for GlobalUUID { fn from(value: TypeUUID) -> Self { - NameElem::Type(value) + GlobalUUID::Type(value) } } -impl From for NameElem { +impl From for GlobalUUID { fn from(value: ConstantUUID) -> Self { - NameElem::Constant(value) + GlobalUUID::Constant(value) } } enum NamespaceElement { - Global(NameElem), - Colission(Box<[NameElem]>), + Global(GlobalUUID), + Colission(Box<[GlobalUUID]>), } -// Represents the fully linked set of all files. Incremental operations such as adding and removing files can be performed +/// The global object that collects all [Module]s, [StructType]s, and [NamedConstant]s that are in the SUS codebase. +/// +/// There should only be one [Linker] globally. +/// +/// 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, pub modules: ArenaAllocator, @@ -199,36 +209,23 @@ impl Linker { } } - pub fn get_link_info(&self, global: NameElem) -> &LinkInfo { + pub fn get_link_info(&self, global: GlobalUUID) -> &LinkInfo { match global { - NameElem::Module(md_id) => &self.modules[md_id].link_info, - NameElem::Type(typ_id) => &self.types[typ_id].link_info, - NameElem::Constant(cst_id) => &self.constants[cst_id].link_info + 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 } } pub fn get_link_info_mut<'l>( modules: &'l mut ArenaAllocator, types: &'l mut ArenaAllocator, constants: &'l mut ArenaAllocator, - global: NameElem + global: GlobalUUID ) -> &'l mut LinkInfo { match global { - NameElem::Module(md_id) => &mut modules[md_id].link_info, - NameElem::Type(typ_id) => &mut types[typ_id].link_info, - NameElem::Constant(cst_id) => &mut constants[cst_id].link_info - } - } - fn get_linking_error_location(&self, global: NameElem) -> LinkingErrorLocation { - let named_type = match global { - NameElem::Module(_) => "Module", - NameElem::Type(_) => "Struct", - NameElem::Constant(_) => "Constant" - }; - let link_info = self.get_link_info(global); - LinkingErrorLocation { - named_type, - full_name: link_info.get_full_name(), - location: link_info.get_span_file(), + 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 } } fn for_all_duplicate_declaration_errors(&self, file_uuid: FileUUID, f: &mut F) { @@ -278,15 +275,15 @@ impl Linker { ) { for v in &self.files[file_uuid].associated_values { match v { - NameElem::Module(md_id) => { + GlobalUUID::Module(md_id) => { let md = &self.modules[*md_id]; for e in &md.link_info.errors { func(e) } md.instantiations.for_each_error(func); } - NameElem::Type(_) => {} - NameElem::Constant(_) => {} + GlobalUUID::Type(_) => {} + GlobalUUID::Constant(_) => {} } } } @@ -309,13 +306,13 @@ impl Linker { let was_new_item_in_set = to_remove_set.insert(v); assert!(was_new_item_in_set); match v { - NameElem::Module(id) => { + GlobalUUID::Module(id) => { self.modules.free(id); } - NameElem::Type(id) => { + GlobalUUID::Type(id) => { self.types.free(id); } - NameElem::Constant(id) => { + GlobalUUID::Constant(id) => { self.constants.free(id); } } @@ -326,7 +323,7 @@ impl Linker { NamespaceElement::Global(g) => !to_remove_set.contains(g), NamespaceElement::Colission(colission) => { let mut retain_vec = - std::mem::replace::>(colission, Box::new([])).into_vec(); + std::mem::replace::>(colission, Box::new([])).into_vec(); retain_vec.retain(|g| !to_remove_set.contains(g)); *colission = retain_vec.into_boxed_slice(); colission.len() > 0 @@ -369,13 +366,14 @@ impl Linker { } } +/// Temporary builder for [crate::flattening::initialization] pub struct FileBuilder<'linker> { pub file_id: FileUUID, pub tree: &'linker Tree, pub file_data: &'linker FileData, pub files: &'linker ArenaAllocator, pub other_parsing_errors: &'linker ErrorCollector<'linker>, - associated_values: &'linker mut Vec, + associated_values: &'linker mut Vec, global_namespace: &'linker mut HashMap, modules: &'linker mut ArenaAllocator, types: &'linker mut ArenaAllocator, @@ -383,7 +381,7 @@ pub struct FileBuilder<'linker> { } impl<'linker> FileBuilder<'linker> { - fn add_name(&mut self, name: String, new_obj_id: NameElem) { + 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) => { let new_val = match occ.get_mut() { @@ -405,21 +403,21 @@ impl<'linker> FileBuilder<'linker> { pub fn add_module(&mut self, md: Module) { let module_name = md.link_info.name.clone(); - let new_module_uuid = NameElem::Module(self.modules.alloc(md)); + let new_module_uuid = GlobalUUID::Module(self.modules.alloc(md)); self.associated_values.push(new_module_uuid); self.add_name(module_name, new_module_uuid); } pub fn add_type(&mut self, typ: StructType) { let type_name = typ.link_info.name.clone(); - let new_type_uuid = NameElem::Type(self.types.alloc(typ)); + let new_type_uuid = GlobalUUID::Type(self.types.alloc(typ)); self.associated_values.push(new_type_uuid); self.add_name(type_name, new_type_uuid); } pub fn add_const(&mut self, cst: NamedConstant) { let const_name = cst.link_info.name.clone(); - let new_const_uuid = NameElem::Constant(self.constants.alloc(cst)); + let new_const_uuid = GlobalUUID::Constant(self.constants.alloc(cst)); self.associated_values.push(new_const_uuid); self.add_name(const_name, new_const_uuid); } diff --git a/src/linker/resolver.rs b/src/linker/resolver.rs index 0a79db1..6d6f5d2 100644 --- a/src/linker/resolver.rs +++ b/src/linker/resolver.rs @@ -8,9 +8,10 @@ use self::checkpoint::ResolvedGlobalsCheckpoint; use super::*; +/// See [GlobalResolver] #[derive(Debug)] pub struct ResolvedGlobals { - referenced_globals: Vec, + referenced_globals: Vec, all_resolved: bool, } @@ -36,6 +37,14 @@ impl ResolvedGlobals { } } +struct LinkingErrorLocation { + pub named_type: &'static str, + pub full_name: String, + pub location: SpanFile, +} + +/// This struct encapsulates the concept of name resolution. It reports name-not-found errors, +/// and remembers all of the requested globals in preparation for #49 pub struct GlobalResolver<'linker> { linker: &'linker Linker, pub file_data: &'linker FileData, @@ -46,7 +55,7 @@ pub struct GlobalResolver<'linker> { } impl<'linker> GlobalResolver<'linker> { - pub fn take_errors_globals(linker: &mut Linker, global_obj: NameElem) -> (ErrorStore, ResolvedGlobals) { + 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(); @@ -54,7 +63,7 @@ impl<'linker> GlobalResolver<'linker> { (errors, resolved_globals) } - pub fn new(linker: &'linker Linker, global_obj: NameElem, errors_globals: (ErrorStore, ResolvedGlobals)) -> Self { + pub fn new(linker: &'linker Linker, global_obj: GlobalUUID, errors_globals: (ErrorStore, ResolvedGlobals)) -> Self { let obj_link_info = linker.get_link_info(global_obj); let file_data = &linker.files[obj_link_info.file]; @@ -74,8 +83,22 @@ impl<'linker> GlobalResolver<'linker> { (errors, resolved_globals) } + fn get_linking_error_location(&self, global: GlobalUUID) -> LinkingErrorLocation { + let named_type = match global { + GlobalUUID::Module(_) => "Module", + GlobalUUID::Type(_) => "Struct", + GlobalUUID::Constant(_) => "Constant" + }; + let link_info = self.linker.get_link_info(global); + LinkingErrorLocation { + named_type, + full_name: link_info.get_full_name(), + location: link_info.get_span_file(), + } + } + /// 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<'slf>(&'slf self, name_span: Span) -> Option { let name = &self.file_data.file_text[name_span]; let mut resolved_globals = self.resolved_globals.borrow_mut(); @@ -90,7 +113,7 @@ impl<'linker> GlobalResolver<'linker> { let err_ref = self.errors.error(name_span, format!("There were colliding imports for the name '{name}'. Pick one and import it by name.")); for collider_global in coll.iter() { - let err_loc = self.linker.get_linking_error_location(*collider_global); + let err_loc = self.get_linking_error_location(*collider_global); err_ref.info( err_loc.location, format!("{} {} declared here", err_loc.named_type, err_loc.full_name), @@ -114,12 +137,9 @@ impl<'linker> GlobalResolver<'linker> { } } - pub fn get_linking_error_location(&self, name_elem: NameElem) -> LinkingErrorLocation { - self.linker.get_linking_error_location(name_elem) - } - pub fn not_expected_global_error(&self, global_ref: &GlobalReference, expected: &str) where NameElem: 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(NameElem::from(global_ref.id)); + let info = self.get_linking_error_location(GlobalUUID::from(global_ref.id)); let name = &info.full_name; let global_type = info.named_type; let err_ref = self.errors.error( @@ -129,7 +149,7 @@ impl<'linker> GlobalResolver<'linker> { err_ref.info(info.location, "Defined here"); } - pub fn get_link_info(&self, id: NameElem) -> &LinkInfo { + pub fn get_link_info(&self, id: GlobalUUID) -> &LinkInfo { self.resolved_globals.borrow_mut().referenced_globals.push(id); self.linker.get_link_info(id) } @@ -141,7 +161,7 @@ impl<'l> Index for GlobalResolver<'l> { fn index(&self, index: ModuleUUID) -> &Self::Output { self.resolved_globals.borrow_mut() .referenced_globals - .push(NameElem::Module(index)); + .push(GlobalUUID::Module(index)); &self.linker.modules[index] } @@ -152,7 +172,7 @@ impl<'l> Index for GlobalResolver<'l> { fn index(&self, index: TypeUUID) -> &Self::Output { self.resolved_globals.borrow_mut() .referenced_globals - .push(NameElem::Type(index)); + .push(GlobalUUID::Type(index)); &self.linker.types[index] } @@ -163,7 +183,7 @@ impl<'l> Index for GlobalResolver<'l> { fn index(&self, index: ConstantUUID) -> &Self::Output { self.resolved_globals.borrow_mut() .referenced_globals - .push(NameElem::Constant(index)); + .push(GlobalUUID::Constant(index)); &self.linker.constants[index] } diff --git a/src/to_string.rs b/src/to_string.rs index 1dde784..eac5fbd 100644 --- a/src/to_string.rs +++ b/src/to_string.rs @@ -9,7 +9,7 @@ use crate::linker::{FileData, LinkInfo}; use crate::typing::{ abstract_type::{AbstractType, DomainType}, concrete_type::ConcreteType, - template::{ConcreteTemplateArg, ConcreteTemplateArgs, TemplateInputs}, + template::{ConcreteTemplateArg, ConcreteTemplateArgs, Parameters}, }; use std::{ @@ -20,8 +20,8 @@ use std::{ use std::fmt::Write; use std::ops::Deref; -pub fn map_to_type_names(template_inputs: &TemplateInputs) -> FlatAlloc { - template_inputs.map(|(_id, v)| v.name.clone()) +pub fn map_to_type_names(parameters: &Parameters) -> FlatAlloc { + parameters.map(|(_id, v)| v.name.clone()) } pub trait TemplateNameGetter { @@ -33,7 +33,7 @@ impl TemplateNameGetter for FlatAlloc { &self[id] } } -impl TemplateNameGetter for TemplateInputs { +impl TemplateNameGetter for Parameters { fn get_template_name(&self, id: TemplateID) -> &str { &self[id].name } @@ -311,7 +311,7 @@ pub fn pretty_print_concrete_instance( where TypVec: Index, { - assert!(given_template_args.len() == target_link_info.template_arguments.len()); + assert!(given_template_args.len() == target_link_info.template_parameters.len()); let object_full_name = target_link_info.get_full_name(); if given_template_args.len() == 0 { return format!("{object_full_name} #()"); @@ -319,7 +319,7 @@ where let mut result = format!("{object_full_name} #(\n"); for (id, arg) in given_template_args { - let arg_in_target = &target_link_info.template_arguments[id]; + let arg_in_target = &target_link_info.template_parameters[id]; write!(result, " {}: ", arg_in_target.name).unwrap(); match arg { ConcreteTemplateArg::Type(concrete_type, how_do_we_know_the_template_arg) => { diff --git a/src/typing/abstract_type.rs b/src/typing/abstract_type.rs index 81ea9cb..a956b70 100644 --- a/src/typing/abstract_type.rs +++ b/src/typing/abstract_type.rs @@ -3,11 +3,11 @@ use crate::prelude::*; use crate::value::Value; use std::ops::Deref; -use super::template::{GlobalReference, TemplateAbstractTypes, TemplateInputs}; +use super::template::{GlobalReference, TemplateAbstractTypes, Parameters}; use super::type_inference::{DomainVariableID, DomainVariableIDMarker, TypeSubstitutor, TypeVariableID, TypeVariableIDMarker, UnifyErrorReport}; use crate::flattening::{BinaryOperator, StructType, TypingAllocator, UnaryOperator, WrittenType}; use crate::linker::get_builtin_type; -use crate::to_string::{map_to_type_names, AbstractTypeDisplay, TemplateNameGetter}; +use crate::to_string::map_to_type_names; /// This contains only the information that can be easily type-checked. /// @@ -16,10 +16,14 @@ use crate::to_string::{map_to_type_names, AbstractTypeDisplay, TemplateNameGette /// What isn't included are the parameters of types. So Array Sizes for example. #[derive(Debug, Clone)] pub enum AbstractType { - Unknown(TypeVariableID), Template(TemplateID), Named(TypeUUID), Array(Box), + /// Referencing [AbstractType::Unknown] is a strong code smell. + /// It is likely you should use [TypeSubstitutor::unify] instead + /// + /// It should only occur in creation `AbstractType::Unknown(self.type_substitutor.alloc())` + Unknown(TypeVariableID), } pub const BOOL_TYPE: AbstractType = AbstractType::Named(get_builtin_type("bool")); @@ -35,7 +39,12 @@ pub enum DomainType { /// These are unified by Hindley-Milner unification /// /// They always point to non-generative domains. - DomainVariable(DomainVariableID) + /// + /// Referencing [DomainType::Unknown] is a strong code smell. + /// It is likely you should use [TypeSubstitutor::unify] instead + /// + /// It should only occur in creation `DomainType::Unknown(self.domain_substitutor.alloc())` + Unknown(DomainVariableID) } impl DomainType { @@ -49,22 +58,26 @@ impl DomainType { match self { DomainType::Generative => true, DomainType::Physical(_) => false, - DomainType::DomainVariable(_) => false, + DomainType::Unknown(_) => false, } } } +/// 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. #[derive(Debug, Clone)] pub struct FullType { pub typ: AbstractType, pub domain: DomainType, } -/// Unification of domains? -/// -/// 'A U 'x -> 'x = 'A +/// Performs Hindley-Milner typing during Flattening. (See [TypeSubstitutor]) +/// +/// 'A U 'x -> Substitute 'x = 'A /// -/// 'x U 'y -> 'x = 'y +/// 'x U 'y -> Substitute 'x = 'y pub struct TypeUnifier { pub template_type_names: FlatAlloc, pub type_substitutor: TypeSubstitutor, @@ -73,11 +86,11 @@ pub struct TypeUnifier { impl TypeUnifier { pub fn new( - template_inputs: &TemplateInputs, + parameters: &Parameters, typing_alloc: TypingAllocator ) -> Self { Self { - template_type_names: map_to_type_names(template_inputs), + 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) } diff --git a/src/typing/concrete_type.rs b/src/typing/concrete_type.rs index 27afcdc..bb03f55 100644 --- a/src/typing/concrete_type.rs +++ b/src/typing/concrete_type.rs @@ -16,6 +16,10 @@ pub enum ConcreteType { Named(TypeUUID), Value(Value), Array(Box<(ConcreteType, ConcreteType)>), + /// Referencing [ConcreteType::Unknown] is a strong code smell. + /// It is likely you should use [crate::typing::type_inference::TypeSubstitutor::unify] instead + /// + /// It should only occur in creation `ConcreteType::Unknown(self.type_substitutor.alloc())` Unknown(ConcreteTypeVariableID) } diff --git a/src/typing/delayed_constraint.rs b/src/typing/delayed_constraint.rs deleted file mode 100644 index 5cedbd7..0000000 --- a/src/typing/delayed_constraint.rs +++ /dev/null @@ -1,67 +0,0 @@ -use std::thread::panicking; - - - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DelayedConstraintStatus { - Resolved, - Progress, - NoProgress -} - -pub trait DelayedConstraint { - 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>>); - -impl DelayedConstraintsList { - pub fn new() -> Self { - Self(Vec::new()) - } - - /// Add a constraint - 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. - /// - /// 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 - } - }); - if !progress_made { - for constraint in std::mem::replace(&mut self.0, Vec::new()) { - constraint.report_could_not_resolve_error(shared_object); - } - return; // Exit - } - } - } -} - -impl Drop for DelayedConstraintsList { - fn drop(&mut self) { - if !panicking() { - assert_eq!(self.0.len(), 0, "DelayedConstraintsList was not resolved."); - } - } -} diff --git a/src/typing/mod.rs b/src/typing/mod.rs index c6215dd..b3eb433 100644 --- a/src/typing/mod.rs +++ b/src/typing/mod.rs @@ -2,4 +2,3 @@ pub mod abstract_type; pub mod concrete_type; pub mod template; pub mod type_inference; -pub mod delayed_constraint; diff --git a/src/typing/template.rs b/src/typing/template.rs index ec62e5a..727fb65 100644 --- a/src/typing/template.rs +++ b/src/typing/template.rs @@ -3,6 +3,13 @@ use crate::{prelude::*, value::Value}; use super::{abstract_type::AbstractType, concrete_type::ConcreteType}; use crate::flattening::WrittenType; +/// References any [crate::flattening::Module], [crate::flattening::StructType], or [crate::flattening::NamedConstant], +/// and includes any template arguments. +/// +/// As an example, this is the struct in charge of representing: +/// ```sus +/// FIFO #(DEPTH : 32, T : type int) +/// ``` #[derive(Debug)] pub struct GlobalReference { pub name_span: Span, @@ -22,46 +29,61 @@ impl GlobalReference { } } +/// The template parameters of an object ([crate::flattening::Module], [crate::flattening::StructType], or [crate::flattening::NamedConstant]) +/// +/// See [crate::linker::LinkInfo] +/// +/// Not to be confused with [TemplateArg], which is the argument passed to this parameter. #[derive(Debug)] -pub struct TemplateInput { +pub struct Parameter { pub name: String, pub name_span: Span, - pub kind: TemplateInputKind, + pub kind: ParameterKind, } +/// See [Parameter] #[derive(Debug)] -pub struct GenerativeTemplateInputKind { +pub struct GenerativeParameterKind { pub decl_span: Span, /// Set at the end of Flattening pub declaration_instruction: FlatID, } +/// See [Parameter] #[derive(Debug)] -pub struct TypeTemplateInputKind {} +pub struct TypeParameterKind {} +/// See [Parameter] #[derive(Debug)] -pub enum TemplateInputKind { - Type(TypeTemplateInputKind), - Generative(GenerativeTemplateInputKind), +pub enum ParameterKind { + Type(TypeParameterKind), + Generative(GenerativeParameterKind), } -impl TemplateInputKind { +impl ParameterKind { #[track_caller] - pub fn unwrap_type(&self) -> &TypeTemplateInputKind { + pub fn unwrap_type(&self) -> &TypeParameterKind { let Self::Type(t) = self else { - unreachable!("TemplateInputKind::unwrap_type on {self:?}") + unreachable!("ParameterKind::unwrap_type on {self:?}") }; t } #[track_caller] - pub fn unwrap_value(&self) -> &GenerativeTemplateInputKind { + pub fn unwrap_value(&self) -> &GenerativeParameterKind { let Self::Generative(v) = self else { - unreachable!("TemplateInputKind::unwrap_value on {self:?}") + unreachable!("ParameterKind::unwrap_value on {self:?}") }; v } } +/// An argument passed to a template parameter. +/// +/// See [GlobalReference] +/// +/// Not to be confused with [Parameter], which it is passed into. +/// +/// When instantiated, this becomes a [ConcreteTemplateArg] #[derive(Debug)] pub struct TemplateArg { pub name_span: Span, @@ -92,6 +114,7 @@ impl TemplateArgKind { } } +/// Tracks how we arrived at this value through type inference. (See [crate::typing::type_inference]) #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum HowDoWeKnowTheTemplateArg { Given, @@ -107,10 +130,17 @@ impl HowDoWeKnowTheTemplateArg { } } +/// Represents the value we're passing into a template argument. +/// +/// It is the instantiated variant of [TemplateArg] +/// +/// And it is passed to a [crate::flattening::Module], [crate::flattening::StructType], or [crate::flattening::NamedConstant]'s [Parameter] #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ConcreteTemplateArg { Type(ConcreteType, HowDoWeKnowTheTemplateArg), Value(Value, HowDoWeKnowTheTemplateArg), + /// It has not been explicitly provided, + /// yet [crate::typing::type_inference] may replace this value when it can figure it out from the context NotProvided, } @@ -127,10 +157,13 @@ impl ConcreteTemplateArg { } } +/// See [TemplateArg] pub type TemplateArgs = FlatAlloc, TemplateIDMarker>; /// 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 type TemplateAbstractTypes = FlatAlloc; -pub type TemplateInputs = FlatAlloc; +/// See [Parameter] +pub type Parameters = FlatAlloc; +/// See [ConcreteTemplateArg] pub type ConcreteTemplateArgs = FlatAlloc; diff --git a/src/typing/type_inference.rs b/src/typing/type_inference.rs index ce999a6..92c1e76 100644 --- a/src/typing/type_inference.rs +++ b/src/typing/type_inference.rs @@ -46,6 +46,11 @@ pub struct FailedUnification { /// Pretty big block size so for most typing needs we only need one 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> { substitution_map: BlockVec, BLOCK_SIZE>, failed_unifications: RefCell>>, @@ -249,7 +254,7 @@ impl HindleyMilner for DomainType { match self { DomainType::Generative => unreachable!("No explicit comparisons with Generative Possible. These should be filtered out first"), DomainType::Physical(domain_id) => HindleyMilnerInfo::TypeFunc(*domain_id), - DomainType::DomainVariable(var) => HindleyMilnerInfo::TypeVar(*var) + DomainType::Unknown(var) => HindleyMilnerInfo::TypeVar(*var) } } @@ -262,7 +267,7 @@ impl HindleyMilner for DomainType { fn fully_substitute(&mut self, substitutor: &TypeSubstitutor) -> bool { match self { DomainType::Generative | DomainType::Physical(_) => true, // Do nothing, These are done already - DomainType::DomainVariable(var) => { + 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.fully_substitute(substitutor) } @@ -320,3 +325,69 @@ impl HindleyMilner for ConcreteType { } } } + + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DelayedConstraintStatus { + Resolved, + Progress, + NoProgress +} + +pub trait DelayedConstraint { + 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>>); + +impl DelayedConstraintsList { + pub fn new() -> Self { + Self(Vec::new()) + } + + /// Add a constraint + 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. + /// + /// 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 + } + }); + if !progress_made { + for constraint in std::mem::replace(&mut self.0, Vec::new()) { + constraint.report_could_not_resolve_error(shared_object); + } + return; // Exit + } + } + } +} + +impl Drop for DelayedConstraintsList { + fn drop(&mut self) { + if !std::thread::panicking() { + assert_eq!(self.0.len(), 0, "DelayedConstraintsList was not resolved."); + } + } +} + diff --git a/src/value.rs b/src/value.rs index b0db252..f3134b8 100644 --- a/src/value.rs +++ b/src/value.rs @@ -174,7 +174,7 @@ impl ConcreteType { let mut arr = Vec::new(); if arr_size > 0 { let content_typ = arr_typ.get_initial_val(); - arr.resize(arr_size as usize, content_typ); + arr.resize(arr_size, content_typ); } Value::Array(arr.into_boxed_slice()) }