diff --git a/Cargo.lock b/Cargo.lock index a962fc96..a89ea34b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -174,6 +174,7 @@ dependencies = [ "diagnostics", "hir", "session", + "utilities", ] [[package]] @@ -184,7 +185,6 @@ dependencies = [ "hir", "hir_format", "inkwell", - "resolver", "session", "utilities", ] @@ -973,12 +973,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eb022374af2f446981254e6bf9efb6e2c9e1a53176d395fca02792fd4435729" -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - [[package]] name = "num-bigint" version = "0.4.3" @@ -1117,15 +1111,6 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - [[package]] name = "pin-project" version = "1.0.12" @@ -1158,12 +1143,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1386,12 +1365,6 @@ dependencies = [ "utilities", ] -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - [[package]] name = "slab" version = "0.4.7" @@ -1428,19 +1401,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared", - "precomputed-hash", -] - [[package]] name = "strsim" version = "0.10.0" @@ -1718,7 +1678,6 @@ dependencies = [ "num-bigint", "rustc-hash", "smallvec", - "string_cache", ] [[package]] diff --git a/compiler/ast/src/format.rs b/compiler/ast/src/format.rs index e0c869a9..e8c41131 100644 --- a/compiler/ast/src/format.rs +++ b/compiler/ast/src/format.rs @@ -431,7 +431,13 @@ impl Format for super::NumberLiteral { .field( "literal", // @Task also print span of literal - &AdHoc(|f, _| write!(f, "{}", self.literal.bare.color(color_palette::INVALID))), + &AdHoc(|f, _| { + write!( + f, + "{}", + self.literal.bare.to_str().color(color_palette::INVALID) + ) + }), ) .finish() } @@ -454,7 +460,7 @@ impl Format for super::TextLiteral { .field( "literal", // @Task also print span of literal - &AdHoc(|f, _| format_text_literal(&self.literal.bare, f)), + &AdHoc(|f, _| format_text_literal(self.literal.bare.to_str(), f)), ) .finish() } @@ -665,7 +671,7 @@ impl Format for Identifier { FormatStruct::new(f, indentation) .name("Identifier") .finish()?; - write!(f, " {}", self.as_str().color(color_palette::VERBATIM)) + write!(f, " {}", self.to_str().color(color_palette::VERBATIM)) } } @@ -674,7 +680,7 @@ impl fmt::Display for Identifier { write!( f, "{:width$}", - self.as_str(), + self.to_str(), width = f.width().unwrap_or_default() ) } @@ -724,14 +730,14 @@ impl Format for super::BareAttributeArgument { FormatStruct::new(f, indentation) .name("Number-Literal") .finish()?; - write!(f, " {}", number.color(color_palette::VERBATIM)) + write!(f, " {}", number.to_str().color(color_palette::VERBATIM)) } Self::TextLiteral(text) => { FormatStruct::new(f, indentation) .name("Text-Literal") .finish()?; write!(f, " ")?; - format_text_literal(text, f) + format_text_literal(text.to_str(), f) } Self::Path(path) => path.format(f, indentation), Self::Named(named) => named.format(f, indentation), diff --git a/compiler/ast/src/lib.rs b/compiler/ast/src/lib.rs index 7b5d4567..65830e4f 100644 --- a/compiler/ast/src/lib.rs +++ b/compiler/ast/src/lib.rs @@ -705,12 +705,12 @@ impl Path { } /// The path head if it is an identifier. - pub fn identifier_head(&self) -> Option<&Identifier> { + pub fn identifier_head(&self) -> Option { if self.hanger.is_some() { return None; } - Some(&self.segments[0]) + Some(self.segments[0]) } } @@ -791,37 +791,34 @@ impl TryFrom for BareHanger { } /// Either a [word](Word) or a symbol. -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub struct Identifier(Spanned); impl Identifier { /// Create a new identifier without checking if it is a valid word or symbol. + // @Task swap args pub const fn new_unchecked(atom: Atom, span: Span) -> Self { Self(Spanned::new(span, atom)) } - pub fn as_atom(&self) -> &Atom { - &self.0.bare - } - - pub fn into_atom(self) -> Atom { + pub fn bare(self) -> Atom { self.0.bare } - pub fn as_str(&self) -> &str { - self.as_atom() + pub fn to_str(self) -> &'static str { + self.0.bare.to_str() } - pub fn as_spanned_str(&self) -> Spanned<&str> { - self.0.as_ref().map(|atom| &**atom) + pub fn into_inner(self) -> Spanned { + self.0 } - pub fn is_symbol(&self) -> bool { + pub fn is_symbol(self) -> bool { // either all characters are symbols or none - token::is_symbol(self.as_atom().chars().next().unwrap()) + token::is_symbol(self.to_str().chars().next().unwrap()) } - pub fn is_word(&self) -> bool { + pub fn is_word(self) -> bool { // either all characters are letters or none !self.is_symbol() } @@ -849,12 +846,7 @@ impl TryFrom for Spanned { fn try_from(identifier: Identifier) -> Result { identifier .is_word() - .then(|| { - Self::new( - identifier.span(), - Word::new_unchecked(identifier.into_atom()), - ) - }) + .then(|| Self::new(identifier.span(), Word::new_unchecked(identifier.bare()))) .ok_or(()) } } @@ -867,7 +859,7 @@ impl Spanning for Identifier { impl PartialEq for Identifier { fn eq(&self, other: &Self) -> bool { - self.as_atom() == other.as_atom() + self.bare() == other.bare() } } @@ -875,7 +867,7 @@ impl Eq for Identifier {} impl Hash for Identifier { fn hash(&self, state: &mut H) { - self.as_atom().hash(state); + self.bare().hash(state); } } diff --git a/compiler/codegen_cranelift/Cargo.toml b/compiler/codegen_cranelift/Cargo.toml index 5f46b050..e2baecc8 100644 --- a/compiler/codegen_cranelift/Cargo.toml +++ b/compiler/codegen_cranelift/Cargo.toml @@ -13,3 +13,4 @@ cranelift-object = "0.93.1" diagnostics = { path = "../diagnostics" } hir = { path = "../hir" } session = { path = "../session" } +utilities = { path = "../utilities" } diff --git a/compiler/codegen_cranelift/src/lib.rs b/compiler/codegen_cranelift/src/lib.rs index ea2334b7..44b3aee9 100644 --- a/compiler/codegen_cranelift/src/lib.rs +++ b/compiler/codegen_cranelift/src/lib.rs @@ -15,8 +15,7 @@ use std::{ path::{Path, PathBuf}, process::Command, }; - -const PROGRAM_ENTRY_NAME: &str = "main"; +use utilities::PROGRAM_ENTRY; pub fn compile_and_link( options: Options, @@ -42,13 +41,20 @@ fn compile( _component_root: &hir::Declaration, session: &Session<'_>, ) -> PathBuf { + let program_entry_name = PROGRAM_ENTRY.to_str(); + let isa = cranelift_native::builder() .unwrap() .finish(Flags::new(settings::builder())) .unwrap(); let mut module = ObjectModule::new( - ObjectBuilder::new(isa, "main", cranelift_module::default_libcall_names()).unwrap(), + ObjectBuilder::new( + isa, + program_entry_name, + cranelift_module::default_libcall_names(), + ) + .unwrap(), ); let mut context = module.make_context(); @@ -81,13 +87,13 @@ fn compile( // println!("{}", context.func.display()); let function_id = module - .declare_function(PROGRAM_ENTRY_NAME, Linkage::Export, &context.func.signature) + .declare_function(program_entry_name, Linkage::Export, &context.func.signature) .unwrap(); module.define_function(function_id, &mut context).unwrap(); let product = module.finish(); - let name = session.component().name().as_str(); + let name = session.component().name().to_str(); let path = match session.root_package() { // @Task ensure that the build folder exists @@ -108,7 +114,7 @@ fn compile( // @Task support linkers other than clang // (e.g. "`cc`", `gcc` (requires us to manually link to `libc` I think)) fn link(path: &Path, session: &Session<'_>) -> Result { - let name = session.component().name().as_str(); + let name = session.component().name().to_str(); // @Task error handling! let output = Command::new("clang") diff --git a/compiler/codegen_llvm/Cargo.toml b/compiler/codegen_llvm/Cargo.toml index abce0558..dabf806d 100644 --- a/compiler/codegen_llvm/Cargo.toml +++ b/compiler/codegen_llvm/Cargo.toml @@ -9,7 +9,6 @@ publish = false diagnostics = { path = "../diagnostics" } hir = { path = "../hir" } hir_format = { path = "../hir_format" } -resolver = { path = "../resolver" } session = { path = "../session" } utilities = { path = "../utilities" } diff --git a/compiler/codegen_llvm/src/lib.rs b/compiler/codegen_llvm/src/lib.rs index 7a0b2626..c37ad2e3 100644 --- a/compiler/codegen_llvm/src/lib.rs +++ b/compiler/codegen_llvm/src/lib.rs @@ -13,7 +13,6 @@ use inkwell::{ types::{FunctionType, IntType}, values::{BasicValueEnum, FunctionValue, GlobalValue, IntValue, UnnamedAddress}, }; -use resolver::ProgramEntryExt; use session::{Session, OUTPUT_FOLDER_NAME}; use std::{ cell::RefCell, @@ -22,9 +21,7 @@ use std::{ path::{Path, PathBuf}, process::{Command, Stdio}, }; -use utilities::{FormatError, HashMap, Str}; - -const PROGRAM_ENTRY_NAME: &str = "main"; +use utilities::{FormatError, HashMap, Str, PROGRAM_ENTRY}; pub fn compile_and_link( options: Options, @@ -93,7 +90,7 @@ fn compile<'ctx>( // (e.g. "`cc`", `gcc` (requires the use of `llc`)) fn link(module: inkwell::module::Module<'_>, session: &Session<'_>) -> Result<(), LinkingError> { let buffer = module.write_bitcode_to_memory(); - let name = session.component().name().as_str(); + let name = session.component().name().to_str(); let output_file_path = match session.root_package() { // @Task ensure that the build folder exists @@ -189,8 +186,7 @@ impl<'a, 'ctx> Generator<'a, 'ctx> { let index = function.binder.index.declaration().unwrap(); // @Task somewhere store the info if we've already found the program entry or not - let is_program_entry = function.binder.as_str() - == Session::PROGRAM_ENTRY_IDENTIFIER + let is_program_entry = function.binder.bare() == PROGRAM_ENTRY && self.session.parent_of(index).unwrap() == self.session.component().root(); let classification = function.expression.as_ref().map(|expression| { @@ -220,7 +216,7 @@ impl<'a, 'ctx> Generator<'a, 'ctx> { // @Beacon @Task simplify Some((Thunk, _)) => { let name = if is_program_entry { - PROGRAM_ENTRY_NAME.into() + PROGRAM_ENTRY.to_str().into() } else { self.name(index) }; @@ -437,7 +433,7 @@ impl<'a, 'ctx> Generator<'a, 'ctx> { } Number(number) => Some(self.compile_number(number).into()), Text(_) => todo!("compiling text"), - Binding(binding) if self.session.specials().is(&binding.0, Type::Type) => None, + Binding(binding) if self.session.specials().is(binding.0, Type::Type) => None, Binding(binding) => { use hir::Index::*; @@ -575,7 +571,7 @@ impl ExpressionExt for hir::Expression { }, Application(_) | IntrinsicApplication(_) => Thunk, Number(_) | Text(_) => Constant, - Binding(binding) if session.specials().is(&binding.0, Type::Type) => Constant, + Binding(binding) if session.specials().is(binding.0, Type::Type) => Constant, // @Note we could make this more nuanced (prefering Constant if possible) Binding(_) => Thunk, Lambda(lambda) => Function(lambda), diff --git a/compiler/documenter/src/format.rs b/compiler/documenter/src/format.rs index 80a8163f..33cb76c1 100644 --- a/compiler/documenter/src/format.rs +++ b/compiler/documenter/src/format.rs @@ -6,8 +6,8 @@ use hir::DeclarationIndex; use hir_format::{ComponentExt, Display, SessionExt}; use joinery::JoinableIterator; use session::Session; -use std::{fmt::Write, iter::once}; -use utilities::displayed; +use std::fmt::Write; +use utilities::{displayed, Atom}; pub(super) fn format_expression( expression: &hir::Expression, @@ -216,16 +216,16 @@ impl<'a> Formatter<'a> { fn module_url_fragment(&self, index: DeclarationIndex) -> String { let component = self.session.component_of(index); + let mut segments = component.local_index_to_path_segments(index.local_unchecked()); + segments.push_front(component.name().into_inner()); + format!( "{}{}/index.html", self.url_prefix, - once(component.name().as_str().into()) - .chain( - component - .local_index_to_path_segments(index.local_unchecked()) - .into_iter() - .map(urlencoding::encode) - ) + segments + .into_iter() + .map(Atom::to_str) + .map(urlencoding::encode) .join_with("/") ) } @@ -233,7 +233,7 @@ impl<'a> Formatter<'a> { fn declaration_url_fragment(&self, index: DeclarationIndex) -> String { use hir::EntityKind::*; - let binder = self.session[index].source.as_str(); + let binder = self.session[index].source.to_str(); match self.session[index].kind { Use { .. } => "#".to_string(), // @Task diff --git a/compiler/documenter/src/lib.rs b/compiler/documenter/src/lib.rs index eb436e36..b0caffa0 100644 --- a/compiler/documenter/src/lib.rs +++ b/compiler/documenter/src/lib.rs @@ -20,7 +20,6 @@ use session::{ Context, Session, OUTPUT_FOLDER_NAME, }; use std::{ - collections::BTreeSet, default::default, fs, io::BufWriter, @@ -28,6 +27,7 @@ use std::{ }; use text_processor::TextProcessor; use token::Word; +use utilities::Atom; mod fonts; mod format; @@ -79,7 +79,7 @@ pub fn document_component( pub fn index_page(context: &Context) -> PathBuf { let mut path = Documenter::folder(context); if context.root_package().is_none() { - path.push(context.root_component().name.as_str()); + path.push(context.root_component().name.to_str()); } path.push("index.html"); path @@ -125,11 +125,11 @@ impl<'a, 'scope> Documenter<'a, 'scope> { let mut path = package.folder().to_path_buf(); path.push(OUTPUT_FOLDER_NAME); path.push(DOC_FOLDER_NAME); - path.push(package.name.as_str()); + path.push(package.name.to_str()); path } None => { - Path::new(context.root_component().name.as_str()).with_extension(DOC_FOLDER_NAME) + Path::new(context.root_component().name.to_str()).with_extension(DOC_FOLDER_NAME) } } } @@ -183,7 +183,7 @@ impl<'a, 'scope> Documenter<'a, 'scope> { fs::write(&page.path, &page.content)?; } - let component_name = self.session.component().name().as_str(); + let component_name = self.session.component().name().to_str(); let component_path = self.path.join(component_name); if !component_path.exists() { @@ -335,7 +335,7 @@ impl<'a, 'scope> Documenter<'a, 'scope> { hir::BareDeclaration::Function(function) => { subsections.functions.0.push(subsections::Function { attributes: &declaration.attributes, - binder: function.binder.as_str(), + binder: function.binder.to_str(), type_: format::format_expression( &function.type_annotation, url_prefix, @@ -352,7 +352,7 @@ impl<'a, 'scope> Documenter<'a, 'scope> { formatted_constructors.push(subsections::Constructor { attributes: &declaration.attributes, - binder: constructor.binder.as_str(), + binder: constructor.binder.to_str(), type_: format::format_expression( &constructor.type_annotation, url_prefix, @@ -366,7 +366,7 @@ impl<'a, 'scope> Documenter<'a, 'scope> { // @Task write a custom formatter for this which prints links to the documentation // of the specific attributes attributes: &declaration.attributes, - binder: type_.binder.as_str(), + binder: type_.binder.to_str(), type_: format::format_expression( &type_.type_annotation, url_prefix, @@ -378,7 +378,7 @@ impl<'a, 'scope> Documenter<'a, 'scope> { hir::BareDeclaration::Module(module) => { subsections.modules.0.push(subsections::Module { attributes: &declaration.attributes, - binder: module.binder.as_str(), + binder: module.binder.to_str(), }); } // @Task re-exports, only public//(public topmost) for --doc-priv-decls??) ones! @@ -400,7 +400,7 @@ impl<'a, 'scope> Documenter<'a, 'scope> { &subsections, url_prefix, default(), - BTreeSet::from([&self.session.root_component().name]), + vec![self.session.root_component().name], )); // main content @@ -444,7 +444,7 @@ impl<'a, 'scope> Documenter<'a, 'scope> { &subsections, url_prefix, default(), - BTreeSet::from([&self.session.root_component().name]), + vec![self.session.root_component().name], )); // main content @@ -490,7 +490,7 @@ impl<'a, 'scope> Documenter<'a, 'scope> { &default(), url_prefix, default(), - BTreeSet::from([&self.session.root_component().name]), + vec![self.session.root_component().name], )); // main content @@ -516,7 +516,7 @@ impl<'a, 'scope> Documenter<'a, 'scope> { for component in package.components.keys() { list.add_child(Element::new("li").child(Element::anchor( format!("{url_prefix}{component}/index.html"), - component.as_str(), + component.to_str(), ))); } @@ -533,7 +533,7 @@ impl<'a, 'scope> Documenter<'a, 'scope> { content: render_page( head( // @Temporary hack - &Word::new_unchecked("__".into()), + Word::new_unchecked(Atom::underscore), url_prefix, format!("Package {name}").into(), ), @@ -546,9 +546,9 @@ impl<'a, 'scope> Documenter<'a, 'scope> { let index = module.binder.local_declaration_index(self.session).unwrap(); let component_name = self.session.component().name(); - let mut path_segments = self.session.component().local_index_to_path_segments(index); - path_segments.push_front(component_name.as_str()); - let page_depth = path_segments.len(); + let mut segments = self.session.component().local_index_to_path_segments(index); + segments.push_front(component_name.into_inner()); + let page_depth = segments.len(); let url_prefix = format!("./{}", "../".repeat(page_depth)); let mut body = Element::new("body").child(ledge( @@ -563,8 +563,13 @@ impl<'a, 'scope> Documenter<'a, 'scope> { container.add_child(sidebar( &subsections, &url_prefix, - self.session.component().dependencies().keys().collect(), - BTreeSet::from([&self.session.root_component().name]), + self.session + .component() + .dependencies() + .keys() + .copied() + .collect(), + vec![self.session.root_component().name], )); // main content @@ -582,12 +587,12 @@ impl<'a, 'scope> Documenter<'a, 'scope> { heading.add_child(" "); - for (position, &path_segment) in path_segments.iter().enumerate() { + for (position, path_segment) in segments.iter().enumerate() { let is_last_segment = position + 1 == page_depth; heading.add_child(Element::anchor( format!("{}index.html", "../".repeat(page_depth - 1 - position)), - path_segment, + path_segment.to_str(), )); if !is_last_segment { @@ -620,12 +625,12 @@ impl<'a, 'scope> Documenter<'a, 'scope> { .component() .local_index_with_root_to_extern_path(index, component_name.to_string()); - let mut path = self.path.join(component_name.as_str()); - path.extend(path_segments.into_iter().skip(1)); - path.push("index.html"); - Page { - path, + path: segments + .into_iter() + .map(Atom::to_str) + .chain(Some("index.html")) + .collect(), content: render_page(head(component_name, &url_prefix, title.into()), body), } } @@ -634,7 +639,7 @@ impl<'a, 'scope> Documenter<'a, 'scope> { fn ledge<'a>( url_prefix: &'a str, package: Option<&'a Package>, - component: Option<&'a Word>, + component: Option, ) -> Element<'a> { let mut context = Element::div("name"); @@ -643,7 +648,7 @@ fn ledge<'a>( context.add_child( Element::new("a") .attribute("href", format!("{url_prefix}index.html")) - .child(Element::span("package").child(package.name.as_str())) + .child(Element::span("package").child(package.name.to_str())) .child(" ") .child(&package.version.0), ); @@ -658,7 +663,7 @@ fn ledge<'a>( context.add_child( Element::anchor( format!("{url_prefix}{component}/index.html"), - component.as_str(), + component.to_str(), ) .class("component"), ); @@ -700,7 +705,7 @@ fn render_page(head: Element<'_>, body: Element<'_>) -> String { } // @Task remove `component` param -fn head<'a>(component: &Word, url_prefix: &str, title: Node<'a>) -> Element<'a> { +fn head<'a>(component: Word, url_prefix: &str, title: Node<'a>) -> Element<'a> { Element::new("head") .child(VoidElement::new("meta").attribute("charset", "utf-8")) .child( @@ -739,8 +744,8 @@ fn head<'a>(component: &Word, url_prefix: &str, title: Node<'a>) -> Element<'a> fn sidebar<'a>( subsections: &subsections::Subsections<'a>, url_prefix: &str, - dependencies: BTreeSet<&'a Word>, - targets: BTreeSet<&'a Word>, + dependencies: Vec, + root_components: Vec, ) -> Element<'a> { let mut sidebar = Element::div("sidebar"); @@ -755,10 +760,10 @@ fn sidebar<'a>( let mut list = Element::new("ul"); for dependency in dependencies { - // @Bug this is erroneous for components that share the same name + // @Bug this is incorrect for components that share the same name let anchor = Element::anchor( format!("{url_prefix}{dependency}/index.html"), - Node::from(dependency.as_str()), + Node::from(dependency.to_str()), ); list.add_child(Element::new("li").child(anchor)); @@ -770,15 +775,15 @@ fn sidebar<'a>( { sidebar.add_child( Element::div("title") - .child("Targets") - .attribute("title", "Target Components"), + .child("Roots") + .attribute("title", "Root Components"), ); let mut list = Element::new("ul"); - for component in targets { + for component in root_components { let anchor = Element::anchor( format!("{url_prefix}{component}/index.html"), - Node::from(component.as_str()), + Node::from(component.to_str()), ); list.add_child(Element::new("li").child(anchor)); diff --git a/compiler/driver/src/cli.rs b/compiler/driver/src/cli.rs index 08c79328..5f134782 100644 --- a/compiler/driver/src/cli.rs +++ b/compiler/driver/src/cli.rs @@ -322,7 +322,7 @@ pub(crate) fn arguments() -> Result<(Command, GlobalOptions)> { mode: match command { subcommand::INITIALIZE => PackageCreationMode::Initialize, subcommand::NEW => PackageCreationMode::New { - package_name: matches.get_one(argument::NAME).cloned().unwrap(), + package_name: matches.get_one(argument::NAME).copied().unwrap(), }, _ => unreachable!(), }, @@ -486,11 +486,11 @@ impl DeserializeExt for ComponentFilter { let mut filter = Self::default(); if let Some(components) = matches.get_many(option::COMPONENT) { - filter.names.extend(components.into_iter().cloned()); + filter.names.extend(components); } if let Some(types) = matches.get_many::(option::COMPONENT_TYPE) { - filter.types.extend(types.into_iter().copied()); + filter.types.extend(types); } filter diff --git a/compiler/driver/src/create.rs b/compiler/driver/src/create.rs index 20da977d..58d44885 100644 --- a/compiler/driver/src/create.rs +++ b/compiler/driver/src/create.rs @@ -4,7 +4,7 @@ use diagnostics::{error::Result, Diagnostic, Reporter}; use session::package::ManifestPath; use std::{fs, io, path::PathBuf}; use token::Word; -use utilities::{FormatError, FILE_EXTENSION}; +use utilities::{Atom, FormatError, FILE_EXTENSION}; const SOURCE_FOLDER_NAME: &str = "source"; const LIBRARY_FILE_STEM: &str = "library"; @@ -15,7 +15,7 @@ pub(crate) fn create_package( options: &PackageCreationOptions, reporter: &Reporter, ) -> Result { - if let Err(error) = create(name.clone(), options) { + if let Err(error) = create(name, options) { return Err(Diagnostic::error() .message(format!("could not create package ‘{name}’")) .with(|it| match &error.path { @@ -32,7 +32,7 @@ pub(crate) fn create_package( fn create(name: Word, options: &PackageCreationOptions) -> Result<(), Error> { let current_path = std::env::current_dir()?; - let package_path = current_path.join(name.as_str()); + let package_path = current_path.join(name.to_str()); fs::create_dir(&package_path).with_path(package_path.clone())?; let source_folder_path = package_path.join(SOURCE_FOLDER_NAME); @@ -41,7 +41,7 @@ fn create(name: Word, options: &PackageCreationOptions) -> Result<(), Error> { { let path = package_path.join(ManifestPath::FILE_NAME); let package_manifest = io::BufWriter::new(fs::File::create(&path).with_path(path)?); - create_package_manifest(&name, options, package_manifest)?; + create_package_manifest(name, options, package_manifest)?; } { @@ -74,14 +74,14 @@ pub(crate) struct PackageCreationOptions { } fn create_package_manifest( - name: &Word, + name: Word, options: &PackageCreationOptions, mut sink: impl io::Write, ) -> io::Result<()> { { write!(sink, "name: ")?; - if let "false" | "true" = name.as_str() { + if let Atom::false_ | Atom::true_ = name.into_inner() { write!(sink, r#""{name}""#)?; } else { write!(sink, "{name}")?; @@ -113,7 +113,7 @@ fn create_package_manifest( } if options.executable { - let executable_name = if name.as_str() != "main" { + let executable_name = if name.into_inner() != Atom::main { "main" } else { "main_" diff --git a/compiler/driver/src/lib.rs b/compiler/driver/src/lib.rs index 95a4c743..8adf3733 100644 --- a/compiler/driver/src/lib.rs +++ b/compiler/driver/src/lib.rs @@ -30,7 +30,7 @@ use std::{ Arc, RwLock, }, }; -use utilities::{displayed, ComponentIndex, FormatError}; +use utilities::{displayed, ComponentIndex, FormatError, PROGRAM_ENTRY}; mod cli; mod create; @@ -377,9 +377,8 @@ fn build_unit( return Err(Diagnostic::error() .code(ErrorCode::E050) .message(format!( - "the component ‘{}’ does not contain a ‘{}’ function in its root module", - unit.name, - Session::PROGRAM_ENTRY_IDENTIFIER, + "the component ‘{}’ does not contain a ‘{PROGRAM_ENTRY}’ function in its root module", + unit.name )) .unlabeled_span(&session.shared_map()[file]) .report(session.reporter())); diff --git a/compiler/hir/src/identifier.rs b/compiler/hir/src/identifier.rs index 0bdba27a..d4b96be5 100644 --- a/compiler/hir/src/identifier.rs +++ b/compiler/hir/src/identifier.rs @@ -1,10 +1,10 @@ use super::{Binding, Item}; use span::{Span, Spanning}; use std::{default::default, fmt}; -use utilities::ComponentIndex; +use utilities::{Atom, ComponentIndex}; /// A name-resolved identifier. -#[derive(Clone, Eq)] +#[derive(Clone, Copy, Eq)] pub struct Identifier { /// Source at the use-site/call-site or def-site if definition. pub source: ast::Identifier, @@ -19,6 +19,7 @@ impl Identifier { } } + // @Task make this test-only & maybe take an Atom pub fn parameter(name: &str) -> Self { Identifier::new( Index::DeBruijnParameter, @@ -26,20 +27,24 @@ impl Identifier { ) } - pub fn as_str(&self) -> &str { - self.source.as_str() + pub fn to_str(self) -> &'static str { + self.source.to_str() + } + + pub fn bare(self) -> Atom { + self.source.bare() } - pub fn into_item>(self) -> Item { + pub fn to_item>(self) -> Item { Item::new(default(), self.span(), Binding(self).into()) } // @Note bad name - pub fn as_innermost(&self) -> Self { - Self::new(DeBruijnIndex(0), self.source.clone()) + pub fn to_innermost(self) -> Self { + Self::new(DeBruijnIndex(0), self.source) } - pub fn is_innermost(&self) -> bool { + pub fn is_innermost(self) -> bool { self.index == DeBruijnIndex(0).into() } @@ -57,11 +62,11 @@ impl Identifier { } } - pub fn declaration_index(&self) -> Option { + pub fn declaration_index(self) -> Option { self.index.declaration() } - pub fn de_bruijn_index(&self) -> Option { + pub fn de_bruijn_index(self) -> Option { self.index.de_bruijn() } } diff --git a/compiler/hir/src/special.rs b/compiler/hir/src/special.rs index 077d0646..4757badd 100644 --- a/compiler/hir/src/special.rs +++ b/compiler/hir/src/special.rs @@ -3,7 +3,7 @@ use diagnostics::{error::Result, Diagnostic, ErrorCode, Substitution}; use num_traits::{CheckedDiv, CheckedSub}; use span::{Span, Spanning}; use std::fmt; -use utilities::HashMap; +use utilities::{Atom, HashMap}; /// A special binding. #[derive(PartialEq, Eq, Hash, Clone, Copy)] @@ -14,49 +14,49 @@ pub enum Binding { } impl Binding { - pub fn parse(namespace: Option<&str>, name: &str) -> Option { + pub fn parse(namespace: Option, name: Atom) -> Option { Some(match (namespace, name) { - (None, "Type") => Type::Type.into(), - (None, "Unit") => Type::Unit.into(), - (None, "Bool") => Type::Bool.into(), - (None, "Text") => Type::Text.into(), - (None, "Option") => Type::Option.into(), - (None, "List") => SequentialType::List.into(), - (None, "Vector") => SequentialType::Vector.into(), - (None, "Tuple") => SequentialType::Tuple.into(), - (None, "Nat") => NumericType::Nat.into(), - (None, "Nat32") => NumericType::Nat32.into(), - (None, "Nat64") => NumericType::Nat64.into(), - (None, "Int") => NumericType::Int.into(), - (None, "Int32") => NumericType::Int32.into(), - (None, "Int64") => NumericType::Int64.into(), - (None, "IO") => Type::IO.into(), - (Some("Unit"), "unit") => Constructor::UnitUnit.into(), - (Some("Bool"), "false") => Constructor::BoolFalse.into(), - (Some("Bool"), "true") => Constructor::BoolTrue.into(), - (Some("Option"), "none") => Constructor::OptionNone.into(), - (Some("Option"), "some") => Constructor::OptionSome.into(), - (Some("List"), "empty") => Constructor::ListEmpty.into(), - (Some("List"), "prepend") => Constructor::ListPrepend.into(), - (Some("Vector"), "empty") => Constructor::VectorEmpty.into(), - (Some("Vector"), "prepend") => Constructor::VectorPrepend.into(), - (Some("Tuple"), "empty") => Constructor::TupleEmpty.into(), - (Some("Tuple"), "prepend") => Constructor::TuplePrepend.into(), - (Some("nat"), "add") => Function::NatAdd.into(), - (Some("nat"), "subtract") => Function::NatSubtract.into(), - (Some("nat"), "unchecked-subtract") => Function::NatUncheckedSubtract.into(), - (Some("nat"), "multiply") => Function::NatMultiply.into(), - (Some("nat"), "divide") => Function::NatDivide.into(), - (Some("nat"), "equal") => Function::NatEqual.into(), - (Some("nat"), "less") => Function::NatLess.into(), - (Some("nat"), "less-equal") => Function::NatLessEqual.into(), - (Some("nat"), "greater") => Function::NatGreater.into(), - (Some("nat"), "greater-equal") => Function::NatGreaterEqual.into(), - (Some("nat"), "display") => Function::NatDisplay.into(), - (Some("text"), "concat") => Function::TextConcat.into(), - (Some("nat32"), "add") => Function::Nat32Add.into(), - (Some("nat32"), "successor") => Function::Nat32Successor.into(), - (Some("io"), "print") => Function::IoPrint.into(), + (None, Atom::Type) => Type::Type.into(), + (None, Atom::Unit) => Type::Unit.into(), + (None, Atom::Bool) => Type::Bool.into(), + (None, Atom::Text) => Type::Text.into(), + (None, Atom::Option) => Type::Option.into(), + (None, Atom::List) => SequentialType::List.into(), + (None, Atom::Vector) => SequentialType::Vector.into(), + (None, Atom::Tuple) => SequentialType::Tuple.into(), + (None, Atom::Nat) => NumericType::Nat.into(), + (None, Atom::Nat32) => NumericType::Nat32.into(), + (None, Atom::Nat64) => NumericType::Nat64.into(), + (None, Atom::Int) => NumericType::Int.into(), + (None, Atom::Int32) => NumericType::Int32.into(), + (None, Atom::Int64) => NumericType::Int64.into(), + (None, Atom::IO) => Type::IO.into(), + (Some(Atom::Unit), Atom::unit) => Constructor::UnitUnit.into(), + (Some(Atom::Bool), Atom::false_) => Constructor::BoolFalse.into(), + (Some(Atom::Bool), Atom::true_) => Constructor::BoolTrue.into(), + (Some(Atom::Option), Atom::none) => Constructor::OptionNone.into(), + (Some(Atom::Option), Atom::some) => Constructor::OptionSome.into(), + (Some(Atom::List), Atom::empty) => Constructor::ListEmpty.into(), + (Some(Atom::List), Atom::prepend) => Constructor::ListPrepend.into(), + (Some(Atom::Vector), Atom::empty) => Constructor::VectorEmpty.into(), + (Some(Atom::Vector), Atom::prepend) => Constructor::VectorPrepend.into(), + (Some(Atom::Tuple), Atom::empty) => Constructor::TupleEmpty.into(), + (Some(Atom::Tuple), Atom::prepend) => Constructor::TuplePrepend.into(), + (Some(Atom::nat), Atom::add) => Function::NatAdd.into(), + (Some(Atom::nat), Atom::subtract) => Function::NatSubtract.into(), + (Some(Atom::nat), Atom::unchecked_subtract) => Function::NatUncheckedSubtract.into(), + (Some(Atom::nat), Atom::multiply) => Function::NatMultiply.into(), + (Some(Atom::nat), Atom::divide) => Function::NatDivide.into(), + (Some(Atom::nat), Atom::equal) => Function::NatEqual.into(), + (Some(Atom::nat), Atom::less) => Function::NatLess.into(), + (Some(Atom::nat), Atom::less_equal) => Function::NatLessEqual.into(), + (Some(Atom::nat), Atom::greater) => Function::NatGreater.into(), + (Some(Atom::nat), Atom::greater_equal) => Function::NatGreaterEqual.into(), + (Some(Atom::nat), Atom::display) => Function::NatDisplay.into(), + (Some(Atom::text), Atom::concat) => Function::TextConcat.into(), + (Some(Atom::nat32), Atom::add) => Function::Nat32Add.into(), + (Some(Atom::nat32), Atom::successor) => Function::Nat32Successor.into(), + (Some(Atom::io), Atom::print) => Function::IoPrint.into(), _ => return None, }) } @@ -494,7 +494,7 @@ impl Bindings { let special = special.into(); self.get(special) - .map(|identifier| identifier.clone().into_item()) + .map(Identifier::to_item) .ok_or_else(|| missing_binding_error(special, user)) } @@ -507,7 +507,7 @@ impl Bindings { attribute: Span, ) -> Result { let special = style - .as_name(&binder) + .as_name(binder) .and_then(|(namespace, name)| Binding::parse(namespace, name)); let Some(special) = special.filter(|special| special.kind() == kind) else { return Err(Diagnostic::error() @@ -517,7 +517,7 @@ impl Bindings { }) .message(format!( "‘{}’ is not {} {kind} binding", - style.as_path(&binder), + style.as_path(binder), kind.article() )) .unlabeled_span(match style { @@ -578,16 +578,16 @@ impl Bindings { self.from.insert(special, binder); } - pub fn get(&self, key: K) -> Option<::Output<'_>> { + pub fn get(&self, key: K) -> Option<::Output> { key.index(self) } - pub fn is(&self, binder: &Identifier, special: impl Into) -> bool { + pub fn is(&self, binder: Identifier, special: impl Into) -> bool { self.get(special).map_or(false, |special| special == binder) } } -pub enum DefinitionStyle<'a, T = &'a str> { +pub enum DefinitionStyle<'a, T = Atom> { /// The name of the special binding is implied by the binder & the namespace of the declaration (e.g. in `@known`). Implicit { namespace: Option }, /// The name of the special binding is given explicitly (e.g. in `@(intrinsic qualified.name)`). @@ -595,7 +595,7 @@ pub enum DefinitionStyle<'a, T = &'a str> { } impl<'a> DefinitionStyle<'a> { - fn as_path(&self, binder: &Identifier) -> String { + fn as_path(&self, binder: Identifier) -> String { match self { Self::Implicit { namespace } => namespace.map_or(binder.to_string(), |namespace| { format!("{namespace}.{binder}") @@ -604,17 +604,17 @@ impl<'a> DefinitionStyle<'a> { } } - fn as_name(&'a self, binder: &'a Identifier) -> Option<(Option<&'a str>, &'a str)> { + fn as_name(&'a self, binder: Identifier) -> Option<(Option, Atom)> { match self { - &Self::Implicit { namespace } => Some((namespace, binder.as_str())), + &Self::Implicit { namespace } => Some((namespace, binder.bare())), Self::Explicit { name } => { if name.hanger.is_some() { return None; } Some(match &*name.segments { - [namespace, name] => (Some(namespace.as_str()), name.as_str()), - [name] => (None, name.as_str()), + [namespace, name] => (Some(namespace.bare()), name.bare()), + [name] => (None, name.bare()), _ => return None, }) } @@ -623,23 +623,23 @@ impl<'a> DefinitionStyle<'a> { } pub trait Key: Sized { - type Output<'a>; + type Output; - fn index(self, bindings: &Bindings) -> Option>; + fn index(self, bindings: &Bindings) -> Option; } impl> Key for B { - type Output<'a> = &'a Identifier; + type Output = Identifier; - fn index(self, bindings: &Bindings) -> Option> { - bindings.from.get(&self.into()) + fn index(self, bindings: &Bindings) -> Option { + bindings.from.get(&self.into()).copied() } } impl Key for DeclarationIndex { - type Output<'a> = Binding; + type Output = Binding; - fn index(self, bindings: &Bindings) -> Option> { + fn index(self, bindings: &Bindings) -> Option { bindings.to.get(&self).copied() } } diff --git a/compiler/hir_format/Cargo.toml b/compiler/hir_format/Cargo.toml index ba844189..21cda4f5 100644 --- a/compiler/hir_format/Cargo.toml +++ b/compiler/hir_format/Cargo.toml @@ -12,8 +12,8 @@ hir = { path = "../hir" } joinery = "3.1.0" session = { path = "../session" } token = { path = "../token" } +utilities = { path = "../utilities" } [dev-dependencies] session = { path = "../session", features = ["test"] } span = { path = "../span" } -utilities = { path = "../utilities" } diff --git a/compiler/hir_format/src/lib.rs b/compiler/hir_format/src/lib.rs index fb748a1b..1ab3c56a 100644 --- a/compiler/hir_format/src/lib.rs +++ b/compiler/hir_format/src/lib.rs @@ -9,6 +9,7 @@ use session::{ }; use std::{collections::VecDeque, fmt}; use token::INDENTATION; +use utilities::Atom; #[cfg(test)] mod test; @@ -221,7 +222,7 @@ fn write_lower_expression( match &expression.bare { Number(literal) => write!(f, "{literal}"), Text(literal) => write!(f, "{literal}"), - Binding(binding) => write!(f, "{}", session.binder_to_path(&binding.0)), + Binding(binding) => write!(f, "{}", session.binder_to_path(binding.0)), // @Beacon @Temporary @Task just write out the path Projection(_projection) => write!(f, "?(projection)"), IO(io) => { @@ -257,7 +258,7 @@ impl Display for hir::Pattern { match &self.bare { Number(number) => write!(f, "{number}"), Text(text) => write!(f, "{text}"), - Binding(binding) => write!(f, "{}", session.binder_to_path(&binding.0)), + Binding(binding) => write!(f, "{}", session.binder_to_path(binding.0)), Binder(binder) => write!(f, "\\{}", binder.0), Application(application) => { write!(f, "(")?; @@ -399,7 +400,7 @@ pub trait SessionExt { /// * `topmost.gamma. String; + fn binder_to_path(&self, binder: hir::Identifier) -> String; /// The textual representation of the path of the given binding relative to the root of the current component. /// @@ -421,7 +422,7 @@ pub trait SessionExt { } impl SessionExt for Session<'_> { - fn binder_to_path(&self, binder: &hir::Identifier) -> String { + fn binder_to_path(&self, binder: hir::Identifier) -> String { use hir::Index::*; match binder.index { @@ -467,7 +468,7 @@ pub trait ComponentExt { ) -> String; // @Task add documentation - fn local_index_to_path_segments(&self, index: hir::LocalDeclarationIndex) -> VecDeque<&str>; + fn local_index_to_path_segments(&self, index: hir::LocalDeclarationIndex) -> VecDeque; } impl ComponentExt for Component { @@ -510,7 +511,7 @@ impl ComponentExt for Component { parent_path.push(' '); } - parent_path += entity.source.as_str(); + parent_path += entity.source.to_str(); parent_path } else { root @@ -520,11 +521,11 @@ impl ComponentExt for Component { fn local_index_to_path_segments( &self, mut index: hir::LocalDeclarationIndex, - ) -> VecDeque<&str> { + ) -> VecDeque { let mut segments = VecDeque::new(); while let Some(parent) = self[index].parent { - segments.push_front(self[index].source.as_str()); + segments.push_front(self[index].source.bare()); index = parent; } diff --git a/compiler/hir_format/src/test.rs b/compiler/hir_format/src/test.rs index 3cf91aa9..3a195dd5 100644 --- a/compiler/hir_format/src/test.rs +++ b/compiler/hir_format/src/test.rs @@ -49,7 +49,7 @@ impl ComponentExt for Component { ) -> Identifier { let identifier = ast::Identifier::new_unchecked(name.into(), default()); let entity = Entity { - source: identifier.clone(), + source: identifier, parent: Some(parent), exposure: Exposure::Unrestricted, attributes: default(), @@ -65,13 +65,13 @@ fn pi_type_application_argument() { let mut component = Component::mock(); let array = component .add("Array", EntityKind::untyped_data_type()) - .into_item(); + .to_item(); let int = component .add("Int", EntityKind::untyped_data_type()) - .into_item(); + .to_item(); let type_ = component .add("Type", EntityKind::untyped_data_type()) - .into_item(); + .to_item(); let mut context = Context::mock(); let session = Session::new(component, &mut context); @@ -114,19 +114,19 @@ fn pi_type_named_parameter() { &Expression::bare( hir::PiType { explicitness: Explicit, - binder: Some(alpha.clone()), + binder: Some(alpha), domain: Expression::bare( hir::Application { - callee: array.into_item(), - argument: int.into_item(), + callee: array.to_item(), + argument: int.to_item(), explicitness: Explicit, } .into(), ), codomain: Expression::bare( hir::Application { - callee: container.into_item(), - argument: alpha.into_item(), + callee: container.to_item(), + argument: alpha.to_item(), explicitness: Explicit, } .into(), @@ -143,7 +143,7 @@ fn pi_type_implicit_parameter() { let mut component = Component::mock(); let type_ = component .add("Type", EntityKind::untyped_data_type()) - .into_item(); + .to_item(); let mut context = Context::mock(); let session = Session::new(component, &mut context); @@ -169,7 +169,7 @@ fn pi_type_higher_order_argument() { let mut component = Component::mock(); let int = component .add("Int", EntityKind::untyped_data_type()) - .into_item(); + .to_item(); let mut context = Context::mock(); let session = Session::new(component, &mut context); @@ -203,13 +203,13 @@ fn pi_type_two_curried_arguments() { let mut component = Component::mock(); let int = component .add("Int", EntityKind::untyped_data_type()) - .into_item(); + .to_item(); let text = component .add("Text", EntityKind::untyped_data_type()) - .into_item(); + .to_item(); let type_ = component .add("Type", EntityKind::untyped_data_type()) - .into_item(); + .to_item(); let mut context = Context::mock(); let session = Session::new(component, &mut context); @@ -243,7 +243,7 @@ fn pi_type_lambda_domain() { let mut component = Component::mock(); let type_ = component .add("Type", EntityKind::untyped_data_type()) - .into_item(); + .to_item(); let x = Identifier::parameter("x"); let mut context = Context::mock(); @@ -257,10 +257,10 @@ fn pi_type_lambda_domain() { binder: None, domain: Expression::bare( hir::Lambda { - binder: x.clone(), + binder: x, domain: None, codomain: None, - body: x.into_item(), + body: x.to_item(), explicitness: Explicit, } .into(), @@ -279,7 +279,7 @@ fn application_three_curried_arguments() { let beta = component.add("beta", EntityKind::UntypedFunction); let type_ = component .add("Type", EntityKind::untyped_data_type()) - .into_item(); + .to_item(); let mut context = Context::mock(); let session = Session::new(component, &mut context); @@ -292,15 +292,15 @@ fn application_three_curried_arguments() { hir::Application { callee: Expression::bare( hir::Application { - callee: Identifier::parameter("alpha").into_item(), - argument: beta.into_item(), + callee: Identifier::parameter("alpha").to_item(), + argument: beta.to_item(), explicitness: Explicit, } .into(), ), argument: Expression::bare( hir::Application { - callee: Identifier::parameter("gamma").into_item(), + callee: Identifier::parameter("gamma").to_item(), argument: type_, explicitness: Explicit, } @@ -334,14 +334,14 @@ fn application_lambda_last_argument() { r"topmost.take (\it => it)", &Expression::bare( hir::Application { - callee: take.into_item(), + callee: take.to_item(), argument: Expression::bare( hir::Lambda { - binder: it.clone(), + binder: it, domain: None, codomain: None, // technically not correct - body: it.into_item(), + body: it.to_item(), explicitness: Explicit, } .into(), @@ -370,14 +370,14 @@ fn application_lambda_argument() { hir::Application { callee: Expression::bare( hir::Application { - callee: take.into_item(), + callee: take.to_item(), argument: Expression::bare( hir::Lambda { - binder: it.clone(), + binder: it, domain: None, codomain: None, // technically not correct - body: it.into_item(), + body: it.to_item(), explicitness: Explicit, } .into(), @@ -401,7 +401,7 @@ fn application_implicit_argument() { let identity = component.add("identity", EntityKind::UntypedFunction); let type_ = component .add("Type", EntityKind::untyped_data_type()) - .into_item(); + .to_item(); let mut context = Context::mock(); let session = Session::new(component, &mut context); @@ -410,7 +410,7 @@ fn application_implicit_argument() { r"topmost.identity 'topmost.Type", &Expression::bare( hir::Application { - callee: identity.into_item(), + callee: identity.to_item(), argument: type_, explicitness: Implicit, } @@ -433,11 +433,11 @@ fn application_complex_implicit_argument() { r"topmost.identity '(prepare topmost.Text)", &Expression::bare( hir::Application { - callee: identity.into_item(), + callee: identity.to_item(), argument: Expression::bare( hir::Application { - callee: Identifier::parameter("prepare").into_item(), - argument: text.into_item(), + callee: Identifier::parameter("prepare").to_item(), + argument: text.to_item(), explicitness: Explicit, } .into(), @@ -466,7 +466,7 @@ fn application_intrinsic_application_callee() { } .into(), ), - argument: Identifier::parameter("omicron").into_item(), + argument: Identifier::parameter("omicron").to_item(), explicitness: Explicit, } .into(), @@ -489,7 +489,7 @@ fn lambda_body_type_annotation() { hir::Lambda { binder: Identifier::parameter("input"), domain: None, - codomain: Some(output.into_item()), + codomain: Some(output.to_item()), body: Expression::bare(Number::Nat(0u8.into()).into()), explicitness: Explicit, } @@ -506,7 +506,7 @@ fn lambda_parameter_type_annotation_body_type_annotation() { let output = component.add("Output", EntityKind::untyped_data_type()); let type_ = component .add("Type", EntityKind::untyped_data_type()) - .into_item(); + .to_item(); let mut context = Context::mock(); let session = Session::new(component, &mut context); @@ -516,8 +516,8 @@ fn lambda_parameter_type_annotation_body_type_annotation() { &Expression::bare( hir::Lambda { binder: Identifier::parameter("input"), - domain: Some(input.into_item()), - codomain: Some(output.into_item()), + domain: Some(input.to_item()), + codomain: Some(output.to_item()), body: type_, explicitness: Explicit, } @@ -532,7 +532,7 @@ fn lambda_implicit_parameter() { let mut component = Component::mock(); let type_ = component .add("Type", EntityKind::untyped_data_type()) - .into_item(); + .to_item(); let mut context = Context::mock(); let session = Session::new(component, &mut context); @@ -569,10 +569,10 @@ fn lambda_implicit_unannotated_parameter() { codomain: None, body: Expression::bare( hir::Lambda { - binder: a.clone(), + binder: a, domain: None, codomain: None, - body: a.into_item(), + body: a.to_item(), explicitness: Explicit, } .into(), @@ -591,7 +591,7 @@ fn lambda_pi_type_body() { let mut component = Component::mock(); let type_ = component .add("Type", EntityKind::untyped_data_type()) - .into_item(); + .to_item(); let x = Identifier::parameter("x"); let mut context = Context::mock(); @@ -601,14 +601,14 @@ fn lambda_pi_type_body() { r"\x => x -> topmost.Type", &Expression::bare( hir::Lambda { - binder: x.clone(), + binder: x, domain: None, codomain: None, body: Expression::bare( hir::PiType { explicitness: Explicit, binder: None, - domain: x.into_item(), + domain: x.to_item(), codomain: type_, } .into(), @@ -654,7 +654,7 @@ fn intrinsic_application_two_arguments() { "add (add 1 3000) 0", &Expression::bare( hir::IntrinsicApplication { - callee: add.clone(), + callee: add, arguments: vec![ Expression::bare( hir::IntrinsicApplication { @@ -686,7 +686,7 @@ fn attributes() { hir::Application { callee: Expression::bare( hir::Application { - callee: Identifier::parameter("==").into_item(), + callee: Identifier::parameter("==").to_item(), argument: Expression::new( Attributes(vec![ Attribute::new(default(), BareAttribute::Static), @@ -703,7 +703,7 @@ fn attributes() { Attributes(vec![Attribute::new(default(), BareAttribute::Static)]), default(), hir::Application { - callee: Identifier::parameter("increment").into_item(), + callee: Identifier::parameter("increment").to_item(), argument: Expression::bare(Number::Nat(1u8.into()).into()), explicitness: Explicit, } @@ -735,11 +735,7 @@ fn path() { let mut context = Context::mock(); let session = Session::new(component, &mut context); - assert_format( - "topmost.overarching.middle.sink", - &sink.into_item(), - &session, - ); + assert_format("topmost.overarching.middle.sink", &sink.to_item(), &session); } #[test] @@ -767,7 +763,7 @@ fn path_identifier_symbol_symbol_identifier_segments() { assert_format( "topmost.overarching.&/.~## . ^^^ .sink", - &sink.into_item(), + &sink.to_item(), &session, ); } diff --git a/compiler/lowered_ast/src/attribute.rs b/compiler/lowered_ast/src/attribute.rs index 294fdab8..c5e9da81 100644 --- a/compiler/lowered_ast/src/attribute.rs +++ b/compiler/lowered_ast/src/attribute.rs @@ -1,7 +1,7 @@ -use derivation::{Discriminant, Elements, FromStr, Str}; +use derivation::{Discriminant, Elements, Str}; use span::{Span, Spanned, Spanning}; use std::fmt; -use utilities::{condition, obtain, Atom}; +use utilities::{condition, obtain, Atom, Str}; /// Something attributes can be ascribed to. /// @@ -287,10 +287,11 @@ impl Attributes { pub type Attribute = Spanned; +// @Task try to get rid of AttributeName #[derive(Clone, PartialEq, Eq, Hash, Discriminant)] #[discriminant( name: - #[derive(Elements, Str, FromStr)] + #[derive(Elements, Str)] #[format(dash_case)] #[str(to_str)] AttributeName @@ -338,7 +339,7 @@ pub enum BareAttribute { /// ```text /// doc <0:content:Text-Literal> /// ``` - Doc { content: Atom }, + Doc { content: Str }, /// Forbid a [lint](Lint). /// /// # Form @@ -561,6 +562,33 @@ impl fmt::Display for BareAttribute { } impl AttributeName { + pub fn parse(name: Atom) -> Option { + Some(match name { + Atom::abstract_ => Self::Abstract, + Atom::allow => Self::Allow, + Atom::deny => Self::Deny, + Atom::deprecated => Self::Deprecated, + Atom::doc => Self::Doc, + Atom::forbid => Self::Forbid, + Atom::if_ => Self::If, + Atom::ignore => Self::Ignore, + Atom::include => Self::Include, + Atom::intrinsic => Self::Intrinsic, + Atom::known => Self::Known, + Atom::location => Self::Location, + Atom::moving => Self::Moving, + Atom::public => Self::Public, + Atom::recursion_limit => Self::RecursionLimit, + Atom::static_ => Self::Static, + Atom::statistics => Self::Statistics, + Atom::test => Self::Test, + Atom::unsafe_ => Self::Unsafe, + Atom::unstable => Self::Unstable, + Atom::warn => Self::Warn, + _ => return None, + }) + } + pub const fn is_implemented(self) -> bool { matches!( self, @@ -650,7 +678,7 @@ data_queries! { Doc: str = BareAttribute::Doc { content } => content, Intrinsic: Special = BareAttribute::Intrinsic(special) => special, Known: Special = BareAttribute::Known(special) => special, - Location: str = BareAttribute::Location { path } => path, + Location: Atom = BareAttribute::Location { path } => path, Public: Public = BareAttribute::Public(reach) => reach, } diff --git a/compiler/lowerer/src/lib.rs b/compiler/lowerer/src/lib.rs index cadf9054..a68b6a0b 100644 --- a/compiler/lowerer/src/lib.rs +++ b/compiler/lowerer/src/lib.rs @@ -139,7 +139,7 @@ impl<'a> Lowerer<'a> { Some(type_) => type_, None => missing_mandatory_type_annotation_error( function.binder.span().fit_end(&function.parameters).end(), - TypeAnnotationTarget::Declaration(&function.binder), + TypeAnnotationTarget::Declaration(function.binder), ) .handle(&mut *self), }; @@ -168,7 +168,7 @@ impl<'a> Lowerer<'a> { default(), default(), lowered_ast::Lambda { - parameter: parameter.bare.binder.clone(), + parameter: parameter.bare.binder, domain: Some(parameter_type.clone()), explicitness: parameter.bare.explicitness, codomain: type_.next(), @@ -197,7 +197,7 @@ impl<'a> Lowerer<'a> { Some(type_) => type_, None => missing_mandatory_type_annotation_error( data_type.binder.span().fit_end(&data_type.parameters).end(), - TypeAnnotationTarget::Declaration(&data_type.binder), + TypeAnnotationTarget::Declaration(data_type.binder), ) .handle(&mut *self), }; @@ -230,7 +230,7 @@ impl<'a> Lowerer<'a> { .span() .fit_end(&constructor.parameters) .end(), - TypeAnnotationTarget::Declaration(&constructor.binder), + TypeAnnotationTarget::Declaration(constructor.binder), ) .handle(&mut *self), }; @@ -287,11 +287,11 @@ impl<'a> Lowerer<'a> { _ = inline_modules.take_last(); path.extend(inline_modules); - path.push(location.bare); + path.push(location.bare.to_str()); } None => { path.extend(&context.inline_modules); - path.push(module.binder.as_str()); + path.push(module.binder.to_str()); } }; @@ -317,14 +317,14 @@ impl<'a> Lowerer<'a> { } }; - let declaration = - match syntax::parse_module_file(file, module.binder.clone(), self.session) { - Ok(declaration) => declaration, - Err(error) => { - self.health.taint(error); - return PossiblyErroneous::error(error); - } - }; + let declaration = match syntax::parse_module_file(file, module.binder, self.session) + { + Ok(declaration) => declaration, + Err(error) => { + self.health.taint(error); + return PossiblyErroneous::error(error); + } + }; // at this point in time, they are still on the module header if at all assert!(declaration.attributes.is_empty()); @@ -403,7 +403,7 @@ impl<'a> Lowerer<'a> { 'discriminate: { match use_.bindings.bare { ast::BareUsePathTree::Single { target, binder } => { - let binder = binder.or_else(|| target.segments.last().cloned()); + let binder = binder.or_else(|| target.segments.last().copied()); let Some(binder) = binder else { // @Task improve the message for `use topmost.(self)`: hint that `self` // is effectively unnamed because `topmost` is unnamed @@ -461,7 +461,7 @@ impl<'a> Lowerer<'a> { } .segments .last() - .cloned() + .copied() }) else { // @Task improve the message for `use topmost.(self)`: hint that `self` // is effectively unnamed because `topmost` is unnamed @@ -530,12 +530,9 @@ impl<'a> Lowerer<'a> { }; let domain = self.lower_expression(domain); - // @Temporary this is a hack until we properly support discards and intern correctly - let binder = if parameter.bare.binder.as_str() != "_" { - Some(parameter.bare.binder) - } else { - None - }; + // @Temporary hack until we properly support discards + let binder = Some(parameter.bare.binder) + .filter(|binder| binder.bare() != Atom::underscore); codomain = lowered_ast::Expression::new( default(), @@ -1155,7 +1152,7 @@ impl BareAttributeExt for lowered_ast::BareAttribute { content: if options.keep_documentation_comments { session.shared_map().snippet(attribute.span) .trim_start_matches(";;") - .into() + .to_owned().into() } else { default() }, @@ -1196,17 +1193,15 @@ impl BareAttributeExt for lowered_ast::BareAttribute { let result = (|| { use AttributeName::*; - let name: AttributeName = binder - .as_str() - .parse() - .map_err(|_| AttributeParsingError::UndefinedAttribute(binder.clone()))?; + let name = AttributeName::parse(binder.bare()) + .ok_or(AttributeParsingError::UndefinedAttribute(*binder))?; Ok(match name { Abstract => Self::Abstract, Allow | Deny | Forbid | Warn => { let lint = lowered_ast::attribute::Lint::parse( argument(arguments, attribute.span, session.reporter())? - .path(Some("lint"), session.reporter())? + .path(Some(Atom::lint), session.reporter())? .clone(), session.reporter(), )?; @@ -1221,25 +1216,26 @@ impl BareAttributeExt for lowered_ast::BareAttribute { } Deprecated => Self::Deprecated(lowered_ast::attribute::Deprecated { reason: optional_argument(arguments) - .map(|argument| argument.text_literal(Some("reason"), session.reporter())) - .transpose()? - .cloned(), + .map(|argument| { + argument.text_literal(Some(Atom::reason), session.reporter()) + }) + .transpose()?, // @Task parse version since: None, // @Task parse version removal: None, replacement: optional_argument(arguments) .map(|argument| { - argument.text_literal(Some("replacement"), session.reporter()) + argument.text_literal(Some(Atom::replacement), session.reporter()) }) - .transpose()? - .cloned(), + .transpose()?, }), Doc => Self::Doc { content: if options.keep_documentation_comments { argument(arguments, attribute.span, session.reporter())? .text_literal(None, session.reporter())? - .clone() + .to_str() + .into() } else { *arguments = &arguments[1..]; default() @@ -1247,7 +1243,7 @@ impl BareAttributeExt for lowered_ast::BareAttribute { }, Intrinsic => { let name = optional_argument(arguments) - .map(|argument| argument.path(Some("name"), session.reporter())) + .map(|argument| argument.path(Some(Atom::name), session.reporter())) .transpose()? .cloned(); @@ -1265,7 +1261,7 @@ impl BareAttributeExt for lowered_ast::BareAttribute { Include => Self::Include, Known => { let name = optional_argument(arguments) - .map(|argument| argument.path(Some("name"), session.reporter())) + .map(|argument| argument.path(Some(Atom::name), session.reporter())) .transpose()? .cloned(); @@ -1273,15 +1269,14 @@ impl BareAttributeExt for lowered_ast::BareAttribute { } Location => { let path = argument(arguments, attribute.span, session.reporter())? - .text_literal(Some("path"), session.reporter())? - .clone(); + .text_literal(Some(Atom::path), session.reporter())?; Self::Location { path } } Moving => Self::Moving, Public => { let reach = optional_argument(arguments) - .map(|argument| argument.path(Some("reach"), session.reporter())) + .map(|argument| argument.path(Some(Atom::reach), session.reporter())) .transpose()? .cloned(); @@ -1290,7 +1285,8 @@ impl BareAttributeExt for lowered_ast::BareAttribute { RecursionLimit => { let depth = argument(arguments, attribute.span, session.reporter())?; let depth = depth - .number_literal(Some("depth"), session.reporter())? + .number_literal(Some(Atom::depth), session.reporter())? + .to_str() .parse::() .map_err(|_| { AttributeParsingError::Erased( @@ -1343,7 +1339,7 @@ impl BareAttributeExt for lowered_ast::BareAttribute { AttributeParsingError::UndefinedAttribute(binder) => Diagnostic::error() .code(ErrorCode::E011) .message(format!("the attribute ‘{binder}’ is not defined")) - .unlabeled_span(&binder) + .unlabeled_span(binder) .report(session.reporter()), AttributeParsingError::Erased(error) => error, }) @@ -1365,47 +1361,46 @@ enum AttributeParsingError { trait AttributeArgumentExt { fn number_literal( &self, - name: Option<&'static str>, + name: Option, reporter: &Reporter, - ) -> Result<&Atom, AttributeParsingError>; + ) -> Result; fn text_literal( &self, - name: Option<&'static str>, + name: Option, reporter: &Reporter, - ) -> Result<&Atom, AttributeParsingError>; + ) -> Result; - fn path( - &self, - name: Option<&'static str>, - reporter: &Reporter, - ) -> Result<&Path, AttributeParsingError>; + fn path(&self, name: Option, reporter: &Reporter) + -> Result<&Path, AttributeParsingError>; } impl AttributeArgumentExt for ast::AttributeArgument { fn number_literal( &self, - name: Option<&'static str>, + name: Option, reporter: &Reporter, - ) -> Result<&Atom, AttributeParsingError> { + ) -> Result { use ast::BareAttributeArgument::*; match &self.bare { - NumberLiteral(literal) => Ok(literal), - Named(named) => named.handle( - name, - |argument| match &argument.bare { - NumberLiteral(literal) => Ok(literal), - bare => Err(AttributeParsingError::Erased( - invalid_attribute_argument_type_error( - Spanned::new(argument.span, bare.name()), - "number literal", - ) - .report(reporter), - )), - }, - reporter, - ), + &NumberLiteral(literal) => Ok(literal), + Named(named) => named + .handle( + name, + |argument| match &argument.bare { + NumberLiteral(literal) => Ok(literal), + bare => Err(AttributeParsingError::Erased( + invalid_attribute_argument_type_error( + Spanned::new(argument.span, bare.name()), + "number literal", + ) + .report(reporter), + )), + }, + reporter, + ) + .copied(), bare => Err(AttributeParsingError::Erased( invalid_attribute_argument_type_error( Spanned::new(self.span, bare.name()), @@ -1418,27 +1413,29 @@ impl AttributeArgumentExt for ast::AttributeArgument { fn text_literal( &self, - name: Option<&'static str>, + name: Option, reporter: &Reporter, - ) -> Result<&Atom, AttributeParsingError> { + ) -> Result { use ast::BareAttributeArgument::*; match &self.bare { - TextLiteral(literal) => Ok(literal), - Named(named) => named.handle( - name, - |argument| match &argument.bare { - TextLiteral(literal) => Ok(literal), - bare => Err(AttributeParsingError::Erased( - invalid_attribute_argument_type_error( - Spanned::new(argument.span, bare.name()), - "text literal", - ) - .report(reporter), - )), - }, - reporter, - ), + &TextLiteral(literal) => Ok(literal), + Named(named) => named + .handle( + name, + |argument| match &argument.bare { + TextLiteral(literal) => Ok(literal), + bare => Err(AttributeParsingError::Erased( + invalid_attribute_argument_type_error( + Spanned::new(argument.span, bare.name()), + "text literal", + ) + .report(reporter), + )), + }, + reporter, + ) + .copied(), bare => Err(AttributeParsingError::Erased( invalid_attribute_argument_type_error( Spanned::new(self.span, bare.name()), @@ -1451,7 +1448,7 @@ impl AttributeArgumentExt for ast::AttributeArgument { fn path( &self, - name: Option<&'static str>, + name: Option, reporter: &Reporter, ) -> Result<&Path, AttributeParsingError> { use ast::BareAttributeArgument::*; @@ -1488,7 +1485,7 @@ impl AttributeArgumentExt for ast::AttributeArgument { trait NamedAttributeArgumentExt { fn handle( &self, - name: Option<&'static str>, + name: Option, handle: impl FnOnce(&ast::AttributeArgument) -> Result<&T, AttributeParsingError>, reporter: &Reporter, ) -> Result<&T, AttributeParsingError>; @@ -1497,17 +1494,17 @@ trait NamedAttributeArgumentExt { impl NamedAttributeArgumentExt for ast::NamedAttributeArgument { fn handle( &self, - name: Option<&'static str>, + name: Option, handle: impl FnOnce(&ast::AttributeArgument) -> Result<&T, AttributeParsingError>, reporter: &Reporter, ) -> Result<&T, AttributeParsingError> { match name { Some(name) => { - if self.binder.as_str() == name { + if self.binder.bare() == name { handle(&self.value) } else { Err(AttributeParsingError::Erased( - unexpected_named_attribute_argument_error(&self.binder, name) + unexpected_named_attribute_argument_error(self.binder, name) .report(reporter), )) } @@ -1559,8 +1556,8 @@ fn incorrectly_positioned_path_hanger_error(hanger: ast::Hanger) -> Diagnostic { // @Temporary signature fn unexpected_named_attribute_argument_error( - actual: &ast::Identifier, - expected: &'static str, + actual: ast::Identifier, + expected: Atom, ) -> Diagnostic { Diagnostic::error() .code(ErrorCode::E028) @@ -1615,7 +1612,7 @@ fn missing_mandatory_type_annotation_error( /// Exclusively used for error reporting. enum TypeAnnotationTarget<'a> { Parameter(&'a Parameter), - Declaration(&'a ast::Identifier), + Declaration(ast::Identifier), } impl TypeAnnotationTarget<'_> { diff --git a/compiler/metadata/src/lexer.rs b/compiler/metadata/src/lexer.rs index 85f67316..598e0feb 100644 --- a/compiler/metadata/src/lexer.rs +++ b/compiler/metadata/src/lexer.rs @@ -301,6 +301,7 @@ impl TokenExt for Token { } } +// @Task retire TokenName! #[derive(Clone, Debug, Discriminant, PartialEq, Eq)] #[discriminant(name: TokenName)] pub enum BareToken { diff --git a/compiler/package/src/error.rs b/compiler/package/src/error.rs index 9e86e67b..28608505 100644 --- a/compiler/package/src/error.rs +++ b/compiler/package/src/error.rs @@ -18,7 +18,7 @@ impl From for DependencyResolutionError { } } -pub(crate) fn undefined_component_error(name: Spanned<&Word>, package: &Word) -> Diagnostic { +pub(crate) fn undefined_component_error(name: Spanned, package: Word) -> Diagnostic { // @Question should we special-case component name = package name? Diagnostic::error() @@ -29,9 +29,9 @@ pub(crate) fn undefined_component_error(name: Spanned<&Word>, package: &Word) -> } pub(crate) fn non_library_dependency_error( - name: Spanned<&Word>, + name: Spanned, type_: ComponentType, - package: &Word, + package: Word, ) -> Diagnostic { Diagnostic::error() .message(format!( diff --git a/compiler/package/src/lib.rs b/compiler/package/src/lib.rs index 617b99f5..9ab4f390 100644 --- a/compiler/package/src/lib.rs +++ b/compiler/package/src/lib.rs @@ -156,7 +156,7 @@ impl BuildQueue { self[manifest_path].components.extend( component_worklist .keys() - .map(|name| (name.bare.clone(), Unresolved)), + .map(|name| (name.bare, Unresolved)), ); while !component_worklist.is_empty() { @@ -166,7 +166,7 @@ impl BuildQueue { for (name, (component, _)) in component_worklist { use error::DependencyResolutionError::*; let dependencies = match self.resolve_dependencies( - &name.bare, + name.bare, manifest_path, component.bare.dependencies.as_ref(), ) { @@ -205,7 +205,7 @@ impl BuildQueue { let component = self.components.insert_with(|index| { BuildUnit { - name: name.bare.clone(), + name: name.bare, index, // @Beacon @Temporary new_unchecked @Bug its use is incorrect! @Task canonicalize (I guess?) path: component.bare.path.as_ref().map(|relative_path| { @@ -229,11 +229,11 @@ impl BuildQueue { // the same name but with a differing type, add a note that only library components are being looked // at during dependency resolution (clarifying that one cannot depend on non-library components) - for cycle in find_cycles_by_key::<&Word, Spanned<&Word>>( + for cycle in find_cycles_by_key::>( &unresolved_components .iter() .map(|(dependent, (_, dependency))| { - (&dependent.bare, dependency.as_ref().unwrap().as_ref()) + (dependent.bare, dependency.unwrap()) }) .collect(), |name| &name.bare, @@ -290,7 +290,7 @@ impl BuildQueue { let library = self .resolve_dependency_by_manifest( Ok(core_manifest_path), - Spanned::bare(&core_package_name), + Spanned::bare(core_package_name), None, Box::new(|| { Diagnostic::error() @@ -311,7 +311,7 @@ impl BuildQueue { self.components.insert_with(|index| { BuildUnit { - name: name.clone(), + name, index, // @Task don't use bare path: Spanned::bare(file_path), @@ -325,7 +325,7 @@ impl BuildQueue { fn resolve_dependencies( &mut self, - dependent_component_name: &Word, + dependent_component_name: Word, dependent_path: ManifestPath, dependencies: Option<&Spanned>>>, ) -> Result, error::DependencyResolutionError> { @@ -336,7 +336,7 @@ impl BuildQueue { let mut resolved_dependencies = HashMap::default(); let mut health = Health::Untainted; - for (dependency_exonym, dependency_declaration) in &dependencies.bare { + for (&dependency_exonym, dependency_declaration) in &dependencies.bare { match self.resolve_dependency( dependent_component_name, dependent_path, @@ -344,7 +344,7 @@ impl BuildQueue { dependency_declaration, ) { Ok(dependency) => { - resolved_dependencies.insert(dependency_exonym.bare.clone(), dependency); + resolved_dependencies.insert(dependency_exonym.bare, dependency); } Err(error::DependencyResolutionError::ErasedNonFatal(error)) => { health.taint(error); @@ -359,14 +359,14 @@ impl BuildQueue { fn resolve_dependency( &mut self, - dependent_component_name: &Word, + dependent_component_name: Word, dependent_path: ManifestPath, - component_exonym: &WeaklySpanned, + component_exonym: WeaklySpanned, declaration: &Spanned, ) -> Result { let dependency = match self.resolve_dependency_declaration( declaration, - &component_exonym.bare, + component_exonym.bare, dependent_path, ) { Ok(dependency) => dependency, @@ -394,8 +394,7 @@ impl BuildQueue { let component_endonym = declaration .bare .component - .as_ref() - .map_or(component_exonym.as_ref().strong(), Spanned::as_ref); + .unwrap_or_else(|| component_exonym.strong()); // @Question do we want to a allow declarations of the form ‘: { … }’ w/o an explicit ‘component: ’? @@ -404,7 +403,7 @@ impl BuildQueue { Dependency::LocalComponent => { let package = &self[dependent_path]; - return match package.components.get(component_endonym.bare) { + return match package.components.get(&component_endonym.bare) { Some(&Resolved(component)) if self[component].type_ == ComponentType::Library => { @@ -414,17 +413,17 @@ impl BuildQueue { Some(&Resolved(component)) => Err(error::non_library_dependency_error( component_endonym, self[component].type_, - &package.name, + package.name, ) .report(&self.reporter) .into()), Some(Unresolved) => { Err(error::DependencyResolutionError::UnresolvedLocalComponent( - component_endonym.cloned(), + component_endonym, )) } None => Err( - error::undefined_component_error(component_endonym, &package.name) + error::undefined_component_error(component_endonym, package.name) .report(&self.reporter) .into(), ), @@ -443,14 +442,14 @@ impl BuildQueue { // @Beacon @Note this probably won't scale to our new order-independent component resolver (maybe) // if so, consider not throwing a cycle error (here / unconditionally) // @Beacon @Task handle component privacy here - return match package.components.get(component_endonym.bare) { + return match package.components.get(&component_endonym.bare) { Some(&Resolved(component)) if self[component].type_ == ComponentType::Library => Ok(component), // @Bug this does not fire when we want to since the it is apparently unresolved at this stage for some reason // @Task test this, is this reachable? Some(&Resolved(component)) => Err(error::non_library_dependency_error( component_endonym, self[component].type_, - &package.name, + package.name, ) .report(&self.reporter) .into()), @@ -471,7 +470,7 @@ impl BuildQueue { // Err(error::DependencyResolutionError::Cycle(Spanned::bare(dependent_component_name.clone()))) } None => Err( - error::undefined_component_error(component_endonym, &package.name) + error::undefined_component_error(component_endonym, package.name) .report(&self.reporter) .into(), ) @@ -481,7 +480,7 @@ impl BuildQueue { self.resolve_dependency_by_manifest( manifest_path, component_endonym, - declaration.bare.package.clone(), + declaration.bare.package, Box::new(|| { Diagnostic::error() .message(format!( @@ -499,7 +498,7 @@ impl BuildQueue { fn resolve_dependency_by_manifest( &mut self, manifest_path: std::io::Result, - component_endonym: Spanned<&Word>, + component_endonym: Spanned, declared_package_name: Option>, load_error: Box Diagnostic + '_>, ) -> Result { @@ -542,14 +541,14 @@ impl BuildQueue { // @Task assert version requirement (if any) is fulfilled let package = Package::from_manifest(manifest.profile, manifest_path); - let package_name = package.name.clone(); + let package_name = package.name; self.packages.insert(manifest_path, package); // @Task handle component privacy let library = match manifest .components .as_ref() - .and_then(|components| components.bare.get(&component_endonym.cloned().weak())) + .and_then(|components| components.bare.get(&component_endonym.weak())) { Some(component) if component.bare.type_.bare == ComponentType::Library => { &component.bare @@ -558,14 +557,14 @@ impl BuildQueue { return Err(error::non_library_dependency_error( component_endonym, component.bare.type_.bare, - &package_name, + package_name, ) .report(&self.reporter) .into()) } None => { return Err( - error::undefined_component_error(component_endonym, &package_name) + error::undefined_component_error(component_endonym, package_name) .report(&self.reporter) .into(), ) @@ -580,23 +579,21 @@ impl BuildQueue { }); // @Question should we prefill all components here too? - self[manifest_path] - .components - .insert(name.clone(), Unresolved); + self[manifest_path].components.insert(name, Unresolved); // Transitive dependencies from the perspective of the dependent package. let dependencies = self.resolve_dependencies(name, manifest_path, library.dependencies.as_ref())?; let library = self.components.insert_with(|index| BuildUnit { - name: name.clone(), + name, index, path: library_component_path, type_: library.type_.bare, dependencies, }); - self.register_package_component(manifest_path, name.clone(), library); + self.register_package_component(manifest_path, name, library); Ok(library) } @@ -614,7 +611,7 @@ impl BuildQueue { fn resolve_dependency_declaration( &self, Spanned!(span, declaration): &Spanned, - exonym: &Word, + exonym: Word, manifest_path: ManifestPath, ) -> Result { // @Beacon @Task create a DependencyDeclaration' that's an enum not a struct with provider @@ -683,8 +680,8 @@ impl BuildQueue { let component = declaration .component .as_ref() - .map_or(exonym, |name| &name.bare); - let path = session::package::distributed_packages_path().join(component.as_str()); + .map_or(exonym, |name| name.bare); + let path = session::package::distributed_packages_path().join(component.to_str()); Ok(Dependency::ForeignPackage(path)) } DependencyProvider::Package => Ok(Dependency::LocalComponent), diff --git a/compiler/parser/src/base.rs b/compiler/parser/src/base.rs index 928cb97d..15030a26 100644 --- a/compiler/parser/src/base.rs +++ b/compiler/parser/src/base.rs @@ -134,9 +134,9 @@ impl<'a> Parser<'a> { self.contexts.clear(); } - /// Obtain a reference to the current token. - pub(crate) fn current(&self) -> &Token { - &self.tokens[self.index] + /// Obtain the current token. + pub(crate) fn current(&self) -> Token { + self.tokens[self.index] } /// Obtain the span of the current token. @@ -144,9 +144,9 @@ impl<'a> Parser<'a> { self.current().span } - /// Obtain a reference to the current (bare) token. - pub(crate) fn token(&self) -> &BareToken { - &self.current().bare + /// Obtain the current token without span. + pub(crate) fn token(&self) -> BareToken { + self.current().bare } /// Look ahead by the given amount of tokens. @@ -154,12 +154,12 @@ impl<'a> Parser<'a> { /// # Panics /// /// Panics on out of bounds accesses. - pub(crate) fn look_ahead(&self, amount: usize) -> &Token { - &self.tokens[self.index + amount] + pub(crate) fn look_ahead(&self, amount: usize) -> Token { + self.tokens[self.index + amount] } - pub(crate) fn look_behind(&self, amount: usize) -> Option<&Token> { - Some(&self.tokens[self.index.checked_sub(amount)?]) + pub(crate) fn look_behind(&self, amount: usize) -> Option { + Some(self.tokens[self.index.checked_sub(amount)?]) } } diff --git a/compiler/parser/src/lib.rs b/compiler/parser/src/lib.rs index 18691709..e79c49ea 100644 --- a/compiler/parser/src/lib.rs +++ b/compiler/parser/src/lib.rs @@ -35,7 +35,7 @@ use std::default::default; #[allow(clippy::wildcard_imports)] use synonym::*; use token::BareToken::{self, *}; -use utilities::{smallvec, SmallVec}; +use utilities::{smallvec, Atom, SmallVec}; mod base; #[cfg(test)] @@ -172,7 +172,7 @@ impl Parser<'_> { let span = self.span(); match self.token() { Word(binder) => { - let binder = ast::Identifier::new_unchecked(binder.clone(), span); + let binder = ast::Identifier::new_unchecked(binder, span); self.advance(); self.finish_parse_function_declaration(binder, attributes) } @@ -283,7 +283,7 @@ impl Parser<'_> { Some(constructors) } name @ Terminator!() => { - if name == &LineBreak { + if name == LineBreak { self.advance(); } None @@ -329,7 +329,7 @@ impl Parser<'_> { ) -> Result { // @Task abstract over this (used below as well), good idea? if let name @ Terminator!() = self.token() { - if name == &LineBreak { + if name == LineBreak { self.advance(); } @@ -346,7 +346,7 @@ impl Parser<'_> { // Out-of-line module declaration. // @Task abstract over this (used above as well), good idea? name @ Terminator!() => { - if name == &LineBreak { + if name == LineBreak { self.advance(); } @@ -448,19 +448,20 @@ impl Parser<'_> { let mut path = self.parse_path_head()?; while self.consume(Dot) { + let mut span = self.span(); match self.token() { Identifier!(segment) => { - let segment = ast::Identifier::new_unchecked(segment.clone(), self.span()); self.advance(); - path.segments.push(segment); + + path.segments + .push(ast::Identifier::new_unchecked(segment, span)); } OpeningRoundBracket => { - let mut span = self.span(); self.advance(); let mut bindings = Vec::new(); - while self.token() != &ClosingRoundBracket { + while self.token() != ClosingRoundBracket { let mut span = self.span(); if self.consume(OpeningRoundBracket) { let target = self.parse_path()?; @@ -503,7 +504,7 @@ impl Parser<'_> { }; Ok(ast::UsePathTree::new( - path.span().merge(&binder), + path.span().merge(binder), ast::BareUsePathTree::Single { target: path, binder, @@ -610,8 +611,8 @@ impl Parser<'_> { domain.span, ast::BareParameter { explicitness: Explicit, - // @Task use an pre-interned underscore! - binder: Identifier::new_unchecked("_".into(), domain.span.start()), + // @Temporary hack until we properly support discards + binder: Identifier::new_unchecked(Atom::underscore, domain.span.start()), type_: Some(domain), }, )], @@ -677,7 +678,6 @@ impl Parser<'_> { let mut span = self.span(); let mut expression = match self.token() { NumberLiteral(literal) => { - let literal = Spanned::new(span, literal.clone()); self.advance(); Expression::new( @@ -685,13 +685,12 @@ impl Parser<'_> { span, ast::NumberLiteral { path: None, - literal, + literal: Spanned::new(span, literal), } .into(), ) } TextLiteral(literal) => { - let literal = Spanned::new(span, literal.clone()); self.advance(); Expression::new( @@ -699,7 +698,7 @@ impl Parser<'_> { span, ast::TextLiteral { path: None, - literal, + literal: Spanned::new(span, literal), } .into(), ) @@ -708,7 +707,7 @@ impl Parser<'_> { self.advance(); let tag = self.parse_word()?; - Expression::new(default(), span.merge(&tag), ast::TypedHole { tag }.into()) + Expression::new(default(), span.merge(tag), ast::TypedHole { tag }.into()) } ForUpper => { self.advance(); @@ -752,7 +751,7 @@ impl Parser<'_> { _ => { self.expected("expression"); return self.error_with(|this, it| { - if this.token() == &ThinArrowRight { + if this.token() == ThinArrowRight { it.help( "consider adding round brackets around the potential \ function type to disambiguate the expression", @@ -771,7 +770,7 @@ impl Parser<'_> { expression = Expression::new( attributes.take().unwrap_or_default(), - expression.span.merge(&field), + expression.span.merge(field), ast::Projection { basis: expression, field, @@ -814,10 +813,9 @@ impl Parser<'_> { /// ``` fn parse_path_head(&mut self) -> Result { let path = match self.token() { - Identifier!(head) => Identifier::new_unchecked(head.clone(), self.span()).into(), + Identifier!(head) => Identifier::new_unchecked(head, self.span()).into(), PathHanger!() => self .current() - .clone() .map(|token| ast::BareHanger::try_from(token).unwrap()) .into(), _ => { @@ -1008,7 +1006,7 @@ impl Parser<'_> { if self.consume(Indentation) { // @Task use parse_block function for this (but don't trash the span!) - while self.token() != &Dedentation { + while self.token() != Dedentation { let pattern = self.parse_pattern()?; self.parse_wide_arrow()?; let body = self.parse_expression()?; @@ -1046,7 +1044,7 @@ impl Parser<'_> { self.expect(Indentation)?; - while self.token() != &Dedentation { + while self.token() != Dedentation { // @Note necessary I guess in cases where we have #Line-Break ##Comment+ #Line-Break if self.consume(LineBreak) { continue; @@ -1130,7 +1128,7 @@ impl Parser<'_> { let parameter = match self.token() { Word(binder) => { - let binder = ast::Identifier::new_unchecked(binder.clone(), self.span()); + let binder = ast::Identifier::new_unchecked(binder, self.span()); self.advance(); ast::Parameter::new( @@ -1210,7 +1208,6 @@ impl Parser<'_> { let mut span = self.span(); let mut pattern = match self.token() { NumberLiteral(literal) => { - let literal = Spanned::new(span, literal.clone()); self.advance(); Pattern::new( @@ -1218,13 +1215,12 @@ impl Parser<'_> { span, ast::NumberLiteral { path: None, - literal, + literal: Spanned::new(span, literal), } .into(), ) } TextLiteral(literal) => { - let literal = Spanned::new(span, literal.clone()); self.advance(); Pattern::new( @@ -1232,7 +1228,7 @@ impl Parser<'_> { span, ast::TextLiteral { path: None, - literal, + literal: Spanned::new(span, literal), } .into(), ) @@ -1240,14 +1236,14 @@ impl Parser<'_> { Backslash => { self.advance(); let binder = self.parse_word()?; - Pattern::new(default(), span.merge(&binder), binder.into()) + Pattern::new(default(), span.merge(binder), binder.into()) } OpeningSquareBracket => { self.advance(); let mut elements = Vec::new(); - while self.token() != &ClosingSquareBracket { + while self.token() != ClosingSquareBracket { elements.push(self.parse_lower_pattern()?); } @@ -1305,7 +1301,7 @@ impl Parser<'_> { { let mut elements = Vec::new(); - while self.token() != &ClosingSquareBracket { + while self.token() != ClosingSquareBracket { elements.push(T::parse_lower(self)?); } @@ -1349,12 +1345,10 @@ impl Parser<'_> { // // Parse an optional argument. // - let (binder, argument) = if self.token() == &OpeningRoundBracket - && let &Spanned!(binder_span, Word(ref binder)) = self.look_ahead(1) + let (binder, argument) = if self.token() == OpeningRoundBracket + && let Spanned!(binder_span, Word(binder)) = self.look_ahead(1) && self.look_ahead(2).bare == Equals { - let binder = binder.clone(); - self.advance(); // "(" self.advance(); // #Word self.advance(); // "=" @@ -1427,12 +1421,11 @@ impl Parser<'_> { let span = self.span(); match self.token() { Identifier!(segment) => { - let segment = ast::Identifier::new_unchecked(segment.clone(), span); self.advance(); - path.segments.push(segment); + path.segments + .push(ast::Identifier::new_unchecked(segment, span)); } NumberLiteral(literal) => { - let literal = Spanned::new(span, literal.clone()); self.advance(); return Ok(ast::Item::new( @@ -1440,13 +1433,12 @@ impl Parser<'_> { path.span().merge(span), ast::NumberLiteral { path: Some(path), - literal, + literal: Spanned::new(span, literal), } .into(), )); } TextLiteral(literal) => { - let literal = Spanned::new(span, literal.clone()); self.advance(); return Ok(ast::Item::new( @@ -1454,7 +1446,7 @@ impl Parser<'_> { path.span().merge(span), ast::TextLiteral { path: Some(path), - literal, + literal: Spanned::new(span, literal), } .into(), )); @@ -1544,7 +1536,7 @@ impl Parser<'_> { let binder = match self.token() { Word(binder) => { - let binder = ast::Identifier::new_unchecked(binder.clone(), self.span()); + let binder = ast::Identifier::new_unchecked(binder, self.span()); span.merging(&binder); self.advance(); @@ -1555,7 +1547,7 @@ impl Parser<'_> { self.advance(); let binder = self.parse_word()?; - while self.token() != &ClosingRoundBracket { + while self.token() != ClosingRoundBracket { arguments.push(self.parse_attribute_argument()?); } @@ -1598,14 +1590,12 @@ impl Parser<'_> { } NumberLiteral(literal) => { span = self.span(); - let literal = literal.clone(); self.advance(); ast::BareAttributeArgument::NumberLiteral(literal) } TextLiteral(literal) => { span = self.span(); - let literal = literal.clone(); self.advance(); ast::BareAttributeArgument::TextLiteral(literal) @@ -1639,10 +1629,9 @@ impl Parser<'_> { /// Identifier ::= #Word | #Symbol /// ``` fn parse_identifier(&mut self) -> Result { - if let Identifier!(identifier) = self.token() { - let identifier = ast::Identifier::new_unchecked(identifier.clone(), self.span()); + if let Spanned!(span, Identifier!(identifier)) = self.current() { self.advance(); - Ok(identifier) + Ok(ast::Identifier::new_unchecked(identifier, span)) } else { self.expected(IDENTIFIER); self.error() @@ -1650,10 +1639,9 @@ impl Parser<'_> { } fn parse_word(&mut self) -> Result { - if let Word(word) = self.token() { - let word = ast::Identifier::new_unchecked(word.clone(), self.span()); + if let Spanned!(span, Word(word)) = self.current() { self.advance(); - Ok(word) + Ok(ast::Identifier::new_unchecked(word, span)) } else { self.expected(WORD); self.error() @@ -1684,7 +1672,7 @@ impl Parser<'_> { .look_behind(1) .map_or(true, |token| matches!(token.bare, Terminator!())) { - Ok(if token == &LineBreak { + Ok(if token == LineBreak { let span = self.span(); self.advance(); @@ -1708,7 +1696,7 @@ impl Parser<'_> { /// /// [implicitness]: ast::Explicitness fn parse_optional_implicitness(&mut self) -> Option { - if self.token() == &Apostrophe { + if self.token() == Apostrophe { let span = self.span(); self.advance(); Some(span) @@ -1739,7 +1727,7 @@ trait Parse: Sized { fn parse(parser: &mut Parser<'_>) -> Result>; fn parse_lower(parser: &mut Parser<'_>) -> Result>; - fn is_lower_prefix(token: &BareToken) -> bool; + fn is_lower_prefix(token: BareToken) -> bool; } impl Parse for ast::BareExpression { @@ -1752,7 +1740,7 @@ impl Parse for ast::BareExpression { parser.parse_lower_expression() } - fn is_lower_prefix(token: &BareToken) -> bool { + fn is_lower_prefix(token: BareToken) -> bool { matches!(token, LowerExpressionPrefix!()) } } @@ -1767,7 +1755,7 @@ impl Parse for ast::BarePattern { parser.parse_lower_pattern() } - fn is_lower_prefix(token: &BareToken) -> bool { + fn is_lower_prefix(token: BareToken) -> bool { matches!(token, LowerPatternPrefix!()) } } diff --git a/compiler/parser/src/test.rs b/compiler/parser/src/test.rs index 515f253b..1103fc5a 100644 --- a/compiler/parser/src/test.rs +++ b/compiler/parser/src/test.rs @@ -607,7 +607,7 @@ lengthy-space-filler (case 0 of ast::Application { explicitness: Explicit, binder: None, - callee: identifier("lengthy-space-filler".into(), span(1, 21)).into(), + callee: identifier("lengthy-space-filler", span(1, 21)).into(), argument: Expression::new( Attributes::new(), span(22, 45), @@ -625,9 +625,9 @@ lengthy-space-filler (case 0 of pattern: Pattern::new( Attributes::new(), span(37, 39), - identifier("n".into(), span(38, 39)).into(), + identifier("n", span(38, 39)).into(), ), - body: identifier("n".into(), span(43, 44)).into(), + body: identifier("n", span(43, 44)).into(), }], } .into(), @@ -678,11 +678,11 @@ fn use_as_plain() { target: Path { hanger: None, segments: smallvec![ - identifier("alpha".into(), span(5, 10)), - identifier("beta".into(), span(11, 15)), + identifier("alpha", span(5, 10)), + identifier("beta", span(11, 15)), ], }, - binder: Some(identifier("gamma".into(), span(19, 24))), + binder: Some(identifier("gamma", span(19, 24))), }, ), } @@ -712,12 +712,12 @@ fn use_as_double_brackets() { bindings: UsePathTree::new( span(5, 28), BareUsePathTree::Multiple { - path: identifier("alpha".into(), span(5, 10)).into(), + path: identifier("alpha", span(5, 10)).into(), bindings: vec![UsePathTree::new( span(12, 27), BareUsePathTree::Single { - target: identifier("beta".into(), span(13, 17)).into(), - binder: Some(identifier("gamma".into(), span(21, 26))), + target: identifier("beta", span(13, 17)).into(), + binder: Some(identifier("gamma", span(21, 26))), }, )], }, @@ -754,14 +754,14 @@ main = Attributes::new(), span(1, 75), ast::Function { - binder: identifier("main".into(), span(1, 5)), + binder: identifier("main", span(1, 5)), parameters: Parameters::new(), type_: None, body: Some(Expression::new( Attributes::new(), span(12, 75), ast::CaseAnalysis { - scrutinee: identifier("x".into(), span(17, 18)).into(), + scrutinee: identifier("x", span(17, 18)).into(), cases: vec![ Case { pattern: Pattern::new( @@ -783,7 +783,7 @@ main = pattern: Pattern::new( Attributes::new(), span(49, 53), - identifier("bar".into(), span(50, 53)).into(), + identifier("bar", span(50, 53)).into(), ), body: Expression::new( Attributes::new(), @@ -830,21 +830,20 @@ main = case x of Attributes::new(), span(1, 59), ast::Function { - binder: identifier("main".into(), span(1, 5)), + binder: identifier("main", span(1, 5)), parameters: Parameters::new(), type_: None, body: Some(Expression::new( Attributes::new(), span(8, 59), ast::CaseAnalysis { - scrutinee: identifier("x".into(), span(13, 14)).into(), + scrutinee: identifier("x", span(13, 14)).into(), cases: vec![ Case { pattern: Pattern::new( Attributes::new(), span(22, 27), - Path::from(identifier("false".into(), span(22, 27))) - .into(), + Path::from(identifier("false", span(22, 27))).into(), ), body: Expression::new( Attributes::new(), @@ -860,7 +859,7 @@ main = case x of pattern: Pattern::new( Attributes::new(), span(37, 41), - identifier("bar".into(), span(38, 41)).into(), + identifier("bar", span(38, 41)).into(), ), body: Expression::new( Attributes::new(), diff --git a/compiler/resolver/src/lib.rs b/compiler/resolver/src/lib.rs index b19bb8c9..7ce30a0b 100644 --- a/compiler/resolver/src/lib.rs +++ b/compiler/resolver/src/lib.rs @@ -35,8 +35,8 @@ use std::{cmp::Ordering, default::default, fmt, mem, sync::Mutex}; use token::Word; use unicode_width::UnicodeWidthStr; use utilities::{ - cycle::find_cycles, displayed, obtain, pluralize, smallvec, AsAutoColoredChangeset, - Conjunction, HashMap, ListingExt, QuoteExt, SmallVec, + cycle::find_cycles, displayed, obtain, pluralize, smallvec, AsAutoColoredChangeset, Atom, + Conjunction, HashMap, ListingExt, QuoteExt, SmallVec, PROGRAM_ENTRY, }; /// Resolve the names of a declaration. @@ -168,14 +168,14 @@ impl<'sess, 'ctx> ResolverMut<'sess, 'ctx> { let module = module.unwrap(); let index = self.define( - function.binder.clone(), + function.binder, exposure, declaration.attributes.clone(), EntityKind::UntypedFunction, Some(module), )?; - let binder = Identifier::new(index.global(self.session), function.binder.clone()); + let binder = Identifier::new(index.global(self.session), function.binder); if let Some(intrinsic) = declaration.attributes.get::<{ AttributeName::Intrinsic }>() && let Err(error) = self.session.define_special( @@ -198,20 +198,20 @@ impl<'sess, 'ctx> ResolverMut<'sess, 'ctx> { // @Task don't return early, see analoguous code for modules let index = self.define( - type_.binder.clone(), + type_.binder, exposure, declaration.attributes.clone(), EntityKind::untyped_data_type(), Some(module), )?; - let binder = Identifier::new(index.global(self.session), type_.binder.clone()); + let binder = Identifier::new(index.global(self.session), type_.binder); let known = declaration.attributes.get::<{ AttributeName::Known }>(); if let Some(known) = known && let Err(error) = self.session.define_special( special::Kind::Known, - binder.clone(), + binder, match &known.bare.name { Some(name) => special::DefinitionStyle::Explicit { name }, None => special::DefinitionStyle::Implicit { namespace: None }, @@ -274,15 +274,14 @@ impl<'sess, 'ctx> ResolverMut<'sess, 'ctx> { }; let index = self.define( - constructor.binder.clone(), + constructor.binder, exposure, declaration.attributes.clone(), EntityKind::UntypedConstructor, Some(namespace), )?; - let binder = - Identifier::new(index.global(self.session), constructor.binder.clone()); + let binder = Identifier::new(index.global(self.session), constructor.binder); // @Task support `@(known name)` on constructors if let Some(known) = known @@ -302,7 +301,7 @@ impl<'sess, 'ctx> ResolverMut<'sess, 'ctx> { // @Note you need to create a fake index for this (an index which points to // a fake, nameless binding) let index = self.define( - submodule.binder.clone(), + submodule.binder, exposure, // @Beacon @Bug this does not account for attributes found on the attribute header! declaration.attributes.clone(), @@ -327,7 +326,7 @@ impl<'sess, 'ctx> ResolverMut<'sess, 'ctx> { let module = module.unwrap(); let index = self.define( - use_.binder.clone(), + use_.binder, exposure, declaration.attributes.clone(), EntityKind::UnresolvedUse, @@ -429,7 +428,7 @@ impl<'sess, 'ctx> ResolverMut<'sess, 'ctx> { let binder = self .as_ref() - .reobtain_resolved_identifier::(&function.binder, module); + .reobtain_resolved_identifier::(function.binder, module); let type_annotation = self .as_ref() @@ -461,7 +460,7 @@ impl<'sess, 'ctx> ResolverMut<'sess, 'ctx> { // or maybe even a *LocalIdentifier? let binder = self .as_ref() - .reobtain_resolved_identifier::(&type_.binder, module); + .reobtain_resolved_identifier::(type_.binder, module); let type_annotation = self .as_ref() @@ -502,7 +501,7 @@ impl<'sess, 'ctx> ResolverMut<'sess, 'ctx> { let binder = self .as_ref() - .reobtain_resolved_identifier::(&constructor.binder, namespace); + .reobtain_resolved_identifier::(constructor.binder, namespace); let type_annotation = self .as_ref() @@ -525,7 +524,7 @@ impl<'sess, 'ctx> ResolverMut<'sess, 'ctx> { // but it is module binding Some(module) => self .as_ref() - .reobtain_resolved_identifier::(&submodule.binder, module) + .reobtain_resolved_identifier::(submodule.binder, module) .local(self.session) .unwrap(), None => self.session.component().root_local(), @@ -559,7 +558,7 @@ impl<'sess, 'ctx> ResolverMut<'sess, 'ctx> { let binder = Identifier::new( self.as_ref() - .reobtain_resolved_identifier::(&use_.binder, module), + .reobtain_resolved_identifier::(use_.binder, module), use_.binder, ); @@ -567,7 +566,7 @@ impl<'sess, 'ctx> ResolverMut<'sess, 'ctx> { declaration.attributes, declaration.span, hir::Use { - binder: Some(binder.clone()), + binder: Some(binder), target: binder, } .into(), @@ -702,8 +701,8 @@ impl<'sess, 'ctx> ResolverMut<'sess, 'ctx> { "re-export of the more private binding ‘{}’", self.session.index_to_path(target_index) )) - .span(&entity.source, "re-exporting binding with greater exposure") - .label(&target.source, "re-exported binding with lower exposure") + .span(entity.source, "re-exporting binding with greater exposure") + .label(target.source, "re-exported binding with lower exposure") .note(format!( "\ expected the exposure of ‘{}’ @@ -748,7 +747,7 @@ impl<'a> Resolver<'a> { let expression = match expression.bare { PiType(pi) => { let domain = self.resolve_expression(pi.domain.clone(), scope); - let codomain = match pi.binder.clone() { + let codomain = match pi.binder { Some(parameter) => self.resolve_expression( pi.codomain.clone(), &scope.extend_with_parameter(parameter), @@ -765,7 +764,6 @@ impl<'a> Resolver<'a> { explicitness: pi.explicitness, binder: pi .binder - .clone() .map(|parameter| Identifier::new(Index::DeBruijnParameter, parameter)), } .into(), @@ -805,21 +803,18 @@ impl<'a> Resolver<'a> { .clone() .map(|type_| self.resolve_expression(type_, scope)); let body_type_annotation = lambda.codomain.clone().map(|type_| { - self.resolve_expression( - type_, - &scope.extend_with_parameter(lambda.parameter.clone()), - ) + self.resolve_expression(type_, &scope.extend_with_parameter(lambda.parameter)) }); let body = self.resolve_expression( lambda.body.clone(), - &scope.extend_with_parameter(lambda.parameter.clone()), + &scope.extend_with_parameter(lambda.parameter), ); hir::Expression::new( expression.attributes, expression.span, hir::Lambda { - binder: Identifier::new(Index::DeBruijnParameter, lambda.parameter.clone()), + binder: Identifier::new(Index::DeBruijnParameter, lambda.parameter), domain: parameter_type_annotation.transpose()?, codomain: body_type_annotation.transpose()?, body: body?, @@ -906,7 +901,7 @@ impl<'a> Resolver<'a> { hir::Binding(self.resolve_path_inside_function(&path, scope)?).into(), ), Binder(binder) => { - binders.push((*binder).clone()); + binders.push(*binder); hir::Pattern::new( pattern.attributes, @@ -999,7 +994,7 @@ impl<'a> Resolver<'a> { None => NumericType::Nat, }; - let Ok(resolved_number) = hir::Number::parse(&literal.bare, type_) else { + let Ok(resolved_number) = hir::Number::parse(literal.bare.to_str(), type_) else { return Err(Diagnostic::error() .code(ErrorCode::E007) .message(format!( @@ -1043,7 +1038,7 @@ impl<'a> Resolver<'a> { .get(type_.bare) .filter(|&intrinsic| matches!(intrinsic, special::Binding::Type(Type::Text))) .ok_or_else(|| { - self.literal_used_for_unsupported_type(&text.bare.literal, "text", type_) + self.literal_used_for_unsupported_type(text.bare.literal, "text", type_) .report(self.session.reporter()) })?, // for now, we default to `Text` until we implement polymorphic text literals and their inference @@ -1137,7 +1132,7 @@ impl<'a> Resolver<'a> { span, hir::Application { // @Task don't throw away attributes & span - callee: hir::Item::new(default(), span, hir::Binding(empty.clone()).into()), + callee: hir::Item::new(default(), span, hir::Binding(empty).into()), explicitness: Explicit, argument: element_type.clone(), } @@ -1150,11 +1145,7 @@ impl<'a> Resolver<'a> { default(), element.span, hir::Application { - callee: hir::Item::new( - default(), - element.span, - hir::Binding(prepend.clone()).into(), - ), + callee: hir::Item::new(default(), element.span, hir::Binding(prepend).into()), explicitness: Explicit, argument: element_type.clone(), } @@ -1228,7 +1219,7 @@ impl<'a> Resolver<'a> { span, hir::Application { // @Task don't throw away attributes & span - callee: hir::Item::new(default(), span, hir::Binding(empty.clone()).into()), + callee: hir::Item::new(default(), span, hir::Binding(empty).into()), explicitness: Explicit, argument: element_type.clone(), } @@ -1248,7 +1239,7 @@ impl<'a> Resolver<'a> { callee: hir::Item::new( default(), element.span, - hir::Binding(prepend.clone()).into(), + hir::Binding(prepend).into(), ), explicitness: Explicit, // @Beacon @Question What happens if the user does not define the intrinsic type `Nat`? @@ -1325,12 +1316,11 @@ impl<'a> Resolver<'a> { let type_ = self.session.specials().get(special::Type::Type).unwrap(); // @Task check if all those attributes & spans make sense - let mut result = - hir::Item::new(default(), elements.span, hir::Binding(empty.clone()).into()); + let mut result = hir::Item::new(default(), elements.span, hir::Binding(empty).into()); let mut list = vec![hir::Item::new( default(), elements.span, - hir::Binding(type_.clone()).into(), + hir::Binding(type_).into(), )]; for [element_type, element] in elements.bare.into_iter().array_chunks().rev() { @@ -1346,7 +1336,7 @@ impl<'a> Resolver<'a> { callee: hir::Item::new( default(), element.span, - hir::Binding(prepend.clone()).into(), + hir::Binding(prepend).into(), ), explicitness: Explicit, argument: element_type.clone(), @@ -1454,7 +1444,7 @@ impl<'a> Resolver<'a> { }; // @Beacon @Task add test for error case - let component: Spanned = component.clone().try_into().map_err(|_| { + let component: Spanned = (*component).try_into().map_err(|_| { // @Task DRY @Question is the common code justified? Diagnostic::error() .code(ErrorCode::E036) @@ -1490,7 +1480,7 @@ impl<'a> Resolver<'a> { let root = component.root(); return match &*path.segments { - [identifier] => Ok(Target::output(root, identifier)), + &[identifier] => Ok(Target::output(root, identifier)), [_, identifiers @ ..] => self.resolve_path::( // @Task use PathView once available &ast::Path::with_segments(identifiers.to_owned().into()), @@ -1520,11 +1510,11 @@ impl<'a> Resolver<'a> { }; } - let index = self.resolve_identifier(&path.segments[0], context)?; + let index = self.resolve_identifier(path.segments[0], context)?; let entity = &self.session[index]; match &*path.segments { - [identifier] => { + &[identifier] => { Target::validate_identifier(identifier, entity) .map_err(|error| error.report(self.session.reporter()))?; Ok(Target::output(index, identifier)) @@ -1538,13 +1528,13 @@ impl<'a> Resolver<'a> { ) } else if entity.is_error() { // @Task add rationale why `last` - Ok(Target::output(index, identifiers.last().unwrap())) + Ok(Target::output(index, *identifiers.last().unwrap())) } else { let diagnostic = self.attempt_to_access_subbinder_of_non_namespace_error( - identifier, + *identifier, &entity.kind, context.namespace, - identifiers.first().unwrap(), + *identifiers.first().unwrap(), ); Err(diagnostic.report(self.session.reporter()).into()) } @@ -1569,7 +1559,7 @@ impl<'a> Resolver<'a> { fn resolve_identifier( &self, - identifier: &ast::Identifier, + identifier: ast::Identifier, context: PathResolutionContext, ) -> Result { let index = self.session[context.namespace] @@ -1578,9 +1568,9 @@ impl<'a> Resolver<'a> { .binders .iter() .copied() - .find(|&index| &self.session[index].source == identifier) - .ok_or_else(|| ResolutionError::UnresolvedBinding { - identifier: identifier.clone(), + .find(|&index| self.session[index].source == identifier) + .ok_or(ResolutionError::UnresolvedBinding { + identifier, namespace: context.namespace, usage: context.usage, })?; @@ -1603,7 +1593,7 @@ impl<'a> Resolver<'a> { if let Some(reason) = &deprecated.bare.reason { message += ": "; - message += reason; + message += reason.to_str(); } Diagnostic::warning() @@ -1621,7 +1611,7 @@ impl<'a> Resolver<'a> { fn handle_exposure( &self, index: DeclarationIndex, - identifier: &ast::Identifier, + identifier: ast::Identifier, origin_namespace: DeclarationIndex, ) -> Result<(), ResolutionError> { let entity = &self.session[index]; @@ -1745,7 +1735,7 @@ impl<'a> Resolver<'a> { // in Resolver::resolve_declaration fn reobtain_resolved_identifier( &self, - identifier: &ast::Identifier, + identifier: ast::Identifier, namespace: LocalDeclarationIndex, ) -> Target::Output { let index = self.session[namespace] @@ -1754,7 +1744,7 @@ impl<'a> Resolver<'a> { .binders .iter() .map(|index| index.local(self.session).unwrap()) - .find(|&index| &self.session[index].source == identifier) + .find(|&index| self.session[index].source == identifier) .unwrap(); let index = self .collapse_use_chain(index.global(self.session), identifier.span()) @@ -1791,8 +1781,8 @@ impl<'a> Resolver<'a> { if let (false, Some(identifier)) = (matches!(scope, Module(_)), query.identifier_head()) { match scope { FunctionParameter { parent, binder } => { - if binder == identifier { - Ok(Identifier::new(DeBruijnIndex(depth), identifier.clone())) + if *binder == identifier { + Ok(Identifier::new(DeBruijnIndex(depth), identifier)) } else { self.resolve_path_inside_function_with_depth( query, @@ -1807,11 +1797,9 @@ impl<'a> Resolver<'a> { .iter() .rev() .zip(depth..) - .find(|(binder, _)| binder == &identifier) + .find(|(&binder, _)| binder == identifier) { - Some((_, depth)) => { - Ok(Identifier::new(DeBruijnIndex(depth), identifier.clone())) - } + Some((_, depth)) => Ok(Identifier::new(DeBruijnIndex(depth), identifier)), None => self.resolve_path_inside_function_with_depth( query, parent, @@ -1829,7 +1817,7 @@ impl<'a> Resolver<'a> { ) .map_err(|error| { self.report_resolution_error_searching_lookalikes(error, |identifier, _| { - self.find_similarly_named(origin, identifier) + self.find_similarly_named(origin, identifier.to_str()) }) }) } @@ -1841,12 +1829,12 @@ impl<'a> Resolver<'a> { /// In the future, we might decide to find not one but several similar names /// but that would be computationally heavier. // @Beacon @Task don't suggest private bindings! - fn find_similarly_named_declaration<'s>( - &'s self, + fn find_similarly_named_declaration( + &self, identifier: &str, - predicate: impl Fn(&'s Entity) -> bool, + predicate: impl Fn(&Entity) -> bool, namespace: DeclarationIndex, - ) -> Option<&'s str> { + ) -> Option { self.session[namespace] .namespace() .unwrap() @@ -1854,8 +1842,8 @@ impl<'a> Resolver<'a> { .iter() .map(|&index| &self.session[index]) .filter(|entity| !entity.is_error() && predicate(entity)) - .map(|entity| entity.source.as_str()) - .find(|some_identifier| is_similar(some_identifier, identifier)) + .map(|entity| entity.source.bare()) + .find(|some_identifier| is_similar(some_identifier.to_str(), identifier)) } /// Find a similarly named binding in the scope. @@ -1870,7 +1858,7 @@ impl<'a> Resolver<'a> { &'s self, scope: &'s FunctionScope<'_>, identifier: &str, - ) -> Option<&'s str> { + ) -> Option { use FunctionScope::*; match scope { @@ -1880,8 +1868,8 @@ impl<'a> Resolver<'a> { module.global(self.session), ), FunctionParameter { parent, binder } => { - if is_similar(identifier, binder.as_str()) { - Some(binder.as_str()) + if is_similar(identifier, binder.to_str()) { + Some(binder.bare()) } else { self.find_similarly_named(parent, identifier) } @@ -1890,9 +1878,9 @@ impl<'a> Resolver<'a> { if let Some(binder) = binders .iter() .rev() - .find(|binder| is_similar(identifier, binder.as_str())) + .find(|binder| is_similar(identifier, binder.to_str())) { - Some(binder.as_str()) + Some(binder.bare()) } else { self.find_similarly_named(parent, identifier) } @@ -1902,14 +1890,14 @@ impl<'a> Resolver<'a> { fn report_resolution_error(&self, error: ResolutionError) -> ErasedReportedError { self.report_resolution_error_searching_lookalikes(error, |identifier, namespace| { - self.find_similarly_named_declaration(identifier, |_| true, namespace) + self.find_similarly_named_declaration(identifier.to_str(), |_| true, namespace) }) } - fn report_resolution_error_searching_lookalikes<'s>( + fn report_resolution_error_searching_lookalikes( &self, error: ResolutionError, - lookalike_finder: impl FnOnce(&str, DeclarationIndex) -> Option<&'s str>, + lookalike_finder: impl FnOnce(Atom, DeclarationIndex) -> Option, ) -> ErasedReportedError { match error { ResolutionError::Erased(error) => error, @@ -1940,19 +1928,21 @@ impl<'a> Resolver<'a> { Diagnostic::error() .code(ErrorCode::E021) .message(message) - .unlabeled_span(&identifier) - .with( - |error| match lookalike_finder(identifier.as_str(), namespace) { + .unlabeled_span(identifier) + .with(|error| { + let identifier = identifier.bare(); + + match lookalike_finder(identifier, namespace) { Some(lookalike) => error.help(format!( "a binding with a similar name exists in scope: {}", Lookalike { - actual: identifier.as_str(), + actual: identifier, lookalike, }, )), None => error, - }, - ) + } + }) .report(self.session.reporter()) } // @Beacon @Bug we cannot just assume this is circular exposure reach, @@ -1973,21 +1963,21 @@ impl<'a> Resolver<'a> { // @Question parent: *Local*DeclarationIndex? fn attempt_to_access_subbinder_of_non_namespace_error( &self, - binder: &ast::Identifier, + binder: ast::Identifier, kind: &EntityKind, parent: DeclarationIndex, - subbinder: &ast::Identifier, + subbinder: ast::Identifier, ) -> Diagnostic { // @Question should we also include lookalike namespaces that don't contain the // subbinding (displaying them in a separate help message?)? let similarly_named_namespace = self.find_similarly_named_declaration( - binder.as_str(), + binder.to_str(), |entity| { entity.namespace().map_or(false, |namespace| { namespace .binders .iter() - .any(|&index| &self.session[index].source == subbinder) + .any(|&index| self.session[index].source == subbinder) }) }, parent, @@ -2009,7 +1999,7 @@ impl<'a> Resolver<'a> { Some(lookalike) => it.help(format!( "a namespace with a similar name exists in scope containing the binding:\n {}", Lookalike { - actual: binder.as_str(), + actual: binder.bare(), lookalike }, )), @@ -2031,8 +2021,6 @@ impl<'a> Resolver<'a> { } pub trait ProgramEntryExt { - const PROGRAM_ENTRY_IDENTIFIER: &'static str = "main"; - fn look_up_program_entry(&self) -> Option; } @@ -2040,11 +2028,10 @@ impl ProgramEntryExt for Session<'_> { fn look_up_program_entry(&self) -> Option { let resolver = Resolver::new(self); - let identifier = - ast::Identifier::new_unchecked(Self::PROGRAM_ENTRY_IDENTIFIER.into(), default()); + let binder = ast::Identifier::new_unchecked(PROGRAM_ENTRY, default()); let index = resolver .resolve_identifier( - &identifier, + binder, PathResolutionContext::new(self.component().root()) .ignore_exposure() .allow_deprecated(), @@ -2056,7 +2043,7 @@ impl ProgramEntryExt for Session<'_> { return None; } - Some(Identifier::new(index, entity.source.clone())) + Some(Identifier::new(index, entity.source)) } } @@ -2273,16 +2260,17 @@ fn is_similar(identifier: &str, other_identifier: &str) -> bool { strsim::levenshtein(other_identifier, identifier) <= std::cmp::max(identifier.len(), 3) / 3 } -struct Lookalike<'a> { - actual: &'a str, - lookalike: &'a str, +struct Lookalike { + actual: Atom, + lookalike: Atom, } -impl fmt::Display for Lookalike<'_> { +impl fmt::Display for Lookalike { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use difference::{Changeset, Difference}; - let changeset = Changeset::new(self.actual, self.lookalike, ""); + let actual = self.actual.to_str(); + let changeset = Changeset::new(actual, self.lookalike.to_str(), ""); let mut purely_additive = true; write!(f, "‘")?; @@ -2299,7 +2287,7 @@ impl fmt::Display for Lookalike<'_> { write!(f, "’")?; - if !(purely_additive || self.actual.width() == 1 && changeset.distance == 2) { + if !(purely_additive || actual.width() == 1 && changeset.distance == 2) { write!(f, " ({})", changeset.auto_colored())?; } @@ -2354,15 +2342,14 @@ impl From for DefinitionError { trait ResolutionTarget { type Output; - fn output(index: DeclarationIndex, identifier: &ast::Identifier) -> Self::Output; + fn output(index: DeclarationIndex, identifier: ast::Identifier) -> Self::Output; fn output_bare_path_hanger( hanger: &ast::Hanger, index: DeclarationIndex, ) -> Result; - fn validate_identifier(identifier: &ast::Identifier, entity: &Entity) - -> Result<(), Diagnostic>; + fn validate_identifier(identifier: ast::Identifier, entity: &Entity) -> Result<(), Diagnostic>; } mod target { @@ -2374,7 +2361,7 @@ mod target { impl ResolutionTarget for Any { type Output = DeclarationIndex; - fn output(index: DeclarationIndex, _: &ast::Identifier) -> Self::Output { + fn output(index: DeclarationIndex, _: ast::Identifier) -> Self::Output { index } @@ -2385,7 +2372,7 @@ mod target { Ok(index) } - fn validate_identifier(_: &ast::Identifier, _: &Entity) -> Result<(), Diagnostic> { + fn validate_identifier(_: ast::Identifier, _: &Entity) -> Result<(), Diagnostic> { Ok(()) } } @@ -2396,8 +2383,8 @@ mod target { impl ResolutionTarget for Value { type Output = Identifier; - fn output(index: DeclarationIndex, identifier: &ast::Identifier) -> Self::Output { - Identifier::new(index, identifier.clone()) + fn output(index: DeclarationIndex, identifier: ast::Identifier) -> Self::Output { + Identifier::new(index, identifier) } fn output_bare_path_hanger( @@ -2408,11 +2395,11 @@ mod target { } fn validate_identifier( - identifier: &ast::Identifier, + identifier: ast::Identifier, entity: &Entity, ) -> Result<(), Diagnostic> { if entity.is_module() { - return Err(module_used_as_a_value_error(identifier.as_spanned_str())); + return Err(module_used_as_a_value_error(identifier.into_inner())); } Ok(()) @@ -2424,7 +2411,7 @@ mod target { impl ResolutionTarget for Module { type Output = DeclarationIndex; - fn output(index: DeclarationIndex, _: &ast::Identifier) -> Self::Output { + fn output(index: DeclarationIndex, _: ast::Identifier) -> Self::Output { index } @@ -2436,7 +2423,7 @@ mod target { } fn validate_identifier( - identifier: &ast::Identifier, + identifier: ast::Identifier, entity: &Entity, ) -> Result<(), Diagnostic> { // @Task print absolute path! diff --git a/compiler/server/src/lib.rs b/compiler/server/src/lib.rs index 85bc2782..edf09bce 100644 --- a/compiler/server/src/lib.rs +++ b/compiler/server/src/lib.rs @@ -35,7 +35,7 @@ use tower_lsp::{ Client, }; use utilities::path::CanonicalPath; -use utilities::{ComponentIndex, FormatError, HashMap}; +use utilities::{ComponentIndex, FormatError, HashMap, PROGRAM_ENTRY}; mod diagnostics; mod span; @@ -334,9 +334,8 @@ fn build_unit(unit: BuildUnit, session: &mut Session<'_>) -> Result) -> Result Option<&hir::Identifier>; + fn find_binding(&self, byte_index: ByteIndex) -> Option; } #[allow(clippy::match_same_arms)] // @Temporary impl FindBinding for hir::Declaration { - fn find_binding(&self, byte_index: ByteIndex) -> Option<&hir::Identifier> { + fn find_binding(&self, byte_index: ByteIndex) -> Option { use hir::BareDeclaration::*; // @Question do we need this check? @@ -394,8 +393,8 @@ impl FindBinding for hir::Declaration { // @Question I wonder if that actually works ^^ // @Note I assume this won't work if we click on path segments that aren't the last segment if use_.target.span().contains(byte_index) { - Some(&use_.target) - } else if let Some(binder) = &use_.binder && binder.span().contains(byte_index) { + Some(use_.target) + } else if let Some(binder) = use_.binder && binder.span().contains(byte_index) { Some(binder) } else { None @@ -410,7 +409,7 @@ impl FindBinding for hir::Declaration { impl FindBinding for hir::Expression { // @Task don't use contains but a function that returns an Ordering!! so we can // know if we should jump to the next thingy - fn find_binding(&self, byte_index: ByteIndex) -> Option<&hir::Identifier> { + fn find_binding(&self, byte_index: ByteIndex) -> Option { use hir::BareExpression::*; // @Question do we need this check? @@ -441,7 +440,7 @@ impl FindBinding for hir::Expression { Text(_) => None, // @Task Binding(binding) => { if binding.0.span().contains(byte_index) { - Some(&binding.0) + Some(binding.0) } else { None } diff --git a/compiler/session/src/component.rs b/compiler/session/src/component.rs index 2417f414..ce626d52 100644 --- a/compiler/session/src/component.rs +++ b/compiler/session/src/component.rs @@ -45,7 +45,7 @@ impl Component { const NAME: &str = "test"; let name = Word::new_unchecked(NAME.into()); - let mut component = Self::new(name.clone(), ComponentIndex(0), None, HashMap::default()); + let mut component = Self::new(name, ComponentIndex(0), None, HashMap::default()); component.bindings.insert(Entity { source: Spanned::bare(name).into(), parent: None, @@ -57,8 +57,8 @@ impl Component { component } - pub fn name(&self) -> &Word { - &self.name + pub fn name(&self) -> Word { + self.name } pub fn index(&self) -> ComponentIndex { @@ -82,7 +82,7 @@ impl Component { pub fn outline(&self) -> ComponentOutline { ComponentOutline { - name: self.name.clone(), + name: self.name, index: self.index, } } diff --git a/compiler/session/src/interfaceable.rs b/compiler/session/src/interfaceable.rs index f77603b2..77123d3c 100644 --- a/compiler/session/src/interfaceable.rs +++ b/compiler/session/src/interfaceable.rs @@ -16,7 +16,7 @@ impl InterfaceableBindingExt for interfaceable::Type { use special::Type::*; macro is_special($binding:ident, $name:ident) { - session.specials().is(&$binding.0, $name) + session.specials().is($binding.0, $name) } Some(match &expression.bare { @@ -77,7 +77,7 @@ impl InterfaceableBindingExt for interfaceable::Value { use special::Constructor::*; macro is_special($binding:ident, $name:ident) { - session.specials().is(&$binding.0, $name) + session.specials().is($binding.0, $name) } Some(match &expression.bare { @@ -175,7 +175,6 @@ impl InterfaceableBindingExt for interfaceable::Value { } } -#[allow(dead_code)] // @Temporary fn application(callee: Expression, argument: Expression) -> Expression { Expression::bare( hir::Application { diff --git a/compiler/session/src/lib.rs b/compiler/session/src/lib.rs index 4470e959..64d5faea 100644 --- a/compiler/session/src/lib.rs +++ b/compiler/session/src/lib.rs @@ -92,7 +92,7 @@ impl<'ctx> Session<'ctx> { binder, match style { Implicit { namespace } => Implicit { - namespace: namespace.map(|namespace| self.component[namespace].source.as_str()), + namespace: namespace.map(|namespace| self.component[namespace].source.bare()), }, Explicit { name } => Explicit { name }, }, @@ -232,7 +232,7 @@ impl Context { handler: impl FnOnce(unit::BuildUnit, &mut Session<'_>) -> T, ) -> T { let component = Component::new( - unit.name.clone(), + unit.name, unit.index, None, std::mem::take(&mut unit.dependencies), diff --git a/compiler/session/src/unit.rs b/compiler/session/src/unit.rs index 3cc429f7..def198f3 100644 --- a/compiler/session/src/unit.rs +++ b/compiler/session/src/unit.rs @@ -22,7 +22,7 @@ impl BuildUnit { // @Temporary pub fn outline(&self) -> ComponentOutline { ComponentOutline { - name: self.name.clone(), + name: self.name, index: self.index, } } diff --git a/compiler/token/src/lib.rs b/compiler/token/src/lib.rs index 87f31172..c11dfa6f 100644 --- a/compiler/token/src/lib.rs +++ b/compiler/token/src/lib.rs @@ -12,7 +12,7 @@ mod word; pub type Token = Spanned; -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum BareToken { // // Comment-Like Tokens @@ -86,7 +86,7 @@ pub enum BareToken { impl BareToken { // @Task move to lexer - pub const fn introduces_indented_section(&self) -> bool { + pub const fn introduces_indented_section(self) -> bool { matches!(self, Do | Of) } } diff --git a/compiler/token/src/word.rs b/compiler/token/src/word.rs index d491d6b9..e20ac685 100644 --- a/compiler/token/src/word.rs +++ b/compiler/token/src/word.rs @@ -1,7 +1,7 @@ use std::fmt; use utilities::Atom; -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct Word(Atom); impl Word { @@ -13,19 +13,19 @@ impl Word { self.0 } - pub fn as_str(&self) -> &str { - &self.0 + pub fn to_str(self) -> &'static str { + self.0.to_str() } } impl fmt::Debug for Word { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}w", self.as_str()) + write!(f, "{:?}w", self.to_str()) } } impl fmt::Display for Word { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.as_str()) + write!(f, "{}", self.to_str()) } } diff --git a/compiler/typer/src/interpreter.rs b/compiler/typer/src/interpreter.rs index ad9b88bb..11f0b442 100644 --- a/compiler/typer/src/interpreter.rs +++ b/compiler/typer/src/interpreter.rs @@ -32,7 +32,7 @@ use utilities::debugged; /// Run the entry point of the given executable component. pub fn evaluate_main_function(session: &Session<'_>) -> Result { Interpreter::new(session).evaluate_expression( - session.look_up_program_entry().unwrap().into_item(), + session.look_up_program_entry().unwrap().to_item(), Context::new(&FunctionScope::Module), ) } @@ -59,9 +59,9 @@ impl<'a> Interpreter<'a> { // @Bug we currently don't support zero-arity intrinsic functions Ok(match expression.clone().bare { - Binding(binding) if self.session.specials().is(&binding.0, Type::Type) => expression, + Binding(binding) if self.session.specials().is(binding.0, Type::Type) => expression, Binding(binding) => { - match self.look_up_value(&binding.0) { + match self.look_up_value(binding.0) { // @Question is this normalization necessary? I mean, yes, we got a new scope, // but the thing in the previous was already normalized (well, it should have been // at least). I guess it is necessary because it can contain parameters which could not @@ -127,13 +127,13 @@ impl<'a> Interpreter<'a> { context, )? } - Binding(binding) if self.is_intrinsic_function(&binding.0) => self + Binding(binding) if self.is_intrinsic_function(binding.0) => self .evaluate_expression( Expression::new( expression.attributes, expression.span, hir::IntrinsicApplication { - callee: binding.0.clone(), + callee: binding.0, arguments: vec![argument], } .into(), @@ -159,7 +159,7 @@ impl<'a> Interpreter<'a> { expression.attributes, expression.span, hir::IntrinsicApplication { - callee: application.callee.clone(), + callee: application.callee, arguments: { let mut arguments = application.arguments.clone(); arguments.push(argument); @@ -192,7 +192,7 @@ impl<'a> Interpreter<'a> { expression.span, hir::PiType { explicitness: pi.explicitness, - binder: pi.binder.clone(), + binder: pi.binder, domain, codomain, } @@ -227,7 +227,7 @@ impl<'a> Interpreter<'a> { expression.attributes, expression.span, hir::Lambda { - binder: lambda.binder.clone(), + binder: lambda.binder, domain: Some(parameter_type), body, codomain: body_type, @@ -263,12 +263,12 @@ impl<'a> Interpreter<'a> { Binding(scrutinee) => { // @Temporary hack (bc we do not follow any principled implementation right now): // a case analysis is indirectly neutral if the subject is a neutral binding - if self.look_up_value(&scrutinee.0).is_neutral() { + if self.look_up_value(scrutinee.0).is_neutral() { return Ok(Expression::new( expression.attributes, expression.span, hir::CaseAnalysis { - scrutinee: scrutinee.0.clone().into_item(), + scrutinee: scrutinee.0.to_item(), cases: analysis.cases.clone(), } .into(), @@ -342,13 +342,13 @@ impl<'a> Interpreter<'a> { .into_iter() .map(|argument| self.evaluate_expression(argument, context)) .collect::, _>>()?; - self.apply_intrinsic_function(application.callee.clone(), arguments.clone())? + self.apply_intrinsic_function(application.callee, arguments.clone())? .unwrap_or_else(|| { Expression::new( expression.attributes, expression.span, hir::IntrinsicApplication { - callee: application.callee.clone(), + callee: application.callee, arguments, } .into(), @@ -431,7 +431,7 @@ impl<'a> Interpreter<'a> { // @Question what about explicitness? (PiType(pi0), PiType(pi1)) => { self.equals(&pi0.domain, &pi1.domain, scope)? - && match (pi0.binder.clone(), pi1.binder.clone()) { + && match (pi0.binder, pi1.binder) { (Some(_), Some(_)) => self.equals( &pi0.codomain, &pi1.codomain, @@ -505,7 +505,7 @@ impl<'a> Interpreter<'a> { }) } - pub(crate) fn look_up_value(&self, binder: &Identifier) -> ValueView { + pub(crate) fn look_up_value(&self, binder: Identifier) -> ValueView { use hir::Index::*; match binder.index { @@ -517,7 +517,7 @@ impl<'a> Interpreter<'a> { pub(crate) fn look_up_type( &self, - binder: &Identifier, + binder: Identifier, scope: &FunctionScope<'_>, ) -> Option { use hir::Index::*; @@ -529,7 +529,7 @@ impl<'a> Interpreter<'a> { } } - pub(crate) fn is_intrinsic_function(&self, binder: &Identifier) -> bool { + pub(crate) fn is_intrinsic_function(&self, binder: Identifier) -> bool { use hir::Index::*; match binder.index { @@ -553,7 +553,7 @@ impl Substitute for Expression { (Binding(binding), Shift(amount)) => hir::Expression::new( self.attributes, self.span, - hir::Binding(binding.0.clone().shift(amount)).into(), + hir::Binding(binding.0.shift(amount)).into(), ), // @Beacon @Question @Bug (Binding(binding), Use(substitution, expression)) => { @@ -563,7 +563,7 @@ impl Substitute for Expression { hir::Expression::new( expression.attributes, expression.span, - hir::Binding(binding.0.clone().unshift()).into(), + hir::Binding(binding.0.unshift()).into(), ) .substitute(*substitution) } @@ -623,10 +623,10 @@ impl Substitute for Expression { expression: pi.codomain.clone(), substitution: match &pi.binder { Some(parameter) => { - let binder = parameter.as_innermost(); + let binder = parameter.to_innermost(); // @Question what about the attributes of the binder? - Use(Box::new(Shift(1).compose(substitution)), binder.into_item()) + Use(Box::new(Shift(1).compose(substitution)), binder.to_item()) } None => substitution, }, @@ -639,7 +639,7 @@ impl Substitute for Expression { self.span, hir::PiType { explicitness: pi.explicitness, - binder: pi.binder.clone(), + binder: pi.binder, domain, codomain, } @@ -666,11 +666,11 @@ impl Substitute for Expression { hir::Substituted { expression: type_, substitution: { - let binder = lambda.binder.as_innermost(); + let binder = lambda.binder.to_innermost(); // @Question what about the attributes of the binder? Use( Box::new(Shift(1).compose(substitution.clone())), - binder.into_item(), + binder.to_item(), ) }, } @@ -684,10 +684,10 @@ impl Substitute for Expression { hir::Substituted { expression: lambda.body.clone(), substitution: { - let binder = lambda.binder.as_innermost(); + let binder = lambda.binder.to_innermost(); // @Question what about the attributes of the binder? - Use(Box::new(Shift(1).compose(substitution)), binder.into_item()) + Use(Box::new(Shift(1).compose(substitution)), binder.to_item()) }, } .into(), @@ -697,7 +697,7 @@ impl Substitute for Expression { self.attributes, self.span, hir::Lambda { - binder: lambda.binder.clone(), + binder: lambda.binder, domain: parameter_type_annotation, codomain: body_type_annotation, body, @@ -742,7 +742,7 @@ impl Substitute for Expression { self.attributes, self.span, hir::IntrinsicApplication { - callee: application.callee.clone(), + callee: application.callee, arguments: application .arguments .iter() diff --git a/compiler/typer/src/lib.rs b/compiler/typer/src/lib.rs index b4d146ae..7811b4cb 100644 --- a/compiler/typer/src/lib.rs +++ b/compiler/typer/src/lib.rs @@ -78,12 +78,12 @@ impl<'sess, 'ctx> Typer<'sess, 'ctx> { attributes: declaration.attributes.clone(), bare: if declaration.attributes.has(AttributeName::Intrinsic) { BareDefinition::IntrinsicFunction { - binder: function.binder.clone(), + binder: function.binder, type_: function.type_annotation.clone(), } } else { BareDefinition::Function { - binder: function.binder.clone(), + binder: function.binder, type_: function.type_annotation.clone(), value: Some(function.expression.clone().unwrap()), } @@ -95,7 +95,7 @@ impl<'sess, 'ctx> Typer<'sess, 'ctx> { self.evaluate_definition(Definition { attributes: declaration.attributes.clone(), bare: BareDefinition::Data { - binder: type_.binder.clone(), + binder: type_.binder, type_: type_.type_annotation.clone(), }, })?; @@ -107,7 +107,7 @@ impl<'sess, 'ctx> Typer<'sess, 'ctx> { self.start_infer_types_in_declaration( constructor, Context { - owning_data_type: Some(type_.binder.clone()), + owning_data_type: Some(type_.binder), }, ) .stain(health); @@ -122,7 +122,7 @@ impl<'sess, 'ctx> Typer<'sess, 'ctx> { self.evaluate_definition(Definition { attributes: declaration.attributes.clone(), bare: BareDefinition::Constructor { - binder: constructor.binder.clone(), + binder: constructor.binder, type_: constructor.type_annotation.clone(), owner_data_type, }, @@ -252,10 +252,7 @@ impl<'sess, 'ctx> Typer<'sess, 'ctx> { interpreter::Context::new(&FunctionScope::Module), )?; - self.assert_constructor_is_instance_of_type( - type_.clone(), - data.clone().into_item(), - )?; + self.assert_constructor_is_instance_of_type(type_.clone(), data.to_item())?; self.carry_out_definition(Definition { attributes: definition.attributes, @@ -440,12 +437,12 @@ expected type ‘{}’ Ok(match expression.bare { // @Task explanation why we need to special-case Type here! - Binding(binding) if self.session.specials().is(&binding.0, Type::Type) => { + Binding(binding) if self.session.specials().is(binding.0, Type::Type) => { self.session.require_special(Type::Type, None)? } Binding(binding) => self .interpreter() - .look_up_type(&binding.0, scope) + .look_up_type(binding.0, scope) .ok_or(OutOfOrderBinding)?, Number(number) => self .session @@ -492,7 +489,7 @@ expected type ‘{}’ expression.span, hir::PiType { explicitness: Explicitness::Explicit, - binder: Some(lambda.binder.clone()), + binder: Some(lambda.binder), domain: parameter_type, codomain: inferred_body_type, } @@ -553,7 +550,7 @@ expected type ‘{}’ OutOfOrderBinding => unreachable!(), })?; - match pi.binder.clone() { + match pi.binder { Some(_) => Expression::new( default(), default(), @@ -659,7 +656,7 @@ expected type ‘_ -> _’ } Binding(binding) => { let constructor_type = - self.interpreter().look_up_type(&binding.0, scope).unwrap(); + self.interpreter().look_up_type(binding.0, scope).unwrap(); self.it_is_actual( subject_type.clone(), @@ -689,7 +686,7 @@ expected type ‘_ -> _’ (Number(_) | Text(_), _argument) => todo!(), (Binding(binding), _argument) => { let _constructor_type = - self.interpreter().look_up_type(&binding.0, scope).unwrap(); + self.interpreter().look_up_type(binding.0, scope).unwrap(); todo!(); } @@ -701,7 +698,7 @@ expected type ‘_ -> _’ "binder ‘{}’ used in callee position inside pattern", binder.0 )) - .unlabeled_span(&binder.0) + .unlabeled_span(binder.0) .help("consider referring to a concrete binding") .report(self.session.reporter()) .into()); diff --git a/compiler/utilities/Cargo.toml b/compiler/utilities/Cargo.toml index 2a164e5b..4ca6ef26 100644 --- a/compiler/utilities/Cargo.toml +++ b/compiler/utilities/Cargo.toml @@ -11,4 +11,3 @@ index_map = { path = "../../project/library/index_map" } num-bigint = "0.4.3" rustc-hash = "1.1.0" smallvec = { version = "1.10.0", features = ["const_generics"] } -string_cache = { version = "0.8.7", default-features = false } diff --git a/compiler/utilities/src/atom.rs b/compiler/utilities/src/atom.rs new file mode 100644 index 00000000..090042fb --- /dev/null +++ b/compiler/utilities/src/atom.rs @@ -0,0 +1,211 @@ +use crate::HashMap; +use index_map::{Index, IndexMap}; +use std::{ + fmt, + iter::zip, + sync::{LazyLock, Mutex}, +}; + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct Atom(u32); + +impl Atom { + pub fn new(value: &str) -> Self { + Interner::the().lock().unwrap().intern(value) + } + + pub fn from_owned(value: String) -> Self { + Interner::the().lock().unwrap().intern_owned(value) + } + + pub fn to_str(self) -> &'static str { + Interner::the().lock().unwrap().get(self) + } +} + +impl Index for Atom { + fn new(index: usize) -> Self { + Self(index.try_into().unwrap()) + } + + fn value(self) -> usize { + self.0 as _ + } +} + +impl fmt::Debug for Atom { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.to_str()) + } +} + +impl fmt::Display for Atom { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.to_str()) + } +} + +impl From<&str> for Atom { + fn from(value: &str) -> Self { + Self::new(value) + } +} + +impl From for Atom { + fn from(value: String) -> Self { + Self::from_owned(value) + } +} + +// Positive ordering impls would be a pitfall: +// +// * Comparison by index would be fast but highly unintuitive and in most cases not what +// the user wants. +// * Comparison by string would be rather slow and the user should explicitly opt-in +// via `Atom::to_str`. +impl !PartialOrd for Atom {} +impl !Ord for Atom {} + +struct Interner { + atoms: HashMap<&'static str, Atom>, + strings: IndexMap, +} + +impl Interner { + fn the() -> &'static Mutex { + static SELF: LazyLock> = LazyLock::new(|| Mutex::new(Interner::new())); + + &SELF + } + + fn with(values: Vec<&'static str>) -> Self { + Self { + atoms: zip(&values, 0..) + .map(|(&string, atom)| (string, Atom(atom))) + .collect(), + strings: IndexMap::bare(values), + } + } + + fn intern(&mut self, value: &str) -> Atom { + if let Some(&atom) = self.atoms.get(value) { + return atom; + } + + self.insert(String::leak(String::from(value))) + } + + fn intern_owned(&mut self, value: String) -> Atom { + if let Some(&atom) = self.atoms.get(&*value) { + return atom; + } + + self.insert(String::leak(value)) + } + + fn insert(&mut self, value: &'static str) -> Atom { + let atom = self.strings.insert(value); + self.atoms.insert(value, atom); + atom + } + + fn get(&self, atom: Atom) -> &'static str { + self.strings[atom] + } +} + +macro_rules! atoms { + ($( $atom:ident $( => $string:literal )? ),* $(,)?) => { + #[allow(non_upper_case_globals)] + impl Atom { + $( + pub const $atom: Self = Self(${ index() }); + )* + } + + impl Interner { + + + fn new() -> Self { + Self::with(vec![ + $( atoms!(@str $atom $( $string )?) ),* + ]) + } + } + }; + (@str $atom:ident $string:literal) => { $string }; + (@str $atom:ident) => { stringify!($atom) }; +} + +atoms! { + abstract_ => "abstract", + add, + allow, + Bool, + concat, + deny, + deprecated, + depth, + display, + divide, + doc, + empty, + equal, + false_ => "false", + forbid, + greater_equal => "greater-equal", + greater, + if_ => "if", + ignore, + include, + Int, + Int32, + Int64, + intrinsic, + io, + IO, + known, + less_equal => "less-equal", + less, + lint, + List, + location, + main, + moving, + multiply, + name, + nat, + Nat, + nat32, + Nat32, + Nat64, + none, + Option, + path, + prepend, + print, + public, + reach, + reason, + recursion_limit => "recursion-limit", + replacement, + some, + static_ => "static", + statistics, + subtract, + successor, + test, + text, + Text, + true_ => "true", + Tuple, + Type, + unchecked_subtract => "unchecked-subtract", + underscore => "_", + unit, + Unit, + unsafe_ => "unsafe", + unstable, + Vector, + warn, +} diff --git a/compiler/utilities/src/lib.rs b/compiler/utilities/src/lib.rs index aa53dbe3..ad03726f 100644 --- a/compiler/utilities/src/lib.rs +++ b/compiler/utilities/src/lib.rs @@ -4,22 +4,26 @@ decl_macro, never_type_fallback, never_type, - anonymous_lifetime_in_impl_trait + lazy_cell, + string_leak, + macro_metavar_expr, + negative_impls )] +pub use atom::Atom; use colored::Colorize; use difference::{Changeset, Difference}; pub use num_bigint::{BigInt as Int, BigUint as Nat}; pub use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; pub use smallvec::smallvec; use std::{cell::Cell, ffi::OsStr, fmt, path::Path}; -pub use string_cache::DefaultAtom as Atom; +pub mod atom; pub mod cycle; pub mod path; -// @Question should this reside somewhere else? -pub const FILE_EXTENSION: &str = "lushui"; +pub const FILE_EXTENSION: &str = "lushui"; // @Question worth to be an Atom? +pub const PROGRAM_ENTRY: Atom = Atom::main; pub type Str = std::borrow::Cow<'static, str>; diff --git a/project/library/index_map/src/lib.rs b/project/library/index_map/src/lib.rs index fccb36e3..ddeb2eea 100644 --- a/project/library/index_map/src/lib.rs +++ b/project/library/index_map/src/lib.rs @@ -19,10 +19,10 @@ impl IndexMap { #[must_use] pub fn with_capacity(capacity: usize) -> Self { - Self::from_vec(Vec::with_capacity(capacity)) + Self::bare(Vec::with_capacity(capacity)) } - fn from_vec(values: Vec) -> Self { + pub fn bare(values: Vec) -> Self { Self { values, _marker: PhantomData, @@ -116,7 +116,7 @@ impl IndexMap { impl Default for IndexMap { fn default() -> Self { - Self::from_vec(Vec::new()) + Self::bare(Vec::new()) } } diff --git a/test/ui/test/packages/circular-components-in-same-package/package.stderr b/test/ui/test/packages/circular-components-in-same-package/package.stderr index 88a7fc5d..98df3866 100644 --- a/test/ui/test/packages/circular-components-in-same-package/package.stderr +++ b/test/ui/test/packages/circular-components-in-same-package/package.stderr @@ -4,7 +4,7 @@ error: the library component ‘loops’ is circular 10 │ dependencies: { loops: {} }, │ ═════ -error: the library components ‘cycle1component0’, ‘cycle1component1’ and ‘cycle1component2’ are circular +error: the library components ‘cycle1component1’, ‘cycle1component2’ and ‘cycle1component0’ are circular ┌─ ${TEST_FOLDER}/packages/circular-components-in-same-package/package.metadata:17:25 │ 17 │ dependencies: { cycle1component1: {} },