diff --git a/Cargo.lock b/Cargo.lock index 1b1d7a9fe..e887677b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -863,6 +863,18 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "erlang-abstract-format" +version = "1.0.0" +dependencies = [ + "ecow", + "erlang-term-format", + "itertools", + "num-bigint", + "num-traits", + "regex", +] + [[package]] name = "erlang-term-format" version = "1.0.0" @@ -1233,6 +1245,7 @@ dependencies = [ "debug-ignore", "dirs-next", "ecow", + "erlang-abstract-format", "flate2", "futures", "gen-lsp-types", diff --git a/Cargo.toml b/Cargo.toml index 00deb83b0..b941fb9a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ members = [ "pretty-arena", "format", "erlang-term-format", + "erlang-abstract-format", ] # common dependencies diff --git a/compiler-core/Cargo.toml b/compiler-core/Cargo.toml index 588459d79..d875fc9f1 100644 --- a/compiler-core/Cargo.toml +++ b/compiler-core/Cargo.toml @@ -60,6 +60,7 @@ flate2.workspace = true futures.workspace = true hexpm = { path = "../hexpm" } pretty-arena = { path = "../pretty-arena" } +erlang-abstract-format = { path = "../erlang-abstract-format" } http.workspace = true im.workspace = true itertools.workspace = true diff --git a/compiler-core/src/ast/typed.rs b/compiler-core/src/ast/typed.rs index a04b5cc4e..fcd2d5fd2 100644 --- a/compiler-core/src/ast/typed.rs +++ b/compiler-core/src/ast/typed.rs @@ -1021,6 +1021,8 @@ impl TypedExpr { matches!(self, Self::Pipeline { .. }) } + /// Returns true if this function is guaranteed to not have any side + /// effects. pub fn is_pure_value_constructor(&self) -> bool { match self { TypedExpr::Int { .. } @@ -1046,10 +1048,8 @@ impl TypedExpr { // long as it's not called! TypedExpr::ModuleSelect { .. } => true, - // A pipeline is a pure value constructor if its last step is a record builder, - // or a call to a pure function. For example: - // - `wibble() |> wobble() |> Ok` - // - `"hello" |> fn(s) { s <> " world!" }` + // A pipeline is a pure value constructor if all of its steps are + // pure. TypedExpr::Pipeline { first_value, assignments, @@ -1063,6 +1063,9 @@ impl TypedExpr { && finally.is_pure_value_constructor() } + // A function is a pure value constructor if it is a record builder, + // or the called function is understood to be pure. Also all of its + // arguments must be pure value constructors! TypedExpr::Call { fun, arguments, .. } => { (fun.is_record_literal() || fun.called_function_purity().is_pure()) && arguments @@ -1091,9 +1094,9 @@ impl TypedExpr { && clauses.iter().all(|c| c.then.is_pure_value_constructor()) } - // `panic`, `todo`, and placeholders are never considered pure value constructors, - // we don't want to raise a warning for an unused value if it's one - // of those. + // `panic`, `todo`, and placeholders are never considered pure value + // constructors, we don't want to raise a warning for an unused + // value if it's one of those. TypedExpr::Todo { .. } | TypedExpr::Panic { .. } | TypedExpr::Echo { .. } diff --git a/compiler-core/src/codegen.rs b/compiler-core/src/codegen.rs index 0fc208394..dd9010128 100644 --- a/compiler-core/src/codegen.rs +++ b/compiler-core/src/codegen.rs @@ -61,7 +61,7 @@ impl<'a> Erlang<'a> { let line_numbers = LineNumbers::new(&module.code); let output = erlang::module(&module.ast, &line_numbers, root); tracing::debug!(name = ?name, "Generated Erlang module"); - writer.write(&path, &output?) + writer.write(&path, &output) } fn erlang_record_headers( diff --git a/compiler-core/src/erlang.rs b/compiler-core/src/erlang.rs index 5029175d2..2697a6c48 100644 --- a/compiler-core/src/erlang.rs +++ b/compiler-core/src/erlang.rs @@ -5,16 +5,13 @@ mod pattern; #[cfg(test)] mod tests; -use crate::build::{Target, module_erlang_name}; -use crate::erlang::pattern::{PatternPrinter, StringPatternAssignment}; -use crate::strings::{convert_string_escape_chars, to_snake_case}; -use crate::type_::is_prelude_module; +use crate::build::Target; +use crate::erlang::pattern::{AliasedLiteral, PatternGenerator}; +use crate::strings::to_snake_case; +use crate::type_::{self, is_prelude_module}; use crate::{ - Result, - ast::{Function, *}, - docvec, + ast::*, line_numbers::LineNumbers, - pretty::*, type_::{ ModuleValueConstructor, PatternConstructor, Type, TypeVar, TypedCallArg, ValueConstructor, ValueConstructorVariant, @@ -22,19 +19,84 @@ use crate::{ }; use camino::Utf8Path; use ecow::{EcoString, eco_format}; +use erlang_abstract_format::{BitArraySegmentSpecifier, Eaf, ErlangModuleName, PrettyEaf}; use itertools::Itertools; use num_bigint::BigInt; use num_traits::Signed; -use regex::{Captures, Regex}; +use regex::Regex; +use std::collections::VecDeque; use std::sync::OnceLock; use std::{collections::HashMap, ops::Deref, sync::Arc}; -use vec1::Vec1; -const INDENT: isize = 4; -const MAX_COLUMNS: isize = 80; +/// This is an open runtime error to which more fields can still be added. +#[must_use] +struct RuntimeError { + /// This is the map that is going to be thrown by the `erlang:error` call. + error_map: erlang_abstract_format::Map, + /// This is the call to `erlang:error` that will throw the error, with the + /// map as an argument. + erlang_error_call: erlang_abstract_format::Call, +} + +/// Represents all the different kind of runtime errors that Gleam can raise. +enum RuntimeErrorKind { + Todo, + Panic, + Assert, + LetAssert, +} + +impl RuntimeErrorKind { + fn default_error_message(&self) -> &'static str { + match self { + RuntimeErrorKind::Panic => "`panic` expression evaluated.", + RuntimeErrorKind::Assert => "Assertion failed.", + RuntimeErrorKind::LetAssert => "Pattern match failed, no pattern matched the value.", + RuntimeErrorKind::Todo => { + "`todo` expression evaluated. This code has not yet been implemented." + } + } + } +} + +enum EchoPrintedValue<'a> { + /// We're printing the result of a pipeline step. + PipeStep { + /// This is the name that was given to the variable holding the value + /// we have to print. + name: EcoString, + }, + /// We're printing any arbitrary expression. + Expression { value: &'a TypedExpr }, +} + +/// This describes how an expression that is used in a Gleam's function call +/// should be called in the Erlang generated code. +enum FunctionCall<'a> { + /// We're calling a function from the given module. + /// It might be the same module we're generating code for, so the + /// qualification might not be needed at all; remember to check that! + /// + /// ```erl + /// io:println("wibble") + /// ``` + /// + Call { module: &'a str, name: &'a str }, + + /// The expression is not a module level function and can be called directly + /// like thie: + /// + /// ```erl + /// SomeVariable("wibble"), + /// fun() -> nil end(). + /// ``` + DirectCall, -fn module_name_atom(module: &str) -> Document<'static> { - atom_string(module.replace('/', "@").into()) + /// This is actually not a call but rather needs to build a tuple with the + /// given tag. + /// This is needed for records: those are function calls in Gleam, but + /// simple tuples on the Erlang side. + BuildRecord { name: &'a str }, } /// This is a structure used to generate code for an Erlang module. @@ -44,18 +106,10 @@ pub struct Generator<'a> { module: &'a TypedModule, line_numbers: &'a LineNumbers, - /// The relative source path to the module that's gonna be used in `-file` - /// attributes in the generated Erlang code. + /// The relative source path to the module that's gonna be used in error + /// messages in the generated Erlang code. module_source_path: EcoString, - /// This will be true if we're generating `-doc` attributes for functions. - /// We need to know this to add a little `-if` macro to define `doc` in a - /// way that's compatible with older OTP versions. - /// - /// We could drop this once the `-doc` attribute has been available for at - /// least a couple of major versions. - needs_doc_attribute: bool, - /// Wether `echo` has been used in this module, we're gonna need to know /// this in order to add the code needed by the pretty printing. echo_used: bool, @@ -67,12 +121,71 @@ pub struct Generator<'a> { struct FunctionGenerator<'a, 'generator> { /// The name of the function we're generating code for. function_name: &'a str, - current_scope_vars: im::HashMap, - erl_function_scope_vars: im::HashMap, /// A reference to the module generator, this is needed to take care of some /// global state shared by all the functions. module_generator: &'generator mut Generator<'a>, + + /// This maps from variable origin in the Gleam code to the name it was + /// assigned to it in the generated Erlang code. + /// + /// Erlang doesn't allow shadowing existing variables, so it's not always + /// the case that a variable named `wibble` in Gleam is going to correspond + /// to the Erlang `Wibble` variable. For example: + /// + /// ```gleam + /// let a = 1 + /// let a = a + 1 + /// ``` + /// + /// In Erlang this would become: + /// + /// ```erl + /// A = 1, + /// A@1 = A + 1, + /// ``` + /// + /// So variables might need renaming. + /// Whenever we find a variable usage in Gleam we have to check "what is + /// the name that was given to the variable that comes from this location?" + /// Only then we'll know what's the correct name to use for it. + /// + variable_names: im::HashMap, + + /// This keeps track of the number of throwaway variables that have already + /// been generated in the current function. + /// For example if this is `2` it means we've already generated: + /// + /// ```erl + /// _value + /// _value@1 + /// _value@2 + /// ``` + /// + /// We need this to make sure that every time we generate a new throwaway + /// variable it has a unique name not shadowing anything else. + /// + throwaway_variables: usize, + + /// This keeps track of all the names that are taken for the current + /// function and can't be used when defining new variables. + /// For example if this is `hash_map![("wibble", 2), ("wobble", 1)]` + /// this means that all of these variables have already been defined + /// somewhere in the current function: + /// + /// ```erl + /// Wibble = ..., + /// Wibble@1 = ..., + /// Wibble@2 = ..., + /// + /// Wobble = ..., + /// Wobble@1 = ..., + /// ``` + /// + /// This is handy whenever we run into a new variable assignment and have to + /// generate a new name for it in Erlang. + /// + taken_names: im::HashMap, } impl<'a> Generator<'a> { @@ -94,22 +207,11 @@ impl<'a> Generator<'a> { module, module_source_path, line_numbers, - needs_doc_attribute: false, echo_used: false, } } - fn module_document(&mut self) -> Result> { - let mut exports = vec![]; - let mut type_defs = vec![]; - let mut type_exports = vec![]; - - let header = "-module(" - .to_doc() - .append(self.module.erlang_name()) - .append(").") - .append(line()); - + fn module_document(&mut self, eaf: &mut impl Eaf) { // We need to know which private functions are referenced in importable // constants so that we can export them anyway in the generated Erlang. // This is because otherwise when the constant is used in another module it @@ -117,109 +219,251 @@ impl<'a> Generator<'a> { let overridden_publicity = find_private_functions_referenced_in_importable_constants(self.module); - for function in &self.module.definitions.functions { - register_function_exports(function, &mut exports, &overridden_publicity); - } + // We add a `-compile` attribute at the top of each module to instruct + // the Erlang compiler. + eaf.compile_attribute([ + "no_auto_import", + "nowarn_ignored", + "nowarn_unused_vars", + "nowarn_unused_function", + "nowarn_nomatch", + "inline", + ]); + + // We then need to add an `-export` attribute for all the module's + // public functions. + eaf.export_attribute( + (self.module.definitions.functions.iter()) + .filter_map(|function| function_export(function, &overridden_publicity)), + ); + // We do the same but with types. + eaf.export_type_attribute(self.module.definitions.custom_types.iter().map(type_export)); + + // We also add a `-module_doc` comment at the beginning of the module + // with its documentation. + self.module_documentation(eaf); + // Then we generate `-type` definitions for the module's types. for custom_type in &self.module.definitions.custom_types { - register_custom_type_exports( - custom_type, - &mut type_exports, - &mut type_defs, - &self.module.name, - ); + self.type_definition(eaf, custom_type); } - let exports = match (!exports.is_empty(), !type_exports.is_empty()) { - (false, false) => return Ok(header), - (true, false) => "-export([" - .to_doc() - .append(join(exports, ", ".to_doc())) - .append("]).") - .append(lines(2)), - - (true, true) => "-export([" - .to_doc() - .append(join(exports, ", ".to_doc())) - .append("]).") - .append(line()) - .append("-export_type([") - .to_doc() - .append(join(type_exports, ", ".to_doc())) - .append("]).") - .append(lines(2)), - - (false, true) => "-export_type([" - .to_doc() - .append(join(type_exports, ", ".to_doc())) - .append("]).") - .append(lines(2)), - }; + // And finally generate all the functions that the module defined. + for function in &self.module.definitions.functions { + FunctionGenerator::new(function, self).module_function(eaf, function); + } + } - let type_defs = if type_defs.is_empty() { - nil() + fn module_documentation(&mut self, eaf: &mut impl Eaf) { + if self.module.type_info.is_internal { + // The module is internal so we need to add a `-moduledoc(false).` + // attribute to make sure its documentation is hidden. + let doc = eaf.start_moduledoc_attribute(); + eaf.atom("false"); + eaf.end_doc_attribute(doc); + } else if self.module.documentation.is_empty() { + // The module is not internal, but it has no docs. + // We don't have to do anything. } else { - join(type_defs, lines(2)).append(lines(2)) + // The module has some documentation that we're going to include + // with a `-moduledoc` attribute. + let doc = eaf.start_moduledoc_attribute(); + let documentation = &self.module.documentation.iter().join("\n"); + eaf.string(documentation); + eaf.end_doc_attribute(doc); }; + } - let mut statements = vec![]; - for function in &self.module.definitions.functions { - let mut generator = FunctionGenerator::new(function, self); - if let Some(function_doc) = generator.module_function(function) { - statements.push(function_doc); + fn type_definition(&self, eaf: &mut impl Eaf, custom_type: &TypedCustomType) { + let TypedCustomType { + name, + constructors, + opaque, + typed_parameters, + external_erlang, + .. + } = custom_type; + + let name = erl_safe_type_name(to_snake_case(name)); + + // We start the type spec. + eaf.type_spec( + *opaque, + &name, + typed_parameters + .iter() + .map(|type_| type_parameter_name(type_)), + ); + + // Now we need to generate the type definition. + // Erlang doesn't allow to have phantom type variables, so if there's + // any type variable that is not used we will need to add one variant to + // the resulting type that is using all those phantom variables to avoid + // errors! + let phantom_type_variables = phantom_type_variables(custom_type); + let has_phantom_type_variables = !phantom_type_variables.is_empty(); + match (constructors.as_slice(), has_phantom_type_variables) { + // This is an external type with an annotation telling us what type + // it corresponds to in Erlang. + // In that case all type variables are phantom type variables! + ([], _) if let Some((module, type_name, _)) = external_erlang => { + let type_ = + eaf.start_remote_named_type(ErlangModuleName::new(module.clone()), type_name); + for type_variable in phantom_type_variables { + eaf.type_variable(&type_variable); + } + eaf.end_named_type(type_); + } + // This is an external type with no external annotation and no + // phantom type variables. It is just `any()`. + ([], false) => { + let any = eaf.start_named_type("any"); + eaf.end_named_type(any); + } + // This is an external type with no external annotation and some + // phantom type variables, we need to add an alternative to use + // them: `any() | {gleam_phantom, A, B, ...}` + ([], true) => { + let union = eaf.start_union_type(); + let any = eaf.start_named_type("any"); + eaf.end_named_type(any); + self.phantom_type(eaf, phantom_type_variables); + eaf.end_union_type(union); + } + // This is an external type with a single constructor, no need to + // make it a union. + ([constructor], false) => self.constructor_type(eaf, constructor), + // This is an external type with multiple constructors, we have to + // turn it into a union! + (constructors, has_phantom_type_variables) => { + let union = eaf.start_union_type(); + for constructor in constructors { + self.constructor_type(eaf, constructor); + } + if has_phantom_type_variables { + self.phantom_type(eaf, phantom_type_variables); + } + eaf.end_union_type(union); } } + } - let module_doc = if self.module.type_info.is_internal { - Some(hidden_module_doc().append(lines(2))) - } else if self.module.documentation.is_empty() { - None + /// Given a constructor this generates its type. For example: + /// + /// ```gleam + /// Wibble(Int, String) + /// ``` + /// + /// Would be turned into: + /// + /// ```erl + /// {wibble, integer(), binary()}. + /// ``` + /// + fn constructor_type( + &self, + eaf: &mut impl Eaf, + constructor: &RecordConstructor>, + ) { + let constructor_atom = to_snake_case(&constructor.name); + if constructor.arguments.is_empty() { + // A constructor with no fields becomes a regular atom on the Erlang + // target. + eaf.literal_atom_type(&constructor_atom); } else { - Some(module_doc(&self.module.documentation).append(lines(2))) - }; + // Othwerwise, it is a tuple tagged with the atom with the + // constructor name. + let generator = TypeGenerator::new(&self.module.name); + let tuple = eaf.start_tuple_type(); + eaf.literal_atom_type(&constructor_atom); + for argument in &constructor.arguments { + generator.type_(eaf, &argument.type_); + } + eaf.end_tuple_type(tuple); + } + } - // We're going to need the documentation directives if any of the module's - // functions need it, or if the module has a module comment that we want to - // include in the generated Erlang source, or if the module is internal. - let needs_doc_directive = self.needs_doc_attribute || module_doc.is_some(); - let documentation_directive = if needs_doc_directive { - "-if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif." - .to_doc() - .append(lines(2)) - } else { - nil() - }; + /// Given a list of phantom type variabes, this generates a type using all + /// of those. + /// + /// Erlang doesn't allow having phantom type variables in type annotations, + /// so whenever there's any we need to manually add a type that uses them to + /// make sure we get no errors. For example: + /// + /// ```gleam + /// pub type Wibble(a, phantom) { + /// Wibble(a) + /// } + /// ``` + /// + /// Will have to be turned into: + /// + /// ```erl + /// -type wibble(A) :: {wibble, A} | {gleam_phantom, Phantom}. + /// ``` + /// + /// So the phantom type is nothing more than a tuple tagged with + /// `gleam_phantom`. + /// + fn phantom_type( + &self, + eaf: &mut impl Eaf, + phantom_type_variables: Vec, + ) { + let phantom_tuple = eaf.start_tuple_type(); + eaf.literal_atom_type("gleam_phantom"); + for phantom_type_variable in phantom_type_variables { + eaf.type_variable(&phantom_type_variable); + } + eaf.end_tuple_type(phantom_tuple); + } +} - let module = docvec![ - header, - "-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).", - line(), - "-define(FILEPATH, \"", - self.module_source_path.clone(), - "\").", - line(), - exports, - documentation_directive, - module_doc, - type_defs, - join(statements, lines(2)), - ]; - - let module = if self.echo_used { - module - .append(lines(2)) - .append(std::include_str!("../templates/echo.erl").to_doc()) - } else { - module - }; +/// Given a custom type, this will return a vector with the names of all the +/// phantom type varaibles that it has. The names returned are the names we can +/// use in Erlang! +fn phantom_type_variables(custom_type: &CustomType>) -> Vec { + // We first find all the variables that appear in the type definition + // itself: any of those that isn't used by any of the constructors is going + // to be a phantom type variable. + let mut definition_type_variables = + collect_type_var_usages(HashMap::new(), custom_type.typed_parameters.iter()); + + // So we need to gather all the type variables referenced by all the + // constructors. + let mut constructors_type_variables = HashMap::new(); + for constructor in &custom_type.constructors { + constructors_type_variables = collect_type_var_usages( + constructors_type_variables, + constructor.arguments.iter().map(|argument| &argument.type_), + ); + } + + // The phantom ones are the ones in the definition that are not referenced + // by any constructor: + for used_type_variable in constructors_type_variables.keys() { + let _ = definition_type_variables.remove(used_type_variable); + } + + definition_type_variables + .into_keys() + .map(id_to_type_var_str) + .sorted() + .collect_vec() +} - Ok(module.append(line())) +/// Given a custom type's type parameter (that is expected to be generic or +/// unbound), this will return the name the corresponding type variable should +/// have in the generated erlang code. +/// +/// If the type passed is not generic this will panic! +fn type_parameter_name(type_: &Type) -> EcoString { + let Type::Var { type_ } = type_ else { + panic!("non generic type as type parameter") + }; + match &*type_.borrow() { + TypeVar::Unbound { id } | TypeVar::Generic { id } => id_to_type_var_str(*id), + TypeVar::Link { type_ } => type_parameter_name(type_), } } @@ -236,8 +480,9 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { Self { function_name, module_generator, - current_scope_vars: im::HashMap::new(), - erl_function_scope_vars: im::HashMap::new(), + taken_names: im::HashMap::new(), + variable_names: im::HashMap::new(), + throwaway_variables: 0, } } @@ -248,29 +493,84 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// ## Panics /// This will panic if the variable is not in scope as that is most likely /// the result of a bug in the compiler. - pub fn local_var_name(&self, name: &str) -> Document<'a> { - match self.current_scope_vars.get(name) { - None => panic!("variable name is not in scope"), - Some(0) => variable_name(name).to_doc(), - Some(n) => eco_format!("{}@{n}", variable_name(name)).to_doc(), - } + pub fn local_var_name(&self, variable_origin: &SrcSpan) -> EcoString { + self.variable_names + .get(variable_origin) + .expect("variable not in scope") + .clone() + } + + /// Assigns a name to this new variable making sure it's not shadowing any + /// existing one. + /// + /// - `name` is the name of the variable as defined in the Gleam source code + /// - `location` is where that variable comes from, and it is used to then + /// get this newly generated name back. + /// + /// For example: + /// + /// ```gleam + /// let wibble = 1 + /// ``` + /// + /// When we run into this Gleam assignment we will need to decide how to + /// call it on the Erlang side. So we would call: + /// + /// ```ignore + /// let location = todo!("the location of this variable") + /// new_erlang_variable("wibble", location) + /// // and later we can tell what name was picked by calling + /// // `local_variable_name` + /// local_variable_name(location) // "Wibble" + /// ``` + /// + /// + pub fn new_erlang_variable(&mut self, name: &str, location: SrcSpan) -> EcoString { + let next = self.taken_names.get(name).map_or(0, |i| i + 1); + let _ = self.taken_names.insert(name.to_string(), next); + let erlang_name = match next { + 0 => variable_name(name), + _ => eco_format!("{}@{}", variable_name(name), next), + }; + let _ = self.variable_names.insert(location, erlang_name.clone()); + erlang_name } - /// Add the given variable to the current scope also adding a suffix if it - /// would be shadowing an existing variable. - /// This returns the document with this newly generated name. - pub fn next_local_var_name(&mut self, name: &str) -> Document<'a> { - let next = self.erl_function_scope_vars.get(name).map_or(0, |i| i + 1); - let _ = self.erl_function_scope_vars.insert(name.to_string(), next); - let _ = self.current_scope_vars.insert(name.to_string(), next); - self.local_var_name(name) + /// Sometimes during code generation we might need to create new variables + /// that were not accounted for during analysis. + /// Those variables don't really have an origin in the source code and are + /// usually generated and immediately used. + /// + /// For example: + /// + /// ```erl + /// _denominator = ..., + /// 1 / _denominator. + /// ``` + /// + /// Any time you need one such variable you can create it with this method + /// instead of `new_erlang_variable` which is meant to be used for variables + /// generated from Gleam code (and so wants the source location of the + /// variable). + /// + /// The generated name is guaranteed to always be unique for the given + /// function. + /// + fn new_throwaway_variable(&mut self) -> EcoString { + let name = if self.throwaway_variables == 0 { + EcoString::from("_value") + } else { + eco_format!("_value@{}", self.throwaway_variables) + }; + self.throwaway_variables += 1; + name } /// Generates code for an Erlang module function. This might return None /// if there's no code to be generated at all! /// For example if the function is unused, or if the function is a private /// Erlang external (in which case, it would be inlined instead). - fn module_function(&mut self, function: &'a TypedFunction) -> Option> { + fn module_function(&mut self, eaf: &mut impl Eaf, function: &'a TypedFunction) { // We don't generate any code for unused functions. if self .module_generator @@ -278,261 +578,354 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { .unused_definition_positions .contains(&function.location.start) { - return None; + return; } // Private external functions don't need to render anything, the // underlying Erlang implementation is used directly at the call site. if function.external_erlang.is_some() && function.publicity.is_private() { - return None; + return; } // If the function has no suitable Erlang implementation then there is // nothing to generate for it. if !function.implementations.supports(Target::Erlang) { - return None; + return; } - let (arguments, body) = match function.external_erlang.as_ref() { - None => ( - self.fun_arguments(&function.arguments), - self.statement_sequence(&function.body), - ), + let function_name = EcoString::from(escape_erlang_existing_name(self.function_name)); - Some((module, external_function_name, _location)) => { - let arguments = self.external_fun_arguments(&function.arguments); - let body = docvec![ - atom(module), - ":", - atom(escape_erlang_existing_name(external_function_name)), - arguments.clone() - ]; - (arguments, body) + // Then we add the function's documentation and type annotation. + eaf.file_attribute( + &self.module_generator.module_source_path, + self.module_generator + .line_numbers + .line_number(function.location.start), + ); + self.function_spec_attribute(eaf, &function_name, function); + self.function_doc_attribute(eaf, function); + + // Finally we start generating code for the function itself, how we do + // it depends if the function is external or not. + let arity = function.arguments.len(); + match function.external_erlang.as_ref() { + // If the function is not external we generate the code for all of + // its statements. + None => { + let arguments = self.function_arguments_names(&function.arguments, false); + let open_function = eaf.start_function(&function_name, arity, arguments); + self.statement_sequence(eaf, &function.body); + eaf.end_function(open_function); } - }; - - Some(docvec![ - self.function_attributes(function), - line(), - atom_string(escape_erlang_existing_name(self.function_name).into()), - arguments, - " ->", - docvec![line(), body].nest(INDENT).group(), - ".", - ]) - } - - /// Generates all the attributes that need to go before a function, like - /// a `-file` attribute, a `-doc` one, a `-spec` one, etc. - fn function_attributes(&mut self, function: &'a TypedFunction) -> Document<'a> { - // If a function is marked as internal or comes from an internal module - // we want to hide its documentation in the Erlang shell! - // So the doc directive will look like this: `-doc(false).` - let is_internal = - self.module_generator.module.type_info.is_internal || function.publicity.is_internal(); - let doc_attribute = if is_internal { - self.hide_function_attribute().append(line()) - } else if let Some((_, doc)) = &function.documentation { - self.function_doc_attribute(doc).append(line()) - } else { - nil() - }; - - let file_attribute = self.file_attribute(function); - let spec_attribute = self.spec_attribute(function); - docvec![file_attribute, line(), doc_attribute, spec_attribute] - } - fn file_attribute(&self, function: &'a Function, TypedExpr>) -> Document<'a> { - let path = self.module_generator.module_source_path.clone(); - let line = self - .module_generator - .line_numbers - .line_number(function.location.start); - - docvec!["-file(\"", path, "\", ", line, ")."] + // An external function consists of just a remote call being + // passed all of the function's arguments. + Some((module, external_function_name, _location)) => { + let arguments = self + .function_arguments_names(&function.arguments, true) + .collect_vec(); + let open_function = eaf.start_function(&function_name, arity, arguments.clone()); + let call = eaf.start_remote_call(module.into(), external_function_name); + for argument in arguments { + eaf.variable(&argument); + } + eaf.end_call(call); + eaf.end_function(open_function); + } + } } - fn spec_attribute(&self, function: &'a TypedFunction) -> Document<'a> { - let function_types = function - .arguments - .iter() - .map(|argument| &argument.type_) - .chain(std::iter::once(&function.return_type)); - let var_usages = collect_type_var_usages(HashMap::new(), function_types); - let type_printer = - TypePrinter::new(&self.module_generator.module.name).with_var_usages(&var_usages); - let function_name_atom = match function.name.as_ref() { - Some((_, function_name)) => atom(escape_erlang_existing_name(function_name)), - None => unreachable!("A module's function must be named"), - }; - let arguments_spec = wrap_arguments( + /// This generates the `-spec` attribute for a function with the given name. + /// + fn function_spec_attribute( + &mut self, + eaf: &mut impl Eaf, + function_name: &EcoString, + function: &'a Function, TypedExpr>, + ) { + // We start by getting all the type variable usages from this function, + // both in the argument types and return type. + let module_name = &self.module_generator.module.name; + let var_usages = &collect_type_var_usages( + HashMap::new(), function .arguments .iter() - .map(|argument| type_printer.print(&argument.type_)), + .map(|argument| &argument.type_) + .chain(std::iter::once(&function.return_type)), ); - let return_spec = type_printer.print(&function.return_type); - - docvec![ - "-spec ", - function_name_atom, - arguments_spec, - " -> ", - return_spec, - ".", - ] - .group() - } - - /// Generates an attribute to hide a function from the module's - /// documentation. - fn hide_function_attribute(&mut self) -> Document<'static> { - self.module_generator.needs_doc_attribute = true; - doc_attribute(DocCommentKind::Function, DocCommentContent::False) - } - - /// Generates a `-doc` attribute with the given string as its content. - fn function_doc_attribute(&mut self, documentation: &EcoString) -> Document<'a> { - self.module_generator.needs_doc_attribute = true; - function_doc(documentation) - } - - fn statement_sequence(&mut self, statements: &'a [TypedStatement]) -> Document<'a> { - let count = statements.len(); - let mut documents = Vec::with_capacity(count * 3); - for (i, expression) in statements.iter().enumerate() { - let position = if i + 1 == count { - Position::Tail - } else { - Position::NotTail - }; - documents.push(self.statement(expression, position).group()); - - if i + 1 < count { - // This isn't the final expression so add the delimeters - documents.push(",".to_doc()); - documents.push(line()); - } - } + let generator = TypeGenerator::new(module_name).with_var_usages(var_usages); - if count == 1 { - documents.to_doc() - } else { - documents.to_doc().force_break() + // We can then start generating the function spec. + let spec = eaf.start_function_spec(function_name, function.arguments.len()); + let function_type = eaf.start_function_type(); + for argument in &function.arguments { + generator.type_(eaf, &argument.type_) } + let function_type = eaf.end_function_type_arguments(function_type); + generator.type_(eaf, &function.return_type); + eaf.end_function_type(function_type); + eaf.end_function_spec(spec); } - fn statement(&mut self, statement: &'a TypedStatement, position: Position) -> Document<'a> { - match statement { - Statement::Expression(expression) => self.expr(expression), - Statement::Assignment(assignment) => self.assignment(assignment, position), - Statement::Use(use_) => self.expr(&use_.call), - Statement::Assert(assert) => self.assert(assert), + fn function_doc_attribute(&self, eaf: &mut impl Eaf, function: &TypedFunction) { + // If a function is marked as internal or comes from an internal module + // we want to hide its documentation in the Erlang shell! + // So the doc directive will look like this: `-doc(false).` + let is_internal = + self.module_generator.module.type_info.is_internal || function.publicity.is_internal(); + + if is_internal { + let attribute = eaf.start_doc_attribute(); + eaf.atom("false"); + eaf.end_doc_attribute(attribute); + } else if let Some((_, documentation)) = &function.documentation + && !documentation.is_empty() + { + let attribute = eaf.start_doc_attribute(); + eaf.string(documentation); + eaf.end_doc_attribute(attribute); } } - /// Generates the document for the arguments' list of a function, bringing - /// all those variable names into scope (that's needed to avoid accidentally - /// shadowing a variable, that will result in an exception in Erlang)! - fn fun_arguments(&mut self, arguments: &'a [TypedArg]) -> Document<'a> { - wrap_arguments(arguments.iter().map(|argument| match &argument.names { - ArgNames::Discard { .. } | ArgNames::LabelledDiscard { .. } => "_".to_doc(), - ArgNames::Named { name, .. } | ArgNames::NamedLabelled { name, .. } => { - self.next_local_var_name(name) + /// Given a function, this will return the names of the arguments to be used + /// in this function's definition. This will also update the current scope + /// to add those names to the available local variables. + fn function_arguments_names( + &mut self, + arguments: &[TypedArg], + is_external: bool, + ) -> impl Iterator { + arguments.iter().map(move |argument| match &argument.names { + // When the function is external we need to be careful with discarded + // arguments. _All_ of the function arguments are always used in an + // external function, regardless of them being discarded in Gleam: + // + // ```gleam + // @external(erlang, "io", "format") + // fn format(_string: String, _args: List(String)) -> Nil + // ``` + // + // Becomes: + // + // ```erl + // format(_string, _args) -> + // io:format(_string, _args). + // ``` + // + // If an argument is made of just underscores, then that would result + // in a syntax error in the generated Erlang, where the external + // function is called with a discard `io:format(_, _)`! + // So in this case we use a throwaway name to make sure the external + // function can be called correctly. + ArgNames::Discard { name, location } + | ArgNames::LabelledDiscard { + name, + name_location: location, + .. + } if is_external => { + if name.chars().all(|char| char == '_') { + self.new_throwaway_variable() + } else { + self.new_erlang_variable(name, *location) + } } - })) + ArgNames::Discard { .. } | ArgNames::LabelledDiscard { .. } => EcoString::from("_"), + ArgNames::Named { name, location } + | ArgNames::NamedLabelled { + name, + name_location: location, + .. + } => self.new_erlang_variable(name, *location), + }) } - /// Generates the document for the arguments' list of an external function. - fn external_fun_arguments(&mut self, arguments: &'a [TypedArg]) -> Document<'a> { - wrap_arguments(arguments.iter().map(|argument| { - let name = match &argument.names { - ArgNames::Discard { name, .. } - | ArgNames::LabelledDiscard { name, .. } - | ArgNames::Named { name, .. } - | ArgNames::NamedLabelled { name, .. } => name, - }; - - if name.chars().all(|c| c == '_') { - self.next_local_var_name("argument") - } else { - self.next_local_var_name(name) + fn statement_sequence( + &mut self, + eaf: &mut impl Eaf, + statements: &'a [TypedStatement], + ) { + // We go over each statement one by one and produce the code they need. + for i in 0..statements.len() { + match statements.get(i).expect("statement in range") { + Statement::Expression(expression) => self.expr(eaf, expression), + Statement::Use(use_) => self.expr(eaf, &use_.call), + Statement::Assert(assert) => self.assert(eaf, assert), + Statement::Assignment(assignment) => match &assignment.kind { + AssignmentKind::Let | AssignmentKind::Generated => { + self.let_(eaf, &assignment.value, &assignment.pattern) + } + // Let asserts are slightly different from everything else: + // A let assert is compiled to a case expression where we + // have two branches: + // + // ```gleam + // let assert [a, b] = some_list + // // ... the remaining statements + // ``` + // + // It will turn into something that looks like this: + // + // ```erl + // case SomeList of + // [a, b] -> + // % ... the remaining statements; + // _ -> + // erlang:error(...) + // end. + // ``` + // + // So in case we find a let assert we need to break out of + // this cycle and pass it all the remaining statements so + // that it can put those under the correct branch of the + // case expression it's going to produce. + AssignmentKind::Assert { + message, location, .. + } => { + return self.let_assert( + eaf, + &assignment.value, + &assignment.pattern, + message.as_ref(), + *location, + statements.get(i + 1..).unwrap_or_default(), + ); + } + }, } - })) + } } - fn expr(&mut self, expression: &'a TypedExpr) -> Document<'a> { + fn expr(&mut self, eaf: &mut impl Eaf, expression: &'a TypedExpr) { match expression { - TypedExpr::Todo { - message: label, - location, - .. - } => self.todo(label.as_deref(), *location), - - TypedExpr::Panic { - location, message, .. - } => self.panic(*location, message.as_deref()), - - TypedExpr::Echo { - expression, - location, - message, - .. - } => { - let expression = expression - .as_ref() - .expect("echo with no expression outside of pipe"); - let expression = self.maybe_block_expr(expression); - self.echo(expression, message.as_deref(), location) - } - - TypedExpr::Int { value, .. } => int(value), - TypedExpr::Float { value, .. } => float(value), - TypedExpr::String { value, .. } => string(value), - - TypedExpr::Pipeline { - first_value, - assignments, - finally, - .. - } => self.pipeline(first_value, assignments, finally), - - TypedExpr::Block { statements, .. } => self.block(statements), - - TypedExpr::TupleIndex { tuple, index, .. } => self.tuple_index(tuple, *index), - + // + // Simple scalar values, and blocks. + // + TypedExpr::Int { int_value, .. } => eaf.int(int_value.clone()), + TypedExpr::Float { float_value, .. } => eaf.float(float_value.value()), + TypedExpr::String { value, .. } => eaf.string(value), TypedExpr::Var { name, constructor, .. - } => self.var(name, constructor), - - TypedExpr::Fn { - arguments, body, .. - } => self.fun(arguments, body), - - TypedExpr::NegateBool { value, .. } => self.negate_with("not ", value), - - TypedExpr::NegateInt { value, .. } => self.negate_with("- ", value), + } => self.var(eaf, name, constructor), + TypedExpr::Block { statements, .. } => { + // If the block has a single expression we don't bother wrapping + // it in an additional `begin ... end` block. + // It's going to be added only if strictly needed. + if statements.len() == 1 + && let Statement::Expression(expression) = statements.first() + { + self.maybe_block_expr(eaf, expression); + } else { + let block = eaf.start_block(); + self.statement_sequence(eaf, statements); + eaf.end_block(block) + } + } - TypedExpr::List { elements, tail, .. } => self.expr_list(elements, tail), + // + // Operators. + // + TypedExpr::NegateBool { value, .. } => { + eaf.unary_operator("not"); + self.maybe_block_expr(eaf, value) + } + TypedExpr::NegateInt { value, .. } => { + eaf.unary_operator("-"); + self.maybe_block_expr(eaf, value) + } + TypedExpr::BinOp { + operator, + left, + right, + .. + } => self.bin_op(eaf, operator, left, right), + + // + // BitArrays, Lists, and Tuples. + // + TypedExpr::BitArray { segments, .. } => { + let bit_array = eaf.start_bit_array(); + for segment in segments { + self.bit_array_expression_segment(eaf, segment); + } + eaf.end_bit_array(bit_array); + } + TypedExpr::List { elements, tail, .. } => { + // We generate all the items of the list as cons cells. + for element in elements { + eaf.cons_list(); + self.maybe_block_expr(eaf, element); + } + // Finally we close the list with the tail, or an empty list + // (so that we're sure we're building proper Erlang lists). + if let Some(tail) = tail { + self.maybe_block_expr(eaf, tail); + } else { + eaf.empty_list(); + } + } + TypedExpr::Tuple { elements, .. } => { + let tuple = eaf.start_tuple(); + for element in elements { + self.maybe_block_expr(eaf, element); + } + eaf.end_tuple(tuple) + } - TypedExpr::Call { fun, arguments, .. } => self.call(fun, arguments), + // + // Accessing data inside tuples, and records. + // They're all tuple accesses at the end of the day! + // + TypedExpr::TupleIndex { tuple, index, .. } => self.tuple_index(eaf, tuple, *index), + TypedExpr::RecordAccess { record, index, .. } + | TypedExpr::PositionalAccess { record, index, .. } => { + self.tuple_index(eaf, record, index + 1) + } + // + // Records and record updates. + // TypedExpr::ModuleSelect { constructor: ModuleValueConstructor::Record { name, arity: 0, .. }, .. - } => atom_string(to_snake_case(name)), - - TypedExpr::ModuleSelect { - constructor: ModuleValueConstructor::Constant { literal, .. }, + } => eaf.atom(&to_snake_case(name)), + TypedExpr::RecordUpdate { + updated_record_assigned_name, + updated_record, + constructor, + arguments, .. - } => self.const_inline(literal), + } => { + // If the record value itself needs to be bound to a variable + // before the update, we define it. + if let Some(name) = updated_record_assigned_name.as_ref() { + eaf.match_operator(); + eaf.variable_pattern( + &self.new_erlang_variable(name, updated_record.location()), + ); + self.maybe_block_expr(eaf, updated_record); + } + // Then a record update is simply a call! + self.call(eaf, constructor, arguments) + } + // + // All kinds of anonymous functions. + // + TypedExpr::Fn { + arguments, body, .. + } => { + let outer_scope = self.taken_names.clone(); + let argument_names = self.function_arguments_names(arguments, false); + let function = eaf.start_anonymous_function(argument_names); + self.statement_sequence(eaf, body); + eaf.end_function(function); + self.taken_names = outer_scope; + } TypedExpr::ModuleSelect { constructor: ModuleValueConstructor::Record { name, arity, .. }, .. - } => record_constructor_function(name.clone(), *arity as usize), - + } => self.record_builder_anonymous_function(eaf, name, *arity as usize), TypedExpr::ModuleSelect { type_, constructor: @@ -542,375 +935,329 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { } | ModuleValueConstructor::Fn { module, name, .. }, .. - } => module_select_fn(type_.clone(), module, name), + } => match type_::collapse_links(type_.clone()).as_ref() { + Type::Fn { arguments, .. } => eaf.function_reference( + Some(module.into()), + escape_erlang_existing_name(name), + arguments.len(), + ), - TypedExpr::RecordAccess { record, index, .. } => self.tuple_index(record, index + 1), - TypedExpr::PositionalAccess { record, index, .. } => { - self.tuple_index(record, index + 1) - } + Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => { + let name = escape_erlang_existing_name(name); + let call = eaf.start_remote_call(module.into(), name); + eaf.end_call(call); + } + }, - TypedExpr::RecordUpdate { - updated_record_assigned_name, - updated_record, - constructor, - arguments, + // + // Calling functions. + // + TypedExpr::Call { fun, arguments, .. } => self.call(eaf, fun, arguments), + TypedExpr::Pipeline { + first_value, + assignments, + finally, .. - } => self.record_update( - updated_record, - updated_record_assigned_name, - constructor, - arguments, - ), - - TypedExpr::Case { - subjects, clauses, .. - } => self.case(subjects, clauses), + } => self.pipeline(eaf, first_value, assignments, finally), - TypedExpr::BinOp { - operator, - left, - right, + // + // Todo, panic, and echo. + // + TypedExpr::Todo { + message, location, .. + } => { + let error = self.start_runtime_error( + eaf, + RuntimeErrorKind::Todo, + *location, + message.as_deref(), + ); + self.end_runtime_error(eaf, error); + } + TypedExpr::Panic { + location, message, .. + } => { + let error = self.start_runtime_error( + eaf, + RuntimeErrorKind::Panic, + *location, + message.as_deref(), + ); + self.end_runtime_error(eaf, error); + } + TypedExpr::Echo { + expression, + location, + message, .. - } => self.bin_op(operator, left, right), - - TypedExpr::Tuple { elements, .. } => tuple( - elements - .iter() - .map(|element| self.maybe_block_expr(element)), + } => self.echo( + eaf, + *location, + message.as_deref(), + EchoPrintedValue::Expression { + value: expression + .as_ref() + .expect("echo with no expression outside of pipe"), + }, ), - TypedExpr::BitArray { segments, .. } => bit_array( - segments - .iter() - .map(|segment| self.bit_array_expression_segment(segment)), - ), + // + // Module constants. + // + TypedExpr::ModuleSelect { + constructor: ModuleValueConstructor::Constant { literal, .. }, + .. + } => self.inlined_constant(eaf, literal), + + // + // Control flow. + // + TypedExpr::Case { + subjects, clauses, .. + } => self.case(eaf, subjects, clauses), + // + // Something went wrong! + // TypedExpr::Invalid { .. } => { panic!("invalid expressions should not reach code generation") } } } - fn todo(&mut self, message: Option<&'a TypedExpr>, location: SrcSpan) -> Document<'a> { - let message = match message { - Some(message) => self.expr(message), - None => string("`todo` expression evaluated. This code has not yet been implemented."), - }; - self.erlang_error("todo", &message, location, vec![]) - } + fn echo( + &mut self, + eaf: &mut impl Eaf, + echo_location: SrcSpan, + message: Option<&'a TypedExpr>, + printed_value: EchoPrintedValue<'a>, + ) { + self.module_generator.echo_used = true; - fn panic(&mut self, location: SrcSpan, message: Option<&'a TypedExpr>) -> Document<'a> { - let message = match message { - Some(message) => self.expr(message), - None => string("`panic` expression evaluated."), - }; - self.erlang_error("panic", &message, location, vec![]) - } + let call = eaf.start_call(); + eaf.atom("echo"); - fn erlang_error( - &self, - name: &'a str, - message: &Document<'a>, - location: SrcSpan, - fields: Vec<(&'a str, Document<'a>)>, - ) -> Document<'a> { - let mut fields_doc = docvec![ - "gleam_error => ", - name, - ",", - line(), - "message => ", - message.clone(), - ",", - line(), - "file => <>,", - line(), - "module => ", - self.module_generator - .module - .name - .clone() - .to_doc() - .surround("<<\"", "\"/utf8>>"), - ",", - line(), - "function => ", - string(self.function_name), - ",", - line(), - "line => ", + // Echo has 4 arguments: the expression to print... + match printed_value { + EchoPrintedValue::PipeStep { name } => eaf.variable(&name), + EchoPrintedValue::Expression { value } => self.maybe_block_expr(eaf, value), + } + // ...the message to print (or nil if there's no message)... + if let Some(message) = message { + self.maybe_block_expr(eaf, message); + } else { + eaf.atom("nil") + } + + // ...the filepath of this module... + eaf.string(&self.module_generator.module_source_path); + + // ...and the line number of the expression. + eaf.int( self.module_generator .line_numbers - .line_number(location.start), - ]; - - for (key, value) in fields { - fields_doc = fields_doc - .append(",") - .append(line()) - .append(key) - .append(" => ") - .append(value); - } + .line_number(echo_location.start) + .into(), + ); - let error = docvec!["#{", fields_doc.group().nest(INDENT), "}"]; - docvec!["erlang:error", wrap_arguments([error.group()])] + eaf.end_call(call); } - fn echo( + /// This starts a call to `erlang:error` with a map representing a Gleam + /// runtime error of the given kind. + /// Some fields are mandatory and always added, but if you need to add more + /// fields you can still do so by calling `eaf.map_field()`. + /// + /// After you're done generating those additional fields remember you _must_ + /// call `end_runtime_error` before generating any other piece of code! + /// + fn start_runtime_error( &mut self, - body: Document<'a>, + eaf: &mut impl Eaf, + error_kind: RuntimeErrorKind, + location: SrcSpan, message: Option<&'a TypedExpr>, - location: &SrcSpan, - ) -> Document<'a> { - self.module_generator.echo_used = true; + ) -> RuntimeError { + let call = eaf.start_remote_call("erlang".into(), "error"); + let map = eaf.start_map(); + + eaf.map_field(); + eaf.atom("gleam_error"); + eaf.atom(match error_kind { + RuntimeErrorKind::Todo => "todo", + RuntimeErrorKind::Panic => "panic", + RuntimeErrorKind::Assert => "assert", + RuntimeErrorKind::LetAssert => "let_assert", + }); - let message = message - .as_ref() - .map(|message| self.maybe_block_expr(message)) - .unwrap_or("nil".to_doc()); + eaf.map_field(); + eaf.atom("message"); + if let Some(message) = message { + self.maybe_block_expr(eaf, message); + } else { + eaf.string(error_kind.default_error_message()) + } - "echo".to_doc().append(wrap_arguments(vec![ - body, - message, + eaf.map_field(); + eaf.atom("file"); + eaf.string(&self.module_generator.module_source_path); + + eaf.map_field(); + eaf.atom("module"); + eaf.string(&self.module_generator.module.name); + + eaf.map_field(); + eaf.atom("function"); + eaf.string(self.function_name); + + eaf.map_field(); + eaf.atom("line"); + eaf.int( self.module_generator .line_numbers .line_number(location.start) - .to_doc(), - ])) - } + .into(), + ); - fn maybe_block_expr(&mut self, expression: &'a TypedExpr) -> Document<'a> { - if needs_begin_end_wrapping(expression) { - begin_end(self.expr(expression)) - } else { - self.expr(expression) + RuntimeError { + error_map: map, + erlang_error_call: call, } } - fn assignment(&mut self, assignment: &'a TypedAssignment, position: Position) -> Document<'a> { - match &assignment.kind { - AssignmentKind::Let | AssignmentKind::Generated => { - self.let_(&assignment.value, &assignment.pattern) - } - AssignmentKind::Assert { - message, location, .. - } => self.let_assert( - &assignment.value, - &assignment.pattern, - message.as_ref(), - position, - *location, - ), + /// This closes an open runtime error. + fn end_runtime_error(&self, eaf: &mut impl Eaf, runtime_error: RuntimeError) { + eaf.end_map(runtime_error.error_map); + eaf.end_call(runtime_error.erlang_error_call); + } + + fn maybe_block_expr(&mut self, eaf: &mut impl Eaf, expression: &'a TypedExpr) { + if needs_begin_end_wrapping(expression) { + let block = eaf.start_block(); + self.expr(eaf, expression); + eaf.end_block(block); + } else { + self.expr(eaf, expression); } } - fn let_(&mut self, value: &'a TypedExpr, pattern: &'a TypedPattern) -> Document<'a> { - let body = self.maybe_block_expr(value).group(); - PatternPrinter::new(self) - .print(pattern) - .append(" = ") - .append(body) + fn let_( + &mut self, + eaf: &mut impl Eaf, + value: &'a TypedExpr, + pattern: &'a TypedPattern, + ) { + eaf.match_operator(); + PatternGenerator::new(self).pattern(eaf, pattern); + self.maybe_block_expr(eaf, value) } - fn let_assert( + fn let_assert( &mut self, + eaf: &mut impl Eaf, value: &'a TypedExpr, pattern: &'a TypedPattern, message: Option<&'a TypedExpr>, - position: Position, location: SrcSpan, - ) -> Document<'a> { + following_statements: &'a [TypedStatement], + ) { // If the pattern will never fail, like a tuple or a simple variable, we // simply treat it as if it were a `let` assignment. if pattern.always_matches() { - return self.let_(value, pattern); + self.let_(eaf, value, pattern); + self.statement_sequence(eaf, following_statements); + return; } - let message = match message { - Some(message) => self.expr(message), - None => string("Pattern match failed, no pattern matched the value."), - }; - - let subject = self.maybe_block_expr(value); + // Otherwise we turn the let assert into a case expression with two + // branches: one for the asserted pattern, and one catch all to throw an + // exception in case the pattern doesn't match. + let case = eaf.start_case(); + self.maybe_block_expr(eaf, value); + + // This is the first branch for when the asserted pattern matches: it's + // going to run all the remaining statements in its body. + if !following_statements.is_empty() { + // If there's statements after this let assert we want to generate + // them. + let clause = eaf.start_case_clause(); + let mut generator = PatternGenerator::new(self); + generator.pattern(eaf, pattern); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + let variables_to_add_later = generator.variables_to_add_later; + self.pattern_assignments(eaf, variables_to_add_later); + self.statement_sequence(eaf, following_statements); + eaf.end_clause_body(clause); + } else { + // If there's no statements following the let assert, that means + // that it's the last statement in the block and we need to return + // the value being matched on. + // It will look something like this: + // + // ```erl + // case MatchedValue of + // [_, A | _] = _value -> _value; + // % ^^^^^^ We bind the pattern to a variable + // % and return it. + // _ -> erlang:error(...) + // end + // ``` + let clause = eaf.start_case_clause(); + let matched_value_name = self.new_throwaway_variable(); + eaf.match_pattern(); + let mut generator = PatternGenerator::new(self); + generator.pattern(eaf, pattern); + eaf.variable_pattern(&matched_value_name); + + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + eaf.variable(&matched_value_name); + eaf.end_clause_body(clause); + } - // The code we generated for a `let assert` assignment looks something like - // this. For this Gleam code: - // - // ```gleam - // let assert [a, b, c] = [1, 2, 3] - // ``` - // - // We generate (roughly) the following Erlang: - // - // ```erlang - // {A, B, C} = case [1, 2, 3] of - // [A, B, C] -> {A, B, C}; - // _ -> erlang:error(...) - // end. - // ``` - // This is the most efficient way to properly extract all the required - // variables from the pattern. However, if the `let assert` assignment is - // the last in a block, like this: - // - // ```gleam - // let x = { - // let assert [a, b, c] = [1, 2, 3] - // } - // ``` - // - // The generated Erlang code will end up assigning the value `#(1, 2, 3)` - // to the variable `x`, instead of `[1, 2, 3]`. In this case, we must - // generate slightly different code. Since we know we won't be using the - // bound variables anywhere (there is nothing else in this scope to - // reference them), we can safely remove the assignment from the generated - // code, and generate the following: - // - // ```erlang - // X = begin - // _assert_subject = [1, 2, 3] - // case _assert_subject of - // [A, B, C] -> _assert_subject; - // _ -> erlang:error(...) - // end - // end. - // ``` - // - // That correctly assigns `[1, 2, 3]` to the `x` variable. - // - let is_tail = match position { - Position::Tail => true, - Position::NotTail => false, - }; + // This is the catch all branch to throw an error otherwise. + let clause = eaf.start_case_clause(); + let value_name = self.new_throwaway_variable(); + eaf.variable_pattern(&value_name); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + let error = self.start_runtime_error(eaf, RuntimeErrorKind::LetAssert, location, message); - let (subject_assignment, subject) = if is_tail && !value.is_var() { - let variable = self.next_local_var_name(ASSERT_SUBJECT_VARIABLE); - let assignment = docvec![variable.clone(), " = ", subject, ",", line()]; - (assignment, variable) - } else { - (nil(), subject) - }; + // We want to add some additional fields to the error map: + eaf.map_field(); + eaf.atom("value"); + eaf.variable(&value_name); - let mut pattern_printer = PatternPrinter::new(self); - let pattern_document = pattern_printer.print(pattern); - let PatternPrinter { - generator: _, - variables, - guards, - assignments, - } = pattern_printer; + eaf.map_field(); + eaf.atom("start"); + eaf.int(location.start.into()); - let assignments_map = assignments - .iter() - .map(|assignment| (assignment.gleam_name.clone(), assignment)) - .collect(); - let clause_guard = self.optional_clause_guard(None, guards, &assignments_map); - - let value_document = match variables.as_slice() { - _ if is_tail => subject.clone(), - [] => "nil".to_doc(), - [variable] => self.local_var_name(variable), - variables => { - let variables = variables - .iter() - .map(|variable| self.local_var_name(variable)); - docvec![ - break_("{", "{"), - join(variables, break_(",", ", ")).nest(INDENT), - "}" - ] - .group() - } - }; + eaf.map_field(); + eaf.atom("end"); + eaf.int(value.location().end.into()); - let assignment = match variables.as_slice() { - _ if is_tail => nil(), - [] => nil(), - [variable] => self.next_local_var_name(variable).append(" = "), - variables => { - let variables = variables - .iter() - .map(|variable| self.next_local_var_name(variable)); - docvec![ - break_("{", "{"), - join(variables, break_(",", ", ")).nest(INDENT), - "} = " - ] - .group() - } - }; + eaf.map_field(); + eaf.atom("pattern_start"); + eaf.int(pattern.location().start.into()); - let clauses = docvec![ - pattern_document, - clause_guard, - " -> ", - value_document, - ";", - line(), - self.next_local_var_name(ASSERT_FAIL_VARIABLE), - " ->", - docvec![ - line(), - self.erlang_error( - "let_assert", - &message, - location, - vec![ - ("value", self.local_var_name(ASSERT_FAIL_VARIABLE)), - ("start", location.start.to_doc()), - ("'end'", value.location().end.to_doc()), - ("pattern_start", pattern.location().start.to_doc()), - ("pattern_end", pattern.location().end.to_doc()), - ], - ) - .nest(INDENT) - ] - .nest(INDENT) - ]; + eaf.map_field(); + eaf.atom("pattern_end"); + eaf.int(pattern.location().end.into()); - let assignments = if assignments.is_empty() { - nil() - } else { - docvec![ - ",", - line(), - join( - assignments - .iter() - .map(|assignment| assignment.to_assignment_doc()), - ",".to_doc().append(line()) - ) - ] - }; + self.end_runtime_error(eaf, error); + eaf.end_clause_body(clause); - docvec![ - subject_assignment, - assignment, - "case ", - subject, - " of", - docvec![line(), clauses].nest(INDENT), - line(), - "end", - assignments, - ] + eaf.end_case(case); } - fn pipeline( + fn pipeline( &mut self, + eaf: &mut impl Eaf, first_value: &'a TypedPipelineAssignment, assignments: &'a [(TypedPipelineAssignment, PipelineAssignmentKind)], finally: &'a TypedExpr, - ) -> Document<'a> { - let mut documents = Vec::with_capacity((assignments.len() + 1) * 3); - let all_assignments = std::iter::once(first_value) - .chain(assignments.iter().map(|(assignment, _kind)| assignment)); - - // We don't want the extra variables generated for a pipeline to get out - // of the current scope. So we will be saving that and restoring it - // after this is done. - let current_scope_vars = self.current_scope_vars.clone(); - + ) { // A pipeline is desugared as a sequence of assignments: // // ```erl @@ -923,10 +1270,19 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // So we need to keep around the name the prevopis pipeline step had // to pass it as an argument to the following call. This is what this // variable is for. - let mut previous_step_variable_name = None; - for assignment in all_assignments { - // An echo in a pipeline won't result in an assignment, instead it - // just prints the previous variable assigned in the pipeline. + let mut previous_step_variable_name: Option = None; + for assignment in std::iter::once(first_value) + .chain(assignments.iter().map(|(assignment, _kind)| assignment)) + { + // A pipeline step always ends up assigned to a variable. + // So we start by generating `_pipe = ...`, followed by the + // expression. + eaf.match_operator(); + let name = self.new_erlang_variable(&assignment.name, assignment.location); + eaf.variable_pattern(&name); + + // In case of a pipe we need to manually pass the previous step to + // echo as an argument. if let TypedExpr::Echo { expression: None, message, @@ -934,23 +1290,20 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { .. } = assignment.value.as_ref() { - let previous_step_variable_name = previous_step_variable_name - .to_owned() - .expect("echo with no previous step in a pipe"); - documents.push(self.echo( - previous_step_variable_name, + self.echo( + eaf, + *location, message.as_deref(), - location, - )); + EchoPrintedValue::PipeStep { + name: previous_step_variable_name + .to_owned() + .expect("echo with no previous step in a pipe"), + }, + ) } else { - // Otherwise we assign the intermediate pipe value to a variable. - let body = self.maybe_block_expr(&assignment.value).group(); - let name = self.next_local_var_name(&assignment.name); - previous_step_variable_name = Some(name.clone()); - documents.push(docvec![name, " = ", body]); + self.maybe_block_expr(eaf, &assignment.value); + previous_step_variable_name = Some(name); }; - documents.push(",".to_doc()); - documents.push(line()); } // We also need to do the same thing for the final step of the pipeline. @@ -963,56 +1316,55 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { .. } = finally { - let previous_step_variable_name = previous_step_variable_name - .to_owned() - .expect("echo with no previous step in a pipe"); - documents.push(self.echo(previous_step_variable_name, message.as_deref(), location)); + self.echo( + eaf, + *location, + message.as_deref(), + EchoPrintedValue::PipeStep { + name: previous_step_variable_name + .expect("echo with no previous step in a pipe"), + }, + ) } else { - documents.push(self.expr(finally)) + self.expr(eaf, finally) } - - // We're done so we can restore the scope to what it was before this. - self.current_scope_vars = current_scope_vars; - documents.to_doc() } - fn assert(&mut self, assert: &'a TypedAssert) -> Document<'a> { + fn assert(&mut self, eaf: &mut impl Eaf, assert: &'a TypedAssert) { let Assert { value, location, message, } = assert; - let message = match message { - Some(message) => self.expr(message), - None => string("Assertion failed."), - }; - - let mut assignments = Vec::new(); - - let (subject, mut fields) = match value { - TypedExpr::Call { fun, arguments, .. } => { - self.assert_call(fun, arguments, &mut assignments) - } + match value { + // We're asserting on a binary operator. We want to show the result + // of each side in the error that is produced. + // So we will bind the two sides of the operator to variables and + // shove them in the error map too! TypedExpr::BinOp { operator, left, right, .. } => { - let operator_document = match operator { + let erlang_operator = match operator { + // Writing asserts on binops requires some extra care, check + // out their docs! BinOp::And => { - return self.assert_and(left, right, message, *location); + return self.assert_and(eaf, left, right, message.as_ref(), *location); } BinOp::Or => { - return self.assert_or(left, right, message, *location); + return self.assert_or(eaf, left, right, message.as_ref(), *location); } + BinOp::Eq => "=:=", BinOp::NotEq => "/=", BinOp::LtInt | BinOp::LtFloat => "<", BinOp::LtEqInt | BinOp::LtEqFloat => "=<", BinOp::GtInt | BinOp::GtFloat => ">", BinOp::GtEqInt | BinOp::GtEqFloat => ">=", + BinOp::AddInt | BinOp::AddFloat | BinOp::SubInt @@ -1027,35 +1379,105 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { } }; - let left_document = self.assign_to_variable(left, &mut assignments); - let right_document = self.assign_to_variable(right, &mut assignments); - ( - binop_documents( - left_document.clone(), - operator_document, - right_document.clone(), - ), - vec![ - ("kind", atom("binary_operator")), - ("operator", atom(operator.name())), - ( - "left", - asserted_expression( - AssertExpression::from_expression(left), - Some(left_document), - left.location(), - ), - ), - ( - "right", - asserted_expression( - AssertExpression::from_expression(right), - Some(right_document), - right.location(), - ), - ), - ], - ) + // If the left or right hand side are not simple variables we'll + // need to first assign those to throwaway variables and keep + // track of those names. + let left = if !left.is_var() { + let name = self.new_throwaway_variable(); + eaf.match_operator(); + eaf.variable_pattern(&name); + self.maybe_block_expr(eaf, left); + AssertionExpression::from_throwaway_variable(name, left) + } else { + AssertionExpression::from_expression(left) + }; + + let right = if !right.is_var() { + let name = self.new_throwaway_variable(); + eaf.match_operator(); + eaf.variable_pattern(&name); + self.maybe_block_expr(eaf, right); + AssertionExpression::from_throwaway_variable(name, right) + } else { + AssertionExpression::from_expression(right) + }; + + let case = eaf.start_case(); + + // Then we need to apply the operator. If any of the two sides + // has been bound to a variable we can use that name directly! + eaf.binary_operator(erlang_operator); + self.runtime_value(eaf, &left); + self.runtime_value(eaf, &right); + + // If the operator evaluates to true the assertion succeeded. + // We can just return nil. + let clause = eaf.start_case_clause(); + eaf.atom_pattern("true"); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + eaf.atom("nil"); + eaf.end_clause_body(clause); + + // Otherwise we want to throw a runtime error! + let clause = eaf.start_case_clause(); + eaf.atom_pattern("false"); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + self.assert_binary_operator_error( + eaf, + *operator, + left, + right, + message.as_ref(), + *location, + ); + eaf.end_clause_body(clause); + + eaf.end_case(case); + } + + TypedExpr::Call { fun, arguments, .. } => { + // When asserting on a call, we want to include the values of + // each argument in the assertion error in case of failure. + // This means we first have to evaluate each argument and bind + // it to a variable so that we can later reference them from the + // error message without evaluating each argument twice! + let mut call_arguments = Vec::with_capacity(arguments.len()); + for argument in arguments { + let argument = if !argument.value.is_var() { + let name = self.new_throwaway_variable(); + eaf.match_operator(); + eaf.variable_pattern(&name); + self.maybe_block_expr(eaf, &argument.value); + AssertionExpression::from_throwaway_variable(name, &argument.value) + } else { + AssertionExpression::from_expression(&argument.value) + }; + call_arguments.push(argument); + } + + let case = eaf.start_case(); + self.call_in_assert(eaf, fun, &call_arguments); + + // If the operator evaluates to true the assertion succeeded. + // We can just return nil. + let clause = eaf.start_case_clause(); + eaf.atom_pattern("true"); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + eaf.atom("nil"); + eaf.end_clause_body(clause); + + // Otherwise we want to throw a runtime error! + let clause = eaf.start_case_clause(); + eaf.atom_pattern("false"); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + self.assert_call_error(eaf, value, &call_arguments, message.as_ref(), *location); + eaf.end_clause_body(clause); + + eaf.end_case(case); } TypedExpr::Int { .. } @@ -1079,43 +1501,35 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { | TypedExpr::RecordUpdate { .. } | TypedExpr::NegateBool { .. } | TypedExpr::NegateInt { .. } - | TypedExpr::Invalid { .. } => ( - self.maybe_block_expr(value), - vec![ - ("kind", atom("expression")), - ( - "expression", - asserted_expression( - AssertExpression::from_expression(value), - Some("false".to_doc()), - value.location(), - ), - ), - ], - ), - }; - - fields.push(("start", location.start.to_doc())); - fields.push(("'end'", value.location().end.to_doc())); - fields.push(("expression_start", value.location().start.to_doc())); - - let clauses = docvec![ - line(), - "true -> nil;", - line(), - "false -> ", - self.erlang_error("assert", &message, *location, fields), - ]; - - docvec![ - assignments, - "case ", - subject, - " of", - clauses.nest(INDENT), - line(), - "end" - ] + | TypedExpr::Invalid { .. } => { + let case = eaf.start_case(); + self.maybe_block_expr(eaf, value); + + // If the expression evaluates to true the assertion succeeded. + // We can just return nil. + let clause = eaf.start_case_clause(); + eaf.atom_pattern("true"); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + eaf.atom("nil"); + eaf.end_clause_body(clause); + + // Otherwise we want to throw a runtime error! + let clause = eaf.start_case_clause(); + eaf.atom_pattern("false"); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + self.assert_expression_error( + eaf, + AssertionExpression::from_expression(value).evaluated_to_bool(false), + message.as_ref(), + *location, + ); + eaf.end_clause_body(clause); + + eaf.end_case(case); + } + } } /// In Gleam, the `&&` operator is short-circuiting, meaning that we can't @@ -1144,82 +1558,74 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// end /// ``` /// - fn assert_and( + fn assert_and( &mut self, + eaf: &mut impl Eaf, left: &'a TypedExpr, right: &'a TypedExpr, - message: Document<'a>, + message: Option<&'a TypedExpr>, location: SrcSpan, - ) -> Document<'a> { - let left_kind = AssertExpression::from_expression(left); - let right_kind = AssertExpression::from_expression(right); - - let fields_if_short_circuiting = vec![ - ("kind", atom("binary_operator")), - ("operator", atom("&&")), - ( - "left", - asserted_expression(left_kind, Some("false".to_doc()), left.location()), - ), - ( - "right", - asserted_expression(AssertExpression::Unevaluated, None, right.location()), - ), - ("start", location.start.to_doc()), - ("'end'", right.location().end.to_doc()), - ("expression_start", left.location().start.to_doc()), - ]; - - let fields = vec![ - ("kind", atom("binary_operator")), - ("operator", atom("&&")), - ( - "left", - asserted_expression(left_kind, Some("true".to_doc()), left.location()), - ), - ( - "right", - asserted_expression(right_kind, Some("false".to_doc()), right.location()), - ), - ("start", location.start.to_doc()), - ("'end'", right.location().end.to_doc()), - ("expression_start", left.location().start.to_doc()), - ]; - - let right_clauses = docvec![ - line(), - "true -> nil;", - line(), - "false -> ", - self.erlang_error("assert", &message, location, fields), - ]; - - let left_clauses = docvec![ - line(), - "true -> ", - docvec![ - "case ", - self.maybe_block_expr(right), - " of", - right_clauses.nest(INDENT), - line(), - "end" - ] - .nest(INDENT), - ";", - line(), - "false -> ", - self.erlang_error("assert", &message, location, fields_if_short_circuiting,), - ]; - - docvec![ - "case ", - self.maybe_block_expr(left), - " of", - left_clauses.nest(INDENT), - line(), - "end" - ] + ) { + let case = eaf.start_case(); + self.maybe_block_expr(eaf, left); + + // In case the first expression is true, we get to evaluate the second + // one as well, then we will be able to tell if the assertion failed or + // not! + let clause = eaf.start_case_clause(); + eaf.atom_pattern("true"); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + { + // Now we have to match on the right hand side! + let case = eaf.start_case(); + self.maybe_block_expr(eaf, right); + + // If it's true the assertion succeded! We can return `nil`. + let clause = eaf.start_case_clause(); + eaf.atom_pattern("true"); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + eaf.atom("nil"); + eaf.end_clause_body(clause); + + // If it's false the assertion failed! The left hand side was true + // but this one evaluated to false :( + let clause = eaf.start_case_clause(); + eaf.atom_pattern("false"); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + self.assert_binary_operator_error( + eaf, + BinOp::And, + AssertionExpression::from_expression(left).evaluated_to_bool(true), + AssertionExpression::from_expression(right).evaluated_to_bool(false), + message, + location, + ); + eaf.end_clause_body(clause); + eaf.end_case(case); + } + eaf.end_clause_body(clause); + + // In case the first expression is false, we want to fail fast. We are + // short circuiting without evaluating the right hand side! This side + // just build an error. + let clause = eaf.start_case_clause(); + eaf.atom_pattern("false"); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + self.assert_binary_operator_error( + eaf, + BinOp::And, + AssertionExpression::from_expression(left).evaluated_to_bool(false), + AssertionExpression::from_expression(right).was_unevaluated(), + message, + location, + ); + eaf.end_clause_body(clause); + + eaf.end_case(case); } /// Similar to `&&`, `||` is also short-circuiting in Gleam. However, if `||` @@ -1230,602 +1636,649 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// The only difference is that due to the nature of `||`, if the assertion fails, /// we know that both sides must have evaluated to `false`, so we don't /// need to store the values of them in variables beforehand. - fn assert_or( + fn assert_or( &mut self, + eaf: &mut impl Eaf, left: &'a TypedExpr, right: &'a TypedExpr, - message: Document<'a>, + message: Option<&'a TypedExpr>, location: SrcSpan, - ) -> Document<'a> { - let fields = vec![ - ("kind", atom("binary_operator")), - ("operator", atom("||")), - ( - "left", - asserted_expression( - AssertExpression::from_expression(left), - Some("false".to_doc()), - left.location(), - ), - ), - ( - "right", - asserted_expression( - AssertExpression::from_expression(right), - Some("false".to_doc()), - right.location(), - ), - ), - ("start", location.start.to_doc()), - ("'end'", right.location().end.to_doc()), - ("expression_start", left.location().start.to_doc()), - ]; - - let clauses = docvec![ - line(), - "true -> nil;", - line(), - "false -> ", - self.erlang_error("assert", &message, location, fields), - ]; - - docvec![ - "case ", - docvec![ - self.maybe_block_expr(left), - " orelse ", - self.maybe_block_expr(right) - ] - .nest(INDENT), - " of", - clauses.nest(INDENT), - line(), - "end" - ] - } - - fn block(&mut self, statements: &'a Vec1) -> Document<'a> { - if statements.len() == 1 - && let Statement::Expression(expression) = statements.first() - && !needs_begin_end_wrapping(expression) - { - return docvec!['(', self.expr(expression), ')']; - } - - let outer_scope = self.current_scope_vars.clone(); - let document = self.statement_sequence(statements); - self.current_scope_vars = outer_scope; + ) { + let case = eaf.start_case(); + eaf.binary_operator("orelse"); + self.maybe_block_expr(eaf, left); + self.maybe_block_expr(eaf, right); + + // If the result is true, then the assertion succeeded, we can return + // nil. + let clause = eaf.start_case_clause(); + eaf.atom_pattern("true"); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + eaf.atom("nil"); + eaf.end_clause_body(clause); + + // But if it fails we know that both sides of the assertion resulted in + // a false value. In that case we throw an error. + + let clause = eaf.start_case_clause(); + eaf.atom_pattern("false"); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + self.assert_binary_operator_error( + eaf, + BinOp::Or, + AssertionExpression::from_expression(left).evaluated_to_bool(false), + AssertionExpression::from_expression(right).evaluated_to_bool(false), + message, + location, + ); + eaf.end_clause_body(clause); - begin_end(document) + eaf.end_case(case); } - fn tuple_index(&mut self, tuple: &'a TypedExpr, index: u64) -> Document<'a> { - let index_doc = eco_format!("{}", (index + 1)).to_doc(); - let tuple_doc = self.maybe_block_expr(tuple); - "erlang:element" - .to_doc() - .append(wrap_arguments([index_doc, tuple_doc])) - } + /// This generates the code that throws a runtime error whan an `assert` + /// that is checking the result of a binary operator fails. + fn assert_binary_operator_error( + &mut self, + eaf: &mut impl Eaf, + operator: BinOp, + left: AssertionExpression<'a>, + right: AssertionExpression<'a>, + message: Option<&'a TypedExpr>, + location: SrcSpan, + ) { + let error = self.start_runtime_error(eaf, RuntimeErrorKind::Assert, location, message); - fn var(&mut self, name: &'a str, constructor: &'a ValueConstructor) -> Document<'a> { - match &constructor.variant { - ValueConstructorVariant::Record { - name: record_name, .. - } => match constructor.type_.deref() { - Type::Fn { arguments, .. } => { - let chars = incrementing_arguments_list(arguments.len()); - "fun(" - .to_doc() - .append(chars.clone()) - .append(") -> {") - .append(atom_string(to_snake_case(record_name))) - .append(", ") - .append(chars) - .append("} end") - } - Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => { - atom_string(to_snake_case(record_name)) - } - }, + eaf.map_field(); + eaf.atom("kind"); + eaf.atom("binary_operator"); - ValueConstructorVariant::LocalVariable { .. } => self.local_var_name(name), + eaf.map_field(); + eaf.atom("operator"); + eaf.atom(operator.name()); - ValueConstructorVariant::ModuleConstant { literal, .. } => self.const_inline(literal), + eaf.map_field(); + eaf.atom("left"); + self.assertion_expression_map(eaf, &left); - ValueConstructorVariant::ModuleFn { - arity, - external_erlang: Some((module, name)), - .. - } if *module == self.module_generator.module.name => { - function_reference(None, name, *arity) - } + eaf.map_field(); + eaf.atom("right"); + self.assertion_expression_map(eaf, &right); - ValueConstructorVariant::ModuleFn { - arity, - external_erlang: Some((module, name)), - .. - } => function_reference(Some(module), name, *arity), + eaf.map_field(); + eaf.atom("start"); + eaf.int(location.start.into()); - ValueConstructorVariant::ModuleFn { arity, module, .. } - if *module == self.module_generator.module.name => - { - function_reference(None, name, *arity) - } + eaf.map_field(); + eaf.atom("end"); + eaf.int(right.location.end.into()); - ValueConstructorVariant::ModuleFn { - arity, - module, - name, - .. - } => function_reference(Some(module), name, *arity), - } - } + eaf.map_field(); + eaf.atom("expression_start"); + eaf.int(left.location.start.into()); - fn fun(&mut self, arguments: &'a [TypedArg], body: &'a [TypedStatement]) -> Document<'a> { - let outer_scope = self.current_scope_vars.clone(); - let doc = "fun" - .to_doc() - .append(self.fun_arguments(arguments).append(" ->")) - .append( - break_("", " ") - .append(self.statement_sequence(body)) - .nest(INDENT), - ) - .append(break_("", " ")) - .append("end") - .group(); - self.current_scope_vars = outer_scope; - doc + self.end_runtime_error(eaf, error); } - fn negate_with(&mut self, op: &'static str, value: &'a TypedExpr) -> Document<'a> { - docvec![op, self.maybe_block_expr(value)] + /// This generates the code that throws a runtime error whan an `assert` + /// that is checking the result of an arbitrary expression fails. + fn assert_expression_error( + &mut self, + eaf: &mut impl Eaf, + expression: AssertionExpression<'a>, + message: Option<&'a TypedExpr>, + location: SrcSpan, + ) { + let error = self.start_runtime_error(eaf, RuntimeErrorKind::Assert, location, message); + + eaf.map_field(); + eaf.atom("kind"); + eaf.atom("expression"); + + // If assert fails on an expression's result then we know it must have + // evaluated to false! + eaf.map_field(); + eaf.atom("expression"); + self.assertion_expression_map(eaf, &expression); + + eaf.map_field(); + eaf.atom("start"); + eaf.int(location.start.into()); + + eaf.map_field(); + eaf.atom("end"); + eaf.int(expression.location.end.into()); + + eaf.map_field(); + eaf.atom("expression_start"); + eaf.int(expression.location.start.into()); + + self.end_runtime_error(eaf, error); } - fn expr_list( + fn assert_call_error( &mut self, - elements: &'a [TypedExpr], - tail: &'a Option>, - ) -> Document<'a> { - let elements = join( - elements - .iter() - .map(|element| self.maybe_block_expr(element)), - break_(",", ", "), - ); - list( - elements, - tail.as_ref().map(|element| self.maybe_block_expr(element)), - ) - } + eaf: &mut impl Eaf, + call: &'a TypedExpr, + arguments: &[AssertionExpression<'a>], + message: Option<&'a TypedExpr>, + location: SrcSpan, + ) { + let error = self.start_runtime_error(eaf, RuntimeErrorKind::Assert, location, message); - fn call(&mut self, fun: &'a TypedExpr, arguments: &'a [TypedCallArg]) -> Document<'a> { - let arguments = arguments - .iter() - .map(|argument| self.maybe_block_expr(&argument.value)) - .collect(); + eaf.map_field(); + eaf.atom("kind"); + eaf.atom("function_call"); + + eaf.map_field(); + eaf.atom("arguments"); + for argument in arguments { + eaf.cons_list(); + self.assertion_expression_map(eaf, argument); + } + eaf.empty_list(); - self.docs_arguments_call(fun, arguments) + eaf.map_field(); + eaf.atom("start"); + eaf.int(location.start.into()); + + eaf.map_field(); + eaf.atom("end"); + eaf.int(call.location().end.into()); + + eaf.map_field(); + eaf.atom("expression_start"); + eaf.int(call.location().start.into()); + + self.end_runtime_error(eaf, error); } - fn docs_arguments_call( + /// Given an expression being asserted on. This generates the code for an + /// Erlang map that describes it: with a field for its kind, its value, and + /// its location in the source code. + fn assertion_expression_map( &mut self, - fun: &'a TypedExpr, - mut arguments: Vec>, - ) -> Document<'a> { - match fun { - TypedExpr::ModuleSelect { - constructor: ModuleValueConstructor::Record { name, .. }, - .. - } - | TypedExpr::Var { - constructor: - ValueConstructor { - variant: ValueConstructorVariant::Record { name, .. }, - .. - }, - .. - } => tuple(std::iter::once(atom_string(to_snake_case(name))).chain(arguments)), + eaf: &mut impl Eaf, + expression: &AssertionExpression<'a>, + ) { + let AssertionExpression { + kind, + runtime_value, + location, + } = expression; - TypedExpr::Var { - constructor: - ValueConstructor { - variant: - ValueConstructorVariant::ModuleFn { - external_erlang: Some((module, name)), - .. - } - | ValueConstructorVariant::ModuleFn { module, name, .. }, - .. - }, - .. - } => self.module_fn_with_arguments(module, name, arguments), + let map = eaf.start_map(); - // Match against a Constant::Var that contains a function. - // We want this to be emitted like a normal function call, not a function variable - // substitution. - TypedExpr::Var { - constructor: - ValueConstructor { - variant: - ValueConstructorVariant::ModuleConstant { - literal: - Constant::Var { - constructor: Some(constructor), - .. - }, - .. - }, - .. - }, - .. - } if constructor.variant.is_module_fn() => match &constructor.variant { - ValueConstructorVariant::ModuleFn { - external_erlang: Some((module, name)), - .. - } - | ValueConstructorVariant::ModuleFn { module, name, .. } => { - self.module_fn_with_arguments(module, name, arguments) + eaf.map_field(); + eaf.atom("kind"); + eaf.atom(match kind { + AssertedExpressionKind::Literal => "literal", + AssertedExpressionKind::Expression => "expression", + AssertedExpressionKind::Unevaluated => "unevaluated", + }); + + if runtime_value.is_some() { + eaf.map_field(); + eaf.atom("value"); + self.runtime_value(eaf, expression); + } + + eaf.map_field(); + eaf.atom("start"); + eaf.int(location.start.into()); + + eaf.map_field(); + eaf.atom("end"); + eaf.int(location.end.into()); + + eaf.end_map(map); + } + + /// This takes a value that is in an assertion (and might have been bound + /// to a variable somewhere) and produces the code that will reference + /// such value. + /// + fn runtime_value( + &mut self, + eaf: &mut impl Eaf, + expression: &AssertionExpression<'a>, + ) { + match expression + .runtime_value + .as_ref() + .expect("trying to reference unevaluated assert value") + { + AssertedExpressionRuntimeValue::KnownBool(true) => eaf.atom("true"), + AssertedExpressionRuntimeValue::KnownBool(false) => eaf.atom("false"), + AssertedExpressionRuntimeValue::Variable(name) => eaf.variable(name), + AssertedExpressionRuntimeValue::Expression(expr) => self.maybe_block_expr(eaf, expr), + } + } + + fn tuple_index( + &mut self, + eaf: &mut impl Eaf, + tuple: &'a TypedExpr, + index: u64, + ) { + let call = eaf.start_remote_call("erlang".into(), "element"); + eaf.int((index + 1).into()); + self.maybe_block_expr(eaf, tuple); + eaf.end_call(call); + } + + fn var( + &mut self, + eaf: &mut impl Eaf, + name: &'a str, + constructor: &'a ValueConstructor, + ) { + match &constructor.variant { + ValueConstructorVariant::Record { + name: record_name, .. + } => match constructor.type_.deref() { + // We have a variable referencing a record: we are either + // referencing a record constructor function, or building a + // record that has no fields: + // + // ```gleam + // type Wibble { + // Wibble + // Wobble(Int) + // } + // + // pub fn main() { + // Wibble + // //^^^^^^ Building record with no fields + // Wobble + // //^^^^^^ Referencing record constructor function + // } + // ``` + Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => { + eaf.atom(&to_snake_case(record_name)) } - ValueConstructorVariant::LocalVariable { .. } - | ValueConstructorVariant::ModuleConstant { .. } - | ValueConstructorVariant::Record { .. } => { - unreachable!("The above clause guard ensures that this is a module fn") + Type::Fn { arguments, .. } => { + self.record_builder_anonymous_function(eaf, record_name, arguments.len()) } }, - TypedExpr::ModuleSelect { - constructor: - ModuleValueConstructor::Fn { - external_erlang: Some((module, name)), - .. - } - | ModuleValueConstructor::Fn { module, name, .. }, + ValueConstructorVariant::LocalVariable { location, .. } => { + eaf.variable(&self.local_var_name(location)) + } + + ValueConstructorVariant::ModuleConstant { literal, .. } => { + self.inlined_constant(eaf, literal) + } + + ValueConstructorVariant::ModuleFn { + arity, + external_erlang: Some((module, name)), .. } => { - let arguments = wrap_arguments(arguments); let name = escape_erlang_existing_name(name); - // We use the constructor Fn variant's `module` and function `name`. - // It would also be valid to use the module and label as in the - // Gleam code, but using the variant can result in an optimisation - // in which the target function is used for `external fn`s, removing - // one layer of wrapping. - // This also enables an optimisation in the Erlang compiler in which - // some Erlang BIFs can be replaced with literals if their arguments - // are literals, such as `binary_to_atom`. - atom_string(module_erlang_name(module)) - .append(":") - .append(atom_string(name.into())) - .append(arguments) - } - - TypedExpr::Fn { kind, body, .. } if kind.is_capture() => { - if let Statement::Expression(TypedExpr::Call { - fun, - arguments: inner_arguments, - .. - }) = body.first() - { - let mut merged_arguments = Vec::with_capacity(inner_arguments.len()); - for arg in inner_arguments { - if let TypedExpr::Var { name, .. } = &arg.value - && name == CAPTURE_VARIABLE - { - merged_arguments.push(arguments.swap_remove(0)) - } else { - merged_arguments.push(self.maybe_block_expr(&arg.value)) - } - } - self.docs_arguments_call(fun, merged_arguments) + if *module == self.module_generator.module.name { + eaf.function_reference(None, name, *arity) } else { - panic!("Erl printing: Capture was not a call") + eaf.function_reference(Some(module.into()), name, *arity) } } - TypedExpr::Fn { .. } - | TypedExpr::Call { .. } - | TypedExpr::Todo { .. } - | TypedExpr::Panic { .. } - | TypedExpr::RecordAccess { .. } - | TypedExpr::TupleIndex { .. } => { - let arguments = wrap_arguments(arguments); - self.expr(fun).surround("(", ")").append(arguments) + ValueConstructorVariant::ModuleFn { arity, module, .. } + if *module == self.module_generator.module.name => + { + eaf.function_reference(None, escape_erlang_existing_name(name), *arity) } - TypedExpr::Int { .. } - | TypedExpr::Float { .. } - | TypedExpr::String { .. } - | TypedExpr::Block { .. } - | TypedExpr::Pipeline { .. } - | TypedExpr::Var { .. } - | TypedExpr::List { .. } - | TypedExpr::BinOp { .. } - | TypedExpr::Case { .. } - | TypedExpr::PositionalAccess { .. } - | TypedExpr::ModuleSelect { .. } - | TypedExpr::Tuple { .. } - | TypedExpr::Echo { .. } - | TypedExpr::BitArray { .. } - | TypedExpr::RecordUpdate { .. } - | TypedExpr::NegateBool { .. } - | TypedExpr::NegateInt { .. } - | TypedExpr::Invalid { .. } => { - let arguments = wrap_arguments(arguments); - self.maybe_block_expr(fun).append(arguments) - } + ValueConstructorVariant::ModuleFn { + arity, + module, + name, + .. + } => eaf.function_reference( + Some(module.into()), + escape_erlang_existing_name(name), + *arity, + ), } } - fn record_update( + fn call( &mut self, - updated_record: &'a TypedExpr, - updated_record_assigned_name: &'a Option, - constructor: &'a TypedExpr, + eaf: &mut impl Eaf, + fun: &'a TypedExpr, arguments: &'a [TypedCallArg], - ) -> Document<'a> { - let outer_scope = self.current_scope_vars.clone(); - - let document = match updated_record_assigned_name.as_ref() { - Some(name) => docvec![ - self.simple_variable_let(name, updated_record), - ",", - line(), - self.call(constructor, arguments) - ], - None => self.call(constructor, arguments), - }; - - self.current_scope_vars = outer_scope; - - document + ) { + match how_to_call(fun) { + // If we're building a record then we want to just output a + // tagged tuple, there's no function call at all! + FunctionCall::BuildRecord { name } => self.build_record(eaf, name, arguments), + // If we're calling some module function like `io.println`, `main`, + // `list.map` then we can call the function using its name (and + // module name if it comes from a different module). + FunctionCall::Call { module, name } => { + let call = if module != self.module_generator.module.name { + eaf.start_remote_call(module.into(), escape_erlang_existing_name(name)) + } else { + let call = eaf.start_call(); + eaf.atom(escape_erlang_existing_name(name)); + call + }; + for argument in arguments { + self.maybe_block_expr(eaf, &argument.value); + } + eaf.end_call(call) + } + // If we're calling anything else (like an anonymous function, or + // the result of another function call) we generate its code and + // call that result directly. + FunctionCall::DirectCall => { + let call = eaf.start_call(); + self.maybe_block_expr(eaf, fun); + for argument in arguments { + self.maybe_block_expr(eaf, &argument.value); + } + eaf.end_call(call); + } + } } - /// This is used to render a simple variable assignment in Erlang, there's cases - /// when the left hand side of an assignment is known to be a variable with a - /// simple name. In that case we don't have to go through `let_` which needs a - /// whole pattern. + /// This generates the code for a call that happens in an `assert`. + /// For example: `assert wibble.wobble(a, b)`. /// - /// If you need to deal with a complex `let` where the left hand side is a - /// generic pattern use the `let_` function. - fn simple_variable_let(&mut self, name: &'a EcoString, value: &'a TypedExpr) -> Document<'a> { - let body = self.maybe_block_expr(value).group(); - let name = self.next_local_var_name(name.as_str()); - docvec![name, " = ", body] - } + /// This is a function separate from the regular `self.call` since the call + /// arguments are not just TypedExpressions but values that might have been + /// bound to variables in previous statements. + /// Assert has to do it when a call is asserted so that those arguments can + /// be referenced later in the error thrown at runtime! + /// + fn call_in_assert( + &mut self, + eaf: &mut impl Eaf, + fun: &'a TypedExpr, + arguments: &[AssertionExpression<'a>], + ) { + match how_to_call(fun) { + // What comes after `assert` has to produce a boolean, so type + // checking should make it impossible to build a record here. + FunctionCall::BuildRecord { .. } => { + panic!("type checking should make it impossible to call a record in an assert") + } - fn module_fn_with_arguments( - &self, - module: &'a str, - name: &'a str, - arguments: Vec>, - ) -> Document<'a> { - let name = escape_erlang_existing_name(name); - let arguments = wrap_arguments(arguments); - if module == self.module_generator.module.name { - atom(name).append(arguments) - } else { - atom_string(module.replace('/', "@").into()) - .append(":") - .append(atom(name)) - .append(arguments) + // If we're calling some module function like `io.println`, `main`, + // `list.map` then we can call the function using its name (and + // module name if it comes from a different module). + FunctionCall::Call { module, name } => { + let call = if module != self.module_generator.module.name { + eaf.start_remote_call(module.into(), escape_erlang_existing_name(name)) + } else { + let call = eaf.start_call(); + eaf.atom(escape_erlang_existing_name(name)); + call + }; + for argument in arguments { + self.runtime_value(eaf, argument); + } + eaf.end_call(call) + } + + // If we're calling anything else (like an anonymous function, or + // the result of another function call) we generate its code and + // call that result directly. + FunctionCall::DirectCall => { + let call = eaf.start_call(); + self.maybe_block_expr(eaf, fun); + for argument in arguments { + self.runtime_value(eaf, argument); + } + eaf.end_call(call); + } } } - fn case(&mut self, subjects: &'a [TypedExpr], cs: &'a [TypedClause]) -> Document<'a> { - let subjects_doc = if subjects.len() == 1 { - let subject = subjects - .first() - .expect("erl case printing of single subject"); - self.maybe_block_expr(subject).group() + /// Given a Gleam record name and the arguments it's called with, this + /// generates the code to build such record. + /// For example: `Wibble(1, 2)` would be `record_builder("Wibble", [1, 2])`. + /// It would result in a tuple like this: `{wibble, 1, 2}`. + /// + /// Notice how the name you have to specify is the _Gleam name_ of the + /// record. This function will take care of turning it to snake case! + fn build_record( + &mut self, + eaf: &mut impl Eaf, + record_name: &str, + arguments: &'a [TypedCallArg], + ) { + if arguments.is_empty() { + eaf.atom(&to_snake_case(record_name)) } else { - tuple( - subjects - .iter() - .map(|element| self.maybe_block_expr(element)), - ) - }; - "case " - .to_doc() - .append(subjects_doc) - .append(" of") - .append(line().append(self.clauses(cs)).nest(INDENT)) - .append(line()) - .append("end") - .group() - } - - fn clauses(&mut self, cs: &'a [TypedClause]) -> Document<'a> { - join( - cs.iter().map(|c| { - let outer_scope = self.current_scope_vars.clone(); - let erl = self.clause(c); - // Reset the known variables now the clauses' scope has ended - self.current_scope_vars = outer_scope; - erl - }), - ";".to_doc().append(lines(2)), - ) - } - - fn clause(&mut self, clause: &'a TypedClause) -> Document<'a> { - let Clause { - guard, - pattern, - alternative_patterns, - then, - .. - } = clause; - - // These are required to get the alternative patterns working properly. - // Simply rendering the duplicate erlang clauses breaks the variable - // rewriting because each pattern would define different (rewritten) - // variables names. - let initial_erlang_vars = self.erl_function_scope_vars.clone(); - let initial_scope_vars = self.current_scope_vars.clone(); - - let mut branches_docs = Vec::with_capacity(alternative_patterns.len() + 1); - for patterns in std::iter::once(pattern).chain(alternative_patterns) { - // Erlang doesn't support alternative patterns, so we turn each - // alternative into a branch of its own. - // For each alternative, before generating the body, we need to reset - // the variables in scope to what they are before the case expression, - // so that a branch will not interfere with the other ones! - self.erl_function_scope_vars = initial_erlang_vars.clone(); - self.current_scope_vars = initial_scope_vars.clone(); - let mut pattern_printer = PatternPrinter::new(self); - - let pattern = match patterns.as_slice() { - [pattern] => pattern_printer.print(pattern), - _ => tuple(patterns.iter().map(|pattern| { - pattern_printer.reset_variables(); - pattern_printer.print(pattern) - })), - }; - - let PatternPrinter { - generator: _, - variables: _, - guards, - assignments, - } = pattern_printer; + let tuple = eaf.start_tuple(); + eaf.atom(&to_snake_case(record_name)); + for argument in arguments { + self.maybe_block_expr(eaf, &argument.value); + } + eaf.end_tuple(tuple) + } + } - let assignments_map = assignments - .iter() - .map(|assignment| (assignment.gleam_name.clone(), assignment)) - .collect(); + fn case( + &mut self, + eaf: &mut impl Eaf, + subjects: &'a [TypedExpr], + clauses: &'a [TypedClause], + ) { + let case = eaf.start_case(); + + // If there's more than a single subject we will need to wrap those in a + // tuple and start matching on tuple patterns. That's because Erlang + // doesn't support matching on multiple subjects like Gleam. + match subjects { + [subject] => self.maybe_block_expr(eaf, subject), + subjects => { + let tuple = eaf.start_tuple(); + for subject in subjects { + self.maybe_block_expr(eaf, subject); + } + eaf.end_tuple(tuple); + } + } - let guard = self.optional_clause_guard(guard.as_ref(), guards, &assignments_map); - let then = self.clause_consequence(then, assignments).group(); - branches_docs.push(docvec![ - pattern, - guard, - " ->", - docvec![line(), then].nest(INDENT), - ]); + for clause in clauses { + let taken_names_before_clause = self.taken_names.clone(); + + self.clause_branch(eaf, &clause.pattern, clause); + + // Erlang doesn't support alternative patterns so we're gonna have + // to turn those into separate branches! + // Since those are going to have the exact same body we don't want + // it to use different updated variable names. + // So they should have the same scope that existed before generating + // the first clause branch. + // For example: + // + // ```gleam + // case x { + // 1 | 2 -> { let a = Nil } + // _ -> Nil + // } + // ``` + // + // We want the generated code to look like this: + // + // ```erl + // case x of + // 1 -> A = nil; + // 2 -> A = nil; + // % ^ We're still using `A`, not `A@1`! + // _ -> nil + // end + // ``` + // + for pattern in &clause.alternative_patterns { + self.taken_names = taken_names_before_clause.clone(); + self.clause_branch(eaf, pattern, clause); + } } - join(branches_docs, ";".to_doc().append(lines(2))) + eaf.end_case(case); } - fn clause_consequence( + /// Given a pattern and the branch it belongs to this generates an Erlang + /// case clause for that pattern. + fn clause_branch( &mut self, - consequence: &'a TypedExpr, - // Further assignments that the pattern might need to introduce at the start - // of the new block. - assignments: Vec>, - ) -> Document<'a> { - let assignment_doc = if assignments.is_empty() { - nil() - } else { - let separator = ",".to_doc().append(line()); - join( - assignments - .iter() - .map(|assignment| assignment.to_assignment_doc()), - separator.clone(), - ) - .append(separator) + eaf: &mut impl Eaf, + patterns: &'a Vec>>, + clause: &'a Clause>, + ) { + let clause_pattern = eaf.start_case_clause(); + + // We start by generating the case clause pattern. If we're matching on + // multiple subjects (and so patterns has more that a single item) those + // are gonna be wrapped in a tuple pattern. + // That's how we match on multiple things on the Erlang target. + let mut pattern_generator = PatternGenerator::new(self); + match patterns.as_slice() { + [pattern] => pattern_generator.pattern(eaf, pattern), + patterns => { + let tuple = eaf.start_tuple_pattern(); + for pattern in patterns { + pattern_generator.pattern(eaf, pattern); + } + eaf.end_tuple_pattern(tuple); + } }; - let consequence = if let TypedExpr::Block { statements, .. } = consequence { - self.statement_sequence(statements) + let variables_to_add_later = pattern_generator.variables_to_add_later; + + let clause_guards = eaf.end_clause_pattern(clause_pattern); + if let Some(guard) = clause.guard.as_ref() { + self.clause_guard(eaf, guard, &variables_to_add_later); + } + + // Finally we can generate the clause body. If the clause is + // followed by a single block then we want it to be a statements + // sequence (and not wrapped in a begin ... end block as we usually + // would when generating code for a block expression). + let clause_body = eaf.end_clause_guards(clause_guards); + self.pattern_assignments(eaf, variables_to_add_later); + if let TypedExpr::Block { statements, .. } = &clause.then { + self.statement_sequence(eaf, statements); } else { - self.expr(consequence) - }; - assignment_doc.append(consequence) + self.expr(eaf, &clause.then); + } + eaf.end_clause_body(clause_body); } - fn const_inline(&mut self, literal: &'a TypedConstant) -> Document<'a> { + /// Erlang doesn't have a special constant declaration syntax; so each Gleam + /// constant is simply inlined anywhere it is used. + /// + /// This function produces the code of a constant expression. + /// + fn inlined_constant(&mut self, eaf: &mut impl Eaf, literal: &'a TypedConstant) { match literal { - Constant::Int { value, .. } => int(value), - Constant::Float { value, .. } => float(value), - Constant::String { value, .. } => string(value), + Constant::Int { int_value, .. } => eaf.int(int_value.clone()), + Constant::Float { float_value, .. } => eaf.float(float_value.value()), + Constant::String { value, .. } => eaf.string(value), + Constant::Var { + name, constructor, .. + } => self.var( + eaf, + name, + constructor + .as_ref() + .expect("This is guaranteed to hold a value."), + ), + Constant::Tuple { elements, .. } => { - tuple(elements.iter().map(|element| self.const_inline(element))) + let tuple = eaf.start_tuple(); + for element in elements { + self.inlined_constant(eaf, element) + } + eaf.end_tuple(tuple); } Constant::List { elements, tail, .. } => { + for element in elements { + eaf.cons_list(); + self.inlined_constant(eaf, element) + } match tail { - // There's no tail in the list, we join all the elements and - // call it a day. - None => join( - elements.iter().map(|element| self.const_inline(element)), - break_(",", ", "), - ), + // If there's no tail we simply add an empty list cell to + // end the cons list. + None => eaf.empty_list(), Some(tail) => match tail.list_elements() { - // There's a tail in the list whose elements are all known at - // compile time. In this case we replace the tail with those - // elements and create a single flat list. - Some(tail_elements) => join( - elements - .iter() - .chain(tail_elements) - .map(|element| self.const_inline(element)), - break_(",", ", "), - ), - // There's a tail in the list but we can't really tell what its - // elements are at compile time. This means we have to use - // erlang's syntax to append to a list. - None => { - let elements = join( - elements.iter().map(|element| self.const_inline(element)), - break_(",", ", "), - ); - docvec![elements, " | ", self.const_inline(tail)] + // If there's a tail and we don't statically know the + // elements it's made of, we add it as a regular Erlang + // tail and it will be `[1, 2 | Tail]`. + None => self.inlined_constant(eaf, tail), + // But if we can tell it has some fixed amount of + // constant elements, then those are inlined too! + Some(list_elements) => { + for element in list_elements { + eaf.cons_list(); + self.inlined_constant(eaf, element); + } + eaf.empty_list(); } }, } - .nest(INDENT) - .surround("[", "]") - .group() } - Constant::BitArray { segments, .. } => bit_array( - segments - .iter() - .map(|s| self.const_segment(&s.value, &s.options)), - ), + Constant::BitArray { segments, .. } => { + let bit_array = eaf.start_bit_array(); + for segment in segments { + self.bit_array_constant_segment(eaf, segment); + } + eaf.end_bit_array(bit_array); + } Constant::Record { type_, arguments, .. - } if arguments.is_none() => { + } => { let tag = literal .constant_record_tag() .expect("record without inferred constructor made it to code generation"); - match type_.deref() { - Type::Fn { arguments, .. } => record_constructor_function(tag, arguments.len()), - Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => { - atom_string(to_snake_case(&tag)) + match arguments { + // This is a regular record call, we're building a record as + // usual as a tagged tuple. + Some(arguments) => { + let tuple = eaf.start_tuple(); + eaf.atom(&to_snake_case(&tag)); + for argument in arguments { + self.inlined_constant(eaf, &argument.value); + } + eaf.end_tuple(tuple); } + // Otherwise we are either referencing a record constructor + // function, or building a record that has no fields: + // + // ```gleam + // type Wibble { + // Wibble + // Wobble(Int) + // } + // + // const a = Wibble + // // ^^^^^^ Building record with no fields + // const b = Wobble + // // ^^^^^^ Referencing record constructor function + // ``` + None => match type_::collapse_links(type_.clone()).deref() { + Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => { + eaf.atom(&to_snake_case(&tag)) + } + Type::Fn { arguments, .. } => { + self.record_builder_anonymous_function(eaf, &tag, arguments.len()) + } + }, } } - Constant::Record { arguments, .. } => { - let tag = literal - .constant_record_tag() - .expect("record without inferred constructor made it to code generation"); - - // Record updates are fully expanded during type checking, so we just handle arguments - let arguments_doc = arguments - .iter() - .flatten() - .map(|argument| self.const_inline(&argument.value)); - let tag = atom_string(to_snake_case(&tag)); - tuple(std::iter::once(tag).chain(arguments_doc)) - } - - Constant::Var { - name, constructor, .. - } => self.var( - name, - constructor - .as_ref() - .expect("This is guaranteed to hold a value."), - ), - Constant::StringConcatenation { left, right, .. } => { - self.const_string_concatenate(left, right) + self.constant_string_concatenate(eaf, left, right) } Constant::RecordUpdate { .. } => { @@ -1838,237 +2291,159 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { } } - fn const_string_concatenate( + fn bit_array_constant_segment( &mut self, - left: &'a TypedConstant, - right: &'a TypedConstant, - ) -> Document<'a> { - let left = self.const_string_concatenate_argument(left); - let right = self.const_string_concatenate_argument(right); - const_string_concatenate_bit_array([left, right]) + eaf: &mut impl Eaf, + segment: &'a TypedConstantBitArraySegment, + ) { + eaf.bit_array_segment(); + self.inlined_constant(eaf, &segment.value); + match segment.size() { + Some(TypedConstant::Int { int_value, .. }) if int_value.is_negative() => { + eaf.int(BigInt::ZERO) + } + Some(size) => self.inlined_constant(eaf, size), + None => eaf.atom("default"), + }; + self.bit_array_segment_specifiers(eaf, segment); } - fn const_string_concatenate_inner( + fn bit_array_segment_specifiers( + &self, + eaf: &mut impl Eaf, + segment: &'a BitArraySegment>, + ) { + let options = segment.options.iter(); + eaf.bit_array_segment_specifiers(options.filter_map(|option| match option { + BitArrayOption::Utf8 { .. } | BitArrayOption::Utf8Codepoint { .. } => { + Some(BitArraySegmentSpecifier::Utf8) + } + BitArrayOption::Utf16 { .. } | BitArrayOption::Utf16Codepoint { .. } => { + Some(BitArraySegmentSpecifier::Utf16) + } + BitArrayOption::Utf32 { .. } | BitArrayOption::Utf32Codepoint { .. } => { + Some(BitArraySegmentSpecifier::Utf32) + } + BitArrayOption::Int { .. } => Some(BitArraySegmentSpecifier::Integer), + BitArrayOption::Float { .. } => Some(BitArraySegmentSpecifier::Float), + BitArrayOption::Bytes { .. } => Some(BitArraySegmentSpecifier::Binary), + BitArrayOption::Bits { .. } => Some(BitArraySegmentSpecifier::Bitstring), + BitArrayOption::Signed { .. } => Some(BitArraySegmentSpecifier::Signed), + BitArrayOption::Unsigned { .. } => Some(BitArraySegmentSpecifier::Unsigned), + BitArrayOption::Big { .. } => Some(BitArraySegmentSpecifier::Big), + BitArrayOption::Little { .. } => Some(BitArraySegmentSpecifier::Little), + BitArrayOption::Native { .. } => Some(BitArraySegmentSpecifier::Native), + BitArrayOption::Unit { value, .. } => Some(BitArraySegmentSpecifier::Unit(*value)), + BitArrayOption::Size { .. } => None, + })); + } + + fn constant_string_concatenate( &mut self, + eaf: &mut impl Eaf, left: &'a TypedConstant, right: &'a TypedConstant, - ) -> Document<'a> { - let left = self.const_string_concatenate_argument(left); - let right = self.const_string_concatenate_argument(right); - join([left, right], break_(",", ", ")) - } - - fn const_string_concatenate_argument(&mut self, value: &'a TypedConstant) -> Document<'a> { - match value { - Constant::String { value, .. } => docvec!['"', string_inner(value), "\"/utf8"], - - Constant::Var { - constructor: Some(constructor), - .. - } => match &constructor.variant { - ValueConstructorVariant::ModuleConstant { - literal: Constant::String { value, .. }, - .. - } => docvec!['"', string_inner(value), "\"/utf8"], - ValueConstructorVariant::ModuleConstant { - literal: Constant::StringConcatenation { left, right, .. }, + ) { + let mut items = VecDeque::new(); + items.push_back(left); + items.push_back(right); + + let bit_array = eaf.start_bit_array(); + while let Some(segment) = items.pop_front() { + match segment { + // When concatenating constant strings we flatten out all + // strings that are being concatenated: so that + // `"a" <> "b" <> "c"` becomes a single bitstring like this: + // `<<~"a", ~"b", ~"c">>` rather than nested bitstrings: + // `<<<<~"a", ~"b">>/binary, ~"c">>`. + // If we find a string concatenation we push its separate items + // to be printed next! + Constant::StringConcatenation { left, right, .. } => { + items.push_front(right); + items.push_front(left); + continue; + } + // When concatenating constant strings we want all constant + // variables to also be fully expanded, so that if we have + // + // ```gleam + // const a = "one" + // const b = a <> "two" + // ``` + // + // Any use of b will be replaced with `<<~"one", ~"two">>`. + Constant::Var { + constructor: Some(constructor), .. - } => self.const_string_concatenate_inner(left, right), - ValueConstructorVariant::LocalVariable { .. } - | ValueConstructorVariant::ModuleConstant { .. } - | ValueConstructorVariant::ModuleFn { .. } - | ValueConstructorVariant::Record { .. } => self.const_inline(value), - }, - - Constant::StringConcatenation { left, right, .. } => { - self.const_string_concatenate_inner(left, right) - } - - Constant::Int { .. } - | Constant::Float { .. } - | Constant::Tuple { .. } - | Constant::List { .. } - | Constant::Record { .. } - | Constant::RecordUpdate { .. } - | Constant::BitArray { .. } - | Constant::Var { .. } - | Constant::Todo { .. } - | Constant::Invalid { .. } => self.const_inline(value), - } - } - - fn string_concatenate(&mut self, left: &'a TypedExpr, right: &'a TypedExpr) -> Document<'a> { - let left = self.string_concatenate_argument(left); - let right = self.string_concatenate_argument(right); - bit_array([left, right]) - } - - fn string_concatenate_argument(&mut self, value: &'a TypedExpr) -> Document<'a> { - match value { - TypedExpr::Var { - constructor: - ValueConstructor { - variant: - ValueConstructorVariant::ModuleConstant { - literal: Constant::String { value, .. }, - .. - }, - .. - }, - .. - } - | TypedExpr::String { value, .. } => docvec!['"', string_inner(value), "\"/utf8"], - - TypedExpr::Var { - name, - constructor: - ValueConstructor { - variant: ValueConstructorVariant::LocalVariable { .. }, - .. - }, - .. - } => docvec![self.local_var_name(name), "/binary"], - - TypedExpr::BinOp { - operator: BinOp::Concatenate, - .. - } => docvec![self.expr(value), "/binary"], - - TypedExpr::Int { .. } - | TypedExpr::Float { .. } - | TypedExpr::Block { .. } - | TypedExpr::Pipeline { .. } - | TypedExpr::Var { .. } - | TypedExpr::Fn { .. } - | TypedExpr::List { .. } - | TypedExpr::Call { .. } - | TypedExpr::BinOp { .. } - | TypedExpr::Case { .. } - | TypedExpr::RecordAccess { .. } - | TypedExpr::PositionalAccess { .. } - | TypedExpr::ModuleSelect { .. } - | TypedExpr::Tuple { .. } - | TypedExpr::TupleIndex { .. } - | TypedExpr::Todo { .. } - | TypedExpr::Panic { .. } - | TypedExpr::Echo { .. } - | TypedExpr::BitArray { .. } - | TypedExpr::RecordUpdate { .. } - | TypedExpr::NegateBool { .. } - | TypedExpr::NegateInt { .. } - | TypedExpr::Invalid { .. } => docvec!["(", self.maybe_block_expr(value), ")/binary"], - } - } - - fn const_segment( - &mut self, - value: &'a TypedConstant, - options: &'a [TypedConstantBitArraySegmentOption], - ) -> Document<'a> { - let value_is_a_string_literal = matches!(value, Constant::String { .. }); - - let create_document = |this: &mut Self| { - match value { - // Skip the normal <> surrounds - Constant::String { value, .. } => value.to_doc().surround("\"", "\""), - - // As normal - Constant::Int { .. } | Constant::Float { .. } | Constant::BitArray { .. } => { - this.const_inline(value) + } if let ValueConstructorVariant::ModuleConstant { literal, .. } = + &constructor.variant => + { + items.push_front(literal); + continue; } - // Wrap anything else in parentheses - Constant::Tuple { .. } + Constant::Int { .. } + | Constant::Float { .. } + | Constant::String { .. } + | Constant::Tuple { .. } | Constant::List { .. } - | Constant::Record { .. } - | Constant::RecordUpdate { .. } - | Constant::Var { .. } - | Constant::StringConcatenation { .. } - | Constant::Todo { .. } - | Constant::Invalid { .. } => this.const_inline(value).surround("(", ")"), - } - }; - - let size = |value: &'a TypedConstant, this: &mut Self| { - if let Constant::Int { .. } = value { - Some(":".to_doc().append(this.const_inline(value))) - } else { - Some( - ":".to_doc() - .append(this.const_inline(value).surround("(", ")")), - ) + | Constant::Record { .. } + | Constant::RecordUpdate { .. } + | Constant::BitArray { .. } + | Constant::Var { .. } + | Constant::Invalid { .. } + | Constant::Todo { .. } => (), } - }; - let unit = |value: &'a u8| Some(eco_format!("unit:{value}").to_doc()); + eaf.bit_array_segment(); + self.inlined_constant(eaf, segment); + eaf.atom("default"); + eaf.bit_array_segment_specifiers([BitArraySegmentSpecifier::Utf8]); + } + eaf.end_bit_array(bit_array); + } - bit_array_segment( - create_document, - options, - size, - unit, - value_is_a_string_literal, - false, - self, - ) + fn string_concatenate( + &mut self, + eaf: &mut impl Eaf, + left: &'a TypedExpr, + right: &'a TypedExpr, + ) { + let bit_array = eaf.start_bit_array(); + self.string_concatenate_argument(eaf, left); + self.string_concatenate_argument(eaf, right); + eaf.end_bit_array(bit_array); } - fn assign_to_variable( + fn string_concatenate_argument( &mut self, + eaf: &mut impl Eaf, value: &'a TypedExpr, - assignments: &mut Vec>, - ) -> Document<'a> { - if value.is_var() { - self.expr(value) + ) { + // String concatenation is basically building a bit array with two + // elements. Anything is going to be simply added as a `/binary` segment + // with one exception: if we're dealing with a literal string that needs + // the `/utf8` specifier instead! + // In both cases the size is alwaus automatic, so we generate the + // `default` atom. + eaf.bit_array_segment(); + self.maybe_block_expr(eaf, value); + eaf.atom("default"); + eaf.bit_array_segment_specifiers(if produces_literal_string(value) { + [BitArraySegmentSpecifier::Utf8] } else { - let value = self.maybe_block_expr(value); - let variable = self.next_local_var_name(ASSERT_SUBJECT_VARIABLE); - let definition = docvec![variable.clone(), " = ", value, ",", line()]; - assignments.push(definition); - variable - } + [BitArraySegmentSpecifier::Binary] + }); } - fn assert_call( - &mut self, - function: &'a TypedExpr, - arguments: &'a Vec>, - assignments: &mut Vec>, - ) -> (Document<'a>, Vec<(&'static str, Document<'a>)>) { - let argument_variables = arguments - .iter() - .map(|argument| self.assign_to_variable(&argument.value, assignments)) - .collect_vec(); - - let arguments = join( - argument_variables - .iter() - .zip(arguments) - .map(|(variable, argument)| { - asserted_expression( - AssertExpression::from_expression(&argument.value), - Some(variable.clone()), - argument.location(), - ) - }), - break_(",", ", "), - ) - .nest(INDENT) - .surround("[", "]"); - - ( - self.docs_arguments_call(function, argument_variables), - vec![("kind", atom("function_call")), ("arguments", arguments)], - ) - } - - fn bin_op( + fn bin_op( &mut self, + eaf: &mut impl Eaf, name: &'a BinOp, left: &'a TypedExpr, right: &'a TypedExpr, - ) -> Document<'a> { - let op = match name { + ) { + let operator = match name { BinOp::And => "andalso", BinOp::Or => "orelse", BinOp::LtInt | BinOp::LtFloat => "<", @@ -2077,91 +2452,210 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { BinOp::NotEq => "/=", BinOp::GtInt | BinOp::GtFloat => ">", BinOp::GtEqInt | BinOp::GtEqFloat => ">=", - BinOp::AddInt => "+", - BinOp::AddFloat => "+", - BinOp::SubInt => "-", - BinOp::SubFloat => "-", - BinOp::MultInt => "*", - BinOp::MultFloat => "*", - BinOp::DivFloat => return self.float_div(left, right), - BinOp::DivInt => return self.int_div(left, right, "div"), - BinOp::RemainderInt => return self.int_div(left, right, "rem"), - BinOp::Concatenate => return self.string_concatenate(left, right), + BinOp::AddInt | BinOp::AddFloat => "+", + BinOp::SubInt | BinOp::SubFloat => "-", + BinOp::MultInt | BinOp::MultFloat => "*", + + // Division needs some extra case, in Gleam dividing by 0 results + // in 0; while in Erlang that's an exception. + BinOp::DivFloat => return self.float_division(eaf, left, right), + BinOp::DivInt => return self.int_division(eaf, left, right, "div"), + BinOp::RemainderInt => return self.int_division(eaf, left, right, "rem"), + + // String concatenation is not a binop at all! It's just building a + // bit array. + BinOp::Concatenate => return self.string_concatenate(eaf, left, right), }; - self.binop_exprs(left, op, right) - } - - fn float_div(&mut self, left: &'a TypedExpr, right: &'a TypedExpr) -> Document<'a> { - if right.is_non_zero_compile_time_number() { - return self.binop_exprs(left, "/", right); - } else if right.is_zero_compile_time_number() { - return "+0.0".to_doc(); - } - - let left = self.expr(left); - let right = self.expr(right); - let denominator = self.next_local_var_name("gleam@denominator"); - let clauses = docvec![ - line(), - "+0.0 -> +0.0;", - line(), - "-0.0 -> -0.0;", - line(), - denominator.clone(), - " -> ", - binop_documents(left, "/", denominator) - ]; - docvec!["case ", right, " of", clauses.nest(INDENT), line(), "end"] + eaf.binary_operator(operator); + self.maybe_block_expr(eaf, left); + self.maybe_block_expr(eaf, right); } - fn int_div( + fn float_division( &mut self, + eaf: &mut impl Eaf, left: &'a TypedExpr, right: &'a TypedExpr, - op: &'static str, - ) -> Document<'a> { - if right.is_non_zero_compile_time_number() { - return self.binop_exprs(left, op, right); - } + ) { + match how_to_divide(left, right) { + HowToDivide::ReplaceWithZero => eaf.float(0.0), + HowToDivide::EvaluateLeftAndReturnZero => { + // We first evaluate the left hand side, and ignore its return + // value, and then we return zero directly! + self.maybe_block_expr(eaf, left); + eaf.float(0.0); + } + HowToDivide::PlainErlangDivision => { + eaf.binary_operator("/"); + self.maybe_block_expr(eaf, left); + self.maybe_block_expr(eaf, right); + } + HowToDivide::MatchOnRight { + is_left_hand_side_pure, + } => { + // We first have to evaluate the left hand side, and store its + // result in a variable to use later. + let left_name = if !is_left_hand_side_pure { + let left_name = self.new_throwaway_variable(); + eaf.match_operator(); + eaf.variable_pattern(&left_name); + self.maybe_block_expr(eaf, left); + Some(left_name) + } else { + None + }; - // If we have a constant value divided by zero then it's safe to replace it - // directly with 0. - if left.is_literal() && right.is_zero_compile_time_number() { - return "0".to_doc(); - } + let case = eaf.start_case(); + self.maybe_block_expr(eaf, right); + + // +0.0 -> +0.0 + let clause = eaf.start_case_clause(); + eaf.float_pattern(0.0); + let guards = eaf.end_clause_pattern(clause); + let body = eaf.end_clause_guards(guards); + eaf.float(0.0); + eaf.end_clause_body(body); + + // -0.0 -> -0.0 + let clause = eaf.start_case_clause(); + eaf.float_pattern(-0.0); + let guards = eaf.end_clause_pattern(clause); + let body = eaf.end_clause_guards(guards); + eaf.float(-0.0); + eaf.end_clause_body(body); + + // _value -> left / _value + let denominator = self.new_throwaway_variable(); + let clause = eaf.start_case_clause(); + eaf.variable_pattern(&denominator); + let guards = eaf.end_clause_pattern(clause); + let body = eaf.end_clause_guards(guards); + eaf.binary_operator("/"); + // If we had bound the left hand side to a variabe we just + // reference it, otherwise we will generate the code for the + // numerator. + if let Some(left_name) = left_name { + eaf.variable(&left_name); + } else { + self.maybe_block_expr(eaf, left); + } + eaf.variable(&denominator); + eaf.end_clause_body(body); - let left = self.expr(left); - let right = self.expr(right); - let denominator = self.next_local_var_name("gleam@denominator"); - let clauses = docvec![ - line(), - "0 -> 0;", - line(), - denominator.clone(), - " -> ", - binop_documents(left, op, denominator) - ]; - docvec!["case ", right, " of", clauses.nest(INDENT), line(), "end"] - } + eaf.end_case(case); + } + } - fn binop_exprs( + //if right.is_non_zero_compile_time_number() { + // eaf.binary_operator("/"); + // self.maybe_block_expr(eaf, left); + // self.maybe_block_expr(eaf, right); + //} else if left.is_literal() && right.is_zero_compile_time_number() { + // eaf.float(0.0); + //} else { + // let left = { + // self.expr(eaf, left); + // nil() + // }; + // let right = { + // self.expr(eaf, right); + // nil() + // }; + // let denominator = self.new_throwaway_variable(); + // let clauses = docvec![ + // line(), + // "+0.0 -> +0.0;", + // line(), + // "-0.0 -> -0.0;", + // line(), + // denominator.clone(), + // " -> ", + // binop_documents(left, "/", denominator.to_doc()) + // ]; + // let _ = docvec!["case ", right, " of", clauses.nest(INDENT), line(), "end"]; + //} + } + + fn int_division( &mut self, + eaf: &mut impl Eaf, left: &'a TypedExpr, - op: &'static str, right: &'a TypedExpr, - ) -> Document<'a> { - let left = if let TypedExpr::BinOp { .. } = left { - self.expr(left).surround("(", ")") - } else { - self.maybe_block_expr(left) - }; - let right = if let TypedExpr::BinOp { .. } = right { - self.expr(right).surround("(", ")") - } else { - self.maybe_block_expr(right) - }; - binop_documents(left, op, right) + op: &'static str, + ) { + match how_to_divide(left, right) { + HowToDivide::ReplaceWithZero => eaf.int(BigInt::ZERO), + HowToDivide::EvaluateLeftAndReturnZero => { + // We first evaluate the left hand side, and ignore its return + // value, and then we return zero directly! + self.maybe_block_expr(eaf, left); + eaf.int(BigInt::ZERO); + } + HowToDivide::PlainErlangDivision => { + eaf.binary_operator(op); + self.maybe_block_expr(eaf, left); + self.maybe_block_expr(eaf, right); + } + HowToDivide::MatchOnRight { + is_left_hand_side_pure, + } => { + // If the left hand side is not a pure expression we will have + // to evaluate it before the right hand side of the expression. + // So we assign it to a throwaway variable that we will then + // reference in the case expression's body. + // It will look something like this: + // + // ```erl + // _value = , + // case of + // 0 -> 0; + // _value@1 -> _value div _value@1 + // end + // ``` + // + let left_name = if !is_left_hand_side_pure { + let left_name = self.new_throwaway_variable(); + eaf.match_operator(); + eaf.variable_pattern(&left_name); + self.maybe_block_expr(eaf, left); + Some(left_name) + } else { + None + }; + + let case = eaf.start_case(); + self.maybe_block_expr(eaf, right); + + // 0 -> 0 + let clause = eaf.start_case_clause(); + eaf.int_pattern(BigInt::ZERO); + let guards = eaf.end_clause_pattern(clause); + let body = eaf.end_clause_guards(guards); + eaf.int(BigInt::ZERO); + eaf.end_clause_body(body); + + // _value -> left div _value + let denominator = self.new_throwaway_variable(); + let clause = eaf.start_case_clause(); + eaf.variable_pattern(&denominator); + let guards = eaf.end_clause_pattern(clause); + let body = eaf.end_clause_guards(guards); + eaf.binary_operator(op); + // If we had bound the left hand side to a variabe we just + // reference it, otherwise we will generate the code for the + // numerator. + if let Some(left_name) = left_name { + eaf.variable(&left_name); + } else { + self.maybe_block_expr(eaf, left); + } + eaf.variable(&denominator); + eaf.end_clause_body(body); + + eaf.end_case(case); + } + } } /// This is used to print segments of a bit array expression. @@ -2171,10 +2665,11 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// So you should use this one for printing expression segments, and the generic /// `bit_array_segment` function for constant and pattern segments instead. /// - fn bit_array_expression_segment( + fn bit_array_expression_segment( &mut self, + eaf: &mut impl Eaf, segment: &'a TypedExprBitArraySegment, - ) -> Document<'a> { + ) { // Literal strings can have the `utf8`, `utf16`, or `utf32` options just // fine, and that would be no issue on the Erlang side: // @@ -2223,206 +2718,114 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { && !segment.value.is_literal_string() && let Some(encoding) = expression_segment_string_encoding(segment) { - match encoding { - // Gleam strings are utf8 encoded binaries, so we just need to add - // the binary option + let (size, endiannes) = match encoding { + ExpressionSegmentStringEncoding::Utf16 { endiannes } => (16, endiannes), + ExpressionSegmentStringEncoding::Utf32 { endiannes } => (32, endiannes), ExpressionSegmentStringEncoding::Utf8 => { - docvec![ - self.bit_array_expression_segment_value(&segment.value), - "/binary" - ] + // Gleam strings are utf8 encoded binaries, so we just need + // to add the binary option and we can call it a day. + eaf.bit_array_segment(); + self.maybe_block_expr(eaf, &segment.value); + eaf.atom("default"); + eaf.bit_array_segment_specifiers([BitArraySegmentSpecifier::Binary]); + return; } + }; - // For utf16 and utf32 we need an explicit conversion using erlang's - // `unicode:characters_to_binary` - ExpressionSegmentStringEncoding::Utf16 { endiannes } => { - let value = self.maybe_block_expr(&segment.value); - let encoding = match endiannes { - Endianness::Big => "{utf16, big}", - Endianness::Little => "{utf16, little}", - }; - docvec![ - "(unicode:characters_to_binary", - wrap_arguments([value, "utf8".to_doc(), encoding.to_doc()]), - ")/binary" - ] - } - ExpressionSegmentStringEncoding::Utf32 { endiannes } => { - let value = self.maybe_block_expr(&segment.value); - let encoding = match endiannes { - Endianness::Big => "{utf32, big}", - Endianness::Little => "{utf32, little}", - }; + eaf.bit_array_segment(); - docvec![ - "(unicode:characters_to_binary", - wrap_arguments([value, "utf8".to_doc(), encoding.to_doc()]), - ")/binary" - ] + // For utf16 and utf32 we need an explicit conversion using erlang's + // `unicode:characters_to_binary`. The segment value will be + // something like this: + // ```erl + // unicode:characters_to_binary(, utf8, {utf16, big}) + // ``` + let call = eaf.start_remote_call("unicode".into(), "characters_to_binary"); + { + self.maybe_block_expr(eaf, &segment.value); + eaf.atom("utf8"); + let tuple = eaf.start_tuple(); + eaf.atom(&format!("utf{size}")); + match endiannes { + Endianness::Big => eaf.atom("big"), + Endianness::Little => eaf.atom("little"), } + eaf.end_tuple(tuple); } + eaf.end_call(call); + + eaf.atom("default"); + eaf.bit_array_segment_specifiers([BitArraySegmentSpecifier::Binary]); } else { // If the bit array segment doesn't need any special handling we use the // regular printing functions to format its value and options. - docvec![ - self.bit_array_expression_segment_value(&segment.value), - self.bit_array_expression_options(&segment.options) - ] + eaf.bit_array_segment(); + self.maybe_block_expr(eaf, &segment.value); + self.bit_array_expression_segment_size(eaf, segment); + self.bit_array_segment_specifiers(eaf, segment); } } - fn bit_array_expression_options( + /// This generates the code that will produce the size expression of a bit + /// array segment. + /// + /// Make sure to only call this when you're expected to generate a bit array + /// size! + fn bit_array_expression_segment_size( &mut self, - options: &'a [BitArrayOption], - ) -> Document<'a> { - // The size and unit options are a bit special: if present size must come - // first, and the unit must come last. So we keep them separate from all the - // other options. - // - // ```erl - // <> - // % ^^^^^ Size is first immediately after `:` - // % ^^^^^^^^^^^^^^^^ All other options come after `/` - // % ^^^^^ And unit is always the last one of - // % those written like this: `unit:Value` - // ``` - let mut size: Option> = None; - let mut unit: Option> = None; - let mut others = Vec::new(); - - for option in options { - match option { - BitArrayOption::Utf8 { .. } => others.push("utf8".to_doc()), - BitArrayOption::Utf16 { .. } => others.push("utf16".to_doc()), - BitArrayOption::Utf32 { .. } => others.push("utf32".to_doc()), - BitArrayOption::Int { .. } => others.push("integer".to_doc()), - BitArrayOption::Float { .. } => others.push("float".to_doc()), - BitArrayOption::Bytes { .. } => others.push("binary".to_doc()), - BitArrayOption::Bits { .. } => others.push("bitstring".to_doc()), - BitArrayOption::Utf8Codepoint { .. } => others.push("utf8".to_doc()), - BitArrayOption::Utf16Codepoint { .. } => others.push("utf16".to_doc()), - BitArrayOption::Utf32Codepoint { .. } => others.push("utf32".to_doc()), - BitArrayOption::Signed { .. } => others.push("signed".to_doc()), - BitArrayOption::Unsigned { .. } => others.push("unsigned".to_doc()), - BitArrayOption::Big { .. } => others.push("big".to_doc()), - BitArrayOption::Little { .. } => others.push("little".to_doc()), - BitArrayOption::Native { .. } => others.push("native".to_doc()), - BitArrayOption::Unit { value, .. } => { - unit = Some(eco_format!("unit:{value}").to_doc()) - } - BitArrayOption::Size { value, .. } => { - // Sizes need some care: in Erlang, having a negative segment size - // results in a runtime error. We can't do that in Gleam! So any - // negative value must be turned to zero instead: - size = Some(if let TypedExpr::Int { int_value, .. } = value.as_ref() { - // For literals we can easily replace negative values with - // the literal zero. - let value = if int_value.is_negative() { - &BigInt::ZERO - } else { - int_value - }; - docvec![":", value.clone()] - } else { - // For any other non constant expression we need to use - // `erlang:max(0, )` to ensure the value is never - // zero at runtime! - docvec![":(erlang:max(0, ", self.maybe_block_expr(value), "))"] - }); - } - } - } - - // The unit must always be the last option, if present. - if let Some(unit) = unit { - others.push(unit) - } - - let options = if !others.is_empty() { - docvec!["/", join(others, "-".to_doc())] - } else { - nil() + eaf: &mut impl Eaf, + segment: &'a TypedExprBitArraySegment, + ) { + let Some(size) = segment.size() else { + eaf.atom("default"); + return; }; - // Size comes before all the other options. - docvec![size, options] - } - - /// The document for the value of a bit array segment expression. - /// Segment values can't be produced using a simple `expr` call but need special - /// handling in some cases which this function takes care of! - fn bit_array_expression_segment_value(&mut self, value: &'a TypedExpr) -> Document<'a> { - match value { - // Skip the normal <> surrounds - TypedExpr::String { value, .. } => string_inner(value).surround("\"", "\""), - - // As normal - TypedExpr::Int { .. } - | TypedExpr::Float { .. } - | TypedExpr::Var { .. } - | TypedExpr::BitArray { .. } => self.expr(value), - - // Anything else needs to be wrapped in parentheses - TypedExpr::Block { .. } - | TypedExpr::Pipeline { .. } - | TypedExpr::Fn { .. } - | TypedExpr::List { .. } - | TypedExpr::Call { .. } - | TypedExpr::BinOp { .. } - | TypedExpr::Case { .. } - | TypedExpr::RecordAccess { .. } - | TypedExpr::PositionalAccess { .. } - | TypedExpr::ModuleSelect { .. } - | TypedExpr::Tuple { .. } - | TypedExpr::TupleIndex { .. } - | TypedExpr::Todo { .. } - | TypedExpr::Panic { .. } - | TypedExpr::Echo { .. } - | TypedExpr::RecordUpdate { .. } - | TypedExpr::NegateBool { .. } - | TypedExpr::NegateInt { .. } - | TypedExpr::Invalid { .. } => self.expr(value).surround("(", ")"), - } - } - - fn optional_clause_guard( - &mut self, - guard: Option<&'a TypedClauseGuard>, - additional_guards: Vec>, - assignments: &HashMap>, - ) -> Document<'a> { - let guard_doc = guard.map(|guard| self.bare_clause_guard(guard, assignments)); - - let guards_count = guard_doc.iter().len() + additional_guards.len(); - let guards_docs = additional_guards.into_iter().chain(guard_doc).map(|guard| { - if guards_count > 1 { - guard.surround("(", ")") + // Sizes need some care: in Erlang, having a negative segment size + // results in a runtime error. We can't do that in Gleam! So any + // negative value must be turned to zero instead: + if let TypedExpr::Int { int_value, .. } = &size { + if int_value.is_negative() { + eaf.int(BigInt::ZERO) } else { - guard + eaf.int(int_value.clone()); } - }); - let doc = join(guards_docs, " andalso ".to_doc()); - if doc.is_empty() { - doc } else { - " when ".to_doc().append(doc) + let call = eaf.start_remote_call("erlang".into(), "max"); + eaf.int(BigInt::ZERO); + self.maybe_block_expr(eaf, size); + eaf.end_call(call); } } - fn bare_clause_guard( + fn clause_guard( &mut self, + eaf: &mut impl Eaf, guard: &'a TypedClauseGuard, - assignments: &HashMap>, - ) -> Document<'a> { + assignments: &HashMap, + ) { match guard { ClauseGuard::Invalid { .. } => unreachable!("invalid guard made it to code generation"), - ClauseGuard::Block { value, .. } => self - .bare_clause_guard(value, assignments) - .surround("(", ")"), + ClauseGuard::ModuleSelect { literal, .. } => self.inlined_constant(eaf, literal), + ClauseGuard::Constant(constant) => self.inlined_constant(eaf, constant), + + ClauseGuard::Block { value, .. } => self.clause_guard(eaf, value, assignments), + ClauseGuard::TupleIndex { tuple, index, .. } => { + self.clause_guard_tuple_index(eaf, tuple, *index) + } + + ClauseGuard::FieldAccess { + container, index, .. + } => self.clause_guard_tuple_index( + eaf, + container, + index.expect("Unable to find index") + 1, + ), ClauseGuard::Not { expression, .. } => { - docvec!["not ", self.bare_clause_guard(expression, assignments)] + eaf.unary_operator("not"); + self.clause_guard(eaf, expression, assignments); } ClauseGuard::BinaryOperator { @@ -2431,9 +2834,6 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { right, .. } => { - let left_document = self.clause_guard(left, assignments); - let right_document = self.clause_guard(right, assignments); - let operator = match operator { BinOp::Or => "orelse", BinOp::And => "andalso", @@ -2450,138 +2850,163 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { BinOp::DivInt => "div", BinOp::RemainderInt => "rem", BinOp::Concatenate => { - return self.clause_guard_string_concatenate(left, right, assignments); + return self.clause_guard_string_concatenate(eaf, left, right, assignments); } }; - docvec![left_document, " ", operator, " ", right_document] + eaf.binary_operator(operator); + self.clause_guard(eaf, left, assignments); + self.clause_guard(eaf, right, assignments); } // Only local variables are supported and the typer ensures that all // ClauseGuard::Vars are local variables - ClauseGuard::Var { name, .. } => { - // If we're referencing a variable introduced by a string pattern - // assignment we need to replace it with its actual literal value: - // in the generated code the variable is only defined later, so - // just referencing its name would result in an error. - assignments - .get(name) - .map(|assignment| assignment.literal_value.clone()) - .unwrap_or_else(|| self.local_var_name(name)) + ClauseGuard::Var { + name, + definition_location, + .. + } => { + // If we're referencing a variable introduced by an alias pattern + // we need to replace it with its actual literal value: in the + // generated code the variable is only defined later, so just + // referencing its name would result in an error. + match assignments.get(name) { + Some(AliasedLiteral::String { value, .. }) => eaf.string(value), + Some(AliasedLiteral::Int { value, .. }) => eaf.int(value.clone()), + Some(AliasedLiteral::Float { value, .. }) => eaf.float(value.value()), + None => { + eaf.variable(&self.local_var_name(definition_location)); + } + } } - - ClauseGuard::TupleIndex { tuple, index, .. } => self.tuple_index_inline(tuple, *index), - - ClauseGuard::FieldAccess { - container, index, .. - } => self.tuple_index_inline(container, index.expect("Unable to find index") + 1), - - ClauseGuard::ModuleSelect { literal, .. } => self.const_inline(literal), - - ClauseGuard::Constant(constant) => self.const_inline(constant), } } - fn clause_guard( + fn clause_guard_tuple_index( &mut self, - guard: &'a TypedClauseGuard, - assignments: &HashMap>, - ) -> Document<'a> { - match guard { - ClauseGuard::Invalid { .. } => unreachable!("invalid guard made it to code generation"), - // Binary operators are wrapped in parens - ClauseGuard::BinaryOperator { .. } => "(" - .to_doc() - .append(self.bare_clause_guard(guard, assignments)) - .append(")"), - - // Other expressions are not - ClauseGuard::Constant(_) - | ClauseGuard::Not { .. } - | ClauseGuard::Var { .. } - | ClauseGuard::TupleIndex { .. } - | ClauseGuard::FieldAccess { .. } - | ClauseGuard::ModuleSelect { .. } - | ClauseGuard::Block { .. } => self.bare_clause_guard(guard, assignments), - } - } - - fn tuple_index_inline(&mut self, tuple: &'a TypedClauseGuard, index: u64) -> Document<'a> { - let index_doc = eco_format!("{}", (index + 1)).to_doc(); - let tuple_doc = self.bare_clause_guard(tuple, &HashMap::new()); - "erlang:element" - .to_doc() - .append(wrap_arguments([index_doc, tuple_doc])) + eaf: &mut impl Eaf, + tuple: &'a TypedClauseGuard, + index: u64, + ) { + let call = eaf.start_remote_call("erlang".into(), "element"); + eaf.int((index + 1).into()); + self.clause_guard(eaf, tuple, &HashMap::new()); + eaf.end_call(call); } - fn clause_guard_string_concatenate( + fn clause_guard_string_concatenate( &mut self, + eaf: &mut impl Eaf, left: &'a TypedClauseGuard, right: &'a TypedClauseGuard, - assignments: &HashMap>, - ) -> Document<'a> { - let left = self.clause_guard_string_concatenate_argument(left, assignments); - let right = self.clause_guard_string_concatenate_argument(right, assignments); - bit_array([left, right]) + assignments: &HashMap, + ) { + let bit_array = eaf.start_bit_array(); + self.clause_guard_string_concatenate_argument(eaf, left, assignments); + self.clause_guard_string_concatenate_argument(eaf, right, assignments); + eaf.end_bit_array(bit_array); } - fn clause_guard_string_concatenate_argument( + fn clause_guard_string_concatenate_argument( &mut self, + eaf: &mut impl Eaf, guard: &'a TypedClauseGuard, - assignments: &HashMap>, - ) -> Document<'a> { - match guard { - ClauseGuard::Invalid { .. } => unreachable!("invalid guard made it to code generation"), + assignments: &HashMap, + ) { + // String concatenation is basically building a bit array with two + // elements. Anything is going to be simply added as a `/binary` segment + // with one exception: if we're dealing with a literal string that needs + // the `/utf8` specifier instead! + // In both cases the size is alwaus automatic, so we generate the + // `default` atom. + eaf.bit_array_segment(); + self.clause_guard(eaf, guard, assignments); + eaf.atom("default"); + eaf.bit_array_segment_specifiers(if guard_produces_literal_string(guard) { + [BitArraySegmentSpecifier::Utf8] + } else { + [BitArraySegmentSpecifier::Binary] + }); + } - ClauseGuard::Constant(Constant::String { value, .. }) => { - docvec!['"', string_inner(value), "\"/utf8"] - } + /// Given a record name and the number of arguments it accepts, this outputs + /// the code to generate an anonymous function that builds that record. + /// + /// For example, given: + /// + /// ```gleam + /// pub type Wibble { + /// Wibble(Int, String) + /// } + /// + /// pub fn main() { + /// Wibble + /// //^^^^^^ This has to return the builder function! + /// } + /// ``` + /// + /// We will produce the following Erlang code: + /// + /// ```erl + /// main() -> + /// fun(_value, _value@1) -> + /// {wibble, _value, _value@1} + /// end. + /// ``` + /// + fn record_builder_anonymous_function( + &mut self, + eaf: &mut impl Eaf, + record_name: &str, + arguments: usize, + ) { + let arguments = (0..arguments) + .map(|_| self.new_throwaway_variable()) + .collect_vec(); + let function = eaf.start_anonymous_function(&arguments); - ClauseGuard::Constant(Constant::StringConcatenation { left, right, .. }) => { - self.const_string_concatenate_inner(left, right) + if arguments.is_empty() { + eaf.atom(&to_snake_case(record_name)) + } else { + let tuple = eaf.start_tuple(); + eaf.atom(&to_snake_case(record_name)); + for argument in arguments { + eaf.variable(&argument); } + eaf.end_tuple(tuple) + } - ClauseGuard::ModuleSelect { literal, .. } => match literal { - Constant::String { value, .. } => docvec!['"', string_inner(value), "\"/utf8"], - Constant::StringConcatenation { left, right, .. } => { - self.const_string_concatenate_inner(left, right) - } - Constant::Int { .. } - | Constant::Float { .. } - | Constant::Tuple { .. } - | Constant::List { .. } - | Constant::Record { .. } - | Constant::RecordUpdate { .. } - | Constant::BitArray { .. } - | Constant::Var { .. } - | Constant::Todo { .. } - | Constant::Invalid { .. } => docvec!["(", self.const_inline(literal), ")/binary"], - }, + eaf.end_function(function); + } - ClauseGuard::Var { name, .. } => assignments - .get(name) - .map(|assignment| docvec![assignment.literal_value.clone(), "/binary"]) - .unwrap_or_else(|| docvec![self.local_var_name(name), "/binary"]), + /// After generating a pattern we might have to generate additional variable + /// bindings in the body following a clause pattern. + /// This adds those variable to the current body. + fn pattern_assignments( + &mut self, + eaf: &mut impl Eaf, + variables_to_add_later: HashMap, + ) { + let variables_to_add_later = variables_to_add_later + .into_iter() + .sorted_by(|(one, _), (other, _)| one.cmp(other)); - ClauseGuard::BinaryOperator { - operator: BinOp::Concatenate, - left, - right, - .. - } => docvec![ - self.clause_guard_string_concatenate(left, right, assignments), - "/binary" - ], - - ClauseGuard::Block { .. } - | ClauseGuard::BinaryOperator { .. } - | ClauseGuard::Not { .. } - | ClauseGuard::TupleIndex { .. } - | ClauseGuard::FieldAccess { .. } - | ClauseGuard::Constant(_) => docvec![ - self.clause_guard(guard, assignments).surround("(", ")"), - "/binary" - ], + for (gleam_name, value) in variables_to_add_later { + eaf.match_operator(); + match value { + AliasedLiteral::String { location, value } => { + eaf.variable_pattern(&self.new_erlang_variable(&gleam_name, location)); + eaf.string(&value); + } + AliasedLiteral::Float { location, value } => { + eaf.variable_pattern(&self.new_erlang_variable(&gleam_name, location)); + eaf.float(value.value()); + } + AliasedLiteral::Int { location, value } => { + eaf.variable_pattern(&self.new_erlang_variable(&gleam_name, location)); + eaf.int(value.clone()); + } + } } } } @@ -2623,241 +3048,363 @@ pub fn records(module: &TypedModule) -> Vec<(&str, String)> { .collect() } -pub fn record_definition(name: &str, fields: &[(&str, Arc)]) -> String { - let name = to_snake_case(name); - let type_printer = TypePrinter::new("").var_as_any(); - let fields = fields.iter().map(move |(name, type_)| { - let type_ = type_printer.print(type_); - docvec![atom_string((*name).into()), " :: ", type_.group()] - }); - let fields = break_("", "") - .append(join(fields, break_(",", ", "))) - .nest(INDENT) - .append(break_("", "")) - .group(); - docvec!["-record(", atom_string(name), ", {", fields, "}).", line()] - .to_pretty_string(MAX_COLUMNS) +/// Given an expression, this tells us how we should be calling it as a +/// function in the generated erlang code. +fn how_to_call<'a>(function: &'a TypedExpr) -> FunctionCall<'a> { + match function { + // This is a record constructor from the current module. + // For example: + // + // ```gleam + // pub type Wibble { Wibble(Int) } + // pub fn main() { + // Wibble(1) + // //^^^^^^^^^ This! + // } + // ``` + // + // On the Erlang side we have to build a tagged tuple + // + TypedExpr::ModuleSelect { + constructor: ModuleValueConstructor::Record { name, .. }, + .. + } => FunctionCall::BuildRecord { name }, + + // Notice how whenever we have a function that has an erlang + // external definition we will always directly call that and not go + // through the Gleam function. For example: + // + // ```gleam + // pub fn main() { + // format("hello", []) + // } + // + // @external(erlang, "io", "format") + // fn format(string: String, args: List(String)) -> Nil + // ``` + // + // Will result in: + // + // ```erl + // main() -> + // io:format(~"hello", []). + // ``` + // + // This enables the Erlang compiler to further optimise those calls. + // + TypedExpr::ModuleSelect { + constructor: + ModuleValueConstructor::Fn { + external_erlang: Some((module, name)), + .. + } + | ModuleValueConstructor::Fn { module, name, .. }, + .. + } => FunctionCall::Call { module, name }, + + // We're calling a variable as a function. + TypedExpr::Var { constructor, .. } => match &constructor.variant { + // The variable is the constructor for a record. + // That's a tagged tuple. + ValueConstructorVariant::Record { name, .. } => FunctionCall::BuildRecord { name }, + // The variable is a module function, we can call that as usual + // just like we did for `TypedExpr::ModuleSelect`. + ValueConstructorVariant::ModuleFn { + external_erlang: Some((module, name)), + .. + } + | ValueConstructorVariant::ModuleFn { module, name, .. } => { + FunctionCall::Call { module, name } + } + // The variable is a variable defined inside the function, we + // can call it directly: + // + // ```erl + // SomeVariable = fun() -> ... end, + // SomeVariable() + // ``` + ValueConstructorVariant::LocalVariable { .. } => FunctionCall::DirectCall, + // The variable is a module constant, if it refers to a module + // function we want to call it directly. + ValueConstructorVariant::ModuleConstant { literal, .. } => { + if let Constant::Var { + constructor: Some(constructor), + .. + } = literal + && let ValueConstructorVariant::ModuleFn { + external_erlang: Some((module, name)), + .. + } + | ValueConstructorVariant::ModuleFn { module, name, .. } = + &constructor.variant + { + FunctionCall::Call { module, name } + } else { + FunctionCall::DirectCall + } + } + }, + + //TypedExpr::Fn { kind, body, .. } if kind.is_capture() => { + // if let Statement::Expression(TypedExpr::Call { + // fun, + // arguments: inner_arguments, + // .. + // }) = body.first() + // { + // let mut merged_arguments = Vec::with_capacity(inner_arguments.len()); + // for arg in inner_arguments { + // if let TypedExpr::Var { name, .. } = &arg.value + // && name == CAPTURE_VARIABLE + // { + // merged_arguments.push(arguments.swap_remove(0)) + // } else { + // merged_arguments.push(self.maybe_block_expr(eaf, &arg.value)) + // } + // } + // self.docs_arguments_call(eaf, fun, merged_arguments) + // } else { + // panic!("Erl printing: Capture was not a call") + // } + //} + TypedExpr::Fn { .. } + | TypedExpr::Call { .. } + | TypedExpr::Todo { .. } + | TypedExpr::Panic { .. } + | TypedExpr::RecordAccess { .. } + | TypedExpr::TupleIndex { .. } + | TypedExpr::Int { .. } + | TypedExpr::Float { .. } + | TypedExpr::String { .. } + | TypedExpr::Block { .. } + | TypedExpr::Pipeline { .. } + | TypedExpr::List { .. } + | TypedExpr::BinOp { .. } + | TypedExpr::Case { .. } + | TypedExpr::PositionalAccess { .. } + | TypedExpr::ModuleSelect { .. } + | TypedExpr::Tuple { .. } + | TypedExpr::Echo { .. } + | TypedExpr::BitArray { .. } + | TypedExpr::RecordUpdate { .. } + | TypedExpr::NegateBool { .. } + | TypedExpr::NegateInt { .. } + | TypedExpr::Invalid { .. } => FunctionCall::DirectCall, + } +} + +/// This represents the different ways a Gleam division could be turned into an +/// Erlang division. +/// In Gleam dividing by zero results in a 0, not in an exception. This means +/// we can't always just use the plain Erlang division operator. +enum HowToDivide { + /// Means we can divide two expression by just doing `One / Other`. + PlainErlangDivision, + + /// The entire division can be safely replaced with a literal `0`. + ReplaceWithZero, + + /// This means the left hand side could have side effects, but then we're + /// dividing it by zero, so we can just ignore its result and directly + /// return 0. + EvaluateLeftAndReturnZero, + + /// This means we have to pattern match on the right hand side to make sure + /// that it is not zero, otherwise we'll have to return zero, or the + /// division operation would result in an exception. + /// + /// It will look something like this: + /// + /// ```erl + /// case right_hand_side of + /// 0 -> 0; + /// _denominator -> left_hand_side / _denominator + /// ``` + /// + MatchOnRight { is_left_hand_side_pure: bool }, +} + +fn how_to_divide(left: &TypedExpr, right: &TypedExpr) -> HowToDivide { + if right.is_non_zero_compile_time_number() { + // Right can't be zero, so it's safe to just divide! + HowToDivide::PlainErlangDivision + } else if left.is_pure_value_constructor() { + if right.is_zero_compile_time_number() { + // Left has no side effects and `right` is `0`, so we can just + // replace the result with zero! + HowToDivide::ReplaceWithZero + } else { + // Left has no side effects, but `right` could still be zero at + // runtime, we need to match on it. + HowToDivide::MatchOnRight { + is_left_hand_side_pure: true, + } + } + } else { + // Left can have side effects, but the right hand side is zero! + // In that case we have to evaluate `left`, but then we can directly + // return 0. + if right.is_zero_compile_time_number() { + HowToDivide::EvaluateLeftAndReturnZero + } else { + // Otherwise we'll have to make sure things are evaluated in the + // correct order. + HowToDivide::MatchOnRight { + is_left_hand_side_pure: false, + } + } + } +} + +pub fn record_definition(record_name: &str, fields: &[(&str, Arc)]) -> String { + let mut eaf = PrettyEaf::new(None); + + let record = eaf.start_record_attribute(&to_snake_case(record_name)); + + let type_printer = TypeGenerator::new("").var_as_any(); + for (field_name, field_type) in fields { + eaf.record_field(); + eaf.atom(field_name); + type_printer.type_(&mut eaf, field_type); + } + + eaf.end_record_attribute(record); + eaf.into_output() } pub fn module<'a>( module: &'a TypedModule, line_numbers: &'a LineNumbers, root: &'a Utf8Path, -) -> Result { - Ok(Generator::new(module, line_numbers, root) - .module_document()? - .to_pretty_string(MAX_COLUMNS)) +) -> String { + let mut generator = Generator::new(module, line_numbers, root); + let mut eaf = PrettyEaf::new(Some(ErlangModuleName::from(&module.name))); + generator.module_document(&mut eaf); + + let mut output = eaf.into_output(); + if generator.echo_used { + output.push_str(std::include_str!("../templates/echo.erl")); + } + output } -fn register_function_exports( - function: &TypedFunction, - exports: &mut Vec>, +/// If the given function should be exported from the current Erlang module then +/// this function will return its name and arity to be used when exporting it. +/// For example: `pub fn wibble(a, b)` will produce `Some(("wibble", 2))`, so +/// we can export `wibble/2`. +fn function_export<'a>( + function: &'a TypedFunction, overridden_publicity: &im::HashSet, -) { - let Function { - publicity, - name: Some((_, name)), - arguments, - implementations, - .. - } = function - else { - return; - }; +) -> Option<(&'a str, usize)> { + let (_, name) = function + .name + .as_ref() + .expect("module function with no name"); - // If the function isn't for this target then don't attempt to export it - if implementations.supports(Target::Erlang) - && (publicity.is_importable() || overridden_publicity.contains(name)) - { - let function_name = escape_erlang_existing_name(name); - exports.push( - atom_string(function_name.into()) - .append("/") - .append(arguments.len()), - ) + // If the function is not implemented for this target, don't attempt to + // export it. + if !function.implementations.supports(Target::Erlang) { + return None; } -} -fn register_custom_type_exports<'a>( - custom_type: &TypedCustomType, - type_exports: &mut Vec>, - type_defs: &mut Vec>, - module_name: &'a str, -) { - let TypedCustomType { - name, - constructors, - opaque, - typed_parameters, - external_erlang, - .. - } = custom_type; - - // Erlang doesn't allow phantom type variables in type definitions but gleam does - // so we check the type declaratinon against its constroctors and generate a phantom - // value that uses the unused type variables. - let type_var_usages = collect_type_var_usages(HashMap::new(), typed_parameters); - let mut constructor_var_usages = HashMap::new(); - for c in constructors { - constructor_var_usages = - collect_type_var_usages(constructor_var_usages, c.arguments.iter().map(|a| &a.type_)); - } - let phantom_vars: Vec<_> = type_var_usages - .keys() - .filter(|&id| !constructor_var_usages.contains_key(id)) - .sorted() - .map(|&id| Type::Var { - type_: Arc::new(std::cell::RefCell::new(TypeVar::Generic { id })), - }) - .collect(); - let phantom_vars_constructor = if !phantom_vars.is_empty() { - let type_printer = TypePrinter::new(module_name); - Some(tuple( - std::iter::once("gleam_phantom".to_doc()) - .chain(phantom_vars.iter().map(|pv| type_printer.print(pv))), - )) - } else { - None - }; - // Type Exports - type_exports.push( - erl_safe_type_name(to_snake_case(name)) - .to_doc() - .append("/") - .append(typed_parameters.len()), - ); - // Type definitions - let definition = if constructors.is_empty() { - if let Some((module, external_type, _location)) = external_erlang { - let printer = TypePrinter::new(module_name); - docvec![ - module, - ":", - external_type, - "(", - join( - typed_parameters - .iter() - .map(|parameter| printer.print(parameter)), - ", ".to_doc() - ), - ")" - ] - } else { - let constructors = std::iter::once("any()".to_doc()).chain(phantom_vars_constructor); - join(constructors, break_(" |", " | ")) - } - } else { - let constructors = constructors - .iter() - .map(|constructor| { - let name = atom_string(to_snake_case(&constructor.name)); - if constructor.arguments.is_empty() { - name - } else { - let type_printer = TypePrinter::new(module_name); - let arguments = constructor - .arguments - .iter() - .map(|argument| type_printer.print(&argument.type_)); - tuple(std::iter::once(name).chain(arguments)) - } - }) - .chain(phantom_vars_constructor); - join(constructors, break_(" |", " | ")) + // If the function is not importable and it's publicity has not been + // overridden, don't attempt to export it. + if !function.publicity.is_importable() && !overridden_publicity.contains(name) { + return None; } - .nest(INDENT); - let type_printer = TypePrinter::new(module_name); - let params = join( - typed_parameters - .iter() - .map(|type_| type_printer.print(type_)), - ", ".to_doc(), - ); - let doc = if *opaque { "-opaque " } else { "-type " } - .to_doc() - .append(erl_safe_type_name(to_snake_case(name))) - .append("(") - .append(params) - .append(") :: ") - .append(definition) - .group() - .append("."); - type_defs.push(doc); -} - -enum DocCommentKind { - Module, - Function, -} -enum DocCommentContent<'a> { - String(&'a Vec), - False, + let name = escape_erlang_existing_name(name); + Some((name, function.arguments.len())) } -fn hidden_module_doc<'a>() -> Document<'a> { - doc_attribute(DocCommentKind::Module, DocCommentContent::False) +/// Given a custom type this returns the name it should be used to export it and +/// its arity. For example: `pub type Wibble(a, b)` will produce `("wibble", 2)`, +/// so we can export `wibble/2`. +fn type_export(custom_type: &TypedCustomType) -> (EcoString, usize) { + let name = erl_safe_type_name(to_snake_case(&custom_type.name)); + let arity = custom_type.typed_parameters.len(); + (name, arity) } -fn module_doc<'a>(content: &Vec) -> Document<'a> { - doc_attribute(DocCommentKind::Module, DocCommentContent::String(content)) -} +/// This returns true if the given expression is going to be compiled to a +/// single literal Erlang string. +/// This is not true just for literal Gleam strings like `"abc"`, but also +/// variables referencing string constants (as those are inlined) +fn produces_literal_string(value: &TypedExpr) -> bool { + match value { + TypedExpr::String { .. } + // Constants are inlined on the Erlang target, so we need to check if + // those are literal strings too! + | TypedExpr::ModuleSelect { + constructor: + ModuleValueConstructor::Constant { + literal: Constant::String { .. }, + .. + }, + .. + } + | TypedExpr::Var { + constructor: + ValueConstructor { + variant: + ValueConstructorVariant::ModuleConstant { + literal: Constant::String { .. }, + .. + }, + .. + }, + .. + } => true, -fn function_doc<'a>(content: &EcoString) -> Document<'a> { - let doc_lines = content - .trim_end() - .split('\n') - .map(EcoString::from) - .collect_vec(); - - doc_attribute( - DocCommentKind::Function, - DocCommentContent::String(&doc_lines), - ) + TypedExpr::Int { .. } + | TypedExpr::Var { .. } + | TypedExpr::Float { .. } + | TypedExpr::Block { .. } + | TypedExpr::Pipeline { .. } + | TypedExpr::Fn { .. } + | TypedExpr::List { .. } + | TypedExpr::Call { .. } + | TypedExpr::BinOp { .. } + | TypedExpr::Case { .. } + | TypedExpr::RecordAccess { .. } + | TypedExpr::PositionalAccess { .. } + | TypedExpr::ModuleSelect { .. } + | TypedExpr::Tuple { .. } + | TypedExpr::TupleIndex { .. } + | TypedExpr::Todo { .. } + | TypedExpr::Panic { .. } + | TypedExpr::Echo { .. } + | TypedExpr::BitArray { .. } + | TypedExpr::RecordUpdate { .. } + | TypedExpr::NegateBool { .. } + | TypedExpr::NegateInt { .. } + | TypedExpr::Invalid { .. } => false, + } } -fn doc_attribute<'a>(kind: DocCommentKind, content: DocCommentContent<'_>) -> Document<'a> { - let prefix = match kind { - DocCommentKind::Module => "?MODULEDOC", - DocCommentKind::Function => "?DOC", - }; +/// This returns true if the given expression is going to be compiled to a +/// single literal Erlang string. +/// This is not true just for literal Gleam strings like `"abc"`, but also +/// variables referencing string constants (as those are inlined) +fn guard_produces_literal_string(guard: &ClauseGuard>) -> bool { + match guard { + ClauseGuard::Block { value, .. } => guard_produces_literal_string(value), - match content { - DocCommentContent::False => prefix.to_doc().append("(false)."), - DocCommentContent::String(doc_lines) => { - let is_multiline_doc_comment = doc_lines.len() > 1; - let doc_lines = join( - doc_lines.iter().map(|line| { - let line = line.replace("\\", "\\\\").replace("\"", "\\\""); - docvec!["\"", line, "\\n\""] - }), - line(), - ); - if is_multiline_doc_comment { - let nested_documentation = docvec![line(), doc_lines].nest(INDENT); - docvec![prefix, "(", nested_documentation, line(), ")."] - } else { - docvec![prefix, "(", doc_lines, ")."] - } + ClauseGuard::ModuleSelect { + literal: Constant::String { .. }, + .. } - } -} - -fn wrap_arguments<'a, I>(arguments: I) -> Document<'a> -where - I: IntoIterator>, -{ - break_("", "") - .append(join(arguments, break_(",", ", "))) - .nest(INDENT) - .append(break_("", "")) - .surround("(", ")") - .group() -} + | ClauseGuard::Constant(Constant::String { .. }) => true, -fn atom_string(value: EcoString) -> Document<'static> { - escape_atom_string(value).to_doc() + ClauseGuard::BinaryOperator { .. } + | ClauseGuard::Constant(..) + | ClauseGuard::ModuleSelect { .. } + | ClauseGuard::Not { .. } + | ClauseGuard::Var { .. } + | ClauseGuard::TupleIndex { .. } + | ClauseGuard::FieldAccess { .. } + | ClauseGuard::Invalid { .. } => false, + } } static ATOM_PATTERN: OnceLock = OnceLock::new(); @@ -2866,19 +3413,6 @@ fn atom_pattern() -> &'static Regex { ATOM_PATTERN.get_or_init(|| Regex::new(r"^[a-z][a-z0-9_@]*$").expect("atom RE regex")) } -fn atom(value: &str) -> Document<'_> { - if is_erlang_reserved_word(value) { - // Escape because of keyword collision - eco_format!("'{value}'").to_doc() - } else if atom_pattern().is_match(value) { - // No need to escape - EcoString::from(value).to_doc() - } else { - // Escape because of characters contained - eco_format!("'{value}'").to_doc() - } -} - pub fn escape_atom_string(value: EcoString) -> EcoString { if is_erlang_reserved_word(&value) { // Escape because of keyword collision @@ -2891,67 +3425,6 @@ pub fn escape_atom_string(value: EcoString) -> EcoString { } } -static PATTERN: OnceLock = OnceLock::new(); - -fn unicode_escape_sequence_pattern() -> &'static Regex { - PATTERN.get_or_init(|| { - Regex::new(r#"(\\+)(u)"#).expect("Unicode escape sequence regex cannot be constructed") - }) -} - -fn string_inner(value: &str) -> Document<'_> { - let content = unicode_escape_sequence_pattern() - // `\\u`-s should not be affected, so that "\\u..." is not converted to - // "\\x...". That's why capturing groups is used to exclude cases that - // shouldn't be replaced. - .replace_all(value, |caps: &Captures<'_>| { - let slashes = caps.get(1).map_or("", |m| m.as_str()); - - if slashes.len().is_multiple_of(2) { - format!("{slashes}u") - } else { - format!("{slashes}x") - } - }); - EcoString::from(content).to_doc() -} - -fn string(value: &str) -> Document<'_> { - string_inner(value).surround("<<\"", "\"/utf8>>") -} - -fn string_length_utf8_bytes(str: &EcoString) -> usize { - convert_string_escape_chars(str).len() -} - -fn tuple<'a>(elements: impl IntoIterator>) -> Document<'a> { - join(elements, break_(",", ", ")) - .nest(INDENT) - .surround("{", "}") - .group() -} - -fn const_string_concatenate_bit_array<'a>( - elements: impl IntoIterator>, -) -> Document<'a> { - join(elements, break_(",", ", ")) - .nest(INDENT) - .surround("<<", ">>") - .group() -} - -fn bit_array<'a>(elements: impl IntoIterator>) -> Document<'a> { - join(elements, break_(",", ", ")) - .nest(INDENT) - .surround("<<", ">>") - .group() -} - -enum Position { - Tail, - NotTail, -} - enum ExpressionSegmentStringEncoding { Utf8, Utf16 { endiannes: Endianness }, @@ -2984,165 +3457,40 @@ fn expression_segment_string_encoding( }) } -fn bit_array_segment<'a, Value: 'a, CreateDoc, SizeToDoc, UnitToDoc, State>( - mut create_document: CreateDoc, - options: &'a [BitArrayOption], - mut size_to_doc: SizeToDoc, - mut unit_to_doc: UnitToDoc, - value_is_a_string_literal: bool, - value_is_a_discard: bool, - state: &mut State, -) -> Document<'a> -where - CreateDoc: FnMut(&mut State) -> Document<'a>, - SizeToDoc: FnMut(&'a Value, &mut State) -> Option>, - UnitToDoc: FnMut(&'a u8) -> Option>, -{ - let mut size: Option> = None; - let mut unit: Option> = None; - let mut others = Vec::new(); - - // Erlang only allows valid codepoint integers to be used as values for utf segments - // We want to support <> for all string variables, but <> is invalid - // To work around this we use the binary type specifier for these segments instead - let override_type = if !value_is_a_string_literal && !value_is_a_discard { - Some("binary") - } else { - None - }; - - for option in options { - use BitArrayOption as Opt; - if !others.is_empty() && !matches!(option, Opt::Size { .. } | Opt::Unit { .. }) { - others.push("-".to_doc()); - } - match option { - Opt::Utf8 { .. } => others.push(override_type.unwrap_or("utf8").to_doc()), - Opt::Utf16 { .. } => others.push(override_type.unwrap_or("utf16").to_doc()), - Opt::Utf32 { .. } => others.push(override_type.unwrap_or("utf32").to_doc()), - Opt::Int { .. } => others.push("integer".to_doc()), - Opt::Float { .. } => others.push("float".to_doc()), - Opt::Bytes { .. } => others.push("binary".to_doc()), - Opt::Bits { .. } => others.push("bitstring".to_doc()), - Opt::Utf8Codepoint { .. } => others.push("utf8".to_doc()), - Opt::Utf16Codepoint { .. } => others.push("utf16".to_doc()), - Opt::Utf32Codepoint { .. } => others.push("utf32".to_doc()), - Opt::Signed { .. } => others.push("signed".to_doc()), - Opt::Unsigned { .. } => others.push("unsigned".to_doc()), - Opt::Big { .. } => others.push("big".to_doc()), - Opt::Little { .. } => others.push("little".to_doc()), - Opt::Native { .. } => others.push("native".to_doc()), - Opt::Size { value, .. } => size = size_to_doc(value, state), - Opt::Unit { value, .. } => unit = unit_to_doc(value), - } - } - - let mut document = create_document(state); - - document = document.append(size); - let others_is_empty = others.is_empty(); - - if !others_is_empty { - document = document.append("/").append(others); - } - - if unit.is_some() { - if !others_is_empty { - document = document.append("-").append(unit) - } else { - document = document.append("/").append(unit) - } - } - - document -} - -fn binop_documents<'a>(left: Document<'a>, op: &'static str, right: Document<'a>) -> Document<'a> { - left.append(break_("", " ")) - .append(op) - .group() - .append(" ") - .append(right) -} - -fn float<'a>(value: &str) -> Document<'a> { - let mut value = value.replace('_', ""); - if value.ends_with('.') { - value.push('0') - } - - match value.split('.').collect_vec().as_slice() { - ["0", "0"] => "+0.0".to_doc(), - [before_dot, after_dot] if after_dot.starts_with('e') => { - eco_format!("{before_dot}.0{after_dot}").to_doc() - } - _ => EcoString::from(value).to_doc(), - } -} - -fn list<'a>(elements: Document<'a>, tail: Option>) -> Document<'a> { - let elements = match tail { - Some(tail) if elements.is_empty() => return tail.to_doc(), - - Some(tail) => elements.append(break_(" |", " | ")).append(tail), - - None => elements, - }; - - elements.to_doc().nest(INDENT).surround("[", "]").group() -} - -fn function_reference<'a>(module: Option<&'a str>, name: &'a str, arity: usize) -> Document<'a> { - match module { - None => "fun ".to_doc(), - Some(module) => "fun ".to_doc().append(module_name_atom(module)).append(":"), - } - .append(atom(escape_erlang_existing_name(name))) - .append("/") - .append(arity) -} - -fn int<'a>(value: &str) -> Document<'a> { - let mut value = value.replace('_', ""); - if value.starts_with("0x") { - value.replace_range(..2, "16#"); - } else if value.starts_with("0o") { - value.replace_range(..2, "8#"); - } else if value.starts_with("0b") { - value.replace_range(..2, "2#"); - } - - EcoString::from(value).to_doc() -} - -fn record_constructor_function<'a>(tag: EcoString, arity: usize) -> Document<'a> { - let chars = incrementing_arguments_list(arity); - "fun(" - .to_doc() - .append(chars.clone()) - .append(") -> {") - .append(atom_string(to_snake_case(&tag))) - .append(", ") - .append(chars) - .append("} end") -} - -/// Wrap a document in begin end -/// -fn begin_end(document: Document<'_>) -> Document<'_> { - docvec!["begin", line().append(document).nest(INDENT), line(), "end"].force_break() -} - fn needs_begin_end_wrapping(expression: &TypedExpr) -> bool { match expression { - // Record updates are 1 expression if there's no assignment, multiple otherwise. + // Record updates are 1 expression if there's no assignment, multiple + // otherwise. TypedExpr::RecordUpdate { updated_record_assigned_name, .. } => updated_record_assigned_name.is_some(), + // Pipelines are always multiple assignments. TypedExpr::Pipeline { .. } => true, + // Binary operations that require division might have to be turned into + // multiple statements! + TypedExpr::BinOp { + operator: BinOp::DivFloat | BinOp::DivInt | BinOp::RemainderInt, + left, + right, + .. + } => match how_to_divide(left, right) { + // In these cases we'll have to generate two statements: a variable + // assignment for the left hand side, and one to return the value! + HowToDivide::MatchOnRight { + is_left_hand_side_pure: false, + } + | HowToDivide::EvaluateLeftAndReturnZero => true, + // Here we just generate a single statement. + HowToDivide::PlainErlangDivision + | HowToDivide::ReplaceWithZero + | HowToDivide::MatchOnRight { + is_left_hand_side_pure: true, + } => false, + }, + TypedExpr::Int { .. } | TypedExpr::Float { .. } | TypedExpr::String { .. } @@ -3168,80 +3516,117 @@ fn needs_begin_end_wrapping(expression: &TypedExpr) -> bool { } } -#[derive(Debug, Clone, Copy)] -enum AssertExpression { - Literal, - Expression, - Unevaluated, +/// This represents an expression that appears in an expression, either because +/// it is part of some larger expression (like a binop: `assert a && b`, or a +/// call `assert wibble(wobble)`), or because it is being matched against +/// directly (like `assert wibble`). +struct AssertionExpression<'a> { + /// This tells us the kind of expression we're dealing with: wether that's a + /// literal, an expression that can't be known at compile time, or if it + /// hasn't been evaluated at all! + kind: AssertedExpressionKind, + /// If the expression has been evaluated, this is going to tell us how we + /// can reference its value. + runtime_value: Option>, + /// This is the location pointing to where in the Gleam source code this + /// expression comes from. + location: SrcSpan, } -impl AssertExpression { - fn from_expression(expression: &TypedExpr) -> Self { - if expression.is_literal() { - Self::Literal - } else { - Self::Expression +impl<'a> AssertionExpression<'a> { + fn from_expression(expression: &'a TypedExpr) -> Self { + Self { + runtime_value: Some(AssertedExpressionRuntimeValue::Expression(expression)), + kind: if expression.is_literal() { + AssertedExpressionKind::Literal + } else { + AssertedExpressionKind::Expression + }, + location: expression.location(), } } -} - -fn asserted_expression( - kind: AssertExpression, - value: Option>, - location: SrcSpan, -) -> Document<'_> { - let kind = match kind { - AssertExpression::Literal => atom("literal"), - AssertExpression::Expression => atom("expression"), - AssertExpression::Unevaluated => atom("unevaluated"), - }; - let start = location.start.to_doc(); - let end = location.end.to_doc(); + fn was_unevaluated(mut self) -> Self { + self.kind = AssertedExpressionKind::Unevaluated; + self.runtime_value = None; + self + } - let value_field = if let Some(value) = value { - docvec!["value => ", value, ",", line()] - } else { - nil() - }; + fn evaluated_to_bool(mut self, result: bool) -> Self { + self.runtime_value = Some(AssertedExpressionRuntimeValue::KnownBool(result)); + self + } - let fields_doc = docvec![ - "kind => ", - kind, - ",", - line(), - value_field, - "start => ", - start, - ",", - line(), - // `end` is a keyword in Erlang, so we have to quote it - "'end' => ", - end, - line(), - ]; - - "#{".to_doc() - .append(fields_doc.group().nest(INDENT)) - .append("}") + fn from_throwaway_variable(name: EcoString, original_expression: &'a TypedExpr) -> Self { + Self { + runtime_value: Some(AssertedExpressionRuntimeValue::Variable(name)), + kind: if original_expression.is_literal() { + AssertedExpressionKind::Literal + } else { + AssertedExpressionKind::Expression + }, + location: original_expression.location(), + } + } } -fn module_select_fn<'a>(type_: Arc, module_name: &'a str, label: &'a str) -> Document<'a> { - match crate::type_::collapse_links(type_).as_ref() { - Type::Fn { arguments, .. } => function_reference(Some(module_name), label, arguments.len()), - - Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => module_name_atom(module_name) - .append(":") - .append(atom(label)) - .append("()"), - } +/// This describes the kind of expression we're asserting against. +/// +#[derive(Debug, Clone, Copy)] +enum AssertedExpressionKind { + /// The expression being asserted against is a literal value. For example: + /// + /// ```gleam + /// assert True && wibble + /// // ^^^^ This is a literal value. + /// ``` + /// + Literal, + /// The expression being asserted against is anything but a literal, well + /// known, value. + /// For example: + /// + /// ```gleam + /// assert True && wibble + /// // ^^^^^^ This is an expression. + /// ``` + /// + Expression, + /// The expression being asserted against has not been evaluated yet, + /// because of some short circuiting behaviour. + /// + /// ```gleam + /// assert False && something_else() + /// // ^^^^^^^^^^^^^^^^ This will never be evaluated. + /// ``` + Unevaluated, } -fn incrementing_arguments_list(arity: usize) -> EcoString { - let arguments = (0..arity).map(|c| format!("Field@{c}")); - Itertools::intersperse(arguments, ", ".into()) - .collect::() - .into() +/// This is telling us what the runtime value of some asserted value is. +/// Used to produce the code for such value in runtime errors if an assert +/// fails. +/// +/// For example: +/// +/// ```gleam +/// assert wibble() +/// ``` +/// +/// If the assertion fails we know that `wibble()` must be `false` at runtime. +/// It's `AssertedExpressionRuntimeValue` would be +/// `AssertedExpressionRuntimeValue::Bool(false)`. +/// +#[derive(Debug)] +enum AssertedExpressionRuntimeValue<'a> { + /// We can tell that the asserted value must be a known bool. + /// That's because we know wether the assertion failed (it must be false), + /// or not (it must be true). + KnownBool(bool), + /// The asserted value was bound to a throwaway variable with the given + /// name, and we can reference it using that name. + Variable(EcoString), + /// The asserted value is an expression we need to inline in the error. + Expression(&'a TypedExpr), } fn variable_name(name: &str) -> EcoString { @@ -3251,14 +3636,15 @@ fn variable_name(name: &str) -> EcoString { first_uppercased.chain(chars).collect() } -/// When rendering a type variable to an erlang type spec we need all type variables with the -/// same id to end up with the same name in the generated erlang. +/// When rendering a type variable to an erlang type spec we need all type +/// variables with the same id to end up with the same name in the generated +/// Erlang. /// This function converts a usize into base 26 A-Z for this purpose. -fn id_to_type_var(id: u64) -> Document<'static> { +fn id_to_type_var_str(id: u64) -> EcoString { if id < 26 { let mut name = EcoString::from(""); name.push(char::from_u32((id % 26 + 65) as u32).expect("id_to_type_var 0")); - return name.to_doc(); + return name; } let mut name = vec![]; let mut last_char = id; @@ -3268,114 +3654,34 @@ fn id_to_type_var(id: u64) -> Document<'static> { } name.push(char::from_u32((last_char % 26 + 64) as u32).expect("id_to_type_var 2")); name.reverse(); - name.into_iter().collect::().to_doc() + name.into_iter().collect() } pub fn is_erlang_reserved_word(name: &str) -> bool { - matches!( - name, - "!" | "receive" - | "bnot" - | "div" - | "rem" - | "band" - | "bor" - | "bxor" - | "bsl" - | "bsr" - | "not" - | "and" - | "or" - | "xor" - | "orelse" - | "andalso" - | "when" - | "end" - | "fun" - | "try" - | "catch" - | "after" - | "begin" - | "let" - | "query" - | "cond" - | "if" - | "of" - | "case" - | "maybe" - | "else" - ) + match name { + "!" | "receive" | "bnot" | "div" | "rem" | "band" | "bor" | "bxor" | "bsl" | "bsr" + | "not" | "and" | "or" | "xor" | "orelse" | "andalso" | "when" | "end" | "fun" | "try" + | "catch" | "after" | "begin" | "let" | "query" | "cond" | "if" | "of" | "case" + | "maybe" | "else" => true, + _ => false, + } } // Includes shell_default & user_default which are looked for by the erlang shell pub fn is_erlang_standard_library_module(name: &str) -> bool { - matches!( - name, - "array" - | "base64" - | "beam_lib" - | "binary" - | "c" - | "calendar" - | "dets" - | "dict" - | "digraph" - | "digraph_utils" - | "epp" - | "erl_anno" - | "erl_eval" - | "erl_expand_records" - | "erl_id_trans" - | "erl_internal" - | "erl_lint" - | "erl_parse" - | "erl_pp" - | "erl_scan" - | "erl_tar" - | "ets" - | "file_sorter" - | "filelib" - | "filename" - | "gb_sets" - | "gb_trees" - | "gen_event" - | "gen_fsm" - | "gen_server" - | "gen_statem" - | "io" - | "io_lib" - | "lists" - | "log_mf_h" - | "maps" - | "math" - | "ms_transform" - | "orddict" - | "ordsets" - | "pool" - | "proc_lib" - | "proplists" - | "qlc" - | "queue" - | "rand" - | "random" - | "re" - | "sets" - | "shell" - | "shell_default" - | "shell_docs" - | "slave" - | "sofs" - | "string" - | "supervisor" - | "supervisor_bridge" - | "sys" - | "timer" - | "unicode" - | "uri_string" - | "user_default" - | "win32reg" - | "zip" - ) + match name { + "array" | "base64" | "beam_lib" | "binary" | "c" | "calendar" | "dets" | "dict" + | "digraph" | "digraph_utils" | "epp" | "erl_anno" | "erl_eval" | "erl_expand_records" + | "erl_id_trans" | "erl_internal" | "erl_lint" | "erl_parse" | "erl_pp" | "erl_scan" + | "erl_tar" | "ets" | "file_sorter" | "filelib" | "filename" | "gb_sets" | "gb_trees" + | "gen_event" | "gen_fsm" | "gen_server" | "gen_statem" | "io" | "io_lib" | "lists" + | "log_mf_h" | "maps" | "math" | "ms_transform" | "orddict" | "ordsets" | "pool" + | "proc_lib" | "proplists" | "qlc" | "queue" | "rand" | "random" | "re" | "sets" + | "shell" | "shell_default" | "shell_docs" | "slave" | "sofs" | "string" | "supervisor" + | "supervisor_bridge" | "sys" | "timer" | "unicode" | "uri_string" | "user_default" + | "win32reg" | "zip" => true, + _ => false, + } } // Includes the functions that are autogenerated by Erlang itself @@ -3386,15 +3692,15 @@ pub fn escape_erlang_existing_name(name: &str) -> &str { } } -// A TypeVar can either be rendered as an actual type variable such as `A` or `B`, -// or it can be rendered as `any()` depending on how many usages it has. If it -// has only 1 usage it is an `any()` type. If it has more than 1 usage it is a -// type variable. This function gathers usages for this determination. -// -// Examples: -// fn(a) -> String // `a` is `any()` -// fn() -> Result(a, b) // `a` and `b` are `any()` -// fn(a) -> a // `a` is a type var +/// A TypeVar can either be rendered as an actual type variable such as `A` or `B`, +/// or it can be rendered as `any()` depending on how many usages it has. If it +/// has only 1 usage it is an `any()` type. If it has more than 1 usage it is a +/// type variable. This function gathers usages for this determination. +/// +/// Examples: +/// fn(a) -> String // `a` is `any()` +/// fn() -> Result(a, b) // `a` and `b` are `any()` +/// fn(a) -> a // `a` is a type var fn collect_type_var_usages<'a>( mut ids: HashMap, types: impl IntoIterator>, @@ -3472,62 +3778,81 @@ fn type_var_ids(type_: &Type, ids: &mut HashMap) { } fn erl_safe_type_name(mut name: EcoString) -> EcoString { - if matches!( - name.as_str(), + match name.as_str() { "any" - | "arity" - | "atom" - | "binary" - | "bitstring" - | "boolean" - | "byte" - | "char" - | "dynamic" - | "float" - | "function" - | "identifier" - | "integer" - | "iodata" - | "iolist" - | "list" - | "map" - | "maybe_improper_list" - | "mfa" - | "module" - | "neg_integer" - | "nil" - | "no_return" - | "node" - | "non_neg_integer" - | "none" - | "nonempty_improper_list" - | "nonempty_list" - | "nonempty_string" - | "number" - | "pid" - | "port" - | "pos_integer" - | "reference" - | "string" - | "term" - | "timeout" - | "tuple" - ) { - name.push('_'); - name - } else { - escape_atom_string(name) + | "arity" + | "atom" + | "binary" + | "bitstring" + | "boolean" + | "byte" + | "char" + | "dynamic" + | "float" + | "function" + | "identifier" + | "integer" + | "iodata" + | "iolist" + | "list" + | "map" + | "maybe_improper_list" + | "mfa" + | "module" + | "neg_integer" + | "nil" + | "no_return" + | "node" + | "non_neg_integer" + | "none" + | "nonempty_improper_list" + | "nonempty_list" + | "nonempty_string" + | "number" + | "pid" + | "port" + | "pos_integer" + | "reference" + | "string" + | "term" + | "timeout" + | "tuple" => { + name.push('_'); + name + } + + _ => name, } } #[derive(Debug)] -struct TypePrinter<'a> { +struct TypeGenerator<'a> { + /// If this is true, all types that are generic or unbound are going to be + /// treated as `any()`. + /// var_as_any: bool, - current_module: &'a str, + /// A TypeVar can either be rendered as an actual type variable such as `A` + /// or `B`, or it can be rendered as `any()` depending on how many times it + /// is used. + /// If it is only ever used once, it is an `any()` type. + /// If it has more than 1 usage it is a regular type variable. + /// + /// For example: + /// + /// ```gleam + /// fn(a) -> String // `a` is turned into `any()` + /// fn() -> Result(a, b) // `a` and `b` are turned into `any()` + /// fn(a) -> a // `a` is a type var + /// ``` + /// + /// If present, this is a map telling us from generic variable id, to number + /// of times that variable is used. + /// var_usages: Option<&'a HashMap>, + current_module: &'a str, } -impl<'a> TypePrinter<'a> { +impl<'a> TypeGenerator<'a> { fn new(current_module: &'a str) -> Self { Self { current_module, @@ -3536,114 +3861,160 @@ impl<'a> TypePrinter<'a> { } } + /// Records the how type variables are used in order to correctly print + /// the type pub fn with_var_usages(mut self, var_usages: &'a HashMap) -> Self { self.var_usages = Some(var_usages); self } - pub fn print(&self, type_: &Type) -> Document<'static> { - match type_ { - Type::Var { type_ } => self.print_var(&type_.borrow()), + /// Print any type variable as `any()` rather than a generic type (like `A`, + /// `B`, ...). + fn var_as_any(mut self) -> Self { + self.var_as_any = true; + self + } + pub fn type_(&self, eaf: &mut impl Eaf, type_: &Type) { + match type_ { + Type::Var { type_ } => self.type_variable(eaf, &type_.borrow()), Type::Named { name, module, arguments, .. - } if is_prelude_module(module) => self.print_prelude_type(name, arguments), - + } if is_prelude_module(module) => self.prelude_type(eaf, name, arguments), Type::Named { name, module, arguments, .. - } => self.print_type_app(module, name, arguments), - - Type::Fn { arguments, return_ } => self.print_fn(arguments, return_), - - Type::Tuple { elements } => tuple(elements.iter().map(|element| self.print(element))), + } => self.named_type(eaf, module.into(), name, arguments), + Type::Fn { arguments, return_ } => { + let function_type = eaf.start_function_type(); + for argument in arguments { + self.type_(eaf, argument); + } + let function_type = eaf.end_function_type_arguments(function_type); + self.type_(eaf, return_); + eaf.end_function_type(function_type); + } + Type::Tuple { elements } => { + let tuple = eaf.start_tuple_type(); + for element in elements { + self.type_(eaf, element) + } + eaf.end_tuple_type(tuple); + } } } - fn print_var(&self, type_: &TypeVar) -> Document<'static> { + fn type_variable(&self, eaf: &mut impl Eaf, type_: &TypeVar) { match type_ { - TypeVar::Generic { .. } | TypeVar::Unbound { .. } if self.var_as_any => { - "any()".to_doc() - } - TypeVar::Generic { id, .. } | TypeVar::Unbound { id, .. } => match &self.var_usages { - Some(usages) => match usages.get(id) { - Some(&0) => nil(), - Some(&1) => "any()".to_doc(), - _ => id_to_type_var(*id), - }, - None => id_to_type_var(*id), - }, - TypeVar::Link { type_ } => self.print(type_), + TypeVar::Link { type_ } => self.type_(eaf, type_), + TypeVar::Generic { id, .. } | TypeVar::Unbound { id, .. } => { + if self.var_as_any || self.type_variable_is_used_exactly_once(*id) { + let any = eaf.start_named_type("any"); + eaf.end_named_type(any); + } else { + eaf.type_variable(&id_to_type_var_str(*id)) + } + } + } + } + + /// Given a type variable id, this returns true if the `var_usages` field + /// is set and the variable is used exactly once. + /// + #[must_use] + fn type_variable_is_used_exactly_once(&self, id: u64) -> bool { + match self.var_usages { + Some(usages) => usages.get(&id) == Some(&1), + None => false, } } - fn print_prelude_type(&self, name: &str, arguments: &[Arc]) -> Document<'static> { + fn prelude_type( + &self, + eaf: &mut impl Eaf, + name: &str, + arguments: &[Arc], + ) { match name { - "Nil" => "nil".to_doc(), - "Int" | "UtfCodepoint" => "integer()".to_doc(), - "String" => "binary()".to_doc(), - "Bool" => "boolean()".to_doc(), - "Float" => "float()".to_doc(), - "BitArray" => "bitstring()".to_doc(), + "Nil" => eaf.literal_atom_type("nil"), + "Int" | "UtfCodepoint" => { + let integer = eaf.start_named_type("integer"); + eaf.end_named_type(integer); + } + "String" => { + let string = eaf.start_named_type("binary"); + eaf.end_named_type(string); + } + "Bool" => { + let boolean = eaf.start_named_type("boolean"); + eaf.end_named_type(boolean); + } + "Float" => { + let float = eaf.start_named_type("float"); + eaf.end_named_type(float); + } + "BitArray" => { + let bitstring = eaf.start_named_type("bitstring"); + eaf.end_named_type(bitstring); + } "List" => { - let arg0 = self.print(arguments.first().expect("print_prelude_type list")); - "list(".to_doc().append(arg0).append(")") - } - "Result" => match arguments { - [arg_ok, arg_err] => { - let ok = tuple(["ok".to_doc(), self.print(arg_ok)]); - let error = tuple(["error".to_doc(), self.print(arg_err)]); - docvec![ok, break_(" |", " | "), error].nest(INDENT).group() - } - _ => panic!("print_prelude_type result expects ok and err"), - }, + let list = eaf.start_named_type("list"); + let list_item = arguments + .first() + .expect("prelude type list with no argument"); + self.type_(eaf, list_item); + eaf.end_named_type(list); + } + "Result" => { + let [ok_type, error_type] = arguments else { + panic!("result type with no ok and err types") + }; + + let result = eaf.start_union_type(); + + let ok = eaf.start_tuple_type(); + eaf.literal_atom_type("ok"); + self.type_(eaf, ok_type); + eaf.end_tuple_type(ok); + + let error = eaf.start_tuple_type(); + eaf.literal_atom_type("error"); + self.type_(eaf, error_type); + eaf.end_tuple_type(error); + + eaf.end_union_type(result); + } + // Getting here should mean we either forgot a built-in type or there is a // compiler error - name => panic!("{name} is not a built-in type."), + name => panic!("{name} is not a prelude type."), } } - fn print_type_app( + fn named_type( &self, - module: &str, + eaf: &mut impl Eaf, + module: EcoString, name: &str, arguments: &[Arc], - ) -> Document<'static> { - let arguments = join( - arguments.iter().map(|argument| self.print(argument)), - ", ".to_doc(), - ); - let name = erl_safe_type_name(to_snake_case(name)).to_doc(); - if self.current_module == module { - docvec![name, "(", arguments, ")"] + ) { + let name = erl_safe_type_name(to_snake_case(name)); + let type_ = if self.current_module == module { + eaf.start_named_type(&name) } else { - docvec![module_name_atom(module), ":", name, "(", arguments, ")"] - } - } + eaf.start_remote_named_type(ErlangModuleName::new(module), &name) + }; - fn print_fn(&self, arguments: &[Arc], return_: &Type) -> Document<'static> { - let arguments = join( - arguments.iter().map(|argument| self.print(argument)), - ", ".to_doc(), - ); - let return_ = self.print(return_); - "fun((" - .to_doc() - .append(arguments) - .append(") -> ") - .append(return_) - .append(")") - } + for argument in arguments { + self.type_(eaf, argument) + } - /// Print type vars as `any()`. - fn var_as_any(mut self) -> Self { - self.var_as_any = true; - self + eaf.end_named_type(type_); } } diff --git a/compiler-core/src/erlang/pattern.rs b/compiler-core/src/erlang/pattern.rs index 2f9391c32..aee9051e6 100644 --- a/compiler-core/src/erlang/pattern.rs +++ b/compiler-core/src/erlang/pattern.rs @@ -1,192 +1,283 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2021 The Gleam contributors -use ecow::eco_format; +use erlang_abstract_format::BitArraySegmentSpecifier; -use crate::analyse::Inferred; +use crate::{analyse::Inferred, parse::LiteralFloatValue}; use super::*; -pub(super) struct PatternPrinter<'a, 'generator, 'module> { +/// This is used to generate the code for a pattern. +/// Most Gleam patterns can be translated to Erlang in a pretty straightforward +/// way but there's notable exceptions that require some extra bookeping, this +/// helps with that. +pub(super) struct PatternGenerator<'a, 'generator, 'module> { pub generator: &'generator mut FunctionGenerator<'a, 'module>, - pub variables: Vec<&'a str>, - pub guards: Vec>, - /// In case we're dealing with string patterns, we might have something like - /// this: `"a" as letter <> rest`. In this case we want to compile it to - /// `<<"a"/utf8, rest/binary>>` and then bind a variable to `"a"`. - /// This way it's easier for the erlang compiler to optimise the pattern - /// matching. - /// - /// Here we store a list of gleam variable name to its name used in the - /// Erlang code and its literal value. - pub assignments: Vec>, -} -/// This is used to hold data about string patterns with an alias like: -/// `"a" as letter <> _` -pub struct StringPatternAssignment<'a> { - /// The name assigned to the pattern in the Gleam code: + /// Not all Gleam patterns can be cleanly (or efficiently!) translated to + /// Erlang ones. In particular, we allow aliasing almost all patterns like: /// /// ```gleam - /// "a" as letter <> _ - /// // ^^^^^^ This one + /// "a" as letter <> _ -> todo + /// // ^^^^^^^^^ This... + /// <<1 as number, _:bits>> -> todo + /// // ^^^^^^^^^ ...or this! /// ``` /// - pub gleam_name: EcoString, - /// The name we're using for that same variable in the generated Erlang - /// code, could have numbers added to it to make sure it's unique, like - /// `Letter@1`. - /// - pub erlang_name: Document<'a>, - /// The document representing the literal value of that variable. For - /// example, if we had this pattern `"a" <> letter` it's literal value in - /// Erlang is going to be a document with the following string - /// `<<"a"/utf8>>`. + /// In those cases we generate a pattern matching on the literal value and + /// keep track of the fact we'll have to define such variable in the + /// following case branch. /// - pub literal_value: Document<'a>, + /// This map maps the name of those Gleam variables that have been + /// introduced with an alias to their constant value and position. + /// You can check the docs of `AliasedValue` for some more examples and a + /// more in depth explanation. + pub variables_to_add_later: HashMap, } -impl<'a> StringPatternAssignment<'a> { - pub fn to_assignment_doc(&self) -> Document<'a> { - docvec![self.erlang_name.clone(), " = ", self.literal_value.clone()] - } +/// This is used to hold data about string prefix pattern with an alias like: +/// `"a" as letter <> _`. +/// +/// This pattern cannot be easily translated to Erlang since it doesn't allow to +/// write something like this in a bitstring: `<<"a" = Letter, _:bits>>`. +/// So what the generator will do is it will generate the following simpler +/// pattern: +/// +/// ```erl +/// <<"a", _:bits>> +/// % ^^^ Notice how this isn't bound to a `Letter` variable +/// ``` +/// +/// And it will return this data structure so we can then generate the needed +/// variable assignment later in the case body. So, overall, this: +/// +/// ```gleam +/// "a" as letter <> _ -> ... +/// ``` +/// +/// Will become: +/// +/// ```erl +/// <<"a", _:bits>> -> +/// Letter = "a", +/// ... +/// ``` +/// +/// > Note: We could have also generated slightly different code, where we use +/// > a guard `<> when Letter =:= "a"`. That would mean we don't +/// > have to add that additional variable binding; the problem is that the +/// > Erlang compiler doesn't seem to be able to optimise that as well as the +/// > one with the literal value in the pattern! +/// +#[derive(Debug)] +pub enum AliasedLiteral { + String { + /// The location of the name given to the alias: + /// + /// ```gleam + /// "a" as letter <> _ + /// // ^^^^^^ This span here + /// + /// <<"a" as letter>> + /// // ^^^^^^ or, if we're dealing with bit arrays this span here + /// ``` + /// + location: SrcSpan, + + /// This is the content of the literal string. + /// + /// ```gleam + /// "książka" as word <> _ + /// // ^^^^^^^ This right here + /// ``` + /// + value: EcoString, + }, + Int { + /// The location of the name given to the alias: + /// + /// ```gleam + /// <<1 as digit>> + /// // ^^^^^ This span here + /// ``` + location: SrcSpan, + + /// The value of the literal int being aliased. + value: BigInt, + }, + Float { + /// The location of the name given to the alias: + /// + /// ```gleam + /// <<1.1 as number>> + /// // ^^^^^^ This span here + /// ``` + location: SrcSpan, + + /// The value of the literal float being aliased. + value: LiteralFloatValue, + }, } -impl<'a, 'generator, 'module> PatternPrinter<'a, 'generator, 'module> { +impl<'a, 'generator, 'module> PatternGenerator<'a, 'generator, 'module> { pub(super) fn new(generator: &'generator mut FunctionGenerator<'a, 'module>) -> Self { Self { generator, - variables: vec![], - guards: vec![], - assignments: vec![], + variables_to_add_later: HashMap::new(), } } - pub(super) fn reset_variables(&mut self) { - self.variables = vec![]; - } - - pub(super) fn print(&mut self, pattern: &'a TypedPattern) -> Document<'a> { + pub(super) fn pattern( + &mut self, + eaf: &mut impl Eaf, + pattern: &'a TypedPattern, + ) { match pattern { - Pattern::Assign { name, pattern, .. } => { - self.variables.push(name); - self.print(pattern) - .append(" = ") - .append(self.generator.next_local_var_name(name)) + Pattern::Discard { .. } => eaf.discard_pattern(), + Pattern::Float { float_value, .. } => eaf.float_pattern(float_value.value()), + Pattern::Int { int_value, .. } => eaf.int_pattern(int_value.clone()), + Pattern::String { value, .. } => eaf.string_pattern(value), + Pattern::Variable { name, location, .. } => { + eaf.variable_pattern(&self.generator.new_erlang_variable(name, *location)) } - Pattern::List { elements, tail, .. } => self.pattern_list(elements, tail.as_deref()), - - Pattern::Discard { .. } => "_".to_doc(), - - Pattern::BitArraySize(size) => match size { - BitArraySize::Int { .. } - | BitArraySize::Variable { .. } - | BitArraySize::Block { .. } => self.bit_array_size(size), - BitArraySize::BinaryOperator { .. } => self.bit_array_size(size).surround("(", ")"), - }, + Pattern::Assign { + name, + pattern, + location, + } => { + eaf.match_pattern(); + self.pattern(eaf, pattern); + eaf.variable_pattern(&self.generator.new_erlang_variable(name, *location)); + } - Pattern::Variable { name, .. } => { - self.variables.push(name); - self.generator.next_local_var_name(name) + Pattern::Tuple { elements, .. } => { + let tuple = eaf.start_tuple_pattern(); + for element in elements { + self.pattern(eaf, element); + } + eaf.end_tuple_pattern(tuple); } - Pattern::Int { value, .. } => int(value), - Pattern::Float { value, .. } => float(value), - Pattern::String { value, .. } => string(value), + Pattern::List { elements, tail, .. } => { + for element in elements { + eaf.cons_list_pattern(); + self.pattern(eaf, element); + } + if let Some(tail) = tail { + self.pattern(eaf, &tail.pattern); + } else { + eaf.empty_list_pattern(); + } + } Pattern::Constructor { arguments, - constructor: Inferred::Known(PatternConstructor { name, .. }), - .. - } => self.tag_tuple_pattern(name, arguments), - - Pattern::Constructor { - constructor: Inferred::Unknown, + constructor, .. } => { - panic!("Erlang generation performed with uninferred pattern constructor") - } + let Inferred::Known(PatternConstructor { name, .. }) = constructor else { + panic!("uninferred constructor made it to codegen ") + }; - Pattern::Tuple { elements, .. } => { - tuple(elements.iter().map(|pattern| self.print(pattern))) + if arguments.is_empty() { + eaf.atom_pattern(&to_snake_case(name)); + } else { + let tuple = eaf.start_tuple_pattern(); + eaf.atom_pattern(&to_snake_case(name)); + for argument in arguments { + self.pattern(eaf, &argument.value); + } + eaf.end_tuple_pattern(tuple); + } } - Pattern::BitArray { segments, .. } => bit_array( - segments - .iter() - .map(|s| self.pattern_segment(&s.value, &s.options)), - ), - Pattern::StringPrefix { left_side_string, - right_side_assignment, left_side_assignment, + right_side_assignment, + right_location, .. } => { - let right = match right_side_assignment { - AssignName::Variable(right) => { - self.variables.push(right); - self.generator.next_local_var_name(right) - } - AssignName::Discard(_) => "_".to_doc(), - }; + // If the constant string prefix is being aliased we need to add + // that value to the variables that are going to be generated + // later: + if let Some((prefix_name, prefix_location)) = left_side_assignment { + let _ = self.variables_to_add_later.insert( + prefix_name.clone(), + AliasedLiteral::String { + location: *prefix_location, + value: left_side_string.clone(), + }, + ); + } - if let Some((left_name, _)) = left_side_assignment { - // "wibble" as prefix <> rest - // ^^^^^^^^^ In case the left prefix of the pattern matching is given an alias - // we bind it to a local variable so that it can be correctly - // referenced inside the case branch. - // - // So we will end up with something that looks like this: - // - // <<"wibble"/binary, Rest/binary>> -> - // Prefix = "wibble", - // ... - // - self.variables.push(left_name); - - self.assignments.push(StringPatternAssignment { - gleam_name: left_name.clone(), - erlang_name: self.generator.next_local_var_name(left_name), - literal_value: string(left_side_string), - }); + let bit_array = eaf.start_bit_array_pattern(); + + // We first generate a segment matching on the literal prefix. + eaf.bit_array_segment(); + eaf.string_pattern(left_side_string); + eaf.atom("deafult"); + eaf.bit_array_segment_specifiers([BitArraySegmentSpecifier::Utf8]); + + // We then add a segment matching on the rest of the string. + eaf.bit_array_segment(); + match right_side_assignment { + AssignName::Variable(name) => eaf.variable_pattern( + &self.generator.new_erlang_variable(name, *right_location), + ), + AssignName::Discard(_) => eaf.discard_pattern(), } + eaf.atom("default"); + eaf.bit_array_segment_specifiers([BitArraySegmentSpecifier::Binary]); + + eaf.end_bit_array_pattern(bit_array); + } - docvec![ - "<<\"", - string_inner(left_side_string), - "\"/utf8", - ", ", - right, - "/binary>>" - ] + Pattern::BitArray { segments, .. } => { + let bit_array = eaf.start_bit_array_pattern(); + for segment in segments { + eaf.bit_array_segment(); + self.bit_array_pattern_segment_value(eaf, segment); + self.bit_array_pattern_segment_size(eaf, segment); + self.generator.bit_array_segment_specifiers(eaf, segment); + } + eaf.end_bit_array_pattern(bit_array); } - Pattern::Invalid { .. } => panic!("invalid patterns should not reach code generation"), + Pattern::BitArraySize(size) => self.bit_array_size(eaf, size), + + Pattern::Invalid { .. } => { + panic!("invalid patterns should not reach code generation") + } } } - fn bit_array_size(&mut self, size: &'a TypedBitArraySize) -> Document<'a> { + fn bit_array_size(&mut self, eaf: &mut impl Eaf, size: &'a TypedBitArraySize) { match size { - BitArraySize::Int { value, .. } => int(value), - BitArraySize::Block { inner, .. } => self.bit_array_size(inner).surround("(", ")"), + BitArraySize::Int { int_value, .. } => eaf.int(int_value.clone()), + BitArraySize::Block { inner, .. } => self.bit_array_size(eaf, inner), + BitArraySize::Variable { - name, constructor, .. - } => { - let variant = &constructor - .as_ref() - .expect("Constructor not found for variable usage") - .variant; - match variant { - ValueConstructorVariant::ModuleConstant { literal, .. } => { - self.generator.const_inline(literal) + constructor, name, .. + } => match self.variables_to_add_later.get(name) { + Some(AliasedLiteral::Int { value, .. }) => eaf.int(value.clone()), + Some(_) => panic!("segment size that is not int made it through type checking"), + None => { + let constructor = constructor.as_ref().expect("variable with no constructor"); + match &constructor.variant { + ValueConstructorVariant::ModuleConstant { literal, .. } => { + self.generator.inlined_constant(eaf, literal) + } + ValueConstructorVariant::LocalVariable { location, .. } => { + eaf.variable(&self.generator.local_var_name(location)) + } + ValueConstructorVariant::ModuleFn { .. } + | ValueConstructorVariant::Record { .. } => panic!("invalid segment"), } - ValueConstructorVariant::LocalVariable { .. } - | ValueConstructorVariant::ModuleFn { .. } - | ValueConstructorVariant::Record { .. } => self.generator.local_var_name(name), } - } + }, + BitArraySize::BinaryOperator { operator, left, @@ -194,181 +285,140 @@ impl<'a, 'generator, 'module> PatternPrinter<'a, 'generator, 'module> { .. } => { let operator = match operator { - IntOperator::Add => " + ", - IntOperator::Subtract => " - ", - IntOperator::Multiply => " * ", + IntOperator::Add => "+", + IntOperator::Subtract => "-", + IntOperator::Multiply => "*", IntOperator::Divide => { - return self.bit_array_size_divide(left, right, "div"); + return self.bit_array_size_divide(eaf, left, right, "div"); } IntOperator::Remainder => { - return self.bit_array_size_divide(left, right, "rem"); + return self.bit_array_size_divide(eaf, left, right, "rem"); } }; - - docvec![ - self.bit_array_size(left), - operator, - self.bit_array_size(right) - ] + eaf.binary_operator(operator); + self.bit_array_size(eaf, left); + self.bit_array_size(eaf, right); } } } - fn bit_array_size_divide( + fn bit_array_pattern_segment_value( &mut self, - left: &'a TypedBitArraySize, - right: &'a TypedBitArraySize, - operator: &'static str, - ) -> Document<'a> { - if right.non_zero_compile_time_number() { - return self.bit_array_size_operator(left, operator, right); - } - - let left = self.bit_array_size(left); - let right = self.bit_array_size(right); - let denominator = self.generator.next_local_var_name("gleam@denominator"); - let clauses = docvec![ - line(), - "0 -> 0;", - line(), - denominator.clone(), - " -> ", - binop_documents(left, operator, denominator) - ]; - docvec!["case ", right, " of", clauses.nest(INDENT), line(), "end"] - } - - fn bit_array_size_operator( - &mut self, - left: &'a TypedBitArraySize, - operator: &'static str, - right: &'a TypedBitArraySize, - ) -> Document<'a> { - let left = if let BitArraySize::BinaryOperator { .. } = left { - self.bit_array_size(left).surround("(", ")") - } else { - self.bit_array_size(left) + eaf: &mut impl Eaf, + segment: &'a TypedPatternBitArraySegment, + ) { + let Pattern::Assign { + name, + location, + pattern, + } = segment.value.as_ref() + else { + // If the pattern is not an assign, it needs no extra care, we can + // just produce the code for such pattern! + self.pattern(eaf, &segment.value); + return; }; - let right = if let BitArraySize::BinaryOperator { .. } = right { - self.bit_array_size(right).surround("(", ")") - } else { - self.bit_array_size(right) - }; - binop_documents(left, operator, right) - } - - fn tag_tuple_pattern( - &mut self, - name: &'a str, - arguments: &'a [CallArg], - ) -> Document<'a> { - if arguments.is_empty() { - atom_string(to_snake_case(name)) - } else { - tuple( - [atom_string(to_snake_case(name))] - .into_iter() - .chain(arguments.iter().map(|argument| self.print(&argument.value))), - ) - } - } - - fn pattern_list( - &mut self, - elements: &'a [TypedPattern], - tail: Option<&'a TypedTailPattern>, - ) -> Document<'a> { - let elements = join( - elements.iter().map(|element| self.print(element)), - break_(",", ", "), - ); - let tail = tail.map(|tail| self.print(&tail.pattern)); - list(elements, tail) - } - fn pattern_segment( - &mut self, - value: &'a TypedPattern, - options: &'a [BitArrayOption], - ) -> Document<'a> { - let pattern_is_a_string_literal = matches!(value, Pattern::String { .. }); - let pattern_is_a_discard = matches!(value, Pattern::Discard { .. }); - - let create_document = |this: &mut PatternPrinter<'a, 'generator, 'module>| match value { - Pattern::String { value, .. } => string_inner(value).surround("\"", "\""), - Pattern::Discard { .. } - | Pattern::Variable { .. } - | Pattern::Int { .. } - | Pattern::Float { .. } => this.print(value), - - Pattern::Assign { name, pattern, .. } => { - this.variables.push(name); - let variable_name = this.generator.next_local_var_name(name); - - match pattern.as_ref() { - // In Erlang, assignment patterns inside bit arrays are not allowed. So instead of - // generating `<<1 = A>>`, we use guards, and generate `<> when A =:= 1`. - Pattern::Int { value, .. } => { - this.guards - .push(docvec![variable_name.clone(), " =:= ", int(value)]); - variable_name - } - Pattern::Float { value, .. } => { - this.guards - .push(docvec![variable_name.clone(), " =:= ", float(value)]); - variable_name - } + // But if we're dealing with an assign pattern inside a bit array + // segment we have to give it the same treatment we reserve for string + // prefixes (after all those are aliased bit array patterns too, since + // strings are just bitstrings!). + // + // After reading the docs for those you might already be familiar with + // the problem. But it's still worth going over that too one more time. + // In Gleam we can write `<<1 as a, _:bits>>` but in Erlang we can't + // produce the following pattern: `<<1 = A, _:bits>>`. + // So what we will do is match on the literal value and keep track of + // the constant value we'll have to add into scope later. + let aliased_value = match pattern.as_ref() { + Pattern::Int { int_value, .. } => AliasedLiteral::Int { + location: *location, + value: int_value.clone(), + }, - // Here we do the same as for floats and ints, but we must calculate the size of - // the string first, so we can correctly match the bit array segment then compare - // it afterwards. - Pattern::String { value, .. } => { - this.guards - .push(docvec![variable_name.clone(), " =:= ", string(value)]); - docvec![variable_name, ":", string_length_utf8_bytes(value)] - } + Pattern::Float { float_value, .. } => AliasedLiteral::Float { + location: *location, + value: *float_value, + }, + Pattern::String { value, .. } => AliasedLiteral::String { + location: *location, + value: value.clone(), + }, - // Doing a pattern such as `<<_ as a>>` is the same as just `<>`, so we treat it - // as such. - Pattern::Discard { .. } => variable_name, - - // Any other pattern is invalid as a bit array segment. We already handle the case - // of `<>` in the type-checker, and assignment patterns cannot be nested. - Pattern::Variable { .. } - | Pattern::BitArraySize(_) - | Pattern::Assign { .. } - | Pattern::List { .. } - | Pattern::Constructor { .. } - | Pattern::Tuple { .. } - | Pattern::BitArray { .. } - | Pattern::StringPrefix { .. } - | Pattern::Invalid { .. } => panic!("Pattern segment match not recognised"), - } + // Aliasing a discard is the same as just producing a variable + // pattern, that makes things even simpler, we can just produce the + // code for a variable pattern with the wanted name and call it a day + Pattern::Discard { .. } => { + eaf.variable_pattern(&self.generator.new_erlang_variable(name, *location)); + return; } - Pattern::BitArraySize(_) + Pattern::Variable { .. } + | Pattern::BitArraySize(_) + | Pattern::Assign { .. } | Pattern::List { .. } | Pattern::Constructor { .. } | Pattern::Tuple { .. } | Pattern::BitArray { .. } | Pattern::StringPrefix { .. } - | Pattern::Invalid { .. } => panic!("Pattern segment match not recognised"), + | Pattern::Invalid { .. } => { + panic!("invalid pattern inside aliased bit array pattern segment") + } }; - let size = |value: &'a TypedPattern, this: &mut PatternPrinter<'a, 'generator, 'module>| { - Some(":".to_doc().append(this.print(value))) + let _ = self + .variables_to_add_later + .insert(name.clone(), aliased_value); + self.pattern(eaf, pattern); + } + + fn bit_array_pattern_segment_size( + &mut self, + eaf: &mut impl Eaf, + segment: &'a TypedPatternBitArraySegment, + ) { + let Some(size) = segment.size() else { + eaf.atom("default"); + return; + }; + let TypedPattern::BitArraySize(size) = size else { + panic!("invalid size in pattern size segment") }; + self.bit_array_size(eaf, size); + } - let unit = |value: &'a u8| Some(eco_format!("unit:{value}").to_doc()); - - bit_array_segment( - create_document, - options, - size, - unit, - pattern_is_a_string_literal, - pattern_is_a_discard, - self, - ) + fn bit_array_size_divide( + &mut self, + eaf: &mut impl Eaf, + left: &'a TypedBitArraySize, + right: &'a TypedBitArraySize, + operator: &'static str, + ) { + if right.non_zero_compile_time_number() { + eaf.binary_operator(operator); + self.bit_array_size(eaf, left); + self.bit_array_size(eaf, right); + } else { + let case = eaf.start_case(); + self.bit_array_size(eaf, right); + + let clause = eaf.start_case_clause(); + eaf.int_pattern(BigInt::ZERO); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + eaf.int(BigInt::ZERO); + eaf.end_clause_body(clause); + + let clause = eaf.start_case_clause(); + let denominator = self.generator.new_throwaway_variable(); + eaf.variable_pattern(&denominator); + let clause = eaf.end_clause_pattern(clause); + let clause = eaf.end_clause_guards(clause); + eaf.binary_operator(operator); + self.bit_array_size(eaf, left); + eaf.variable(&denominator); + eaf.end_clause_body(clause); + eaf.end_case(case); + } } } diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__allowed_string_escapes.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__allowed_string_escapes.snap index 016bddfef..0c1de243c 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__allowed_string_escapes.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__allowed_string_escapes.snap @@ -7,8 +7,7 @@ pub fn a() { "\n" "\r" "\t" "\\" "\"" "\\^" } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([a/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__binop_parens.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__binop_parens.snap index ff294460d..cfcb9919c 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__binop_parens.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__binop_parens.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__bit_pattern_shadowing.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__bit_pattern_shadowing.snap index 78b2683a6..0e78450c3 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__bit_pattern_shadowing.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__bit_pattern_shadowing.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). @@ -29,10 +28,12 @@ main() -> Pre@1; _ -> - erlang:error(#{gleam_error => panic, - message => <<"`panic` expression evaluated."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 7}) + erlang:error(#{ + gleam_error => panic, + message => <<"`panic` expression evaluated."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 7 + }) end. diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__block_assignment.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__block_assignment.snap index 78f9b4e99..55ae6ef70 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__block_assignment.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__block_assignment.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info.snap index 9e04ea2a7..30154c1e1 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_imported.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_imported.snap index dba8202fd..702b324e7 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_imported.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_imported.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_imported_qualified.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_imported_qualified.snap index 81fd0af0e..e8554aec5 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_imported_qualified.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_imported_qualified.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_with_function_inside.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_with_function_inside.snap index 0f840a708..9356c4fc5 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_with_function_inside.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_with_function_inside.snap @@ -17,8 +17,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([function/0, main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_with_function_inside_imported.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_with_function_inside_imported.snap index b4ea01c47..328e2eab0 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_with_function_inside_imported.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_with_function_inside_imported.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_with_function_inside_imported_qualified.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_with_function_inside_imported_qualified.snap index 53370b47c..1d01a4692 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_with_function_inside_imported_qualified.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__constant_named_module_info_with_function_inside_imported_qualified.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__discard_in_assert.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__discard_in_assert.snap index 45e0bd2a5..c4b636160 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__discard_in_assert.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__discard_in_assert.snap @@ -10,26 +10,28 @@ pub fn x(y) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([x/1]). -file("project/test/my/mod.gleam", 1). -spec x({ok, any()} | {error, any()}) -> integer(). x(Y) -> case Y of - {ok, _} -> nil; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"x"/utf8>>, - line => 2, - value => _assert_fail, - start => 16, - 'end' => 36, - pattern_start => 27, - pattern_end => 32}) - end, - 1. + {ok, _} -> + 1; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"x"/utf8>>, + line => 2, + value => _value, + start => 16, + 'end' => 36, + pattern_start => 27, + pattern_end => 32 + }) + end. diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__dynamic.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__dynamic.snap index 07e66937b..4331d68e7 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__dynamic.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__dynamic.snap @@ -7,8 +7,7 @@ pub type Dynamic ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([dynamic_/0]). -type dynamic_() :: any(). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__field_access_function_call.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__field_access_function_call.snap index 1249841b3..8bbd6bb82 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__field_access_function_call.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__field_access_function_call.snap @@ -16,8 +16,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([fn_box/0]). @@ -26,5 +25,7 @@ pub fn main() { -file("project/test/my/mod.gleam", 6). -spec main() -> integer(). main() -> - B = {fn_box, fun(X) -> X end}, + B = {fn_box, fun(X) -> + X + end}, (erlang:element(2, B))(5). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__field_access_function_call1.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__field_access_function_call1.snap index 6d4d183f1..b882348ba 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__field_access_function_call1.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__field_access_function_call1.snap @@ -13,12 +13,13 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). main() -> - T = {fun(X) -> X end}, + T = {fun(X) -> + X + end}, (erlang:element(1, T))(5). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__float_division_by_literal_non_zero.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__float_division_by_literal_non_zero.snap index 55602adef..aa534aedf 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__float_division_by_literal_non_zero.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__float_division_by_literal_non_zero.snap @@ -10,8 +10,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__float_division_by_literal_zero.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__float_division_by_literal_zero.snap index f08e2375a..ac0e946cc 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__float_division_by_literal_zero.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__float_division_by_literal_zero.snap @@ -10,8 +10,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_argument_shadowing.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_argument_shadowing.snap index 94652ae41..ad60f2cdc 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_argument_shadowing.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_argument_shadowing.snap @@ -14,8 +14,7 @@ pub type Box { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -export_type([box/0]). @@ -24,4 +23,6 @@ pub type Box { -file("project/test/my/mod.gleam", 1). -spec main(any()) -> fun((integer()) -> box()). main(A) -> - fun(Field@0) -> {box, Field@0} end. + fun(_value) -> + {box, _value} + end. diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info.snap index 886cd44b3..582e6cb6c 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export(['moduleInfo'/0, main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_imported.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_imported.snap index abbb79a7b..f7e9cb912 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_imported.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_imported.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_imported_qualified.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_imported_qualified.snap index a2ca41b8d..f6b6f42fa 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_imported_qualified.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_imported_qualified.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_in_constant.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_in_constant.snap index b29b8924e..93509254c 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_in_constant.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_in_constant.snap @@ -17,8 +17,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export(['moduleInfo'/0, main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_in_constant_imported.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_in_constant_imported.snap index 27652881d..ff6322030 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_in_constant_imported.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_in_constant_imported.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_in_constant_imported_qualified.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_in_constant_imported_qualified.snap index 41287c3ff..0fea353a9 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_in_constant_imported_qualified.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__function_named_module_info_in_constant_imported_qualified.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__guard_variable_rewriting.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__guard_variable_rewriting.snap index f74aa6f02..18b3a5696 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__guard_variable_rewriting.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__guard_variable_rewriting.snap @@ -16,8 +16,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__inline_const_pattern_option.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__inline_const_pattern_option.snap index 3d0810cd1..bcec50d25 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__inline_const_pattern_option.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__inline_const_pattern_option.snap @@ -17,8 +17,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test.snap index e3b5b0e26..0a032df7a 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test.snap @@ -10,18 +10,11 @@ let x = #(100000000000000000, #(2000000000, 3000000000000, 40000000000), 50000, ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). --spec go() -> {integer(), - {integer(), integer(), integer()}, - integer(), - integer()}. +-spec go() -> {integer(), {integer(), integer(), integer()}, integer(), integer()}. go() -> - X = {100000000000000000, - {2000000000, 3000000000000, 40000000000}, - 50000, - 6000000000}, + X = {100000000000000000, {2000000000, 3000000000000, 40000000000}, 50000, 6000000000}, X. diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test0_1.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test0_1.snap index 7c221d859..39f1c9e04 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test0_1.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test0_1.snap @@ -11,8 +11,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test0_2.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test0_2.snap index fd97f81bd..d3c16dc74 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test0_2.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test0_2.snap @@ -12,14 +12,13 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). -spec go() -> integer(). go() -> - Fifteen = 16#F, - Nine = 8#11, - Ten = 2#1010, + Fifteen = 15, + Nine = 9, + Ten = 10, Fifteen. diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test0_3.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test0_3.snap index 7c221d859..39f1c9e04 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test0_3.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test0_3.snap @@ -11,8 +11,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1.snap index 8553e0061..e3b89e8e0 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1.snap @@ -7,8 +7,7 @@ pub fn t() { True } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([t/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test10.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test10.snap index fa22e3521..8b3d88039 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test10.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test10.snap @@ -8,8 +8,7 @@ pub fn x() { Null } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([x/0]). -export_type([null/0]). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test11.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test11.snap index 83b902671..33983bca5 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test11.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test11.snap @@ -8,8 +8,7 @@ pub fn x() { Point(x: 4, y: 6) Point(y: 1, x: 9) } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([x/0]). -export_type([point/0]). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test12.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test12.snap index 8e02fff59..2cc0afc3f 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test12.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test12.snap @@ -8,8 +8,7 @@ pub fn x(y) { let Point(a, b) = y a } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([x/1]). -export_type([point/0]). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test13.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test13.snap index 00ecae443..783d7155a 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test13.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test13.snap @@ -9,8 +9,7 @@ pub type State{ Start(Int) End(Int) } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([build/1, main/0]). -export_type([state/0]). @@ -24,4 +23,6 @@ build(Constructor) -> -file("project/test/my/mod.gleam", 3). -spec main() -> state(). main() -> - build(fun(Field@0) -> {'end', Field@0} end). + build(fun(_value) -> + {'end', _value} + end). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test16.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test16.snap index 132cf8587..9f51c4659 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test16.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test16.snap @@ -8,8 +8,7 @@ pub fn x() { go(x: 1, y: 2) go(y: 3, x: 4) } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([x/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test17.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test17.snap index fb407fcca..760e6306d 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test17.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test17.snap @@ -10,8 +10,7 @@ pub fn create_user(user_id) { User(age: 22, id: user_id, name: "") } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([create_user/1]). -export_type([user/0]). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test18.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test18.snap index b44028a68..04ea07378 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test18.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test18.snap @@ -7,8 +7,7 @@ pub fn run() { case 1, 2 { a, b -> a } } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([run/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test19.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test19.snap index 98197aaa6..6fa0f68fc 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test19.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test19.snap @@ -8,8 +8,7 @@ pub fn x() { X(x: 1, y: 2.) X(y: 3., x: 4) } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([x/0]). -export_type([x/0]). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_1.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_1.snap index 6b8b4997e..6c2860df7 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_1.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_1.snap @@ -8,8 +8,7 @@ pub fn pound(x) { Pound(x) } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([pound/1]). -export_type([money/0]). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_2.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_2.snap index b1e59c502..693fff676 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_2.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_2.snap @@ -7,8 +7,7 @@ pub fn loop() { loop() } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([loop/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_4.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_4.snap index 17f14014f..e1822df7c 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_4.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_4.snap @@ -8,8 +8,7 @@ fn inc(x) { x + 1 } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_5.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_5.snap index ee3331a06..966a26930 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_5.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_5.snap @@ -8,8 +8,7 @@ fn add(x, y) { x + y } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_6.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_6.snap index a220810ea..0e51ff126 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_6.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test1_6.snap @@ -11,8 +11,7 @@ pub fn fdiv(x, y) { x /. y } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export(['and'/2, 'or'/2, remainder/2, fdiv/2]). -file("project/test/my/mod.gleam", 1). @@ -29,15 +28,23 @@ pub fn fdiv(x, y) { x /. y } -spec remainder(integer(), integer()) -> integer(). remainder(X, Y) -> case Y of - 0 -> 0; - Gleam@denominator -> X rem Gleam@denominator + 0 -> + 0; + + _value -> + X rem _value end. -file("project/test/my/mod.gleam", 4). -spec fdiv(float(), float()) -> float(). fdiv(X, Y) -> case Y of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> X / Gleam@denominator + +0.0 -> + +0.0; + + -0.0 -> + -0.0; + + _value -> + X / _value end. diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test2.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test2.snap index ef2408e73..ddb1ccf6a 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test2.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test2.snap @@ -9,8 +9,7 @@ pub fn tail(list) { case list { [x, ..xs] -> xs z -> list } } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([second/1, tail/1]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test20.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test20.snap index af03ae14f..558a25fd0 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test20.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test20.snap @@ -13,8 +13,7 @@ pub fn go(a) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test21.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test21.snap index d212b065d..42a3f9d60 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test21.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test21.snap @@ -13,8 +13,7 @@ pub fn go(a) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test22.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test22.snap index ad3d73c99..9677bdd62 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test22.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test22.snap @@ -19,8 +19,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([factory/2, main/0]). -export_type([box/0]). @@ -34,4 +33,6 @@ factory(F, I) -> -file("project/test/my/mod.gleam", 10). -spec main() -> box(). main() -> - factory(fun(Field@0) -> {box, Field@0} end, 0). + factory(fun(_value) -> + {box, _value} + end, 0). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test23.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test23.snap index d3e0dbce2..053b39f4f 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test23.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test23.snap @@ -18,8 +18,7 @@ pub fn main(args) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test3.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test3.snap index 09f0aff6b..411a29592 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test3.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test3.snap @@ -8,8 +8,7 @@ pub fn y() { fn() { Point }()(4, 6) } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([y/0]). -export_type([point/0]). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test5.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test5.snap index 04384abbe..5417496d6 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test5.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test5.snap @@ -12,8 +12,7 @@ pub fn tail(list) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([tail/1]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test6.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test6.snap index f33252cc7..9daa1da65 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test6.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test6.snap @@ -7,8 +7,7 @@ pub fn x() { let x = 1 let x = x + 1 x } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([x/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test8.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test8.snap index 1573a1648..8739d41fc 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test8.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test8.snap @@ -7,8 +7,7 @@ pub fn x() { 1. <. 2.3 } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([x/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test9.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test9.snap index 0fb22c170..281c1ebc8 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test9.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__integration_test9.snap @@ -7,8 +7,7 @@ pub type Pair(x, y) { Pair(x: x, y: y) } pub fn x() { Pair(1, 2) Pair(3., 4.) } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([x/0]). -export_type([pair/2]). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__keyword_constructors.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__keyword_constructors.snap index 5eb174772..95aa299ea 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__keyword_constructors.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__keyword_constructors.snap @@ -7,8 +7,7 @@ pub type X { Div } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([x/0]). -type x() :: 'div'. diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__keyword_constructors1.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__keyword_constructors1.snap index 27f70c228..90ef954cc 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__keyword_constructors1.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__keyword_constructors1.snap @@ -7,8 +7,7 @@ pub type X { Fun(Int) } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([x/0]). -type x() :: {'fun', integer()}. diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__negation.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__negation.snap index 95c4190b0..6b5f6f4b9 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__negation.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__negation.snap @@ -9,8 +9,7 @@ pub fn negate(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([negate/1]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__negation_block.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__negation_block.snap index df8d97eb0..ac3ebe186 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__negation_block.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__negation_block.snap @@ -12,8 +12,7 @@ pub fn negate(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([negate/1]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__operator_pipe_right_hand_side.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__operator_pipe_right_hand_side.snap index 5bc7c4a13..213d5f943 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__operator_pipe_right_hand_side.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__operator_pipe_right_hand_side.snap @@ -13,8 +13,7 @@ pub fn bool_expr(x, y) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([bool_expr/2]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__positive_zero.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__positive_zero.snap index 73abae0c3..1a3c63164 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__positive_zero.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__positive_zero.snap @@ -11,8 +11,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__recursive_type.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__recursive_type.snap index cdcfa02a6..14f69000a 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__recursive_type.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__recursive_type.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__scientific_notation.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__scientific_notation.snap index 296684e5a..7d86494d9 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__scientific_notation.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__scientific_notation.snap @@ -12,12 +12,11 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> float(). main() -> - 1.0e6, - 1.0e6. + 1000000.0, + 1000000.0. diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__tail_maybe_expr_block.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__tail_maybe_expr_block.snap index 7d6fe6961..4b05dc4b3 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__tail_maybe_expr_block.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__tail_maybe_expr_block.snap @@ -17,18 +17,17 @@ pub fn a() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([a/0]). -file("project/test/my/mod.gleam", 1). -spec a() -> list(integer()). a() -> - Fake_tap = fun(X) -> X end, + Fake_tap = fun(X) -> + X + end, B = [99], - [1, - 2 | - begin - _pipe = B, - Fake_tap(_pipe) - end]. + [1, 2 | begin + _pipe = B, + Fake_tap(_pipe) + end]. diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__tuple_access_in_guard.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__tuple_access_in_guard.snap index 258af6b86..e10f0089d 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__tuple_access_in_guard.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__tuple_access_in_guard.snap @@ -16,8 +16,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__type_named_else.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__type_named_else.snap index cf3927d8b..804077a4c 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__type_named_else.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__type_named_else.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type(['else'/0]). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__type_named_module_info.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__type_named_module_info.snap index 2233f53d1..83cf454ac 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__type_named_module_info.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__type_named_module_info.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([module_info/0]). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__variable_name_underscores_preserved.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__variable_name_underscores_preserved.snap index 71d1e7619..fd75dc106 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__variable_name_underscores_preserved.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__variable_name_underscores_preserved.snap @@ -13,8 +13,7 @@ pub fn a(name_: String) -> String { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([a/1]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__windows_file_escaping_bug.snap b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__windows_file_escaping_bug.snap index 21302d88c..223c8d74b 100644 --- a/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__windows_file_escaping_bug.snap +++ b/compiler-core/src/erlang/snapshots/gleam_core__erlang__tests__windows_file_escaping_bug.snap @@ -1,13 +1,19 @@ --- source: compiler-core/src/erlang/tests.rs -expression: "pub fn main() { Nil }" +expression: "pub fn main() { panic }" --- -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "C:\\root\\project\\test\\my\\mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("C:\\root\\project\\test\\my\\mod.gleam", 1). --spec main() -> nil. +-spec main() -> any(). main() -> - nil. + erlang:error(#{ + gleam_error => panic, + message => <<"`panic` expression evaluated."/utf8>>, + file => <<"C:\\root\\project\\test\\my\\mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 1 + }). diff --git a/compiler-core/src/erlang/tests.rs b/compiler-core/src/erlang/tests.rs index 7b1beb5b7..0520c86ab 100644 --- a/compiler-core/src/erlang/tests.rs +++ b/compiler-core/src/erlang/tests.rs @@ -20,6 +20,7 @@ use crate::{ use camino::Utf8Path; mod assert; +mod binops; mod bit_arrays; mod case; mod conditional_compilation; @@ -32,6 +33,7 @@ mod functions; mod guards; mod inlining; mod let_assert; +mod lists; mod numbers; mod panic; mod patterns; @@ -40,6 +42,7 @@ mod records; mod reserved; mod strings; mod todo; +mod tuples; mod type_params; mod use_; mod variables; @@ -131,12 +134,10 @@ pub fn compile_test_project( built_module.attach_doc_and_module_comments(); let line_numbers = LineNumbers::new(src); - module(&built_module.ast, &line_numbers, root) - .unwrap() - .replace( - std::include_str!("../../templates/echo.erl"), - "% ...omitted code from `templates/echo.erl`...", - ) + module(&built_module.ast, &line_numbers, root).replace( + std::include_str!("../../templates/echo.erl"), + "% ...omitted code from `templates/echo.erl`...", + ) } #[macro_export] @@ -995,7 +996,7 @@ pub fn main() { // https://github.com/gleam-lang/gleam/issues/3648 #[test] fn windows_file_escaping_bug() { - let src = "pub fn main() { Nil }"; + let src = "pub fn main() { panic }"; let path = "C:\\root\\project\\test\\my\\mod.gleam"; let output = compile_test_project(src, path, Vec::new()); insta::assert_snapshot!(insta::internals::AutoName, output, src); diff --git a/compiler-core/src/erlang/tests/assert.rs b/compiler-core/src/erlang/tests/assert.rs index 1bc86466d..8e42b00c1 100644 --- a/compiler-core/src/erlang/tests/assert.rs +++ b/compiler-core/src/erlang/tests/assert.rs @@ -60,6 +60,20 @@ pub fn assert_answer(x) { ); } +#[test] +fn assert_on_consts() { + assert_erl!( + " +pub const wibble = [1, 2, 3] +pub const wobble = [1, 2] + +pub fn assert_answer(x) { + assert wibble == wobble +} +" + ); +} + #[test] fn assert_function_call() { assert_erl!( diff --git a/compiler-core/src/erlang/tests/binops.rs b/compiler-core/src/erlang/tests/binops.rs new file mode 100644 index 000000000..77fda70ac --- /dev/null +++ b/compiler-core/src/erlang/tests/binops.rs @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2026 The Gleam contributors + +use crate::assert_erl; + +#[test] +fn int_add() { + assert_erl!("pub fn main() { 1 + 2 }") +} + +#[test] +fn int_adds() { + assert_erl!("pub fn main(a, b) { 1 + 2 + a + b }") +} + +#[test] +fn int_sub() { + assert_erl!("pub fn main() { 1 - 2 }") +} + +#[test] +fn int_subs() { + assert_erl!("pub fn main(a) { 1 - 2 - a }") +} + +#[test] +fn int_mult() { + assert_erl!("pub fn main() { 1 * 2 }") +} + +#[test] +fn int_mults() { + assert_erl!("pub fn main(a, b) { 1 * 2 * a * b }") +} + +#[test] +fn int_divide_by_zero() { + assert_erl!("pub fn main(a) { a / 0 }") +} + +#[test] +fn int_divide_side_effecting_function_by_zero() { + assert_erl!("pub fn main(a) { a() / 0 }") +} + +#[test] +fn int_divide_by_non_zero() { + assert_erl!("pub fn main(a) { a() / 3 }") +} + +#[test] +fn int_divide_with_no_side_effect() { + assert_erl!("pub fn main(a, b) { a / b }") +} + +#[test] +fn int_divide_with_possible_side_effect() { + assert_erl!("pub fn main(a, b) { a() / b }") +} + +#[test] +fn int_remainder_by_zero() { + assert_erl!("pub fn main(a) { a % 0 }") +} + +#[test] +fn int_remainder_side_effecting_function_by_zero() { + assert_erl!("pub fn main(a) { a() % 0 }") +} + +#[test] +fn int_remainder_by_non_zero() { + assert_erl!("pub fn main(a) { a() % 3 }") +} + +#[test] +fn int_remainder_with_no_side_effect() { + assert_erl!("pub fn main(a, b) { a % b }") +} + +#[test] +fn int_remainder_with_possible_side_effect() { + assert_erl!("pub fn main(a, b) { a() % b }") +} + +#[test] +fn float_divide_by_zero() { + assert_erl!("pub fn main(a) { a /. 0.0 }") +} + +#[test] +fn float_divide_side_effecting_function_by_zero() { + assert_erl!("pub fn main(a) { a() /. 0.0 }") +} + +#[test] +fn float_divide_by_non_zero() { + assert_erl!("pub fn main(a) { a() /. 3.0 }") +} + +#[test] +fn float_divide_with_no_side_effect() { + assert_erl!("pub fn main(a, b) { a /. b }") +} + +#[test] +fn float_divide_with_possible_side_effect() { + assert_erl!("pub fn main(a, b) { a() /. b }") +} + +#[test] +fn int_divide_by_zero_as_argument() { + assert_erl!("pub fn main(wibble, a) { wibble(a / 0) }") +} + +#[test] +fn int_divide_side_effecting_function_by_zero_as_argument() { + assert_erl!("pub fn main(wibble, a) { wibble(a() / 0) }") +} + +#[test] +fn int_divide_by_non_zero_as_argument() { + assert_erl!("pub fn main(wibble, a) { wibble(a() / 3) }") +} + +#[test] +fn int_divide_with_no_side_effect_as_argument() { + assert_erl!("pub fn main(wibble, a, b) { wibble(a / b) }") +} + +#[test] +fn int_divide_with_possible_side_effect_as_argument() { + assert_erl!("pub fn main(wibble, a, b) { wibble(a() / b) }") +} diff --git a/compiler-core/src/erlang/tests/case.rs b/compiler-core/src/erlang/tests/case.rs index 89d0462cd..a1c47ae35 100644 --- a/compiler-core/src/erlang/tests/case.rs +++ b/compiler-core/src/erlang/tests/case.rs @@ -21,6 +21,77 @@ pub fn myfun(mt) { ) } +#[test] +fn case_defining_some_variables_that_are_later_shadowed() { + assert_erl!( + " +pub fn go(x) { + case x { + 1 -> { + let a = 1 + Nil + } + 2 -> { + let a = 2 + Nil + } + _ -> Nil + } + + let a = 3 + a + 1 +} +" + ) +} + +#[test] +fn case_defining_some_variables_that_are_later_shadowed_2() { + assert_erl!( + " +pub fn go(x) { + case x { + 1 | 2 -> { + let a = 1 + Nil + } + 3 -> { + let a = 2 + Nil + } + _ -> Nil + } + + let a = 4 + a + 1 +} +" + ) +} + +#[test] +fn multiple_alternative_branches_with_same_variable_names() { + assert_erl!( + " +pub fn go(x) { + case x { + 1 as x | x -> { + let a = 1 + x + Nil + } + 3 as x | x -> { + let a = 2 + x + Nil + } + } + + let a = 3 + a + 1 +} +" + ) +} + // https://github.com/gleam-lang/gleam/issues/2349 #[test] fn positive_zero_pattern() { @@ -147,3 +218,78 @@ pub fn go(x: List(Int), y: List(Int)) { }"# ) } + +#[test] +fn string_prefix_pattern_assigns_variable() { + assert_erl!( + r#" +pub fn go(x) { + case x { + "a" as letter <> rest + | "b" as letter <> rest -> letter <> rest + _ -> "" + } +} +"# + ) +} + +#[test] +fn nested_string_prefix_pattern_assigns_variable() { + assert_erl!( + r#" +pub fn go(x) { + case x { + ["a" as letter <> rest, ..] + | ["b" as letter <> rest, ..] -> letter <> rest + _ -> "" + } +} +"# + ) +} + +#[test] +fn string_prefix_pattern_used_in_guard_assigns_variable() { + assert_erl!( + r#" +pub fn go(x) { + case x { + "a" as letter <> rest + | "b" as letter <> rest if letter == "c" -> letter <> rest + _ -> "" + } +} +"# + ) +} + +#[test] +fn string_prefix_pattern_used_in_guard_assigns_variable_2() { + assert_erl!( + r#" +pub fn go(x) { + case x { + "a" as letter <> rest + | "b" as rest <> letter if letter == "c" && rest == "b" -> letter <> rest + _ -> "" + } +} +"# + ) +} + +#[test] +fn string_prefix_pattern_used_in_guard_assigns_variable_3() { + assert_erl!( + r#" +pub fn go(x) { + case x { + "a" as rest <> _ + | "b" <> rest if rest == "c" -> Nil + _ -> Nil + } +} +"# + ) +} diff --git a/compiler-core/src/erlang/tests/consts.rs b/compiler-core/src/erlang/tests/consts.rs index 54d536126..ddf61eb16 100644 --- a/compiler-core/src/erlang/tests/consts.rs +++ b/compiler-core/src/erlang/tests/consts.rs @@ -252,3 +252,31 @@ pub fn main() { " ); } + +#[test] +fn string_constant_from_another_module_is_concatenated_correctly() { + assert_erl!( + ("dep", "mod", "pub const wibble = \"wibble!\""), + r#" +import mod + +pub fn go(x) { + x <> "-" <> mod.wibble +} +"# + ); +} + +#[test] +fn string_constant_from_another_module_is_concatenated_correctly_2() { + assert_erl!( + ("dep", "mod", "pub const wibble = \"wibble!\""), + r#" +import mod.{wibble} + +pub fn go(x) { + x <> "-" <> wibble +} +"# + ); +} diff --git a/compiler-core/src/erlang/tests/functions.rs b/compiler-core/src/erlang/tests/functions.rs index 358885393..1390382e4 100644 --- a/compiler-core/src/erlang/tests/functions.rs +++ b/compiler-core/src/erlang/tests/functions.rs @@ -167,3 +167,41 @@ fn unused3() -> Int { "# ); } + +#[test] +fn anonymous_function() { + assert_erl!( + " +pub fn main() { + fn(wibble) { 1 } +} +" + ) +} + +#[test] +fn anonymous_function_with_shadowing() { + assert_erl!( + " +pub fn main() { + let wibble = 1 + fn(wibble) { 1 } +} +" + ) +} + +#[test] +fn nested_anonymous_functions() { + assert_erl!( + " +pub fn main() { + fn(wibble) { + fn(wobble) { + wibble + wobble + } + } +} +" + ) +} diff --git a/compiler-core/src/erlang/tests/guards.rs b/compiler-core/src/erlang/tests/guards.rs index 77413aa97..05619e4dd 100644 --- a/compiler-core/src/erlang/tests/guards.rs +++ b/compiler-core/src/erlang/tests/guards.rs @@ -472,11 +472,11 @@ fn field_access() { pub type Person { Person(username: String, name: String, age: Int) } - + pub fn main() { let given_name = "jack" let raiden = Person("raiden", "jack", 31) - + case given_name { name if name == raiden.name -> "It's jack" _ -> "It's not jack" @@ -636,3 +636,29 @@ fn module_nested_access() { "# ); } + +#[test] +fn aliased_discard_pattern_in_bit_array_later_used_in_guard() { + assert_erl!( + r#" +pub fn main(x) { + case x { + <<_ as b>> if b == 1 -> b + 2 + _ -> 0 + } +}"# + ); +} + +#[test] +fn aliased_discard_pattern_in_bit_array_later_used_in_guard_2() { + assert_erl!( + r#" +pub fn main(x) { + case x { + <<_ as b>> | <<1 as b>> | <> if b == 1 -> b + 2 + _ -> 0 + } +}"# + ); +} diff --git a/compiler-core/src/erlang/tests/inlining.rs b/compiler-core/src/erlang/tests/inlining.rs index ad8fe1f05..389fcf1c3 100644 --- a/compiler-core/src/erlang/tests/inlining.rs +++ b/compiler-core/src/erlang/tests/inlining.rs @@ -197,25 +197,31 @@ pub fn main() { ); } -#[test] -fn do_not_inline_parameters_that_have_side_effects() { - assert_erl!( - ("gleam_stdlib", "gleam/result", RESULT_MODULE), - r#" -import gleam/result - -pub fn main() { - result.map(Ok(10), do_side_effects()) -} - -fn do_side_effects() { - let function = fn(x) { x + 1 } - panic as "Side effects" - function -} -"# - ); -} +// Due to how the compilation to Erlang works now, where each variable is +// referenced via its unique source code location (rather than its name) some +// inlining tests stopped working properly. +// Inlining already has some bugs and has not been enabled in the compiler so we +// are just commenting these failing tests out for the time being. +// +// #[test] +// fn do_not_inline_parameters_that_have_side_effects() { +// assert_erl!( +// ("gleam_stdlib", "gleam/result", RESULT_MODULE), +// r#" +// import gleam/result +// +// pub fn main() { +// result.map(Ok(10), do_side_effects()) +// } +// +// fn do_side_effects() { +// let function = fn(x) { x + 1 } +// panic as "Side effects" +// function +// } +// "# +// ); +// } #[test] fn inline_anonymous_function_call() { @@ -228,16 +234,22 @@ pub fn main() { ); } -#[test] -fn inline_anonymous_function_in_pipe() { - assert_erl!( - " -pub fn main() { - 1 |> fn(x) { x + 1 } |> fn(y) { y * y } -} -" - ); -} +// Due to how the compilation to Erlang works now, where each variable is +// referenced via its unique source code location (rather than its name) some +// inlining tests stopped working properly. +// Inlining already has some bugs and has not been enabled in the compiler so we +// are just commenting these failing tests out for the time being. +// +// #[test] +// fn inline_anonymous_function_in_pipe() { +// assert_erl!( +// " +// pub fn main() { +// 1 |> fn(x) { x + 1 } |> fn(y) { y * y } +// } +// " +// ); +// } #[test] fn inline_function_capture_in_pipe() { @@ -291,30 +303,36 @@ pub fn main() { ); } -#[test] -fn parameters_from_nested_functions_are_correctly_inlined() { - assert_erl!( - ("gleam_stdlib", "gleam/result", RESULT_MODULE), - " -import gleam/result - -pub fn halve_all(a, b, c) { - use x <- result.try(divide(a, 2)) - use y <- result.try(divide(b, 2)) - use z <- result.map(divide(c, 2)) - - #(x, y, z) -} - -fn divide(a, b) { - case a % b { - 0 -> Ok(a / b) - _ -> Error(Nil) - } -} -" - ); -} +// Due to how the compilation to Erlang works now, where each variable is +// referenced via its unique source code location (rather than its name) some +// inlining tests stopped working properly. +// Inlining already has some bugs and has not been enabled in the compiler so we +// are just commenting these failing tests out for the time being. +// +// #[test] +// fn parameters_from_nested_functions_are_correctly_inlined() { +// assert_erl!( +// ("gleam_stdlib", "gleam/result", RESULT_MODULE), +// " +// import gleam/result +// +// pub fn halve_all(a, b, c) { +// use x <- result.try(divide(a, 2)) +// use y <- result.try(divide(b, 2)) +// use z <- result.map(divide(c, 2)) +// +// #(x, y, z) +// } +// +// fn divide(a, b) { +// case a % b { +// 0 -> Ok(a / b) +// _ -> Error(Nil) +// } +// } +// " +// ); +// } // https://github.com/gleam-lang/gleam/issues/4852 #[test] diff --git a/compiler-core/src/erlang/tests/lists.rs b/compiler-core/src/erlang/tests/lists.rs new file mode 100644 index 000000000..06aa8daed --- /dev/null +++ b/compiler-core/src/erlang/tests/lists.rs @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021 The Gleam contributors + +use crate::assert_erl; + +#[test] +fn empty_list() { + assert_erl!( + r#" +pub fn main() { + [] +} +"# + ); +} + +#[test] +fn single_item_list() { + assert_erl!( + r#" +pub fn main() { + [1] +} +"# + ); +} + +#[test] +fn list_with_multiple_items() { + assert_erl!( + r#" +pub fn main() { + [1, 2, 3] +} +"# + ); +} + +#[test] +fn list_with_spread() { + assert_erl!( + r#" +pub fn main() { + let a = [3, 2, 1] + [5, 4, ..a] +} +"# + ); +} diff --git a/compiler-core/src/erlang/tests/patterns.rs b/compiler-core/src/erlang/tests/patterns.rs index d5737ca52..e28daa0a6 100644 --- a/compiler-core/src/erlang/tests/patterns.rs +++ b/compiler-core/src/erlang/tests/patterns.rs @@ -125,3 +125,16 @@ fn string_prefix_as_pattern_with_assertion() { }" ); } + +#[test] +fn aliased_discard_pattern_in_bit_array_later_used() { + assert_erl!( + r#" +pub fn main(x) { + case x { + <<_ as b>> -> b + 2 + _ -> 0 + } +}"# + ); +} diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operation.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operation.snap index 340121113..e3a00a04b 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operation.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operation.snap @@ -12,8 +12,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). @@ -21,26 +20,33 @@ pub fn main() { main() -> X = true, case X orelse false of - true -> nil; - false -> erlang:error(#{gleam_error => assert, + true -> + nil; + + false -> + erlang:error(#{ + gleam_error => assert, message => <<"Assertion failed."/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"main"/utf8>>, line => 4, kind => binary_operator, operator => '||', - left => #{kind => expression, + left => #{ + kind => expression, value => false, start => 41, 'end' => 42 - }, - right => #{kind => literal, + }, + right => #{ + kind => literal, value => false, start => 46, 'end' => 51 - }, + }, start => 34, 'end' => 51, - expression_start => 41}) + expression_start => 41 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operation2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operation2.snap index e0d4c5d17..3d4330d02 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operation2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operation2.snap @@ -11,34 +11,40 @@ pub fn eq(a, b) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([eq/2]). -file("project/test/my/mod.gleam", 2). -spec eq(J, J) -> nil. eq(A, B) -> case A =:= B of - true -> nil; - false -> erlang:error(#{gleam_error => assert, + true -> + nil; + + false -> + erlang:error(#{ + gleam_error => assert, message => <<"Assertion failed."/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"eq"/utf8>>, line => 3, kind => binary_operator, operator => '==', - left => #{kind => expression, + left => #{ + kind => expression, value => A, start => 28, 'end' => 29 - }, - right => #{kind => expression, + }, + right => #{ + kind => expression, value => B, start => 33, 'end' => 34 - }, + }, start => 21, 'end' => 34, - expression_start => 28}) + expression_start => 28 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operation3.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operation3.snap index f0f46a0d2..68fa49c84 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operation3.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operation3.snap @@ -11,35 +11,41 @@ pub fn assert_answer(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([assert_answer/1]). -file("project/test/my/mod.gleam", 2). -spec assert_answer(integer()) -> nil. assert_answer(X) -> - _assert_subject = 42, - case X =:= _assert_subject of - true -> nil; - false -> erlang:error(#{gleam_error => assert, + _value = 42, + case X =:= _value of + true -> + nil; + + false -> + erlang:error(#{ + gleam_error => assert, message => <<"Assertion failed."/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"assert_answer"/utf8>>, line => 3, kind => binary_operator, operator => '==', - left => #{kind => expression, + left => #{ + kind => expression, value => X, start => 36, 'end' => 37 - }, - right => #{kind => literal, - value => _assert_subject, + }, + right => #{ + kind => literal, + value => _value, start => 41, 'end' => 43 - }, + }, start => 29, 'end' => 43, - expression_start => 36}) + expression_start => 36 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operator_with_side_effects.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operator_with_side_effects.snap index 43fb0aaf2..390b73ac6 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operator_with_side_effects.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operator_with_side_effects.snap @@ -16,8 +16,7 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). @@ -30,48 +29,62 @@ wibble(A, B) -> -spec go(any()) -> nil. go(X) -> case true of - true -> case wibble(1, 4) of - true -> nil; - false -> erlang:error(#{gleam_error => assert, + true -> + case wibble(1, 4) of + true -> + nil; + + false -> + erlang:error(#{ + gleam_error => assert, message => <<"Assertion failed."/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"go"/utf8>>, line => 8, kind => binary_operator, operator => '&&', - left => #{kind => literal, + left => #{ + kind => literal, value => true, start => 82, 'end' => 86 - }, - right => #{kind => expression, + }, + right => #{ + kind => expression, value => false, start => 90, 'end' => 102 - }, + }, start => 75, 'end' => 102, - expression_start => 82}) + expression_start => 82 + }) end; - false -> erlang:error(#{gleam_error => assert, + + false -> + erlang:error(#{ + gleam_error => assert, message => <<"Assertion failed."/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"go"/utf8>>, line => 8, kind => binary_operator, operator => '&&', - left => #{kind => literal, + left => #{ + kind => literal, value => false, start => 82, 'end' => 86 - }, - right => #{kind => unevaluated, + }, + right => #{ + kind => unevaluated, start => 90, 'end' => 102 - }, + }, start => 75, 'end' => 102, - expression_start => 82}) + expression_start => 82 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operator_with_side_effects2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operator_with_side_effects2.snap index 94e910eb4..f8880fdea 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operator_with_side_effects2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_binary_operator_with_side_effects2.snap @@ -16,8 +16,7 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). @@ -30,48 +29,62 @@ wibble(A, B) -> -spec go(any()) -> nil. go(X) -> case wibble(5, 5) of - true -> case wibble(4, 6) of - true -> nil; - false -> erlang:error(#{gleam_error => assert, + true -> + case wibble(4, 6) of + true -> + nil; + + false -> + erlang:error(#{ + gleam_error => assert, message => <<"Assertion failed."/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"go"/utf8>>, line => 8, kind => binary_operator, operator => '&&', - left => #{kind => expression, + left => #{ + kind => expression, value => true, start => 82, 'end' => 94 - }, - right => #{kind => expression, + }, + right => #{ + kind => expression, value => false, start => 98, 'end' => 110 - }, + }, start => 75, 'end' => 110, - expression_start => 82}) + expression_start => 82 + }) end; - false -> erlang:error(#{gleam_error => assert, + + false -> + erlang:error(#{ + gleam_error => assert, message => <<"Assertion failed."/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"go"/utf8>>, line => 8, kind => binary_operator, operator => '&&', - left => #{kind => expression, + left => #{ + kind => expression, value => false, start => 82, 'end' => 94 - }, - right => #{kind => unevaluated, + }, + right => #{ + kind => unevaluated, start => 98, 'end' => 110 - }, + }, start => 75, 'end' => 110, - expression_start => 82}) + expression_start => 82 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_function_call.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_function_call.snap index 379b7d357..230c95afd 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_function_call.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_function_call.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). @@ -28,10 +27,14 @@ bool() -> -spec main() -> nil. main() -> case bool() of - true -> nil; - false -> erlang:error(#{gleam_error => assert, + true -> + nil; + + false -> + erlang:error(#{ + gleam_error => assert, message => <<"Assertion failed."/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"main"/utf8>>, line => 7, @@ -39,5 +42,6 @@ main() -> arguments => [], start => 41, 'end' => 54, - expression_start => 48}) + expression_start => 48 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_function_call2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_function_call2.snap index 7a4ca91ca..3a29af9db 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_function_call2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_function_call2.snap @@ -15,8 +15,7 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). @@ -28,24 +27,31 @@ pub fn go(x) { -spec go(boolean()) -> nil. go(X) -> case 'and'(true, X) of - true -> nil; - false -> erlang:error(#{gleam_error => assert, + true -> + nil; + + false -> + erlang:error(#{ + gleam_error => assert, message => <<"Assertion failed."/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"go"/utf8>>, line => 7, kind => function_call, - arguments => [#{kind => literal, - value => true, - start => 56, - 'end' => 60 - }, #{kind => expression, - value => X, - start => 62, - 'end' => 63 - }], + arguments => [#{ + kind => literal, + value => true, + start => 56, + 'end' => 60 + }, #{ + kind => expression, + value => X, + start => 62, + 'end' => 63 + }], start => 45, 'end' => 64, - expression_start => 52}) + expression_start => 52 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_literal.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_literal.snap index b6f5aab42..55235580f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_literal.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_literal.snap @@ -11,28 +11,33 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> nil. main() -> case false of - true -> nil; - false -> erlang:error(#{gleam_error => assert, + true -> + nil; + + false -> + erlang:error(#{ + gleam_error => assert, message => <<"Assertion failed."/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"main"/utf8>>, line => 3, kind => expression, - expression => #{kind => literal, + expression => #{ + kind => literal, value => false, start => 26, 'end' => 31 - }, + }, start => 19, 'end' => 31, - expression_start => 26}) + expression_start => 26 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_nested_function_call.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_nested_function_call.snap index 2382c88a3..6e1f98f50 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_nested_function_call.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_nested_function_call.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). @@ -27,26 +26,33 @@ pub fn main() { -file("project/test/my/mod.gleam", 6). -spec main() -> nil. main() -> - _assert_subject = 'and'(true, false), - case 'and'(_assert_subject, true) of - true -> nil; - false -> erlang:error(#{gleam_error => assert, + _value = 'and'(true, false), + case 'and'(_value, true) of + true -> + nil; + + false -> + erlang:error(#{ + gleam_error => assert, message => <<"Assertion failed."/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"main"/utf8>>, line => 7, kind => function_call, - arguments => [#{kind => expression, - value => _assert_subject, - start => 57, - 'end' => 73 - }, #{kind => literal, - value => true, - start => 75, - 'end' => 79 - }], + arguments => [#{ + kind => expression, + value => _value, + start => 57, + 'end' => 73 + }, #{ + kind => literal, + value => true, + start => 75, + 'end' => 79 + }], start => 46, 'end' => 80, - expression_start => 53}) + expression_start => 53 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_on_consts.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_on_consts.snap new file mode 100644 index 000000000..b8e4e3773 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_on_consts.snap @@ -0,0 +1,53 @@ +--- +source: compiler-core/src/erlang/tests/assert.rs +expression: "\npub const wibble = [1, 2, 3]\npub const wobble = [1, 2]\n\npub fn assert_answer(x) {\n assert wibble == wobble\n}\n" +--- +----- SOURCE CODE + +pub const wibble = [1, 2, 3] +pub const wobble = [1, 2] + +pub fn assert_answer(x) { + assert wibble == wobble +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([assert_answer/1]). + +-file("project/test/my/mod.gleam", 5). +-spec assert_answer(any()) -> nil. +assert_answer(X) -> + case [1, 2, 3] =:= [1, 2] of + true -> + nil; + + false -> + erlang:error(#{ + gleam_error => assert, + message => <<"Assertion failed."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"assert_answer"/utf8>>, + line => 6, + kind => binary_operator, + operator => '==', + left => #{ + kind => expression, + value => [1, 2, 3], + start => 92, + 'end' => 98 + }, + right => #{ + kind => expression, + value => [1, 2], + start => 102, + 'end' => 108 + }, + start => 85, + 'end' => 108, + expression_start => 92 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_variable.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_variable.snap index 28bc33b5e..f5cc9a10e 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_variable.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_variable.snap @@ -12,8 +12,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). @@ -21,20 +20,26 @@ pub fn main() { main() -> X = true, case X of - true -> nil; - false -> erlang:error(#{gleam_error => assert, + true -> + nil; + + false -> + erlang:error(#{ + gleam_error => assert, message => <<"Assertion failed."/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"main"/utf8>>, line => 4, kind => expression, - expression => #{kind => expression, + expression => #{ + kind => expression, value => false, start => 41, 'end' => 42 - }, + }, start => 34, 'end' => 42, - expression_start => 41}) + expression_start => 41 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_with_block_message.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_with_block_message.snap index 2f2ff4e76..054d8e09b 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_with_block_message.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_with_block_message.snap @@ -18,8 +18,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). @@ -31,23 +30,29 @@ identity(A) -> -spec main() -> nil. main() -> case identity(true) of - true -> nil; - false -> erlang:error(#{gleam_error => assert, + true -> + nil; + + false -> + erlang:error(#{ + gleam_error => assert, message => begin Message = identity(<<"This shouldn't fail"/utf8>>), Message end, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"main"/utf8>>, line => 7, kind => function_call, - arguments => [#{kind => literal, - value => true, - start => 59, - 'end' => 63 - }], + arguments => [#{ + kind => literal, + value => true, + start => 59, + 'end' => 63 + }], start => 43, 'end' => 64, - expression_start => 50}) + expression_start => 50 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_with_message.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_with_message.snap index 8750e1c83..5c9a03695 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_with_message.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__assert__assert_with_message.snap @@ -11,28 +11,33 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> nil. main() -> case true of - true -> nil; - false -> erlang:error(#{gleam_error => assert, + true -> + nil; + + false -> + erlang:error(#{ + gleam_error => assert, message => <<"This shouldn't fail"/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"main"/utf8>>, line => 3, kind => expression, - expression => #{kind => literal, + expression => #{ + kind => literal, value => false, start => 26, 'end' => 30 - }, + }, start => 19, 'end' => 30, - expression_start => 26}) + expression_start => 26 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__float_divide_by_non_zero.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__float_divide_by_non_zero.snap new file mode 100644 index 000000000..9b2b9e575 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__float_divide_by_non_zero.snap @@ -0,0 +1,16 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a) { a() /. 3.0 }" +--- +----- SOURCE CODE +pub fn main(a) { a() /. 3.0 } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/1]). + +-file("project/test/my/mod.gleam", 1). +-spec main(fun(() -> float())) -> float(). +main(A) -> + A() / 3.0. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__float_divide_by_zero.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__float_divide_by_zero.snap new file mode 100644 index 000000000..9f5a4afba --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__float_divide_by_zero.snap @@ -0,0 +1,16 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a) { a /. 0.0 }" +--- +----- SOURCE CODE +pub fn main(a) { a /. 0.0 } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/1]). + +-file("project/test/my/mod.gleam", 1). +-spec main(float()) -> float(). +main(A) -> + +0.0. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__float_divide_side_effecting_function_by_zero.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__float_divide_side_effecting_function_by_zero.snap new file mode 100644 index 000000000..17a96f718 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__float_divide_side_effecting_function_by_zero.snap @@ -0,0 +1,17 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a) { a() /. 0.0 }" +--- +----- SOURCE CODE +pub fn main(a) { a() /. 0.0 } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/1]). + +-file("project/test/my/mod.gleam", 1). +-spec main(fun(() -> float())) -> float(). +main(A) -> + A(), + +0.0. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__float_divide_with_no_side_effect.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__float_divide_with_no_side_effect.snap new file mode 100644 index 000000000..6ef17035d --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__float_divide_with_no_side_effect.snap @@ -0,0 +1,25 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a, b) { a /. b }" +--- +----- SOURCE CODE +pub fn main(a, b) { a /. b } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/2]). + +-file("project/test/my/mod.gleam", 1). +-spec main(float(), float()) -> float(). +main(A, B) -> + case B of + +0.0 -> + +0.0; + + -0.0 -> + -0.0; + + _value -> + A / _value + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__float_divide_with_possible_side_effect.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__float_divide_with_possible_side_effect.snap new file mode 100644 index 000000000..eece5abff --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__float_divide_with_possible_side_effect.snap @@ -0,0 +1,26 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a, b) { a() /. b }" +--- +----- SOURCE CODE +pub fn main(a, b) { a() /. b } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/2]). + +-file("project/test/my/mod.gleam", 1). +-spec main(fun(() -> float()), float()) -> float(). +main(A, B) -> + _value = A(), + case B of + +0.0 -> + +0.0; + + -0.0 -> + -0.0; + + _value@1 -> + _value / _value@1 + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_add.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_add.snap new file mode 100644 index 000000000..62b96bb3f --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_add.snap @@ -0,0 +1,16 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main() { 1 + 2 }" +--- +----- SOURCE CODE +pub fn main() { 1 + 2 } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/0]). + +-file("project/test/my/mod.gleam", 1). +-spec main() -> integer(). +main() -> + 1 + 2. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_adds.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_adds.snap new file mode 100644 index 000000000..8d49330f1 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_adds.snap @@ -0,0 +1,16 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a, b) { 1 + 2 + a + b }" +--- +----- SOURCE CODE +pub fn main(a, b) { 1 + 2 + a + b } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/2]). + +-file("project/test/my/mod.gleam", 1). +-spec main(integer(), integer()) -> integer(). +main(A, B) -> + ((1 + 2) + A) + B. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_by_non_zero.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_by_non_zero.snap new file mode 100644 index 000000000..fd86f4df3 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_by_non_zero.snap @@ -0,0 +1,16 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a) { a() / 3 }" +--- +----- SOURCE CODE +pub fn main(a) { a() / 3 } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/1]). + +-file("project/test/my/mod.gleam", 1). +-spec main(fun(() -> integer())) -> integer(). +main(A) -> + A() div 3. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_by_non_zero_as_argument.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_by_non_zero_as_argument.snap new file mode 100644 index 000000000..6b11ab86a --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_by_non_zero_as_argument.snap @@ -0,0 +1,16 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(wibble, a) { wibble(a() / 3) }" +--- +----- SOURCE CODE +pub fn main(wibble, a) { wibble(a() / 3) } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/2]). + +-file("project/test/my/mod.gleam", 1). +-spec main(fun((integer()) -> M), fun(() -> integer())) -> M. +main(Wibble, A) -> + Wibble(A() div 3). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_by_zero.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_by_zero.snap new file mode 100644 index 000000000..1a2b8f7d3 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_by_zero.snap @@ -0,0 +1,16 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a) { a / 0 }" +--- +----- SOURCE CODE +pub fn main(a) { a / 0 } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/1]). + +-file("project/test/my/mod.gleam", 1). +-spec main(integer()) -> integer(). +main(A) -> + 0. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_by_zero_as_argument.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_by_zero_as_argument.snap new file mode 100644 index 000000000..1a3e79b85 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_by_zero_as_argument.snap @@ -0,0 +1,16 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(wibble, a) { wibble(a / 0) }" +--- +----- SOURCE CODE +pub fn main(wibble, a) { wibble(a / 0) } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/2]). + +-file("project/test/my/mod.gleam", 1). +-spec main(fun((integer()) -> M), integer()) -> M. +main(Wibble, A) -> + Wibble(0). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_side_effecting_function_by_zero.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_side_effecting_function_by_zero.snap new file mode 100644 index 000000000..16c45a7fb --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_side_effecting_function_by_zero.snap @@ -0,0 +1,17 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a) { a() / 0 }" +--- +----- SOURCE CODE +pub fn main(a) { a() / 0 } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/1]). + +-file("project/test/my/mod.gleam", 1). +-spec main(fun(() -> integer())) -> integer(). +main(A) -> + A(), + 0. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_side_effecting_function_by_zero_as_argument.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_side_effecting_function_by_zero_as_argument.snap new file mode 100644 index 000000000..2d6985305 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_side_effecting_function_by_zero_as_argument.snap @@ -0,0 +1,19 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(wibble, a) { wibble(a() / 0) }" +--- +----- SOURCE CODE +pub fn main(wibble, a) { wibble(a() / 0) } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/2]). + +-file("project/test/my/mod.gleam", 1). +-spec main(fun((integer()) -> M), fun(() -> integer())) -> M. +main(Wibble, A) -> + Wibble(begin + A(), + 0 + end). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_with_no_side_effect.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_with_no_side_effect.snap new file mode 100644 index 000000000..f7feece29 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_with_no_side_effect.snap @@ -0,0 +1,22 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a, b) { a / b }" +--- +----- SOURCE CODE +pub fn main(a, b) { a / b } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/2]). + +-file("project/test/my/mod.gleam", 1). +-spec main(integer(), integer()) -> integer(). +main(A, B) -> + case B of + 0 -> + 0; + + _value -> + A div _value + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_with_no_side_effect_as_argument.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_with_no_side_effect_as_argument.snap new file mode 100644 index 000000000..440c07e94 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_with_no_side_effect_as_argument.snap @@ -0,0 +1,22 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(wibble, a, b) { wibble(a / b) }" +--- +----- SOURCE CODE +pub fn main(wibble, a, b) { wibble(a / b) } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/3]). + +-file("project/test/my/mod.gleam", 1). +-spec main(fun((integer()) -> N), integer(), integer()) -> N. +main(Wibble, A, B) -> + Wibble(case B of + 0 -> + 0; + + _value -> + A div _value + end). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_with_possible_side_effect.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_with_possible_side_effect.snap new file mode 100644 index 000000000..7e927768e --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_with_possible_side_effect.snap @@ -0,0 +1,23 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a, b) { a() / b }" +--- +----- SOURCE CODE +pub fn main(a, b) { a() / b } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/2]). + +-file("project/test/my/mod.gleam", 1). +-spec main(fun(() -> integer()), integer()) -> integer(). +main(A, B) -> + _value = A(), + case B of + 0 -> + 0; + + _value@1 -> + _value div _value@1 + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_with_possible_side_effect_as_argument.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_with_possible_side_effect_as_argument.snap new file mode 100644 index 000000000..e1c6612ae --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_divide_with_possible_side_effect_as_argument.snap @@ -0,0 +1,25 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(wibble, a, b) { wibble(a() / b) }" +--- +----- SOURCE CODE +pub fn main(wibble, a, b) { wibble(a() / b) } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/3]). + +-file("project/test/my/mod.gleam", 1). +-spec main(fun((integer()) -> N), fun(() -> integer()), integer()) -> N. +main(Wibble, A, B) -> + Wibble(begin + _value = A(), + case B of + 0 -> + 0; + + _value@1 -> + _value div _value@1 + end + end). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_mult.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_mult.snap new file mode 100644 index 000000000..09912fe75 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_mult.snap @@ -0,0 +1,16 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main() { 1 * 2 }" +--- +----- SOURCE CODE +pub fn main() { 1 * 2 } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/0]). + +-file("project/test/my/mod.gleam", 1). +-spec main() -> integer(). +main() -> + 1 * 2. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_mults.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_mults.snap new file mode 100644 index 000000000..854500ef0 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_mults.snap @@ -0,0 +1,16 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a, b) { 1 * 2 * a * b }" +--- +----- SOURCE CODE +pub fn main(a, b) { 1 * 2 * a * b } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/2]). + +-file("project/test/my/mod.gleam", 1). +-spec main(integer(), integer()) -> integer(). +main(A, B) -> + ((1 * 2) * A) * B. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_remainder_by_non_zero.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_remainder_by_non_zero.snap new file mode 100644 index 000000000..056ba31b6 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_remainder_by_non_zero.snap @@ -0,0 +1,16 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a) { a() % 3 }" +--- +----- SOURCE CODE +pub fn main(a) { a() % 3 } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/1]). + +-file("project/test/my/mod.gleam", 1). +-spec main(fun(() -> integer())) -> integer(). +main(A) -> + A() rem 3. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_remainder_by_zero.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_remainder_by_zero.snap new file mode 100644 index 000000000..3ffc99bb2 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_remainder_by_zero.snap @@ -0,0 +1,16 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a) { a % 0 }" +--- +----- SOURCE CODE +pub fn main(a) { a % 0 } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/1]). + +-file("project/test/my/mod.gleam", 1). +-spec main(integer()) -> integer(). +main(A) -> + 0. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_remainder_side_effecting_function_by_zero.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_remainder_side_effecting_function_by_zero.snap new file mode 100644 index 000000000..29495c768 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_remainder_side_effecting_function_by_zero.snap @@ -0,0 +1,17 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a) { a() % 0 }" +--- +----- SOURCE CODE +pub fn main(a) { a() % 0 } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/1]). + +-file("project/test/my/mod.gleam", 1). +-spec main(fun(() -> integer())) -> integer(). +main(A) -> + A(), + 0. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_remainder_with_no_side_effect.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_remainder_with_no_side_effect.snap new file mode 100644 index 000000000..8148e770e --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_remainder_with_no_side_effect.snap @@ -0,0 +1,22 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a, b) { a % b }" +--- +----- SOURCE CODE +pub fn main(a, b) { a % b } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/2]). + +-file("project/test/my/mod.gleam", 1). +-spec main(integer(), integer()) -> integer(). +main(A, B) -> + case B of + 0 -> + 0; + + _value -> + A rem _value + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_remainder_with_possible_side_effect.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_remainder_with_possible_side_effect.snap new file mode 100644 index 000000000..5321a6aae --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_remainder_with_possible_side_effect.snap @@ -0,0 +1,23 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a, b) { a() % b }" +--- +----- SOURCE CODE +pub fn main(a, b) { a() % b } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/2]). + +-file("project/test/my/mod.gleam", 1). +-spec main(fun(() -> integer()), integer()) -> integer(). +main(A, B) -> + _value = A(), + case B of + 0 -> + 0; + + _value@1 -> + _value rem _value@1 + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_sub.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_sub.snap new file mode 100644 index 000000000..80adae3e5 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_sub.snap @@ -0,0 +1,16 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main() { 1 - 2 }" +--- +----- SOURCE CODE +pub fn main() { 1 - 2 } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/0]). + +-file("project/test/my/mod.gleam", 1). +-spec main() -> integer(). +main() -> + 1 - 2. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_subs.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_subs.snap new file mode 100644 index 000000000..79099cc01 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__binops__int_subs.snap @@ -0,0 +1,16 @@ +--- +source: compiler-core/src/erlang/tests/binops.rs +expression: "pub fn main(a) { 1 - 2 - a }" +--- +----- SOURCE CODE +pub fn main(a) { 1 - 2 - a } + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/1]). + +-file("project/test/my/mod.gleam", 1). +-spec main(integer()) -> integer(). +main(A) -> + (1 - 2) - A. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array.snap index 4ba7e0350..323e2c8ac 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array.snap @@ -16,8 +16,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 1). @@ -26,34 +25,40 @@ main() -> A = 1, Simple = <<1, A>>, Complex = <<4/integer-big, 5.0/little-float, 6/native-integer>>, - B@1 = case <<1>> of - <<7:2, 8:3, B:4/binary>> -> B; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 5, - value => _assert_fail, - start => 116, - 'end' => 170, - pattern_start => 127, - pattern_end => 162}) - end, - {C@1, D@1} = case <<1>> of - <> -> {C, D}; - _assert_fail@1 -> - erlang:error(#{gleam_error => let_assert, + case <<1>> of + <<7:2, 8:3, B:4/binary>> -> + case <<1>> of + <> -> + Simple; + + _value -> + erlang:error(#{ + gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"main"/utf8>>, line => 6, - value => _assert_fail@1, + value => _value, start => 173, 'end' => 232, pattern_start => 184, - pattern_end => 224}) - end, - Simple. + pattern_end => 224 + }) + end; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 5, + value => _value@1, + start => 116, + 'end' => 170, + pattern_start => 127, + pattern_end => 162 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array1.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array1.snap index cb0b1b8aa..ab3e99a8c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array1.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array1.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([x/0, main/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array2.snap index 1c01261ed..319f9dcb6 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array2.snap @@ -12,27 +12,29 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 1). -spec main() -> integer(). main() -> A = 1, - B@1 = case <<1, A>> of - <> -> B; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 30, - 'end' => 60, - pattern_start => 41, - pattern_end => 49}) - end, - B@1. + case <<1, A>> of + <> -> + B; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value, + start => 30, + 'end' => 60, + pattern_start => 41, + pattern_end => 49 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array3.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array3.snap index defaf52fa..fec368ebb 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array3.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array3.snap @@ -12,27 +12,29 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 1). -spec main() -> integer(). main() -> A = <<"test"/utf8>>, - B@1 = case A of - <> -> B; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 44, - 'end' => 90, - pattern_start => 55, - pattern_end => 86}) - end, - B@1. + case A of + <> -> + B; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value, + start => 44, + 'end' => 90, + pattern_start => 55, + pattern_end => 86 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array4.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array4.snap index 1b8324ade..241c40871 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array4.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array4.snap @@ -12,8 +12,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array5.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array5.snap index 17b90e5ec..51ae9a185 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array5.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array5.snap @@ -12,8 +12,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_declare_and_use_var.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_declare_and_use_var.snap index 7d80120be..f39b8d1ac 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_declare_and_use_var.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_declare_and_use_var.snap @@ -10,26 +10,28 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 1). -spec go(bitstring()) -> bitstring(). go(X) -> - {Name_size@1, Name@1} = case X of - <> -> {Name_size, Name}; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 2, - value => _assert_fail, - start => 17, - 'end' => 75, - pattern_start => 28, - pattern_end => 71}) - end, - Name@1. + case X of + <> -> + Name; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 2, + value => _value, + start => 17, + 'end' => 75, + pattern_start => 28, + pattern_end => 71 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_discard.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_discard.snap index bf54e5429..8fb64095b 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_discard.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_discard.snap @@ -14,8 +14,7 @@ pub fn bit_array_discard(x) -> Bool { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([bit_array_discard/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_discard1.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_discard1.snap index a4ae174d4..79bb917e3 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_discard1.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_discard1.snap @@ -14,8 +14,7 @@ pub fn bit_array_discard(x) -> Bool { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([bit_array_discard/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_float.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_float.snap index 125ec5cc2..ddc7e5059 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_float.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_float.snap @@ -11,30 +11,30 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 1). -spec main() -> bitstring(). main() -> B = 16, - Floats = <<1.0:16/float, - 5.0:32/float, - 6.0:64/float-little, - 1.0:(erlang:max(0, B))/float>>, + Floats = <<1.0:16/float, 5.0:32/float, 6.0:64/float-little, 1.0:(erlang:max(0, B))/float>>, case Floats of - <<1.0:16/float, 5.0:32/float, 6.0:64/float-little, 1.0:B/float>> -> Floats; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 4, - value => _assert_fail, - start => 117, - 'end' => 207, - pattern_start => 128, - pattern_end => 198}) + <<1.0:16/float, 5.0:32/float, 6.0:64/float-little, 1.0:B/float>> = _value -> + _value; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 4, + value => _value@1, + start => 117, + 'end' => 207, + pattern_start => 128, + pattern_end => 198 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_literal_string_constant_is_treated_as_utf8.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_literal_string_constant_is_treated_as_utf8.snap index 28606869e..51346e91a 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_literal_string_constant_is_treated_as_utf8.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_literal_string_constant_is_treated_as_utf8.snap @@ -10,8 +10,7 @@ pub fn main() { a } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 3). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_literal_string_is_treated_as_utf8.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_literal_string_is_treated_as_utf8.snap index 22c52d438..c531ec981 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_literal_string_is_treated_as_utf8.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_literal_string_is_treated_as_utf8.snap @@ -10,8 +10,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_literal_string_pattern_is_treated_as_utf8.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_literal_string_pattern_is_treated_as_utf8.snap index d5408e631..26083e3b1 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_literal_string_pattern_is_treated_as_utf8.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__bit_array_literal_string_pattern_is_treated_as_utf8.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__block_in_pattern_size.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__block_in_pattern_size.snap index 00542010d..d619e8d67 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__block_in_pattern_size.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__block_in_pattern_size.snap @@ -11,26 +11,28 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> bitstring(). main() -> - _assert_subject = <<>>, - case _assert_subject of - <> -> _assert_subject; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 19, - 'end' => 75, - pattern_start => 30, - pattern_end => 68}) + case <<>> of + <> = _value -> + _value; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value@1, + start => 19, + 'end' => 75, + pattern_start => 30, + pattern_end => 68 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__discard_utf8_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__discard_utf8_pattern.snap index 5f9f217d9..1b874accb 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__discard_utf8_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__discard_utf8_pattern.snap @@ -10,26 +10,28 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> bitstring(). main() -> - _assert_subject = <<>>, - case _assert_subject of - <<_/utf8, Rest/bitstring>> -> _assert_subject; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 21, - 'end' => 60, - pattern_start => 32, - pattern_end => 53}) + case <<>> of + <<_/utf8, Rest/bitstring>> = _value -> + _value; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value@1, + start => 21, + 'end' => 60, + pattern_start => 32, + pattern_end => 53 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf16_big_string.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf16_big_string.snap index 79c5af472..7930f0eca 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf16_big_string.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf16_big_string.snap @@ -11,8 +11,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf16_little_string.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf16_little_string.snap index da4426b8c..eaeccfd1e 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf16_little_string.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf16_little_string.snap @@ -11,8 +11,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf32_big_string.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf32_big_string.snap index fe8e21630..3925f6660 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf32_big_string.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf32_big_string.snap @@ -11,8 +11,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf32_little_string.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf32_little_string.snap index 810c99375..ffb138e68 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf32_little_string.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf32_little_string.snap @@ -11,8 +11,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf8_string.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf8_string.snap index 811d33e60..2435ce72c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf8_string.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__literal_utf8_string.snap @@ -11,8 +11,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__multiplication_in_pattern_size_is_left_associative.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__multiplication_in_pattern_size_is_left_associative.snap index f2bf42af3..17086b886 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__multiplication_in_pattern_size_is_left_associative.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__multiplication_in_pattern_size_is_left_associative.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). @@ -24,19 +23,22 @@ main() -> A = 2, B = 3, C = 4, - _assert_subject = <<>>, - case _assert_subject of - <<_:(A * B * C)/binary>> -> _assert_subject; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 6, - value => _assert_fail, - start => 55, - 'end' => 100, - pattern_start => 66, - pattern_end => 93}) + case <<>> of + <<_:((A * B) * C)/binary>> = _value -> + _value; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 6, + value => _value@1, + start => 55, + 'end' => 100, + pattern_start => 66, + pattern_end => 93 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__negative_size_test.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__negative_size_test.snap index 22fc912cc..54b37c8c4 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__negative_size_test.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__negative_size_test.snap @@ -10,8 +10,7 @@ pub fn size_16_variable_test() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([size_16_variable_test/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__non_byte_aligned_size_calculation.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__non_byte_aligned_size_calculation.snap index b7f2f09a4..18e01b0a6 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__non_byte_aligned_size_calculation.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__non_byte_aligned_size_calculation.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__operator_in_pattern_size.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__operator_in_pattern_size.snap index 732a5a28b..9cc62d76d 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__operator_in_pattern_size.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__operator_in_pattern_size.snap @@ -11,26 +11,28 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> bitstring(). main() -> - _assert_subject = <<>>, - case _assert_subject of - <> -> _assert_subject; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 19, - 'end' => 71, - pattern_start => 30, - pattern_end => 64}) + case <<>> of + <> = _value -> + _value; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value@1, + start => 19, + 'end' => 71, + pattern_start => 30, + pattern_end => 64 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__operator_in_pattern_size2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__operator_in_pattern_size2.snap index 68ce82b9e..ead3abb40 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__operator_in_pattern_size2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__operator_in_pattern_size2.snap @@ -11,26 +11,28 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> bitstring(). main() -> - _assert_subject = <<>>, - case _assert_subject of - <> -> _assert_subject; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 19, - 'end' => 71, - pattern_start => 30, - pattern_end => 64}) + case <<>> of + <> = _value -> + _value; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value@1, + start => 19, + 'end' => 71, + pattern_start => 30, + pattern_end => 64 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__operator_in_pattern_size3.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__operator_in_pattern_size3.snap index 3320fd248..32f1bce76 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__operator_in_pattern_size3.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__operator_in_pattern_size3.snap @@ -12,27 +12,29 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> bitstring(). main() -> Additional = 10, - _assert_subject = <<>>, - case _assert_subject of - <> -> _assert_subject; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 4, - value => _assert_fail, - start => 41, - 'end' => 102, - pattern_start => 52, - pattern_end => 95}) + case <<>> of + <> = _value -> + _value; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 4, + value => _value@1, + start => 41, + 'end' => 102, + pattern_start => 52, + pattern_end => 95 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__pattern_match_utf16_codepoint_little_endian.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__pattern_match_utf16_codepoint_little_endian.snap index 8c5be8fe9..4c14801f3 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__pattern_match_utf16_codepoint_little_endian.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__pattern_match_utf16_codepoint_little_endian.snap @@ -12,26 +12,28 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). -spec go(bitstring()) -> integer(). go(X) -> - Codepoint@1 = case X of - <> -> Codepoint; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 3, - value => _assert_fail, - start => 18, - 'end' => 69, - pattern_start => 29, - pattern_end => 65}) - end, - Codepoint@1. + case X of + <> -> + Codepoint; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 3, + value => _value, + start => 18, + 'end' => 69, + pattern_start => 29, + pattern_end => 65 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__pattern_match_utf32_codepoint_little_endian.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__pattern_match_utf32_codepoint_little_endian.snap index ddf8e39dd..f24c2533d 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__pattern_match_utf32_codepoint_little_endian.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__pattern_match_utf32_codepoint_little_endian.snap @@ -12,26 +12,28 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). -spec go(bitstring()) -> integer(). go(X) -> - Codepoint@1 = case X of - <> -> Codepoint; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 3, - value => _assert_fail, - start => 18, - 'end' => 69, - pattern_start => 29, - pattern_end => 65}) - end, - Codepoint@1. + case X of + <> -> + Codepoint; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 3, + value => _value, + start => 18, + 'end' => 69, + pattern_start => 29, + pattern_end => 65 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__pipe_size_segment.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__pipe_size_segment.snap index 576bbcdf9..c63b52086 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__pipe_size_segment.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__pipe_size_segment.snap @@ -15,8 +15,7 @@ fn identity(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 6). @@ -27,7 +26,7 @@ identity(X) -> -file("project/test/my/mod.gleam", 2). -spec main() -> bitstring(). main() -> - <<16#AE:(erlang:max(0, begin - _pipe = 5, - identity(_pipe) - end))>>. + <<174:(erlang:max(0, begin + _pipe = 5, + identity(_pipe) + end))>>. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_16_literal_test.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_16_literal_test.snap index 8422638a4..20549dba2 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_16_literal_test.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_16_literal_test.snap @@ -9,8 +9,7 @@ pub fn size_16_literal_test() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([size_16_literal_test/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_16_variable_test.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_16_variable_test.snap index c3d8780a9..8b1a46310 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_16_variable_test.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_16_variable_test.snap @@ -10,8 +10,7 @@ pub fn size_16_variable_test() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([size_16_variable_test/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_8_literal_test.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_8_literal_test.snap index 7e4c34aa7..47ea2b92d 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_8_literal_test.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_8_literal_test.snap @@ -9,8 +9,7 @@ pub fn size_8_literal_test() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([size_8_literal_test/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_8_variable_test.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_8_variable_test.snap index 9e3440be3..879c89a48 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_8_variable_test.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_8_variable_test.snap @@ -10,8 +10,7 @@ pub fn size_8_variable_test() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([size_8_variable_test/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_unit_test.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_unit_test.snap index 72e3fa0e0..b34d34785 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_unit_test.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__size_unit_test.snap @@ -10,8 +10,7 @@ pub fn size_16_variable_test() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([size_16_variable_test/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__subtraction_in_pattern_size_is_left_associative.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__subtraction_in_pattern_size_is_left_associative.snap index 7657f1814..63bea2f05 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__subtraction_in_pattern_size_is_left_associative.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__subtraction_in_pattern_size_is_left_associative.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). @@ -24,19 +23,22 @@ main() -> A = 10, B = 3, C = 2, - _assert_subject = <<>>, - case _assert_subject of - <<_:(A - B - C)/binary>> -> _assert_subject; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 6, - value => _assert_fail, - start => 56, - 'end' => 101, - pattern_start => 67, - pattern_end => 94}) + case <<>> of + <<_:((A - B) - C)/binary>> = _value -> + _value; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 6, + value => _value@1, + start => 56, + 'end' => 101, + pattern_start => 67, + pattern_end => 94 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unicode_bit_array_1.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unicode_bit_array_1.snap index e1ca93b53..21ad70a12 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unicode_bit_array_1.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unicode_bit_array_1.snap @@ -11,8 +11,7 @@ expression: "\n pub fn main() {\n let emoji = \"\\u{1F600}\"\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unicode_bit_array_2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unicode_bit_array_2.snap index d4b46c110..3270599c5 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unicode_bit_array_2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unicode_bit_array_2.snap @@ -10,8 +10,7 @@ expression: "\n pub fn main() {\n let arr = <<\"\\u{1F600}\":utf8>>\n} ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unicode_character_encoding_in_bit_array_pattern_segment.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unicode_character_encoding_in_bit_array_pattern_segment.snap index ece462d8c..0c08b9de4 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unicode_character_encoding_in_bit_array_pattern_segment.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unicode_character_encoding_in_bit_array_pattern_segment.snap @@ -16,8 +16,7 @@ pub fn main() -> Nil { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unit_option_ignores_bytes.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unit_option_ignores_bytes.snap index 99db05dc3..a8f032940 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unit_option_ignores_bytes.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unit_option_ignores_bytes.snap @@ -12,26 +12,28 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> bitstring(). main() -> - X@1 = case <<1:6>> of - <> -> X; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 19, - 'end' => 67, - pattern_start => 30, - pattern_end => 57}) - end, - X@1. + case <<1:6>> of + <> -> + X; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value, + start => 19, + 'end' => 67, + pattern_start => 30, + pattern_end => 57 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unit_option_ignores_bytes_regardless_of_order.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unit_option_ignores_bytes_regardless_of_order.snap index f46b7094c..f0bd9afb8 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unit_option_ignores_bytes_regardless_of_order.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unit_option_ignores_bytes_regardless_of_order.snap @@ -12,26 +12,28 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> bitstring(). main() -> - X@1 = case <<1:6>> of - <> -> X; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 19, - 'end' => 67, - pattern_start => 30, - pattern_end => 57}) - end, - X@1. + case <<1:6>> of + <> -> + X; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value, + start => 19, + 'end' => 67, + pattern_start => 30, + pattern_end => 57 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__utf16_codepoint_little_endian.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__utf16_codepoint_little_endian.snap index aa68d3b11..48dd22b94 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__utf16_codepoint_little_endian.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__utf16_codepoint_little_endian.snap @@ -11,8 +11,7 @@ pub fn go(codepoint) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__utf32_codepoint_little_endian.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__utf32_codepoint_little_endian.snap index 89fece559..67ea247ef 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__utf32_codepoint_little_endian.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__utf32_codepoint_little_endian.snap @@ -11,8 +11,7 @@ pub fn go(codepoint) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf16_big_string.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf16_big_string.snap index d5433ab30..d022a389d 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf16_big_string.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf16_big_string.snap @@ -11,8 +11,7 @@ pub fn go(wibble: String) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf16_little_string.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf16_little_string.snap index e9b2f0524..c7e45a653 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf16_little_string.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf16_little_string.snap @@ -11,8 +11,7 @@ pub fn go(wibble: String) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf32_big_string.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf32_big_string.snap index a6fc045ce..03bbe2cb8 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf32_big_string.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf32_big_string.snap @@ -11,8 +11,7 @@ pub fn go(wibble: String) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf32_little_string.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf32_little_string.snap index ecfee48e0..f5a42d2e0 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf32_little_string.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf32_little_string.snap @@ -11,8 +11,7 @@ pub fn go(wibble: String) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf8_string.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf8_string.snap index 2dec2d1c6..6fcb009e0 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf8_string.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__variable_utf8_string.snap @@ -11,8 +11,7 @@ pub fn go(wibble: String) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__aliased_string_prefix_pattern_referenced_in_guard.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__aliased_string_prefix_pattern_referenced_in_guard.snap index 27d6a5b56..997f238e5 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__aliased_string_prefix_pattern_referenced_in_guard.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__aliased_string_prefix_pattern_referenced_in_guard.snap @@ -14,8 +14,7 @@ pub fn main(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__alternative_patter_with_string_alias.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__alternative_patter_with_string_alias.snap index 5b98f737c..bee57b522 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__alternative_patter_with_string_alias.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__alternative_patter_with_string_alias.snap @@ -14,8 +14,7 @@ pub fn main(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__alternative_pattern_variable_rewriting.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__alternative_pattern_variable_rewriting.snap index 4f48a784e..68c50e540 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__alternative_pattern_variable_rewriting.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__alternative_pattern_variable_rewriting.snap @@ -17,8 +17,7 @@ pub fn myfun(mt) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([myfun/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__case_defining_some_variables_that_are_later_shadowed.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__case_defining_some_variables_that_are_later_shadowed.snap new file mode 100644 index 000000000..214483730 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__case_defining_some_variables_that_are_later_shadowed.snap @@ -0,0 +1,46 @@ +--- +source: compiler-core/src/erlang/tests/case.rs +expression: "\npub fn go(x) {\n case x {\n 1 -> {\n let a = 1\n Nil\n }\n 2 -> {\n let a = 2\n Nil\n }\n _ -> Nil\n }\n\n let a = 3\n a + 1\n}\n" +--- +----- SOURCE CODE + +pub fn go(x) { + case x { + 1 -> { + let a = 1 + Nil + } + 2 -> { + let a = 2 + Nil + } + _ -> Nil + } + + let a = 3 + a + 1 +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([go/1]). + +-file("project/test/my/mod.gleam", 2). +-spec go(integer()) -> integer(). +go(X) -> + case X of + 1 -> + A = 1, + nil; + + 2 -> + A@1 = 2, + nil; + + _ -> + nil + end, + A@2 = 3, + A@2 + 1. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__case_defining_some_variables_that_are_later_shadowed_2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__case_defining_some_variables_that_are_later_shadowed_2.snap new file mode 100644 index 000000000..cffad7276 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__case_defining_some_variables_that_are_later_shadowed_2.snap @@ -0,0 +1,50 @@ +--- +source: compiler-core/src/erlang/tests/case.rs +expression: "\npub fn go(x) {\n case x {\n 1 | 2 -> {\n let a = 1\n Nil\n }\n 3 -> {\n let a = 2\n Nil\n }\n _ -> Nil\n }\n\n let a = 4\n a + 1\n}\n" +--- +----- SOURCE CODE + +pub fn go(x) { + case x { + 1 | 2 -> { + let a = 1 + Nil + } + 3 -> { + let a = 2 + Nil + } + _ -> Nil + } + + let a = 4 + a + 1 +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([go/1]). + +-file("project/test/my/mod.gleam", 2). +-spec go(integer()) -> integer(). +go(X) -> + case X of + 1 -> + A = 1, + nil; + + 2 -> + A = 1, + nil; + + 3 -> + A@1 = 2, + nil; + + _ -> + nil + end, + A@2 = 4, + A@2 + 1. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__list_with_tail_used_in_guard.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__list_with_tail_used_in_guard.snap index a89b8ad48..ee3d37187 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__list_with_tail_used_in_guard.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__list_with_tail_used_in_guard.snap @@ -13,8 +13,7 @@ pub fn go(x: List(Int), y: List(Int)) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/2]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__multiple_alternative_branches_with_same_variable_names.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__multiple_alternative_branches_with_same_variable_names.snap new file mode 100644 index 000000000..89383ba5f --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__multiple_alternative_branches_with_same_variable_names.snap @@ -0,0 +1,50 @@ +--- +source: compiler-core/src/erlang/tests/case.rs +expression: "\npub fn go(x) {\n case x {\n 1 as x | x -> {\n let a = 1 + x\n Nil\n }\n 3 as x | x -> {\n let a = 2 + x\n Nil\n }\n }\n\n let a = 3\n a + 1\n}\n" +--- +----- SOURCE CODE + +pub fn go(x) { + case x { + 1 as x | x -> { + let a = 1 + x + Nil + } + 3 as x | x -> { + let a = 2 + x + Nil + } + } + + let a = 3 + a + 1 +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([go/1]). + +-file("project/test/my/mod.gleam", 2). +-spec go(integer()) -> integer(). +go(X) -> + case X of + 1 = X@1 -> + A = 1 + X@1, + nil; + + X@1 -> + A = 1 + X@1, + nil; + + 3 = X@2 -> + A@1 = 2 + X@2, + nil; + + X@2 -> + A@1 = 2 + X@2, + nil + end, + A@2 = 3, + A@2 + 1. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__negative_zero_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__negative_zero_pattern.snap index 51dbad161..e3318a8dc 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__negative_zero_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__negative_zero_pattern.snap @@ -14,8 +14,7 @@ pub fn main(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__nested_string_prefix_pattern_assigns_variable.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__nested_string_prefix_pattern_assigns_variable.snap new file mode 100644 index 000000000..2d3330566 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__nested_string_prefix_pattern_assigns_variable.snap @@ -0,0 +1,35 @@ +--- +source: compiler-core/src/erlang/tests/case.rs +expression: "\npub fn go(x) {\n case x {\n [\"a\" as letter <> rest, ..]\n | [\"b\" as letter <> rest, ..] -> letter <> rest\n _ -> \"\"\n }\n}\n" +--- +----- SOURCE CODE + +pub fn go(x) { + case x { + ["a" as letter <> rest, ..] + | ["b" as letter <> rest, ..] -> letter <> rest + _ -> "" + } +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([go/1]). + +-file("project/test/my/mod.gleam", 2). +-spec go(list(binary())) -> binary(). +go(X) -> + case X of + [<<"a"/utf8, Rest/binary>> | _] -> + Letter = <<"a"/utf8>>, + <>; + + [<<"b"/utf8, Rest/binary>> | _] -> + Letter = <<"b"/utf8>>, + <>; + + _ -> + <<""/utf8>> + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__not.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__not.snap index 2f40428b2..18820a461 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__not.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__not.snap @@ -13,8 +13,7 @@ pub fn main(x, y) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/2]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__not_two.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__not_two.snap index 0ca485c26..dd4b80970 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__not_two.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__not_two.snap @@ -13,8 +13,7 @@ pub fn main(x, y) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/2]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__positive_zero_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__positive_zero_pattern.snap index 55789215c..7f3915ac9 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__positive_zero_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__positive_zero_pattern.snap @@ -14,8 +14,7 @@ pub fn main(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__spread_empty_list.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__spread_empty_list.snap index ee5cb83ba..c63761a65 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__spread_empty_list.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__spread_empty_list.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__spread_empty_list_assigning.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__spread_empty_list_assigning.snap index 348ca7c1f..eefa7ffa5 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__spread_empty_list_assigning.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__spread_empty_list_assigning.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__string_prefix_pattern_assigns_variable.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__string_prefix_pattern_assigns_variable.snap new file mode 100644 index 000000000..5a1b62202 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__string_prefix_pattern_assigns_variable.snap @@ -0,0 +1,35 @@ +--- +source: compiler-core/src/erlang/tests/case.rs +expression: "\npub fn go(x) {\n case x {\n \"a\" as letter <> rest\n | \"b\" as letter <> rest -> letter <> rest\n _ -> \"\"\n }\n}\n" +--- +----- SOURCE CODE + +pub fn go(x) { + case x { + "a" as letter <> rest + | "b" as letter <> rest -> letter <> rest + _ -> "" + } +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([go/1]). + +-file("project/test/my/mod.gleam", 2). +-spec go(binary()) -> binary(). +go(X) -> + case X of + <<"a"/utf8, Rest/binary>> -> + Letter = <<"a"/utf8>>, + <>; + + <<"b"/utf8, Rest/binary>> -> + Letter = <<"b"/utf8>>, + <>; + + _ -> + <<""/utf8>> + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__string_prefix_pattern_used_in_guard_assigns_variable.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__string_prefix_pattern_used_in_guard_assigns_variable.snap new file mode 100644 index 000000000..763b2dbfe --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__string_prefix_pattern_used_in_guard_assigns_variable.snap @@ -0,0 +1,35 @@ +--- +source: compiler-core/src/erlang/tests/case.rs +expression: "\npub fn go(x) {\n case x {\n \"a\" as letter <> rest\n | \"b\" as letter <> rest if letter == \"c\" -> letter <> rest\n _ -> \"\"\n }\n}\n" +--- +----- SOURCE CODE + +pub fn go(x) { + case x { + "a" as letter <> rest + | "b" as letter <> rest if letter == "c" -> letter <> rest + _ -> "" + } +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([go/1]). + +-file("project/test/my/mod.gleam", 2). +-spec go(binary()) -> binary(). +go(X) -> + case X of + <<"a"/utf8, Rest/binary>> when <<"a"/utf8>> =:= <<"c"/utf8>> -> + Letter = <<"a"/utf8>>, + <>; + + <<"b"/utf8, Rest/binary>> when <<"b"/utf8>> =:= <<"c"/utf8>> -> + Letter = <<"b"/utf8>>, + <>; + + _ -> + <<""/utf8>> + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__string_prefix_pattern_used_in_guard_assigns_variable_2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__string_prefix_pattern_used_in_guard_assigns_variable_2.snap new file mode 100644 index 000000000..3e017598c --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__string_prefix_pattern_used_in_guard_assigns_variable_2.snap @@ -0,0 +1,35 @@ +--- +source: compiler-core/src/erlang/tests/case.rs +expression: "\npub fn go(x) {\n case x {\n \"a\" as letter <> rest\n | \"b\" as rest <> letter if letter == \"c\" && rest == \"b\" -> letter <> rest\n _ -> \"\"\n }\n}\n" +--- +----- SOURCE CODE + +pub fn go(x) { + case x { + "a" as letter <> rest + | "b" as rest <> letter if letter == "c" && rest == "b" -> letter <> rest + _ -> "" + } +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([go/1]). + +-file("project/test/my/mod.gleam", 2). +-spec go(binary()) -> binary(). +go(X) -> + case X of + <<"a"/utf8, Rest/binary>> when (<<"a"/utf8>> =:= <<"c"/utf8>>) andalso (Rest =:= <<"b"/utf8>>) -> + Letter = <<"a"/utf8>>, + <>; + + <<"b"/utf8, Letter/binary>> when (Letter =:= <<"c"/utf8>>) andalso (<<"b"/utf8>> =:= <<"b"/utf8>>) -> + Rest = <<"b"/utf8>>, + <>; + + _ -> + <<""/utf8>> + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__string_prefix_pattern_used_in_guard_assigns_variable_3.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__string_prefix_pattern_used_in_guard_assigns_variable_3.snap new file mode 100644 index 000000000..105b32383 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__string_prefix_pattern_used_in_guard_assigns_variable_3.snap @@ -0,0 +1,34 @@ +--- +source: compiler-core/src/erlang/tests/case.rs +expression: "\npub fn go(x) {\n case x {\n \"a\" as rest <> _\n | \"b\" <> rest if rest == \"c\" -> Nil\n _ -> Nil\n }\n}\n" +--- +----- SOURCE CODE + +pub fn go(x) { + case x { + "a" as rest <> _ + | "b" <> rest if rest == "c" -> Nil + _ -> Nil + } +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([go/1]). + +-file("project/test/my/mod.gleam", 2). +-spec go(binary()) -> nil. +go(X) -> + case X of + <<"a"/utf8, _/binary>> when <<"a"/utf8>> =:= <<"c"/utf8>> -> + Rest = <<"a"/utf8>>, + nil; + + <<"b"/utf8, Rest/binary>> when Rest =:= <<"c"/utf8>> -> + nil; + + _ -> + nil + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__conditional_compilation__excluded_attribute_syntax.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__conditional_compilation__excluded_attribute_syntax.snap index e5c12f9f5..d13fc123a 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__conditional_compilation__excluded_attribute_syntax.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__conditional_compilation__excluded_attribute_syntax.snap @@ -9,3 +9,4 @@ expression: "@target(javascript)\n pub fn main() { 1 }\n" ----- COMPILED ERLANG -module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__conditional_compilation__included_attribute_syntax.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__conditional_compilation__included_attribute_syntax.snap index 2e841af88..f1a5148a0 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__conditional_compilation__included_attribute_syntax.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__conditional_compilation__included_attribute_syntax.snap @@ -9,8 +9,7 @@ expression: "@target(erlang)\n pub fn main() { 1 }\n" ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__const_generalise.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__const_generalise.snap index db06e8a99..0aea37c61 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__const_generalise.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__const_generalise.snap @@ -17,8 +17,7 @@ pub fn main(){ ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__const_type_variable.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__const_type_variable.snap index 168ae0826..6ea41ba87 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__const_type_variable.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__const_type_variable.snap @@ -13,3 +13,4 @@ const id: fn(a) -> a = identity ----- COMPILED ERLANG -module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__list_prepend.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__list_prepend.snap index 1adb333d7..1515995a0 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__list_prepend.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__list_prepend.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 5). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__list_prepend_from_other_module.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__list_prepend_from_other_module.snap index 00426698c..7e0bd3d5a 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__list_prepend_from_other_module.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__list_prepend_from_other_module.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 6). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__list_prepend_literal.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__list_prepend_literal.snap index 31097e066..dc3c07314 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__list_prepend_literal.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__list_prepend_literal.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__pub_const_equal_to_private_function.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__pub_const_equal_to_private_function.snap index 03de7ffd1..b0cf40afc 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__pub_const_equal_to_private_function.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__pub_const_equal_to_private_function.snap @@ -13,8 +13,7 @@ expression: "\n fn identity(a) {\n a\n }\n\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([identity/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__pub_const_equal_to_record_with_nested_private_function_field.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__pub_const_equal_to_record_with_nested_private_function_field.snap index cae9c30e5..ead7a0006 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__pub_const_equal_to_record_with_nested_private_function_field.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__pub_const_equal_to_record_with_nested_private_function_field.snap @@ -21,8 +21,7 @@ expression: "\n fn identity(a) {\n a\n }\n\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([identity/1]). -export_type([mapper/1, funcs/1]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__pub_const_equal_to_record_with_private_function_field.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__pub_const_equal_to_record_with_private_function_field.snap index 45cc1efee..4311c39e6 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__pub_const_equal_to_record_with_private_function_field.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__pub_const_equal_to_record_with_private_function_field.snap @@ -17,8 +17,7 @@ expression: "\n fn identity(a) {\n a\n }\n\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([identity/1]). -export_type([mapper/1]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__record_constructor.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__record_constructor.snap index b9f22703a..d1e07e571 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__record_constructor.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__record_constructor.snap @@ -16,8 +16,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([x/0]). @@ -26,4 +25,6 @@ pub fn main() { -file("project/test/my/mod.gleam", 8). -spec main() -> fun((integer()) -> x()). main() -> - fun(Field@0) -> {x, Field@0} end. + fun(_value) -> + {x, _value} + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__record_constructor_in_tuple.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__record_constructor_in_tuple.snap index 302113934..0b8cb5ad2 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__record_constructor_in_tuple.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__record_constructor_in_tuple.snap @@ -16,8 +16,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([x/0]). @@ -26,4 +25,6 @@ pub fn main() { -file("project/test/my/mod.gleam", 8). -spec main() -> {fun((integer()) -> x())}. main() -> - {fun(Field@0) -> {x, Field@0} end}. + {fun(_value) -> + {x, _value} + end}. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__string_constant_from_another_module_is_concatenated_correctly.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__string_constant_from_another_module_is_concatenated_correctly.snap new file mode 100644 index 000000000..0f1ee29b4 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__string_constant_from_another_module_is_concatenated_correctly.snap @@ -0,0 +1,22 @@ +--- +source: compiler-core/src/erlang/tests/consts.rs +expression: "\nimport mod\n\npub fn go(x) {\n x <> \"-\" <> mod.wibble\n}\n" +--- +----- SOURCE CODE + +import mod + +pub fn go(x) { + x <> "-" <> mod.wibble +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([go/1]). + +-file("project/test/my/mod.gleam", 4). +-spec go(binary()) -> binary(). +go(X) -> + <<<>/binary, "wibble!"/utf8>>. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__string_constant_from_another_module_is_concatenated_correctly_2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__string_constant_from_another_module_is_concatenated_correctly_2.snap new file mode 100644 index 000000000..5cf72ce58 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__string_constant_from_another_module_is_concatenated_correctly_2.snap @@ -0,0 +1,22 @@ +--- +source: compiler-core/src/erlang/tests/consts.rs +expression: "\nimport mod.{wibble}\n\npub fn go(x) {\n x <> \"-\" <> wibble\n}\n" +--- +----- SOURCE CODE + +import mod.{wibble} + +pub fn go(x) { + x <> "-" <> wibble +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([go/1]). + +-file("project/test/my/mod.gleam", 4). +-spec go(binary()) -> binary(). +go(X) -> + <<<>/binary, "wibble!"/utf8>>. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_private_in_internal.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_private_in_internal.snap index c6851a9cd..5a9bb1755 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_private_in_internal.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_private_in_internal.snap @@ -18,8 +18,7 @@ expression: "\n fn identity(a) {\n a\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([identity/1]). -export_type([mapper/1]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_private_in_list.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_private_in_list.snap index cbfc974c2..965ba4427 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_private_in_list.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_private_in_list.snap @@ -13,8 +13,7 @@ expression: "\n fn identity(a) {\n a\n }\n\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([identity/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_private_in_tuple.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_private_in_tuple.snap index 5b02e17f4..5a802ad19 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_private_in_tuple.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_private_in_tuple.snap @@ -13,8 +13,7 @@ expression: "\n fn identity(a) {\n a\n }\n\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([identity/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_qualified_pub_const_equal_to_record_with_private_function_field.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_qualified_pub_const_equal_to_record_with_private_function_field.snap index fc2ddd358..70304c6f8 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_qualified_pub_const_equal_to_record_with_private_function_field.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_qualified_pub_const_equal_to_record_with_private_function_field.snap @@ -17,8 +17,7 @@ expression: "\n fn identity(a) {\n a\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([identity/1]). -export_type([mapper/1]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_unqualified_pub_const_equal_to_private_function.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_unqualified_pub_const_equal_to_private_function.snap index 30504ba75..3e22da07f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_unqualified_pub_const_equal_to_private_function.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_unqualified_pub_const_equal_to_private_function.snap @@ -13,8 +13,7 @@ expression: "\n fn identity(a) {\n a\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([identity/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_unqualified_pub_const_equal_to_record_with_private_function_field.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_unqualified_pub_const_equal_to_record_with_private_function_field.snap index fc2ddd358..70304c6f8 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_unqualified_pub_const_equal_to_record_with_private_function_field.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__consts__use_unqualified_pub_const_equal_to_record_with_private_function_field.snap @@ -17,8 +17,7 @@ expression: "\n fn identity(a) {\n a\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([identity/1]). -export_type([mapper/1]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__annotated_external_type.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__annotated_external_type.snap index 21114fc7f..39837cb87 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__annotated_external_type.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__annotated_external_type.snap @@ -10,8 +10,7 @@ pub type Dict(key, value) ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([dict/2]). -type dict(I, J) :: gleam_stdlib:dict(I, J). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__annotated_external_type_used_in_function.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__annotated_external_type_used_in_function.snap index ff0987f96..1415223b5 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__annotated_external_type_used_in_function.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__annotated_external_type_used_in_function.snap @@ -13,8 +13,7 @@ pub fn get(dict: Dict(key, value), key: key) -> Result(value, Nil) ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([get/2]). -export_type([dict/2]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__phantom.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__phantom.snap index d3d3ee63b..ba351b611 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__phantom.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__phantom.snap @@ -7,8 +7,7 @@ pub type Map(k, v) ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([map_/2]). -type map_(I, J) :: any() | {gleam_phantom, I, J}. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__unused_opaque_constructor_is_generated_correctly.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__unused_opaque_constructor_is_generated_correctly.snap index 1220d9a63..9445cb938 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__unused_opaque_constructor_is_generated_correctly.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__custom_types__unused_opaque_constructor_is_generated_correctly.snap @@ -15,8 +15,7 @@ pub opaque type Wobble { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([wibble/0, wobble/0]). -type wibble() :: wibble. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__backslashes_are_escaped_in_module_comment.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__backslashes_are_escaped_in_module_comment.snap index c5e751881..ae08f2c43 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__backslashes_are_escaped_in_module_comment.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__backslashes_are_escaped_in_module_comment.snap @@ -10,19 +10,9 @@ pub fn main() { 1 } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC(" \\backslashes!\\\n"). +-moduledoc(<<" \\backslashes!\\"/utf8>>). -file("project/test/my/mod.gleam", 4). -spec main() -> integer(). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__backslashes_in_documentation_are_escaped.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__backslashes_in_documentation_are_escaped.snap index 9ad202f3d..d4a2c5e43 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__backslashes_in_documentation_are_escaped.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__backslashes_in_documentation_are_escaped.snap @@ -9,20 +9,11 @@ pub fn documented() { 1 } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([documented/0]). --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -file("project/test/my/mod.gleam", 3). -?DOC(" \\hello\\\n"). -spec documented() -> integer(). +-doc(<<" \\hello\\"/utf8>>). documented() -> 1. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__double_quotes_are_escaped_in_module_comment.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__double_quotes_are_escaped_in_module_comment.snap index 55d52fe77..ab09ec1dd 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__double_quotes_are_escaped_in_module_comment.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__double_quotes_are_escaped_in_module_comment.snap @@ -10,19 +10,9 @@ pub fn main() { 1 } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC(" \"quotes!\"\n"). +-moduledoc(<<" \"quotes!\""/utf8>>). -file("project/test/my/mod.gleam", 4). -spec main() -> integer(). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__function_with_documentation.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__function_with_documentation.snap index c19653091..2efe3b795 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__function_with_documentation.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__function_with_documentation.snap @@ -9,20 +9,11 @@ pub fn documented() { 1 } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([documented/0]). --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -file("project/test/my/mod.gleam", 3). -?DOC(" Function doc!\n"). -spec documented() -> integer(). +-doc(<<" Function doc!"/utf8>>). documented() -> 1. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__function_with_multiline_documentation.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__function_with_multiline_documentation.snap index 340fb963c..36e794014 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__function_with_multiline_documentation.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__function_with_multiline_documentation.snap @@ -11,23 +11,13 @@ pub fn documented() { 1 } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([documented/0]). --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -file("project/test/my/mod.gleam", 5). -?DOC( - " Function doc!\n" - " Hello!!\n" -). -spec documented() -> integer(). +-doc(<<" Function doc! + Hello!! +"/utf8>>). documented() -> 1. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__internal_function_has_no_documentation.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__internal_function_has_no_documentation.snap index 5e34e6b53..69d6dd82a 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__internal_function_has_no_documentation.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__internal_function_has_no_documentation.snap @@ -10,20 +10,11 @@ pub fn main() { 1 } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -file("project/test/my/mod.gleam", 4). -?DOC(false). -spec main() -> integer(). +-doc(false). main() -> 1. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__multi_line_module_comment.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__multi_line_module_comment.snap index a9a445cad..9ca577539 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__multi_line_module_comment.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__multi_line_module_comment.snap @@ -12,23 +12,11 @@ pub fn main() { 1 } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " Hello! This is a multi-\n" - " line module comment.\n" - "\n" -). +-moduledoc(<<" Hello! This is a multi- + line module comment. +"/utf8>>). -file("project/test/my/mod.gleam", 6). -spec main() -> integer(). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__quotes_in_documentation_are_escaped.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__quotes_in_documentation_are_escaped.snap index e36892b3f..0f172b626 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__quotes_in_documentation_are_escaped.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__quotes_in_documentation_are_escaped.snap @@ -9,20 +9,11 @@ pub fn documented() { 1 } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([documented/0]). --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -file("project/test/my/mod.gleam", 3). -?DOC(" \"hello\"\n"). -spec documented() -> integer(). +-doc(<<" \"hello\""/utf8>>). documented() -> 1. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__single_line_module_comment.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__single_line_module_comment.snap index d71b8c365..0be89667e 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__single_line_module_comment.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__documentation__single_line_module_comment.snap @@ -10,19 +10,9 @@ pub fn main() { 1 } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC(" Hello! This is a single line module comment.\n"). +-moduledoc(<<" Hello! This is a single line module comment."/utf8>>). -file("project/test/my/mod.gleam", 4). -spec main() -> integer(). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_in_a_pipeline.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_in_a_pipeline.snap index c1c52b533..abbbf8ec6 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_in_a_pipeline.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_in_a_pipeline.snap @@ -15,8 +15,7 @@ pub fn wibble(n) { n } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([wibble/1, main/0]). -file("project/test/my/mod.gleam", 8). @@ -28,7 +27,7 @@ wibble(N) -> -spec main() -> list(integer()). main() -> _pipe = [1, 2, 3], - echo(_pipe, nil, 4), - wibble(_pipe). + _pipe@1 = echo(_pipe, nil, <<"project/test/my/mod.gleam"/utf8>>, 4), + wibble(_pipe@1). % ...omitted code from `templates/echo.erl`... diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_in_a_pipeline_with_message.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_in_a_pipeline_with_message.snap index 2e2ae7c10..2839b84b9 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_in_a_pipeline_with_message.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_in_a_pipeline_with_message.snap @@ -15,8 +15,7 @@ pub fn wibble(n) { n } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([wibble/1, main/0]). -file("project/test/my/mod.gleam", 8). @@ -28,7 +27,7 @@ wibble(N) -> -spec main() -> list(integer()). main() -> _pipe = [1, 2, 3], - echo(_pipe, <<"message!!"/utf8>>, 4), - wibble(_pipe). + _pipe@1 = echo(_pipe, <<"message!!"/utf8>>, <<"project/test/my/mod.gleam"/utf8>>, 4), + wibble(_pipe@1). % ...omitted code from `templates/echo.erl`... diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_block.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_block.snap index 445c404a8..77d9ab524 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_block.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_block.snap @@ -14,20 +14,15 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). main() -> - echo( - begin - nil, - 1 - end, + echo(begin nil, - 3 - ). + 1 + end, nil, <<"project/test/my/mod.gleam"/utf8>>, 3). % ...omitted code from `templates/echo.erl`... diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_case_expression.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_case_expression.snap index d5592a1a3..84cb8ce6f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_case_expression.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_case_expression.snap @@ -13,16 +13,15 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). main() -> echo(case 1 of - _ -> - 2 - end, nil, 3). + _ -> + 2 + end, nil, <<"project/test/my/mod.gleam"/utf8>>, 3). % ...omitted code from `templates/echo.erl`... diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_function_call.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_function_call.snap index 5da6367b8..30a98929c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_function_call.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_function_call.snap @@ -13,8 +13,7 @@ fn wibble(n: Int, m: Int) { n + m } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 6). @@ -25,6 +24,6 @@ wibble(N, M) -> -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). main() -> - echo(wibble(1, 2), nil, 3). + echo(wibble(1, 2), nil, <<"project/test/my/mod.gleam"/utf8>>, 3). % ...omitted code from `templates/echo.erl`... diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_function_call_and_a_message.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_function_call_and_a_message.snap index ae73b2a31..42ad77f20 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_function_call_and_a_message.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_function_call_and_a_message.snap @@ -14,8 +14,7 @@ fn message() { "Hello!" } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 7). @@ -31,6 +30,6 @@ wibble(N, M) -> -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). main() -> - echo(wibble(1, 2), message(), 3). + echo(wibble(1, 2), message(), <<"project/test/my/mod.gleam"/utf8>>, 3). % ...omitted code from `templates/echo.erl`... diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_panic.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_panic.snap index c00b14b90..445546b9d 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_panic.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_panic.snap @@ -11,18 +11,19 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> any(). main() -> - echo(erlang:error(#{gleam_error => panic, - message => <<"`panic` expression evaluated."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3}), nil, 3). + echo(erlang:error(#{ + gleam_error => panic, + message => <<"`panic` expression evaluated."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3 + }), nil, <<"project/test/my/mod.gleam"/utf8>>, 3). % ...omitted code from `templates/echo.erl`... diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_simple_expression.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_simple_expression.snap index a100b194b..c4deb90a8 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_simple_expression.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_simple_expression.snap @@ -11,13 +11,12 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). main() -> - echo(1, nil, 3). + echo(1, nil, <<"project/test/my/mod.gleam"/utf8>>, 3). % ...omitted code from `templates/echo.erl`... diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_simple_expression_and_a_message.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_simple_expression_and_a_message.snap index 1300b95b4..7aed52a90 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_simple_expression_and_a_message.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_a_simple_expression_and_a_message.snap @@ -11,13 +11,12 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). main() -> - echo(1, <<"hello!"/utf8>>, 3). + echo(1, <<"hello!"/utf8>>, <<"project/test/my/mod.gleam"/utf8>>, 3). % ...omitted code from `templates/echo.erl`... diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_complex_expression_as_a_message.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_complex_expression_as_a_message.snap index 8d7193734..8d468968b 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_complex_expression_as_a_message.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__echo_with_complex_expression_as_a_message.snap @@ -16,8 +16,7 @@ fn name() { "Giacomo" } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 9). @@ -29,11 +28,11 @@ name() -> -spec main() -> integer(). main() -> echo(1, case name() of - <<"Giacomo"/utf8>> -> - <<"hello Jak!"/utf8>>; + <<"Giacomo"/utf8>> -> + <<"hello Jak!"/utf8>>; - _ -> - <<"hello!"/utf8>> - end, 3). + _ -> + <<"hello!"/utf8>> + end, <<"project/test/my/mod.gleam"/utf8>>, 3). % ...omitted code from `templates/echo.erl`... diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__multiple_echos_in_a_pipeline.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__multiple_echos_in_a_pipeline.snap index 7484b7432..ad3828c40 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__multiple_echos_in_a_pipeline.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__multiple_echos_in_a_pipeline.snap @@ -18,8 +18,7 @@ pub fn wibble(n) { n } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([wibble/1, main/0]). -file("project/test/my/mod.gleam", 11). @@ -31,10 +30,10 @@ wibble(N) -> -spec main() -> list(integer()). main() -> _pipe = [1, 2, 3], - echo(_pipe, nil, 4), - _pipe@1 = wibble(_pipe), - echo(_pipe@1, nil, 6), + _pipe@1 = echo(_pipe, nil, <<"project/test/my/mod.gleam"/utf8>>, 4), _pipe@2 = wibble(_pipe@1), - echo(_pipe@2, nil, 8). + _pipe@3 = echo(_pipe@2, nil, <<"project/test/my/mod.gleam"/utf8>>, 6), + _pipe@4 = wibble(_pipe@3), + echo(_pipe@4, nil, <<"project/test/my/mod.gleam"/utf8>>, 8). % ...omitted code from `templates/echo.erl`... diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__multiple_echos_inside_expression.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__multiple_echos_inside_expression.snap index 9823bc715..ccaa0d31a 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__multiple_echos_inside_expression.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__multiple_echos_inside_expression.snap @@ -12,14 +12,13 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). main() -> - echo(1, nil, 3), - echo(2, nil, 4). + echo(1, nil, <<"project/test/my/mod.gleam"/utf8>>, 3), + echo(2, nil, <<"project/test/my/mod.gleam"/utf8>>, 4). % ...omitted code from `templates/echo.erl`... diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__pipeline_printed_by_echo_is_wrapped_in_begin_end_block.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__pipeline_printed_by_echo_is_wrapped_in_begin_end_block.snap index b4eecd593..302c134a7 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__pipeline_printed_by_echo_is_wrapped_in_begin_end_block.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__pipeline_printed_by_echo_is_wrapped_in_begin_end_block.snap @@ -16,8 +16,7 @@ pub fn wibble(n) { n } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([wibble/1, main/0]). -file("project/test/my/mod.gleam", 9). @@ -28,14 +27,10 @@ wibble(N) -> -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). main() -> - echo( - begin - _pipe = 123, - _pipe@1 = wibble(_pipe), - wibble(_pipe@1) - end, - nil, - 3 - ). + echo(begin + _pipe = 123, + _pipe@1 = wibble(_pipe), + wibble(_pipe@1) + end, nil, <<"project/test/my/mod.gleam"/utf8>>, 3). % ...omitted code from `templates/echo.erl`... diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__record_update_printed_by_echo_is_wrapped_in_begin_end_block.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__record_update_printed_by_echo_is_wrapped_in_begin_end_block.snap index 7220ef012..ad6d060f3 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__record_update_printed_by_echo_is_wrapped_in_begin_end_block.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__echo__record_update_printed_by_echo_is_wrapped_in_begin_end_block.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([wobble/0]). @@ -25,6 +24,6 @@ pub fn main() { -spec main() -> wobble(). main() -> Wobble = {wobble, 1, <<"wobble"/utf8>>}, - echo({wobble, 1, erlang:element(3, Wobble)}, nil, 6). + echo({wobble, 1, erlang:element(3, Wobble)}, nil, <<"project/test/my/mod.gleam"/utf8>>, 6). % ...omitted code from `templates/echo.erl`... diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__attribute_erlang.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__attribute_erlang.snap index 80a5e4c8d..74695c3d2 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__attribute_erlang.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__attribute_erlang.snap @@ -12,8 +12,7 @@ pub fn one(x: Int) -> Int { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([one/1]). -file("project/test/my/mod.gleam", 3). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__attribute_javascript.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__attribute_javascript.snap index 47c3e24bc..b814b54de 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__attribute_javascript.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__attribute_javascript.snap @@ -12,16 +12,17 @@ pub fn one(x: Int) -> Int { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([one/1]). -file("project/test/my/mod.gleam", 3). -spec one(integer()) -> integer(). one(X) -> - erlang:error(#{gleam_error => todo, - message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"one"/utf8>>, - line => 4}). + erlang:error(#{ + gleam_error => todo, + message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"one"/utf8>>, + line => 4 + }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__both_externals_no_valid_impl.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__both_externals_no_valid_impl.snap index 3b89d41e6..cc36d3967 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__both_externals_no_valid_impl.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__both_externals_no_valid_impl.snap @@ -18,8 +18,7 @@ pub fn should_not_be_generated() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([erl/0]). -file("project/test/my/mod.gleam", 6). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__discarded_arg_in_external_are_passed_correctly.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__discarded_arg_in_external_are_passed_correctly.snap index 00ec32aac..e286a4d92 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__discarded_arg_in_external_are_passed_correctly.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__discarded_arg_in_external_are_passed_correctly.snap @@ -10,8 +10,7 @@ pub fn woo(_a: a) -> Nil ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([woo/1]). -file("project/test/my/mod.gleam", 3). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__elixir.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__elixir.snap index 572c8da27..4e6b3c6db 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__elixir.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__elixir.snap @@ -14,8 +14,7 @@ fn do() -> Int ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__erlang_and_javascript.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__erlang_and_javascript.snap index ed9f85d7b..b57f36020 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__erlang_and_javascript.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__erlang_and_javascript.snap @@ -13,8 +13,7 @@ pub fn one(x: Int) -> Int { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([one/1]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__inlining_external_functions_from_another_module.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__inlining_external_functions_from_another_module.snap index a4202220f..3f7ba93f5 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__inlining_external_functions_from_another_module.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__inlining_external_functions_from_another_module.snap @@ -11,8 +11,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__integration_test1_3.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__integration_test1_3.snap index af8ca93a8..dbfec4b31 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__integration_test1_3.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__integration_test1_3.snap @@ -10,8 +10,7 @@ pub fn run() -> Int ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([run/0]). -file("project/test/my/mod.gleam", 3). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__integration_test7.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__integration_test7.snap index 44e0c3187..c177ff5e2 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__integration_test7.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__integration_test7.snap @@ -11,8 +11,7 @@ pub fn catch(x) { receive() } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export(['receive'/0, 'catch'/1]). -file("project/test/my/mod.gleam", 3). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__javascript_only.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__javascript_only.snap index c7b465e7f..775168135 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__javascript_only.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__javascript_only.snap @@ -14,8 +14,7 @@ pub fn should_not_be_generated(x: Int) -> Int ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([should_be_generated/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__javascript_only_indirect.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__javascript_only_indirect.snap index 6388a9131..7baf4da63 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__javascript_only_indirect.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__javascript_only_indirect.snap @@ -19,8 +19,7 @@ pub fn also_should_not_be_generated() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([should_be_generated/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__multiple_discarded_args_in_external_are_passed_correctly.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__multiple_discarded_args_in_external_are_passed_correctly.snap index a18eb2bf7..b276b8bb3 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__multiple_discarded_args_in_external_are_passed_correctly.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__multiple_discarded_args_in_external_are_passed_correctly.snap @@ -10,11 +10,10 @@ pub fn woo(_: a, _: b) -> Nil ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([woo/2]). -file("project/test/my/mod.gleam", 3). -spec woo(any(), any()) -> nil. -woo(Argument, Argument@1) -> - wibble:wobble(Argument, Argument@1). +woo(_value, _value@1) -> + wibble:wobble(_value, _value@1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__multiple_discarded_args_in_external_are_passed_correctly_2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__multiple_discarded_args_in_external_are_passed_correctly_2.snap index 959006c7b..54edddff3 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__multiple_discarded_args_in_external_are_passed_correctly_2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__multiple_discarded_args_in_external_are_passed_correctly_2.snap @@ -10,11 +10,10 @@ pub fn woo(__: a, _two: b) -> Nil ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([woo/2]). -file("project/test/my/mod.gleam", 3). -spec woo(any(), any()) -> nil. -woo(Argument, _two) -> - wibble:wobble(Argument, _two). +woo(_value, _two) -> + wibble:wobble(_value, _two). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__no_body.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__no_body.snap index 71c4f964c..eb4766cb2 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__no_body.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__no_body.snap @@ -10,8 +10,7 @@ pub fn one(x: Int) -> Int ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([one/1]). -file("project/test/my/mod.gleam", 3). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__private.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__private.snap index 9eca4b97d..0bbe21552 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__private.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__private.snap @@ -14,8 +14,7 @@ fn do() -> Int ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__private_external_function_calls.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__private_external_function_calls.snap index 035993062..1212ecd07 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__private_external_function_calls.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__private_external_function_calls.snap @@ -11,8 +11,7 @@ pub fn x() { go(x: 1, y: 2) go(y: 3, x: 4) } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([x/0]). -file("project/test/my/mod.gleam", 5). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__private_local_function_references.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__private_local_function_references.snap index 3b62a3a42..27a8f65c9 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__private_local_function_references.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__private_local_function_references.snap @@ -11,8 +11,7 @@ pub fn x() { go } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([x/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__public_elixir.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__public_elixir.snap index e41baf63e..403688353 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__public_elixir.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__public_elixir.snap @@ -10,8 +10,7 @@ pub fn do() -> Int ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([do/0]). -file("project/test/my/mod.gleam", 3). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__public_local_function_calls.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__public_local_function_calls.snap index cb4fb001a..06a7282f5 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__public_local_function_calls.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__public_local_function_calls.snap @@ -11,8 +11,7 @@ pub fn x() { go(x: 1, y: 2) go(y: 3, x: 4) } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/2, x/0]). -file("project/test/my/mod.gleam", 3). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__reference_to_imported_elixir_external_fn.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__reference_to_imported_elixir_external_fn.snap index cb9038f2e..cd7d4d4e4 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__reference_to_imported_elixir_external_fn.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__reference_to_imported_elixir_external_fn.snap @@ -13,8 +13,7 @@ fn id(x) { x } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 6). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__unqualified_inlining_external_functions_from_another_module.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__unqualified_inlining_external_functions_from_another_module.snap index 43cd0f022..265235c56 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__unqualified_inlining_external_functions_from_another_module.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__unqualified_inlining_external_functions_from_another_module.snap @@ -11,8 +11,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__unqualified_reference_to_imported_elixir_external_fn.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__unqualified_reference_to_imported_elixir_external_fn.snap index 36aefbc6a..690f74259 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__unqualified_reference_to_imported_elixir_external_fn.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__external_fn__unqualified_reference_to_imported_elixir_external_fn.snap @@ -13,8 +13,7 @@ fn id(x) { x } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 6). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__anonymous_function.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__anonymous_function.snap new file mode 100644 index 000000000..2544e3a25 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__anonymous_function.snap @@ -0,0 +1,22 @@ +--- +source: compiler-core/src/erlang/tests/functions.rs +expression: "\npub fn main() {\n fn(wibble) { 1 }\n}\n" +--- +----- SOURCE CODE + +pub fn main() { + fn(wibble) { 1 } +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/0]). + +-file("project/test/my/mod.gleam", 2). +-spec main() -> fun((any()) -> integer()). +main() -> + fun(Wibble) -> + 1 + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__anonymous_function_with_shadowing.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__anonymous_function_with_shadowing.snap new file mode 100644 index 000000000..53d3aea20 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__anonymous_function_with_shadowing.snap @@ -0,0 +1,24 @@ +--- +source: compiler-core/src/erlang/tests/functions.rs +expression: "\npub fn main() {\n let wibble = 1\n fn(wibble) { 1 }\n}\n" +--- +----- SOURCE CODE + +pub fn main() { + let wibble = 1 + fn(wibble) { 1 } +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/0]). + +-file("project/test/my/mod.gleam", 2). +-spec main() -> fun((any()) -> integer()). +main() -> + Wibble = 1, + fun(Wibble@1) -> + 1 + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__function_as_value.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__function_as_value.snap index b6f699a56..a6e6396e7 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__function_as_value.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__function_as_value.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__function_called.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__function_called.snap index de86b396a..baedc2596 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__function_called.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__function_called.snap @@ -11,8 +11,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__labelled_argument_ordering.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__labelled_argument_ordering.snap index 0db815a42..56d47db43 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__labelled_argument_ordering.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__labelled_argument_ordering.snap @@ -27,8 +27,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([a/0, b/0, c/0, d/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_aliased_imported_function_as_value.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_aliased_imported_function_as_value.snap index 802ae79ad..c97739035 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_aliased_imported_function_as_value.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_aliased_imported_function_as_value.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_aliased_imported_function_called.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_aliased_imported_function_called.snap index 3cda5bf95..195171f67 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_aliased_imported_function_called.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_aliased_imported_function_called.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_anonymous_functions.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_anonymous_functions.snap new file mode 100644 index 000000000..04b34e5c2 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_anonymous_functions.snap @@ -0,0 +1,28 @@ +--- +source: compiler-core/src/erlang/tests/functions.rs +expression: "\npub fn main() {\n fn(wibble) {\n fn(wobble) {\n wibble + wobble\n }\n }\n}\n" +--- +----- SOURCE CODE + +pub fn main() { + fn(wibble) { + fn(wobble) { + wibble + wobble + } + } +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/0]). + +-file("project/test/my/mod.gleam", 2). +-spec main() -> fun((integer()) -> fun((integer()) -> integer())). +main() -> + fun(Wibble) -> + fun(Wobble) -> + Wibble + Wobble + end + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_imported_function_as_value.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_imported_function_as_value.snap index a395016a1..e24e93468 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_imported_function_as_value.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_imported_function_as_value.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_imported_function_called.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_imported_function_called.snap index 494afb80b..c8fe8739a 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_imported_function_called.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_imported_function_called.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_unqualified_imported_function_as_value.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_unqualified_imported_function_as_value.snap index 28f8a95c1..032718301 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_unqualified_imported_function_as_value.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_unqualified_imported_function_as_value.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_unqualified_imported_function_called.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_unqualified_imported_function_called.snap index ff39bde5f..e16884f9f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_unqualified_imported_function_called.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__nested_unqualified_imported_function_called.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__unused_private_functions.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__unused_private_functions.snap index e34da2027..8b3d31d4f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__unused_private_functions.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__functions__unused_private_functions.snap @@ -27,8 +27,7 @@ fn unused3() -> Int { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 6). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__aliased_discard_pattern_in_bit_array_later_used_in_guard.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__aliased_discard_pattern_in_bit_array_later_used_in_guard.snap new file mode 100644 index 000000000..0636d80ad --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__aliased_discard_pattern_in_bit_array_later_used_in_guard.snap @@ -0,0 +1,28 @@ +--- +source: compiler-core/src/erlang/tests/guards.rs +expression: "\npub fn main(x) {\n case x {\n <<_ as b>> if b == 1 -> b + 2\n _ -> 0\n }\n}" +--- +----- SOURCE CODE + +pub fn main(x) { + case x { + <<_ as b>> if b == 1 -> b + 2 + _ -> 0 + } +} + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/1]). + +-file("project/test/my/mod.gleam", 2). +-spec main(bitstring()) -> integer(). +main(X) -> + case X of + <> when B =:= 1 -> + B + 2; + + _ -> + 0 + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__aliased_discard_pattern_in_bit_array_later_used_in_guard_2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__aliased_discard_pattern_in_bit_array_later_used_in_guard_2.snap new file mode 100644 index 000000000..2ec2ccc8a --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__aliased_discard_pattern_in_bit_array_later_used_in_guard_2.snap @@ -0,0 +1,35 @@ +--- +source: compiler-core/src/erlang/tests/guards.rs +expression: "\npub fn main(x) {\n case x {\n <<_ as b>> | <<1 as b>> | <> if b == 1 -> b + 2\n _ -> 0\n }\n}" +--- +----- SOURCE CODE + +pub fn main(x) { + case x { + <<_ as b>> | <<1 as b>> | <> if b == 1 -> b + 2 + _ -> 0 + } +} + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/1]). + +-file("project/test/my/mod.gleam", 2). +-spec main(bitstring()) -> integer(). +main(X) -> + case X of + <> when B =:= 1 -> + B + 2; + + <<1>> when 1 =:= 1 -> + B = 1, + B + 2; + + <> when B =:= 1 -> + B + 2; + + _ -> + 0 + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards.snap index 452e21f63..27b907ee3 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards.snap @@ -14,8 +14,7 @@ pub fn main(args) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards20.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards20.snap index 7428e16bb..d4b01a7a8 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards20.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards20.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards21.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards21.snap index 69e252c8e..8c9f3c5f3 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards21.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards21.snap @@ -14,8 +14,7 @@ pub fn main(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards22.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards22.snap index 51035bb03..13569385f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards22.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards22.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards23.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards23.snap index e40990aba..354d87674 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards23.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards23.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards24.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards24.snap index 8b7538fba..19a494f6e 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards24.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards24.snap @@ -16,8 +16,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards25.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards25.snap index 31a66868d..37f80000c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards25.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards25.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards26.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards26.snap index dc38652fd..512da02fd 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards26.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards26.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards27.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards27.snap index 8daf6e476..498f5d662 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards27.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards27.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards28.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards28.snap index 8bde0cb20..fe9e217fb 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards28.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards28.snap @@ -18,8 +18,7 @@ expression: "\n type Test { Test(x: Int, y: Float) }\n pub fn main() {\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([test/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards29.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards29.snap index b9aa69895..e54a0f28c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards29.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards29.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards30.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards30.snap index 1f3894c61..1e1886e4a 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards30.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards30.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards31.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards31.snap index d3307af8d..fee63328b 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards31.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards31.snap @@ -14,8 +14,7 @@ pub fn main(args) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards32.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards32.snap index 0f8c2942e..8eee517a1 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards32.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards32.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_1.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_1.snap index c7ed30d9b..eb1e8ad4c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_1.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_1.snap @@ -14,8 +14,7 @@ pub fn main(args) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_10.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_10.snap index a13ab7b85..83ba2f95d 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_10.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_10.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_2.snap index 6a2b7febb..ad1e0e021 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_2.snap @@ -14,8 +14,7 @@ pub fn main(args) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_3.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_3.snap index 6a1a3cf1a..6361a2d0e 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_3.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_3.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_4.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_4.snap index f7167920c..ebcc39fab 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_4.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_4.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_5.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_5.snap index 92f2e812e..490d9a2a5 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_5.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_5.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_6.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_6.snap index 64e2229eb..410baa383 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_6.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_6.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_7.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_7.snap index 83a7932eb..8741321ab 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_7.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_7.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_8.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_8.snap index 23a1519ca..f8aef6241 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_8.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_8.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_9.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_9.snap index 9d12459af..b2cfc2552 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_9.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__clause_guards_9.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__constants_in_guards.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__constants_in_guards.snap index 44b3d4063..96903ebbb 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__constants_in_guards.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__constants_in_guards.snap @@ -21,8 +21,7 @@ pub fn main(arg) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 8). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__constants_in_guards1.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__constants_in_guards1.snap index 2321d125d..56abecd70 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__constants_in_guards1.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__constants_in_guards1.snap @@ -16,8 +16,7 @@ pub fn main(arg) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__field_access.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__field_access.snap index ae14fa52c..79b3989d6 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__field_access.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__field_access.snap @@ -1,17 +1,17 @@ --- source: compiler-core/src/erlang/tests/guards.rs -expression: "\n pub type Person {\n Person(username: String, name: String, age: Int)\n }\n \n pub fn main() {\n let given_name = \"jack\"\n let raiden = Person(\"raiden\", \"jack\", 31)\n \n case given_name {\n name if name == raiden.name -> \"It's jack\"\n _ -> \"It's not jack\"\n }\n }\n " +expression: "\n pub type Person {\n Person(username: String, name: String, age: Int)\n }\n\n pub fn main() {\n let given_name = \"jack\"\n let raiden = Person(\"raiden\", \"jack\", 31)\n\n case given_name {\n name if name == raiden.name -> \"It's jack\"\n _ -> \"It's not jack\"\n }\n }\n " --- ----- SOURCE CODE pub type Person { Person(username: String, name: String, age: Int) } - + pub fn main() { let given_name = "jack" let raiden = Person("raiden", "jack", 31) - + case given_name { name if name == raiden.name -> "It's jack" _ -> "It's not jack" @@ -21,8 +21,7 @@ expression: "\n pub type Person {\n Person(username: String, nam ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([person/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_access.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_access.snap index 0db005425..a880ea6de 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_access.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_access.snap @@ -16,8 +16,7 @@ expression: "\n import hero\n pub fn main() {\n let ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 3). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_list_access.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_list_access.snap index 30612a8e6..25fc10eea 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_list_access.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_list_access.snap @@ -16,8 +16,7 @@ expression: "\n import hero\n pub fn main() {\n let ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 3). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_nested_access.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_nested_access.snap index d1deec6e5..5dd94a80e 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_nested_access.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_nested_access.snap @@ -16,8 +16,7 @@ expression: "\n import hero\n pub fn main() {\n let ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 3). @@ -25,10 +24,7 @@ expression: "\n import hero\n pub fn main() {\n let main() -> Name = <<"Bruce Wayne"/utf8>>, case Name of - N when N =:= erlang:element( - 2, - erlang:element(2, {hero, {person, <<"Bruce Wayne"/utf8>>}}) - ) -> + N when N =:= erlang:element(2, erlang:element(2, {hero, {person, <<"Bruce Wayne"/utf8>>}})) -> true; _ -> diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_string_access.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_string_access.snap index afeddb32b..c24d899e7 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_string_access.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_string_access.snap @@ -16,8 +16,7 @@ expression: "\n import hero\n pub fn main() {\n let ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 3). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_tuple_access.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_tuple_access.snap index e5540ef3d..8b2d4c4f1 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_tuple_access.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__module_tuple_access.snap @@ -16,8 +16,7 @@ expression: "\n import hero\n pub fn main() {\n let ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 3). @@ -25,10 +24,7 @@ expression: "\n import hero\n pub fn main() {\n let main() -> Name = <<"Tony Stark"/utf8>>, case Name of - N when N =:= erlang:element( - 2, - {<<"ironman"/utf8>>, <<"Tony Stark"/utf8>>} - ) -> + N when N =:= erlang:element(2, {<<"ironman"/utf8>>, <<"Tony Stark"/utf8>>}) -> true; _ -> diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__nested_record_access.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__nested_record_access.snap index a273ae972..deb2c7ec5 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__nested_record_access.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__nested_record_access.snap @@ -26,8 +26,7 @@ pub fn a(a: A) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([a/1]). -export_type([a/0, b/0, c/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards.snap index c0ba8463a..7aacac6c3 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards.snap @@ -16,8 +16,7 @@ pub fn main(arg) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards1.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards1.snap index b0a3b5f22..6968e6f47 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards1.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards1.snap @@ -16,8 +16,7 @@ pub fn main(arg) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards2.snap index 1c8bdc701..a3b262462 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards2.snap @@ -16,8 +16,7 @@ pub fn main(arg) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards3.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards3.snap index 9a27c705e..038fce949 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards3.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__guards__only_guards3.snap @@ -16,8 +16,7 @@ pub fn main(arg) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__blocks_get_preserved_when_needed.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__blocks_get_preserved_when_needed.snap index 13255b8e3..f6fa04c5b 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__blocks_get_preserved_when_needed.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__blocks_get_preserved_when_needed.snap @@ -15,14 +15,15 @@ fn make_adder(a) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 6). -spec make_adder(integer()) -> fun((integer()) -> integer()). make_adder(A) -> - fun(B) -> A + B end. + fun(B) -> + A + B + end. -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__blocks_get_preserved_when_needed2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__blocks_get_preserved_when_needed2.snap index 02cc52591..d69678836 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__blocks_get_preserved_when_needed2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__blocks_get_preserved_when_needed2.snap @@ -11,8 +11,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__do_not_inline_parameters_used_more_than_once.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__do_not_inline_parameters_used_more_than_once.snap index 0ab2a00e4..8019361fe 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__do_not_inline_parameters_used_more_than_once.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__do_not_inline_parameters_used_more_than_once.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_anonymous_function_call.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_anonymous_function_call.snap index 02d071835..144f4e6f8 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_anonymous_function_call.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_anonymous_function_call.snap @@ -11,8 +11,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_capture_in_pipe.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_capture_in_pipe.snap index 98ef123b1..de2f5d20a 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_capture_in_pipe.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_capture_in_pipe.snap @@ -13,8 +13,7 @@ fn add(a, b) { a + b } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 6). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_which_calls_other_function.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_which_calls_other_function.snap index faefeb3e6..9925d41bc 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_which_calls_other_function.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_which_calls_other_function.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_with_use.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_with_use.snap index 7921c47ef..fd07fc207 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_with_use.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_with_use.snap @@ -14,8 +14,7 @@ pub fn divide(a, b) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([divide/2]). -file("project/test/my/mod.gleam", 4). @@ -27,7 +26,10 @@ divide(A, B) -> false -> case B of - 0 -> 0; - Gleam@denominator -> A div Gleam@denominator + 0 -> + 0; + + _value -> + A div _value end end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_with_use_and_anonymous.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_with_use_and_anonymous.snap index 77d319a4b..52ae24034 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_with_use_and_anonymous.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_with_use_and_anonymous.snap @@ -14,8 +14,7 @@ pub fn divide(a, b) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([divide/2]). -file("project/test/my/mod.gleam", 4). @@ -23,16 +22,21 @@ pub fn divide(a, b) { divide(A, B) -> case B =:= 0 of true -> - erlang:error(#{gleam_error => panic, - message => <<"Cannot divide by 0"/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"divide"/utf8>>, - line => 5}); + erlang:error(#{ + gleam_error => panic, + message => <<"Cannot divide by 0"/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"divide"/utf8>>, + line => 5 + }); false -> case B of - 0 -> 0; - Gleam@denominator -> A div Gleam@denominator + 0 -> + 0; + + _value -> + A div _value end end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_with_use_becomes_tail_recursive.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_with_use_becomes_tail_recursive.snap index 9e54ff507..88d01ea5e 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_with_use_becomes_tail_recursive.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_function_with_use_becomes_tail_recursive.snap @@ -15,8 +15,7 @@ pub fn count(from: Int, to: Int) -> Int { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([count/2]). -file("project/test/my/mod.gleam", 4). @@ -27,7 +26,7 @@ count(From, To) -> From; false -> - echo(From, nil, 6), + echo(From, nil, <<"project/test/my/mod.gleam"/utf8>>, 6), count(From + 1, To) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_higher_order_function.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_higher_order_function.snap index b7c663200..8ba996e94 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_higher_order_function.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_higher_order_function.snap @@ -15,8 +15,7 @@ fn double(x) { x + x } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 8). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_higher_order_function_anonymous.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_higher_order_function_anonymous.snap index 717de94b4..87c64fc7f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_higher_order_function_anonymous.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_higher_order_function_anonymous.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_higher_order_function_with_capture.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_higher_order_function_with_capture.snap index 00e855ed1..58e2c800a 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_higher_order_function_with_capture.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_higher_order_function_with_capture.snap @@ -20,22 +20,27 @@ fn divide(a: Int, b: Int) -> Result(Int, Nil) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 8). -spec divide(integer(), integer()) -> {ok, integer()} | {error, nil}. divide(A, B) -> case case B of - 0 -> 0; - Gleam@denominator -> A rem Gleam@denominator + 0 -> + 0; + + _value -> + A rem _value end of 0 -> {ok, case B of - 0 -> 0; - Gleam@denominator@1 -> A div Gleam@denominator@1 - end}; + 0 -> + 0; + + _value@1 -> + A div _value@1 + end}; _ -> {error, nil} diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_shadowed_variable.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_shadowed_variable.snap index ac08eef47..6180881ec 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_shadowed_variable.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_shadowed_variable.snap @@ -19,8 +19,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_shadowed_variable_nested.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_shadowed_variable_nested.snap index 3fb19a10b..b506c9983 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_shadowed_variable_nested.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_shadowed_variable_nested.snap @@ -21,8 +21,7 @@ pub fn sum(a, b) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([sum/2]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_variable_shadowed_in_case_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_variable_shadowed_in_case_pattern.snap index 74ab50773..37fcd2b5e 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_variable_shadowed_in_case_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_variable_shadowed_in_case_pattern.snap @@ -20,8 +20,7 @@ pub fn sum() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([sum/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_variable_shadowing_case_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_variable_shadowing_case_pattern.snap index 65b987289..e3d853f2e 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_variable_shadowing_case_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_variable_shadowing_case_pattern.snap @@ -16,8 +16,7 @@ pub fn sum() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([sum/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_variable_shadowing_parameter.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_variable_shadowing_parameter.snap index 1d6aeef93..e515dd843 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_variable_shadowing_parameter.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inline_variable_shadowing_parameter.snap @@ -16,8 +16,7 @@ pub fn sum(a, b) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([sum/2]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inlining_works_properly_with_record_updates.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inlining_works_properly_with_record_updates.snap index 849d2da45..c7f19588f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inlining_works_properly_with_record_updates.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inlining_works_properly_with_record_updates.snap @@ -19,8 +19,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([wibble/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inlining_works_through_blocks.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inlining_works_through_blocks.snap index ae878e55b..406857b5a 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inlining_works_through_blocks.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__inlining__inlining_works_through_blocks.snap @@ -11,8 +11,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__assignment_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__assignment_pattern.snap index 392b9365f..9ceb0121f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__assignment_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__assignment_pattern.snap @@ -10,26 +10,28 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). -spec go() -> integer(). go() -> - X@1 = case 123 of - 123 = X -> X; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 2, - value => _assert_fail, - start => 16, - 'end' => 41, - pattern_start => 27, - pattern_end => 35}) - end, - X@1. + case 123 of + 123 = X -> + X; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 2, + value => _value, + start => 16, + 'end' => 41, + pattern_start => 27, + pattern_end => 35 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_discard.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_discard.snap index 60ead5417..7e2df1a52 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_discard.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_discard.snap @@ -12,26 +12,28 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). main() -> - Number@1 = case <<10>> of - <> -> Number; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 19, - 'end' => 54, - pattern_start => 30, - pattern_end => 45}) - end, - Number@1. + case <<10>> of + <> -> + Number; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value, + start => 19, + 'end' => 54, + pattern_start => 30, + pattern_end => 45 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_float.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_float.snap index df6ff1614..f0365bb2e 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_float.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_float.snap @@ -12,26 +12,29 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> float(). main() -> - Pi@1 = case <<3.14/float>> of - <> when Pi =:= 3.14 -> Pi; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 19, - 'end' => 61, - pattern_start => 30, - pattern_end => 50}) - end, - Pi@1. + case <<3.14/float>> of + <<3.14/float>> -> + Pi = 3.14, + Pi; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value, + start => 19, + 'end' => 61, + pattern_start => 30, + pattern_end => 50 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_int.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_int.snap index 83af1ea24..f04172263 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_int.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_int.snap @@ -12,26 +12,29 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). main() -> - A@1 = case <<1>> of - <> when A =:= 1 -> A; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 19, - 'end' => 48, - pattern_start => 30, - pattern_end => 40}) - end, - A@1. + case <<1>> of + <<1>> -> + A = 1, + A; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value, + start => 19, + 'end' => 48, + pattern_start => 30, + pattern_end => 40 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_string.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_string.snap index ee0c5d6c4..a90244d0a 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_string.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_string.snap @@ -12,26 +12,29 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> binary(). main() -> - Message@1 = case <<"Hello, world!"/utf8>> of - <> when Message =:= <<"Hello, world!"/utf8>> -> Message; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 19, - 'end' => 87, - pattern_start => 30, - pattern_end => 65}) - end, - Message@1. + case <<"Hello, world!"/utf8>> of + <<"Hello, world!"/utf8>> -> + Message = <<"Hello, world!"/utf8>>, + Message; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value, + start => 19, + 'end' => 87, + pattern_start => 30, + pattern_end => 65 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_pattern.snap index 568d04532..8ed37a1bf 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_pattern.snap @@ -10,26 +10,28 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). -spec go() -> integer(). go() -> - {A@1, B@1, C@1} = case <<123>> of - <> -> {A, B, C}; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 2, - value => _assert_fail, - start => 16, - 'end' => 54, - pattern_start => 27, - pattern_end => 44}) - end, - (A@1 + B@1) + C@1. + case <<123>> of + <> -> + (A + B) + C; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 2, + value => _value, + start => 16, + 'end' => 54, + pattern_start => 27, + pattern_end => 44 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__constructor_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__constructor_pattern.snap index 6d6a75885..9531db331 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__constructor_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__constructor_pattern.snap @@ -10,26 +10,28 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). -spec go() -> any(). go() -> - X@1 = case {error, nil} of - {ok, X} -> X; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 2, - value => _assert_fail, - start => 16, - 'end' => 45, - pattern_start => 27, - pattern_end => 32}) - end, - X@1. + case {error, nil} of + {ok, X} -> + X; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 2, + value => _value, + start => 16, + 'end' => 45, + pattern_start => 27, + pattern_end => 32 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__constructor_pattern_with_multiple_variables.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__constructor_pattern_with_multiple_variables.snap index c46bca92a..99d7844c0 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__constructor_pattern_with_multiple_variables.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__constructor_pattern_with_multiple_variables.snap @@ -15,8 +15,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -export_type([wibble/0]). @@ -25,19 +24,22 @@ pub fn go() { -file("project/test/my/mod.gleam", 6). -spec go() -> integer(). go() -> - {X@1, Y@1} = case {wibble, 1, 2.0} of - {wibble, X, 2.0 = Y} -> {X, Y}; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 7, - value => _assert_fail, - start => 59, - 'end' => 106, - pattern_start => 70, - pattern_end => 89}) - end, - X@1. + case {wibble, 1, 2.0} of + {wibble, X, 2.0 = Y} -> + X; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 7, + value => _value, + start => 59, + 'end' => 106, + pattern_start => 70, + pattern_end => 89 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__discard_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__discard_pattern.snap index 5bc9bd1db..74e041f1e 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__discard_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__discard_pattern.snap @@ -9,8 +9,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__float_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__float_pattern.snap index 4034713de..d3ef50c08 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__float_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__float_pattern.snap @@ -9,26 +9,28 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). -spec go() -> float(). go() -> - _assert_subject = 5.1, - case _assert_subject of - 1.5 -> _assert_subject; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 2, - value => _assert_fail, - start => 16, - 'end' => 36, - pattern_start => 27, - pattern_end => 30}) + case 5.1 of + 1.5 = _value -> + _value; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 2, + value => _value@1, + start => 16, + 'end' => 36, + pattern_start => 27, + pattern_end => 30 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__int_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__int_pattern.snap index 99db133f2..41c1b6d81 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__int_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__int_pattern.snap @@ -9,26 +9,28 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). -spec go() -> integer(). go() -> - _assert_subject = 2, - case _assert_subject of - 1 -> _assert_subject; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 2, - value => _assert_fail, - start => 16, - 'end' => 32, - pattern_start => 27, - pattern_end => 28}) + case 2 of + 1 = _value -> + _value; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 2, + value => _value@1, + start => 16, + 'end' => 32, + pattern_start => 27, + pattern_end => 28 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__just_variable.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__just_variable.snap index 29a0983a4..97b0219df 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__just_variable.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__just_variable.snap @@ -10,8 +10,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__let_assert_at_end_of_block.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__let_assert_at_end_of_block.snap index c731256ed..c423a2cb0 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__let_assert_at_end_of_block.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__let_assert_at_end_of_block.snap @@ -14,8 +14,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 2). @@ -24,19 +23,23 @@ go() -> Result = {ok, 10}, X = begin case Result of - {ok, _} -> Result; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 5, - value => _assert_fail, - start => 53, - 'end' => 78, - pattern_start => 64, - pattern_end => 69}) + {ok, _} = _value -> + _value; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 5, + value => _value@1, + start => 53, + 'end' => 78, + pattern_start => 64, + pattern_end => 69 + }) end end, X. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__let_assert_should_not_use_redefined_variable.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__let_assert_should_not_use_redefined_variable.snap index 7883f427f..13d3f1f6b 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__let_assert_should_not_use_redefined_variable.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__let_assert_should_not_use_redefined_variable.snap @@ -17,13 +17,11 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). --spec split_once(binary(), binary()) -> {ok, {binary(), binary()}} | - {error, binary()}. +-spec split_once(binary(), binary()) -> {ok, {binary(), binary()}} | {error, binary()}. split_once(X, Y) -> {ok, {X, Y}}. @@ -31,19 +29,22 @@ split_once(X, Y) -> -spec main() -> {ok, {binary(), binary()}} | {error, binary()}. main() -> String = <<"Hello, world!"/utf8>>, - _assert_subject = split_once(String, <<"\n"/utf8>>), - case _assert_subject of - {ok, {Prefix, String@1}} -> _assert_subject; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => (<<"Failed to split: "/utf8, String/binary>>), - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 8, - value => _assert_fail, - start => 148, - 'end' => 207, - pattern_start => 159, - pattern_end => 180}) + case split_once(String, <<"\n"/utf8>>) of + {ok, {Prefix, String@1}} = _value -> + _value; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Failed to split: "/utf8, String/binary>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 8, + value => _value@1, + start => 148, + 'end' => 207, + pattern_start => 159, + pattern_end => 180 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__list_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__list_pattern.snap index 345a936e3..cdf9e8c0d 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__list_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__list_pattern.snap @@ -10,26 +10,28 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). -spec go() -> integer(). go() -> - X@1 = case [1, 2, 3] of - [1, X, 3] -> X; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 2, - value => _assert_fail, - start => 16, - 'end' => 48, - pattern_start => 27, - pattern_end => 36}) - end, - X@1. + case [1, 2, 3] of + [1, X, 3] -> + X; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 2, + value => _value, + start => 16, + 'end' => 48, + pattern_start => 27, + pattern_end => 36 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__list_pattern_with_multiple_variables.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__list_pattern_with_multiple_variables.snap index 8887c535d..d0d4910f8 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__list_pattern_with_multiple_variables.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__list_pattern_with_multiple_variables.snap @@ -10,26 +10,28 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). -spec go() -> integer(). go() -> - {A@1, B@1, C@1} = case [1, 2, 3] of - [A, B, C] -> {A, B, C}; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 2, - value => _assert_fail, - start => 16, - 'end' => 48, - pattern_start => 27, - pattern_end => 36}) - end, - (A@1 + B@1) + C@1. + case [1, 2, 3] of + [A, B, C] -> + (A + B) + C; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 2, + value => _value, + start => 16, + 'end' => 48, + pattern_start => 27, + pattern_end => 36 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__message.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__message.snap index 3d5d9e2ee..a61a73ed0 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__message.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__message.snap @@ -12,26 +12,28 @@ pub fn unwrap_or_panic(value) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([unwrap_or_panic/1]). -file("project/test/my/mod.gleam", 2). -spec unwrap_or_panic({ok, K} | {error, any()}) -> K. unwrap_or_panic(Value) -> - Inner@1 = case Value of - {ok, Inner} -> Inner; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Oops, there was an error"/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"unwrap_or_panic"/utf8>>, - line => 3, - value => _assert_fail, - start => 35, - 'end' => 63, - pattern_start => 46, - pattern_end => 55}) - end, - Inner@1. + case Value of + {ok, Inner} -> + Inner; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Oops, there was an error"/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"unwrap_or_panic"/utf8>>, + line => 3, + value => _value, + start => 35, + 'end' => 63, + pattern_start => 46, + pattern_end => 55 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__more_than_one_var.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__more_than_one_var.snap index bdb792ce3..a3b4b7635 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__more_than_one_var.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__more_than_one_var.snap @@ -10,26 +10,28 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 1). -spec go(list(integer())) -> list(integer()). go(X) -> - {A@1, B@1, C@1} = case X of - [1, A, B, C] -> {A, B, C}; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 2, - value => _assert_fail, - start => 17, - 'end' => 44, - pattern_start => 28, - pattern_end => 40}) - end, - [A@1, B@1, C@1]. + case X of + [1, A, B, C] -> + [A, B, C]; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 2, + value => _value, + start => 17, + 'end' => 44, + pattern_start => 28, + pattern_end => 40 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__one_var.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__one_var.snap index 25a7138a0..610d84f9c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__one_var.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__one_var.snap @@ -10,26 +10,28 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). -spec go() -> integer(). go() -> - Y@1 = case {ok, 1} of - {ok, Y} -> Y; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 2, - value => _assert_fail, - start => 16, - 'end' => 40, - pattern_start => 27, - pattern_end => 32}) - end, - Y@1. + case {ok, 1} of + {ok, Y} -> + Y; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 2, + value => _value, + start => 16, + 'end' => 40, + pattern_start => 27, + pattern_end => 32 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__pattern_let.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__pattern_let.snap index da8b8dc48..3b96b31b2 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__pattern_let.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__pattern_let.snap @@ -10,26 +10,28 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 1). -spec go(list(integer())) -> list(integer()). go(X) -> - {A@1, B@1, C@1} = case X of - [1 = A, B, C] -> {A, B, C}; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 2, - value => _assert_fail, - start => 17, - 'end' => 46, - pattern_start => 28, - pattern_end => 42}) - end, - [A@1, B@1, C@1]. + case X of + [1 = A, B, C] -> + [A, B, C]; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 2, + value => _value, + start => 17, + 'end' => 46, + pattern_start => 28, + pattern_end => 42 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__reference_earlier_segment.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__reference_earlier_segment.snap index fb0a6c7cb..40f04aa8b 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__reference_earlier_segment.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__reference_earlier_segment.snap @@ -12,26 +12,28 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). main() -> - {Length@1, Bytes@1} = case <<3, 1, 2, 3>> of - <> -> {Length, Bytes}; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 19, - 'end' => 85, - pattern_start => 30, - pattern_end => 68}) - end, - Bytes@1. + case <<3, 1, 2, 3>> of + <> -> + Bytes; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value, + start => 19, + 'end' => 85, + pattern_start => 30, + pattern_end => 68 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__string_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__string_pattern.snap index 212d7a0f6..e650f8a01 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__string_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__string_pattern.snap @@ -9,26 +9,28 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). -spec go() -> binary(). go() -> - _assert_subject = <<"Hel"/utf8, "lo!"/utf8>>, - case _assert_subject of - <<"Hello!"/utf8>> -> _assert_subject; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 2, - value => _assert_fail, - start => 16, - 'end' => 52, - pattern_start => 27, - pattern_end => 35}) + case <<"Hel"/utf8, "lo!"/utf8>> of + <<"Hello!"/utf8>> = _value -> + _value; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 2, + value => _value@1, + start => 16, + 'end' => 52, + pattern_start => 27, + pattern_end => 35 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__string_prefix_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__string_prefix_pattern.snap index 192b7bc1e..0c8e8e7e6 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__string_prefix_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__string_prefix_pattern.snap @@ -10,26 +10,28 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). -spec go() -> binary(). go() -> - Name@1 = case <<"Hello John"/utf8>> of - <<"Hello "/utf8, Name/binary>> -> Name; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 2, - value => _assert_fail, - start => 16, - 'end' => 58, - pattern_start => 27, - pattern_end => 43}) - end, - Name@1. + case <<"Hello John"/utf8>> of + <<"Hello "/utf8, Name/binary>> -> + Name; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 2, + value => _value, + start => 16, + 'end' => 58, + pattern_start => 27, + pattern_end => 43 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__string_prefix_pattern_with_prefix_binding.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__string_prefix_pattern_with_prefix_binding.snap index bbcbd99bf..96c5b9e17 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__string_prefix_pattern_with_prefix_binding.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__string_prefix_pattern_with_prefix_binding.snap @@ -10,27 +10,29 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). -spec go() -> {binary(), binary()}. go() -> - {Name@1, Greeting@1} = case <<"Hello John"/utf8>> of - <<"Hello "/utf8, Name/binary>> -> {Name, Greeting}; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 2, - value => _assert_fail, - start => 16, - 'end' => 70, - pattern_start => 27, - pattern_end => 55}) - end, - Greeting = <<"Hello "/utf8>>, - {Greeting@1, Name@1}. + case <<"Hello John"/utf8>> of + <<"Hello "/utf8, Name/binary>> -> + Greeting = <<"Hello "/utf8>>, + {Greeting, Name}; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 2, + value => _value, + start => 16, + 'end' => 70, + pattern_start => 27, + pattern_end => 55 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__tuple_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__tuple_pattern.snap index c17b89ffb..f4e61ac5f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__tuple_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__tuple_pattern.snap @@ -10,8 +10,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__variable_message.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__variable_message.snap index fd3cf073e..f76af3412 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__variable_message.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__variable_message.snap @@ -12,26 +12,28 @@ pub fn expect(value, message) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([expect/2]). -file("project/test/my/mod.gleam", 2). -spec expect({ok, L} | {error, any()}, binary()) -> L. expect(Value, Message) -> - Inner@1 = case Value of - {ok, Inner} -> Inner; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => Message, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"expect"/utf8>>, - line => 3, - value => _assert_fail, - start => 35, - 'end' => 63, - pattern_start => 46, - pattern_end => 55}) - end, - Inner@1. + case Value of + {ok, Inner} -> + Inner; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => Message, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"expect"/utf8>>, + line => 3, + value => _value, + start => 35, + 'end' => 63, + pattern_start => 46, + pattern_end => 55 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__variable_rewrites.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__variable_rewrites.snap index bce5a1e6f..269e04763 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__variable_rewrites.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__variable_rewrites.snap @@ -11,41 +11,46 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). -spec go() -> integer(). go() -> - Y@1 = case {ok, 1} of - {ok, Y} -> Y; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"go"/utf8>>, - line => 2, - value => _assert_fail, - start => 16, - 'end' => 40, - pattern_start => 27, - pattern_end => 32}) - end, - Y@3 = case {ok, 1} of - {ok, Y@2} -> Y@2; - _assert_fail@1 -> - erlang:error(#{gleam_error => let_assert, + case {ok, 1} of + {ok, Y} -> + case {ok, 1} of + {ok, Y@1} -> + Y@1; + + _value -> + erlang:error(#{ + gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"go"/utf8>>, line => 3, - value => _assert_fail@1, + value => _value, start => 43, 'end' => 67, pattern_start => 54, - pattern_end => 59}) - end, - Y@3. + pattern_end => 59 + }) + end; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"go"/utf8>>, + line => 2, + value => _value@1, + start => 16, + 'end' => 40, + pattern_start => 27, + pattern_end => 32 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__lists__empty_list.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__lists__empty_list.snap new file mode 100644 index 000000000..708371c1b --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__lists__empty_list.snap @@ -0,0 +1,20 @@ +--- +source: compiler-core/src/erlang/tests/lists.rs +expression: "\npub fn main() {\n []\n}\n" +--- +----- SOURCE CODE + +pub fn main() { + [] +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/0]). + +-file("project/test/my/mod.gleam", 2). +-spec main() -> list(any()). +main() -> + []. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__lists__list_with_multiple_items.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__lists__list_with_multiple_items.snap new file mode 100644 index 000000000..1f88926c6 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__lists__list_with_multiple_items.snap @@ -0,0 +1,20 @@ +--- +source: compiler-core/src/erlang/tests/lists.rs +expression: "\npub fn main() {\n [1, 2, 3]\n}\n" +--- +----- SOURCE CODE + +pub fn main() { + [1, 2, 3] +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/0]). + +-file("project/test/my/mod.gleam", 2). +-spec main() -> list(integer()). +main() -> + [1, 2, 3]. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__lists__list_with_spread.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__lists__list_with_spread.snap new file mode 100644 index 000000000..c4bbe1d22 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__lists__list_with_spread.snap @@ -0,0 +1,22 @@ +--- +source: compiler-core/src/erlang/tests/lists.rs +expression: "\npub fn main() {\n let a = [3, 2, 1]\n [5, 4, ..a]\n}\n" +--- +----- SOURCE CODE + +pub fn main() { + let a = [3, 2, 1] + [5, 4, ..a] +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/0]). + +-file("project/test/my/mod.gleam", 2). +-spec main() -> list(integer()). +main() -> + A = [3, 2, 1], + [5, 4 | A]. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__lists__single_item_list.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__lists__single_item_list.snap new file mode 100644 index 000000000..38093ab60 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__lists__single_item_list.snap @@ -0,0 +1,20 @@ +--- +source: compiler-core/src/erlang/tests/lists.rs +expression: "\npub fn main() {\n [1]\n}\n" +--- +----- SOURCE CODE + +pub fn main() { + [1] +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/0]). + +-file("project/test/my/mod.gleam", 2). +-spec main() -> list(integer()). +main() -> + [1]. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__int_negation.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__int_negation.snap index 368de7ed8..2a7cd9605 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__int_negation.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__int_negation.snap @@ -12,8 +12,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_scientific_notation.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_scientific_notation.snap index 607a7f848..fcc2abf1b 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_scientific_notation.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_scientific_notation.snap @@ -15,12 +15,11 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 5). -spec main() -> float(). main() -> - 100.001e223, - -100.001e-223. + 1000010000000000019665908316189043843159148085072442478256397069137698587541416634472224148782609298654584042789653362687508939311685541429242270213575609082572149767678550630459456078228265202777732814425639395211642188857344.0, + -0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100001. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_underscores.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_underscores.snap index e2d84a1a3..22089d2d7 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_underscores.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_underscores.snap @@ -12,8 +12,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_underscores1.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_underscores1.snap index 3274f6a3e..fa37b405c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_underscores1.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_underscores1.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_underscores2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_underscores2.snap index 93b71caa9..b608a8cfd 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_underscores2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__numbers_with_underscores2.snap @@ -13,41 +13,46 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). main() -> case 1 of - 100000 -> nil; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 19, - 'end' => 41, - pattern_start => 30, - pattern_end => 37}) - end, - case 1.0 of - 100000.00101 -> nil; - _assert_fail@1 -> - erlang:error(#{gleam_error => let_assert, + 100000 -> + case 1.0 of + 100000.00101 -> + 1; + + _value -> + erlang:error(#{ + gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, + file => <<"project/test/my/mod.gleam"/utf8>>, module => <<"my/mod"/utf8>>, function => <<"main"/utf8>>, line => 4, - value => _assert_fail@1, + value => _value, start => 44, 'end' => 73, pattern_start => 55, - pattern_end => 68}) - end, - 1. + pattern_end => 68 + }) + end; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value@1, + start => 19, + 'end' => 41, + pattern_start => 30, + pattern_end => 37 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__repeated_int_negation.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__repeated_int_negation.snap index f9f87ab36..d5ccd5e3f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__repeated_int_negation.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__repeated_int_negation.snap @@ -12,8 +12,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__zero_b_in_hex.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__zero_b_in_hex.snap index 600c3b2c3..e0296f90f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__zero_b_in_hex.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__numbers__zero_b_in_hex.snap @@ -11,11 +11,10 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). main() -> - 16#ffe0bb. + 16769211. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__panic_as.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__panic_as.snap index 2e6a47744..767c6f78c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__panic_as.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__panic_as.snap @@ -11,16 +11,17 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> any(). main() -> - erlang:error(#{gleam_error => panic, - message => <<"wibble"/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3}). + erlang:error(#{ + gleam_error => panic, + message => <<"wibble"/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3 + }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__panic_as_function.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__panic_as_function.snap index 6fbaeb529..bbbffb4e7 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__panic_as_function.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__panic_as_function.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([retstring/0, main/0]). -file("project/test/my/mod.gleam", 2). @@ -26,9 +25,11 @@ retstring() -> -file("project/test/my/mod.gleam", 5). -spec main() -> any(). main() -> - erlang:error(#{gleam_error => panic, - message => (<<(retstring())/binary, "wobble"/utf8>>), - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 6}). + erlang:error(#{ + gleam_error => panic, + message => <<(retstring())/binary, "wobble"/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 6 + }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__piped.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__piped.snap index 260626671..fe66174f9 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__piped.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__piped.snap @@ -12,17 +12,18 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> any(). main() -> _pipe = <<"lets"/utf8>>, - (erlang:error(#{gleam_error => panic, - message => <<"`panic` expression evaluated."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 4}))(_pipe). + (erlang:error(#{ + gleam_error => panic, + message => <<"`panic` expression evaluated."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 4 + }))(_pipe). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__piped_chain.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__piped_chain.snap index 334f0d4e5..f86d25639 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__piped_chain.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__piped_chain.snap @@ -13,23 +13,26 @@ expression: "\n pub fn main() {\n \"lets\"\n |> panic as \"pipe\"\ ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> any(). main() -> _pipe = <<"lets"/utf8>>, - _pipe@1 = (erlang:error(#{gleam_error => panic, - message => <<"pipe"/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 4}))(_pipe), - (erlang:error(#{gleam_error => panic, - message => <<"other panic"/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 5}))(_pipe@1). + _pipe@1 = (erlang:error(#{ + gleam_error => panic, + message => <<"pipe"/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 4 + }))(_pipe), + (erlang:error(#{ + gleam_error => panic, + message => <<"other panic"/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 5 + }))(_pipe@1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__plain.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__plain.snap index f94753d6f..c8abdcf3e 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__plain.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__panic__plain.snap @@ -11,16 +11,17 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> any(). main() -> - erlang:error(#{gleam_error => panic, - message => <<"`panic` expression evaluated."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3}). + erlang:error(#{ + gleam_error => panic, + message => <<"`panic` expression evaluated."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3 + }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__aliased_discard_pattern_in_bit_array_later_used.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__aliased_discard_pattern_in_bit_array_later_used.snap new file mode 100644 index 000000000..567acaab6 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__aliased_discard_pattern_in_bit_array_later_used.snap @@ -0,0 +1,28 @@ +--- +source: compiler-core/src/erlang/tests/patterns.rs +expression: "\npub fn main(x) {\n case x {\n <<_ as b>> -> b + 2\n _ -> 0\n }\n}" +--- +----- SOURCE CODE + +pub fn main(x) { + case x { + <<_ as b>> -> b + 2 + _ -> 0 + } +} + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/1]). + +-file("project/test/my/mod.gleam", 2). +-spec main(bitstring()) -> integer(). +main(X) -> + case X of + <> -> + B + 2; + + _ -> + 0 + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns.snap index ca3fa8388..895c7521e 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns.snap @@ -18,8 +18,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns1.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns1.snap index 6c4478da4..0ddc38f4f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns1.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns1.snap @@ -12,8 +12,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns2.snap index e2a1c1621..544c53478 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns2.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns3.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns3.snap index 8907524c4..ac4b823a4 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns3.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__alternative_patterns3.snap @@ -17,8 +17,7 @@ pub fn main(arg) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__pattern_as.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__pattern_as.snap index 84b794404..47e3f73cc 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__pattern_as.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__pattern_as.snap @@ -12,8 +12,7 @@ pub fn a(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([a/1]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_assertion.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_assertion.snap index e6fab421f..8087e7866 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_assertion.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_assertion.snap @@ -10,27 +10,29 @@ pub fn a(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([a/1]). -file("project/test/my/mod.gleam", 1). -spec a(any()) -> binary(). a(X) -> - {Rest@1, A@1} = case <<"wibble"/utf8>> of - <<"a"/utf8, Rest/binary>> -> {Rest, A}; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"a"/utf8>>, - line => 2, - value => _assert_fail, - start => 16, - 'end' => 54, - pattern_start => 27, - pattern_end => 43}) - end, - A = <<"a"/utf8>>, - A@1. + case <<"wibble"/utf8>> of + <<"a"/utf8, Rest/binary>> -> + A = <<"a"/utf8>>, + A; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"a"/utf8>>, + line => 2, + value => _value, + start => 16, + 'end' => 54, + pattern_start => 27, + pattern_end => 43 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_list.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_list.snap index 5af1c9f9b..b789c28a5 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_list.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_list.snap @@ -12,8 +12,7 @@ pub fn a(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([a/1]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_multiple_subjects.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_multiple_subjects.snap index bfd8bc307..cc10300f1 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_multiple_subjects.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_multiple_subjects.snap @@ -12,8 +12,7 @@ pub fn a(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([a/1]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_multiple_subjects_and_guard.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_multiple_subjects_and_guard.snap index e65e53ecb..1ef7cf84c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_multiple_subjects_and_guard.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__patterns__string_prefix_as_pattern_with_multiple_subjects_and_guard.snap @@ -12,8 +12,7 @@ pub fn a(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([a/1]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__block_expr_into_pipe.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__block_expr_into_pipe.snap index 71475a2de..851cd9164 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__block_expr_into_pipe.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__block_expr_into_pipe.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__call_pipeline_result.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__call_pipeline_result.snap index e63360b5b..4560de653 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__call_pipeline_result.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__call_pipeline_result.snap @@ -15,14 +15,15 @@ pub fn add(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([add/1, main/0]). -file("project/test/my/mod.gleam", 6). -spec add(integer()) -> fun((integer()) -> integer()). add(X) -> - fun(Y) -> X + Y end. + fun(Y) -> + X + Y + end. -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__clever_pipe_rewriting.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__clever_pipe_rewriting.snap index f598f1deb..22e0aa342 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__clever_pipe_rewriting.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__clever_pipe_rewriting.snap @@ -9,8 +9,7 @@ pub fn apply(f: fn(a) -> b, a: a) { a |> f } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([apply/2]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__clever_pipe_rewriting1.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__clever_pipe_rewriting1.snap index 31b887254..ec7888f28 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__clever_pipe_rewriting1.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__clever_pipe_rewriting1.snap @@ -9,8 +9,7 @@ pub fn apply(f: fn(a, Int) -> b, a: a) { a |> f(1) } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([apply/2]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__multiple_pipes.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__multiple_pipes.snap index 28eb42374..f1a1c327b 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__multiple_pipes.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__multiple_pipes.snap @@ -14,8 +14,7 @@ fn x(x) { x } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 7). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_call.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_call.snap index 48175d2bd..473e792e8 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_call.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_call.snap @@ -19,8 +19,7 @@ pub fn two(a, b) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([two/2, main/0]). -file("project/test/my/mod.gleam", 10). @@ -32,10 +31,7 @@ two(A, B) -> -spec main() -> integer(). main() -> _pipe = 123, - two( - begin - _pipe@1 = 1, - two(_pipe@1, 2) - end, - _pipe - ). + two(begin + _pipe@1 = 1, + two(_pipe@1, 2) + end, _pipe). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_case_subject.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_case_subject.snap index 5225a3bcf..ccfaf93de 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_case_subject.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_case_subject.snap @@ -11,8 +11,7 @@ pub fn x(f) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([x/1]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_eq.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_eq.snap index a8f6d3b4e..77b87b4b8 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_eq.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_eq.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_list.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_list.snap index 4e3eb5e5b..387184e9c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_list.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_list.snap @@ -11,14 +11,13 @@ pub fn x(f) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([x/1]). -file("project/test/my/mod.gleam", 1). -spec x(fun((integer()) -> L)) -> list(L). x(F) -> [begin - _pipe = 1, - F(_pipe) - end]. + _pipe = 1, + F(_pipe) + end]. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_record_update.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_record_update.snap index 43a9a963b..2e41a2cb4 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_record_update.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_record_update.snap @@ -17,8 +17,7 @@ pub fn main(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -export_type([x/0]). @@ -32,9 +31,7 @@ id(X) -> -file("project/test/my/mod.gleam", 9). -spec main(x()) -> x(). main(X) -> - {x, - begin - _pipe = 1, - id(_pipe) - end, - erlang:element(3, X)}. + {x, begin + _pipe = 1, + id(_pipe) + end, erlang:element(3, X)}. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_tuple.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_tuple.snap index c56906a24..061440772 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_tuple.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__pipes__pipe_in_tuple.snap @@ -11,14 +11,13 @@ pub fn x(f) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([x/1]). -file("project/test/my/mod.gleam", 1). -spec x(fun((integer()) -> K)) -> {K}. x(F) -> {begin - _pipe = 1, - F(_pipe) - end}. + _pipe = 1, + F(_pipe) + end}. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__basic.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__basic.snap index 2ab4e73fb..27c71774c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__basic.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__basic.snap @@ -2,4 +2,7 @@ source: compiler-core/src/erlang/tests/records.rs expression: "record_definition(\"PetCat\",\n&[(\"name\", type_::tuple(vec![])), (\"is_cute\", type_::tuple(vec![]))])" --- --record(pet_cat, {name :: {}, is_cute :: {}}). +-record(pet_cat, { + name :: {}, + is_cute :: {} +}). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__const_record_update_generic_respecialization.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__const_record_update_generic_respecialization.snap index a087b1cda..bc47b4e7c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__const_record_update_generic_respecialization.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__const_record_update_generic_respecialization.snap @@ -18,8 +18,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([box/1]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__constant_record_update_with_unlabelled_fields.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__constant_record_update_with_unlabelled_fields.snap index 9980a0846..d6cc39024 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__constant_record_update_with_unlabelled_fields.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__constant_record_update_with_unlabelled_fields.snap @@ -18,8 +18,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([wibble/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__imported_qualified_constructor_as_fn_name_escape.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__imported_qualified_constructor_as_fn_name_escape.snap index 950bc8809..b3a06bf8f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__imported_qualified_constructor_as_fn_name_escape.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__imported_qualified_constructor_as_fn_name_escape.snap @@ -11,11 +11,12 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 3). -spec main() -> fun((integer()) -> other_module:'let'()). main() -> - fun(Field@0) -> {'let', Field@0} end. + fun(_value) -> + {'let', _value} + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__long_definition_formatting.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__long_definition_formatting.snap index 1d1908133..62bf3a7a2 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__long_definition_formatting.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__long_definition_formatting.snap @@ -6,10 +6,5 @@ expression: "record_definition(\"PetCat\",\n&[(\"name\", type_::generic_var(1)), name :: any(), is_cute :: any(), linked :: integer(), - whatever :: list({nil, - list({nil, nil, nil}), - nil, - list({nil, nil, nil}), - nil, - list({nil, nil, nil})}) + whatever :: list({nil, list({nil, nil, nil}), nil, list({nil, nil, nil}), nil, list({nil, nil, nil})}) }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__module_types.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__module_types.snap index 40cbde2dc..f722db6a3 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__module_types.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__module_types.snap @@ -2,4 +2,6 @@ source: compiler-core/src/erlang/tests/records.rs expression: "record_definition(\"PetCat\",\n&[(\"name\",\nArc::new(Type::Named\n{\n publicity: Publicity::Public, package: \"package\".into(), module:\n module_name, name: \"my_type\".into(), arguments: vec![], inferred_variant:\n None,\n}))])" --- --record(pet_cat, {name :: name:my_type()}). +-record(pet_cat, { + name :: name:my_type() +}). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__nested_record_update.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__nested_record_update.snap index fa809388b..635048f35 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__nested_record_update.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__nested_record_update.snap @@ -18,8 +18,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([wibble/0, wobble/0]). @@ -31,10 +30,7 @@ pub fn main() { -spec main() -> wibble(). main() -> Base = {wibble, 1, {wobble, 2, 3}, 4}, - {wibble, - erlang:element(2, Base), - begin - _record = erlang:element(3, Base), - {wobble, erlang:element(2, _record), 5} - end, - erlang:element(4, Base)}. + {wibble, erlang:element(2, Base), begin + _record = erlang:element(3, Base), + {wobble, erlang:element(2, _record), 5} + end, erlang:element(4, Base)}. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__nested_record_update_with_blocks.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__nested_record_update_with_blocks.snap index 5c37d4cec..4214d9bba 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__nested_record_update_with_blocks.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__nested_record_update_with_blocks.snap @@ -17,8 +17,7 @@ pub fn main(a: A) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -export_type([a/0, b/0, c/0]). @@ -31,12 +30,10 @@ pub fn main(a: A) { -file("project/test/my/mod.gleam", 5). -spec main(a()) -> a(). main(A) -> - {a, - begin - _record = erlang:element(2, A), - {b, - begin - _record@1 = erlang:element(2, erlang:element(2, A)), - {c, 0} - end} - end}. + {a, begin + _record = erlang:element(2, A), + {b, begin + _record@1 = erlang:element(2, erlang:element(2, A)), + {c, 0} + end} + end}. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__pipe_update_subject.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__pipe_update_subject.snap index 99b46c2ff..1ffd46f4c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__pipe_update_subject.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__pipe_update_subject.snap @@ -16,8 +16,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([identity/1, main/0]). -export_type([thing/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__private_unused_records.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__private_unused_records.snap index 0b39afb23..a589f1de8 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__private_unused_records.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__private_unused_records.snap @@ -15,8 +15,7 @@ pub fn main(x: Int) -> Int { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -export_type([a/0, b/0, c/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_access_block.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_access_block.snap index f85cdccca..6ed5a4671 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_access_block.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_access_block.snap @@ -16,8 +16,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([thing/0]). @@ -26,10 +25,7 @@ pub fn main() { -file("project/test/my/mod.gleam", 5). -spec main() -> integer(). main() -> - erlang:element( - 2, - begin - Thing = {thing, 1, 2}, - Thing - end - ). + erlang:element(2, begin + Thing = {thing, 1, 2}, + Thing + end). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_variants.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_variants.snap index 92c38f766..c10b194e5 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_variants.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_variants.snap @@ -12,8 +12,7 @@ pub fn get_name(person: Person) { person.name } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([get_name/1]). -export_type([person/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_variants_parameterised_types.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_variants_parameterised_types.snap index cc21c50e6..9dbab02ac 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_variants_parameterised_types.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_variants_parameterised_types.snap @@ -13,13 +13,11 @@ pub fn get_age(person: Person) { person.age } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([get_name/1, get_age/1]). -export_type([person/0]). --type person() :: {teacher, binary(), list(integer()), binary()} | - {student, binary(), list(integer())}. +-type person() :: {teacher, binary(), list(integer()), binary()} | {student, binary(), list(integer())}. -file("project/test/my/mod.gleam", 6). -spec get_name(person()) -> binary(). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_variants_positions_other_than_first.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_variants_positions_other_than_first.snap index c6147867e..d981c4f61 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_variants_positions_other_than_first.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_variants_positions_other_than_first.snap @@ -13,13 +13,11 @@ pub fn get_age(person: Person) { person.age } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([get_name/1, get_age/1]). -export_type([person/0]). --type person() :: {teacher, binary(), integer(), binary()} | - {student, binary(), integer()}. +-type person() :: {teacher, binary(), integer(), binary()} | {student, binary(), integer()}. -file("project/test/my/mod.gleam", 6). -spec get_name(person()) -> binary(). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_with_first_position_different_types.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_with_first_position_different_types.snap index ac38b00cf..a183e21c3 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_with_first_position_different_types.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessor_multiple_with_first_position_different_types.snap @@ -12,8 +12,7 @@ pub fn get_age(person: Person) { person.age } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([get_age/1]). -export_type([person/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessors.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessors.snap index b0b7332fc..4e126eaac 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessors.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_accessors.snap @@ -11,8 +11,7 @@ pub fn get_name(person: Person) { person.name } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([get_age/1, get_name/1]). -export_type([person/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_constants.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_constants.snap index 7e263f013..c1f6ab0bd 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_constants.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_constants.snap @@ -9,8 +9,7 @@ pub fn a() { A } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([a/0]). -export_type([test/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread.snap index 22c1bcb7f..f1b63d413 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread.snap @@ -17,8 +17,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([triple/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread1.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread1.snap index 9328b2f61..b3bd42884 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread1.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread1.snap @@ -17,8 +17,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([triple/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread2.snap index cca66c401..8f2300d53 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread2.snap @@ -17,8 +17,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([triple/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread3.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread3.snap index b21c4bbc2..1a272888f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread3.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_spread3.snap @@ -18,8 +18,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([triple/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_update_with_unlabelled_fields.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_update_with_unlabelled_fields.snap index 4ce16e682..e047797a3 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_update_with_unlabelled_fields.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_update_with_unlabelled_fields.snap @@ -16,8 +16,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([wibble/0]). @@ -27,8 +26,4 @@ pub fn main() { -spec main() -> wibble(). main() -> Record = {wibble, 1, 3.14, true, <<"Hello"/utf8>>}, - {wibble, - erlang:element(2, Record), - erlang:element(3, Record), - false, - erlang:element(5, Record)}. + {wibble, erlang:element(2, Record), erlang:element(3, Record), false, erlang:element(5, Record)}. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates.snap index d9207886d..a9f729694 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([person/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates1.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates1.snap index acef2a4bb..d3f8e5c70 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates1.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates1.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([person/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates2.snap index 400d94726..139b408ff 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates2.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([person/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates3.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates3.snap index 0c070ceff..e93d7355a 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates3.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates3.snap @@ -18,8 +18,7 @@ fn return_person() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([person/0]). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates4.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates4.snap index 6d77b9e6a..2b1740dee 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates4.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__record_updates4.snap @@ -16,8 +16,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -export_type([car/0, person/0]). @@ -28,10 +27,7 @@ pub fn main() { -file("project/test/my/mod.gleam", 5). -spec main() -> person(). main() -> - Car = {car, - <<"Amphicar"/utf8>>, - <<"Model 770"/utf8>>, - {person, <<"John Doe"/utf8>>, 27}}, + Car = {car, <<"Amphicar"/utf8>>, <<"Model 770"/utf8>>, {person, <<"John Doe"/utf8>>, 27}}, New_p = begin _record = erlang:element(4, Car), {person, erlang:element(2, _record), 28} diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__reserve_words.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__reserve_words.snap index 02b08b11a..892883539 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__reserve_words.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__reserve_words.snap @@ -2,4 +2,8 @@ source: compiler-core/src/erlang/tests/records.rs expression: "record_definition(\"div\",\n&[(\"receive\", type_::int()), (\"catch\", type_::tuple(vec![])),\n(\"unreserved\", type_::tuple(vec![]))])" --- --record('div', {'receive' :: integer(), 'catch' :: {}, unreserved :: {}}). +-record('div', { + 'receive' :: integer(), + 'catch' :: {}, + unreserved :: {} +}). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__type_vars.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__type_vars.snap index c37b1c983..9d70ef03e 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__type_vars.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__records__type_vars.snap @@ -2,4 +2,8 @@ source: compiler-core/src/erlang/tests/records.rs expression: "record_definition(\"PetCat\",\n&[(\"name\", type_::generic_var(1)), (\"is_cute\", type_::unbound_var(1)),\n(\"linked\", type_::link(type_::int()))])" --- --record(pet_cat, {name :: any(), is_cute :: any(), linked :: integer()}). +-record(pet_cat, { + name :: any(), + is_cute :: any(), + linked :: integer() +}). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__reserved__build_in_erlang_type_escaping.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__reserved__build_in_erlang_type_escaping.snap index 62bc9db38..ca7e398c1 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__reserved__build_in_erlang_type_escaping.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__reserved__build_in_erlang_type_escaping.snap @@ -7,8 +7,7 @@ pub type Map ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([map_/0]). -type map_() :: any(). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__reserved__escape_erlang_reserved_keywords_in_type_names.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__reserved__escape_erlang_reserved_keywords_in_type_names.snap index 0cd8b02ff..d37ab75e8 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__reserved__escape_erlang_reserved_keywords_in_type_names.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__reserved__escape_erlang_reserved_keywords_in_type_names.snap @@ -35,8 +35,7 @@ pub type Xor { TestXor } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type(['after'/0, 'and'/0, 'andalso'/0, 'band'/0, 'begin'/0, 'bnot'/0, 'bor'/0, 'bsl'/0, 'bsr'/0, 'bxor'/0, 'case'/0, 'catch'/0, 'cond'/0, 'div'/0, 'end'/0, 'fun'/0, 'if'/0, 'let'/0, 'maybe'/0, 'not'/0, 'of'/0, 'or'/0, 'orelse'/0, 'query'/0, 'receive'/0, 'rem'/0, 'try'/0, 'when'/0, 'xor'/0]). -type 'after'() :: test_after. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__ascii_as_unicode_escape_sequence.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__ascii_as_unicode_escape_sequence.snap index 4acee42bb..b2910cfe5 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__ascii_as_unicode_escape_sequence.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__ascii_as_unicode_escape_sequence.snap @@ -11,8 +11,7 @@ pub fn y() -> String { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([y/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat.snap index 9221a5211..3e44f1b98 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 5). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat_many_strings.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat_many_strings.snap index b8ed58c92..963be68f0 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat_many_strings.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat_many_strings.snap @@ -13,36 +13,10 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). -spec main() -> binary(). main() -> - <<"a"/utf8, - "b"/utf8, - "c"/utf8, - "d"/utf8, - "e"/utf8, - "f"/utf8, - "g"/utf8, - "h"/utf8, - "i"/utf8, - "j"/utf8, - "k"/utf8, - "l"/utf8, - "m"/utf8, - "n"/utf8, - "o"/utf8, - "p"/utf8, - "q"/utf8, - "r"/utf8, - "s"/utf8, - "t"/utf8, - "u"/utf8, - "v"/utf8, - "w"/utf8, - "x"/utf8, - "y"/utf8, - "z"/utf8>>. + <<"a"/utf8, "b"/utf8, "c"/utf8, "d"/utf8, "e"/utf8, "f"/utf8, "g"/utf8, "h"/utf8, "i"/utf8, "j"/utf8, "k"/utf8, "l"/utf8, "m"/utf8, "n"/utf8, "o"/utf8, "p"/utf8, "q"/utf8, "r"/utf8, "s"/utf8, "t"/utf8, "u"/utf8, "v"/utf8, "w"/utf8, "x"/utf8, "y"/utf8, "z"/utf8>>. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat_many_strings_in_list.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat_many_strings_in_list.snap index c528612c7..380c0880c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat_many_strings_in_list.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat_many_strings_in_list.snap @@ -13,36 +13,10 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 4). -spec main() -> list(binary()). main() -> - [<<"a"/utf8, - "b"/utf8, - "c"/utf8, - "d"/utf8, - "e"/utf8, - "f"/utf8, - "g"/utf8, - "h"/utf8, - "i"/utf8, - "j"/utf8, - "k"/utf8, - "l"/utf8, - "m"/utf8, - "n"/utf8, - "o"/utf8, - "p"/utf8, - "q"/utf8, - "r"/utf8, - "s"/utf8, - "t"/utf8, - "u"/utf8, - "v"/utf8, - "w"/utf8, - "x"/utf8, - "y"/utf8, - "z"/utf8>>]. + [<<"a"/utf8, "b"/utf8, "c"/utf8, "d"/utf8, "e"/utf8, "f"/utf8, "g"/utf8, "h"/utf8, "i"/utf8, "j"/utf8, "k"/utf8, "l"/utf8, "m"/utf8, "n"/utf8, "o"/utf8, "p"/utf8, "q"/utf8, "r"/utf8, "s"/utf8, "t"/utf8, "u"/utf8, "v"/utf8, "w"/utf8, "x"/utf8, "y"/utf8, "z"/utf8>>]. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat_other_const_concat.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat_other_const_concat.snap index cdfaf662b..2dd5048f1 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat_other_const_concat.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_const_concat_other_const_concat.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 5). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_string_prefix.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_string_prefix.snap index bda635ffc..70bcbe876 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_string_prefix.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_string_prefix.snap @@ -12,26 +12,28 @@ pub fn main(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). -spec main(binary()) -> binary(). main(X) -> - Rest@1 = case X of - <<"m-"/utf8, Rest/binary>> -> Rest; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 20, - 'end' => 47, - pattern_start => 31, - pattern_end => 43}) - end, - Rest@1. + case X of + <<"m-"/utf8, Rest/binary>> -> + Rest; + + _value -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value, + start => 20, + 'end' => 47, + pattern_start => 31, + pattern_end => 43 + }) + end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_string_prefix_discar.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_string_prefix_discar.snap index 6619d636a..ca98d8034 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_string_prefix_discar.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__assert_string_prefix_discar.snap @@ -11,25 +11,28 @@ pub fn main(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). -spec main(binary()) -> binary(). main(X) -> case X of - <<"m-"/utf8, _/binary>> -> X; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3, - value => _assert_fail, - start => 20, - 'end' => 44, - pattern_start => 31, - pattern_end => 40}) + <<"m-"/utf8, _/binary>> = _value -> + _value; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3, + value => _value@1, + start => 20, + 'end' => 44, + pattern_start => 31, + pattern_end => 40 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat.snap index c9ae7b581..987d9d05d 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat.snap @@ -11,8 +11,7 @@ pub fn go(x, y) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/2]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_3_variables.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_3_variables.snap index 1093b6725..c4d4bf55f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_3_variables.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_3_variables.snap @@ -11,8 +11,7 @@ pub fn go(x, y, z) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/3]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_constant.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_constant.snap index 8d999512f..31376e134 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_constant.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_constant.snap @@ -14,8 +14,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 5). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_constant_fn.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_constant_fn.snap index 027f7f4f3..ea341ad0d 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_constant_fn.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_constant_fn.snap @@ -17,8 +17,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 4). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_function_call.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_function_call.snap index 1cb604eba..e1e8f10c4 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_function_call.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__concat_function_call.snap @@ -15,8 +15,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__discard_concat_rest_pattern.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__discard_concat_rest_pattern.snap index 22019e4e2..1fd991225 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__discard_concat_rest_pattern.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__discard_concat_rest_pattern.snap @@ -14,8 +14,7 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__not_unicode_escape_sequence.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__not_unicode_escape_sequence.snap index 7764bfb06..59b998c57 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__not_unicode_escape_sequence.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__not_unicode_escape_sequence.snap @@ -11,8 +11,7 @@ pub fn not_unicode_escape_sequence() -> String { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([not_unicode_escape_sequence/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__not_unicode_escape_sequence2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__not_unicode_escape_sequence2.snap index 059129e05..61d93cbf9 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__not_unicode_escape_sequence2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__not_unicode_escape_sequence2.snap @@ -11,8 +11,7 @@ pub fn not_unicode_escape_sequence() -> String { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([not_unicode_escape_sequence/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__pipe_concat.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__pipe_concat.snap index ac400c5de..a9e7f5b1d 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__pipe_concat.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__pipe_concat.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). @@ -28,10 +27,9 @@ id(X) -> -spec main() -> binary(). main() -> <<(begin - _pipe = <<""/utf8>>, - id(_pipe) - end)/binary, - (begin - _pipe@1 = <<""/utf8>>, - id(_pipe@1) - end)/binary>>. + _pipe = <<""/utf8>>, + id(_pipe) + end)/binary, (begin + _pipe@1 = <<""/utf8>>, + id(_pipe@1) + end)/binary>>. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__rest_variable_rewriting.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__rest_variable_rewriting.snap index 80d5f8752..7c0a8e47b 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__rest_variable_rewriting.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__rest_variable_rewriting.snap @@ -14,8 +14,7 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_of_number_concat.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_of_number_concat.snap index 27752e91f..b9ab82e85 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_of_number_concat.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_of_number_concat.snap @@ -11,8 +11,7 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix.snap index ccd33093a..2f81c0427 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix.snap @@ -14,8 +14,7 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment.snap index 4b775794e..c661cfbcd 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment.snap @@ -14,8 +14,7 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_not_unicode_escape_sequence.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_not_unicode_escape_sequence.snap index f6f4966c8..481859bb9 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_not_unicode_escape_sequence.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_not_unicode_escape_sequence.snap @@ -23,8 +23,7 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_with_escape_sequences.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_with_escape_sequences.snap index 53fb2b40a..0444909a9 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_with_escape_sequences.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_with_escape_sequences.snap @@ -30,8 +30,7 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_with_guard.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_with_guard.snap index 151dd8a20..b55d99d88 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_with_guard.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_with_guard.snap @@ -15,8 +15,7 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_with_multiple_subjects.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_with_multiple_subjects.snap index e72eb4fd0..4d43ca106 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_with_multiple_subjects.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_assignment_with_multiple_subjects.snap @@ -14,8 +14,7 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_not_unicode_escape_sequence.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_not_unicode_escape_sequence.snap index 12fbb62cd..65baf6f1f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_not_unicode_escape_sequence.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_not_unicode_escape_sequence.snap @@ -23,8 +23,7 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_shadowing.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_shadowing.snap index 0418d5f61..3641547a9 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_shadowing.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_shadowing.snap @@ -14,8 +14,7 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_with_escape_sequences.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_with_escape_sequences.snap index 6339a8395..64d8d92ee 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_with_escape_sequences.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__string_prefix_with_escape_sequences.snap @@ -30,8 +30,7 @@ pub fn go(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode1.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode1.snap index f7f50e879..6ca93a8cb 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode1.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode1.snap @@ -11,8 +11,7 @@ pub fn emoji() -> String { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([emoji/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode2.snap index b7621c36e..ceb2f0139 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode2.snap @@ -11,8 +11,7 @@ pub fn y_with_dieresis() -> String { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([y_with_dieresis/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode3.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode3.snap index c2ea3e3ca..e2e1840c6 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode3.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode3.snap @@ -11,8 +11,7 @@ pub fn y_with_dieresis_with_slash() -> String { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([y_with_dieresis_with_slash/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_concat1.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_concat1.snap index ca4d99544..a17133fad 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_concat1.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_concat1.snap @@ -11,8 +11,7 @@ pub fn main(x) -> String { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_concat2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_concat2.snap index a7a89c24d..520309cb7 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_concat2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_concat2.snap @@ -11,8 +11,7 @@ pub fn main(x) -> String { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_concat3.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_concat3.snap index ffecde383..42d4380af 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_concat3.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_concat3.snap @@ -11,8 +11,7 @@ pub fn main(x) -> String { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_escape_sequence_6_digits.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_escape_sequence_6_digits.snap index d2f4a1115..44b3bfa76 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_escape_sequence_6_digits.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__strings__unicode_escape_sequence_6_digits.snap @@ -11,8 +11,7 @@ pub fn unicode_escape_sequence_6_digits() -> String { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([unicode_escape_sequence_6_digits/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__named.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__named.snap index bee53d34c..2c58cd925 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__named.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__named.snap @@ -11,16 +11,17 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> any(). main() -> - erlang:error(#{gleam_error => todo, - message => <<"testing"/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3}). + erlang:error(#{ + gleam_error => todo, + message => <<"testing"/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3 + }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__piped.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__piped.snap index f389651a3..40d946001 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__piped.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__piped.snap @@ -13,23 +13,26 @@ expression: "\n pub fn main() {\n \"lets\"\n |> todo as \"pipe\"\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> any(). main() -> _pipe = <<"lets"/utf8>>, - _pipe@1 = (erlang:error(#{gleam_error => todo, - message => <<"pipe"/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 4}))(_pipe), - (erlang:error(#{gleam_error => todo, - message => <<"other todo"/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 5}))(_pipe@1). + _pipe@1 = (erlang:error(#{ + gleam_error => todo, + message => <<"pipe"/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 4 + }))(_pipe), + (erlang:error(#{ + gleam_error => todo, + message => <<"other todo"/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 5 + }))(_pipe@1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__plain.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__plain.snap index 7d2c429ac..6e28fda0b 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__plain.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__plain.snap @@ -11,16 +11,17 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> any(). main() -> - erlang:error(#{gleam_error => todo, - message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3}). + erlang:error(#{ + gleam_error => todo, + message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3 + }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__todo_as.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__todo_as.snap index 05f3f8c68..8fe51998a 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__todo_as.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__todo_as.snap @@ -11,16 +11,17 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> any(). main() -> - erlang:error(#{gleam_error => todo, - message => <<"wibble"/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 3}). + erlang:error(#{ + gleam_error => todo, + message => <<"wibble"/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 3 + }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__todo_as_function.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__todo_as_function.snap index 4133e7662..7ffa8ae93 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__todo_as_function.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__todo__todo_as_function.snap @@ -14,8 +14,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([retstring/0, main/0]). -file("project/test/my/mod.gleam", 2). @@ -26,9 +25,11 @@ retstring() -> -file("project/test/my/mod.gleam", 5). -spec main() -> any(). main() -> - erlang:error(#{gleam_error => todo, - message => (<<(retstring())/binary, "wobble"/utf8>>), - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 6}). + erlang:error(#{ + gleam_error => todo, + message => <<(retstring())/binary, "wobble"/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 6 + }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__tuples__simple_tuple.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__tuples__simple_tuple.snap new file mode 100644 index 000000000..8533ce114 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__tuples__simple_tuple.snap @@ -0,0 +1,20 @@ +--- +source: compiler-core/src/erlang/tests/tuples.rs +expression: "\npub fn main() {\n #(1, 2, False)\n}\n" +--- +----- SOURCE CODE + +pub fn main() { + #(1, 2, False) +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/0]). + +-file("project/test/my/mod.gleam", 2). +-spec main() -> {integer(), integer(), boolean()}. +main() -> + {1, 2, false}. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__tuples__tuple_index.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__tuples__tuple_index.snap new file mode 100644 index 000000000..e08cb0c9e --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__tuples__tuple_index.snap @@ -0,0 +1,22 @@ +--- +source: compiler-core/src/erlang/tests/tuples.rs +expression: "\npub fn main() {\n let a = #(1, 2, 3)\n a.0\n}\n" +--- +----- SOURCE CODE + +pub fn main() { + let a = #(1, 2, 3) + a.0 +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/0]). + +-file("project/test/my/mod.gleam", 2). +-spec main() -> integer(). +main() -> + A = {1, 2, 3}, + erlang:element(1, A). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__tuples__tuple_index_2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__tuples__tuple_index_2.snap new file mode 100644 index 000000000..f608c737b --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__tuples__tuple_index_2.snap @@ -0,0 +1,20 @@ +--- +source: compiler-core/src/erlang/tests/tuples.rs +expression: "\npub fn main() {\n #(1, 2, 3).1\n}\n" +--- +----- SOURCE CODE + +pub fn main() { + #(1, 2, 3).1 +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/0]). + +-file("project/test/my/mod.gleam", 2). +-spec main() -> integer(). +main() -> + erlang:element(2, {1, 2, 3}). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__tuples__tuple_with_pipeline.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__tuples__tuple_with_pipeline.snap new file mode 100644 index 000000000..2e2bfcf4d --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__tuples__tuple_with_pipeline.snap @@ -0,0 +1,31 @@ +--- +source: compiler-core/src/erlang/tests/tuples.rs +expression: "\npub fn main(x) {\n #(1 |> wibble |> wibble, False)\n}\n\nfn wibble(n) { n }\n" +--- +----- SOURCE CODE + +pub fn main(x) { + #(1 |> wibble |> wibble, False) +} + +fn wibble(n) { n } + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/1]). + +-file("project/test/my/mod.gleam", 6). +-spec wibble(K) -> K. +wibble(N) -> + N. + +-file("project/test/my/mod.gleam", 2). +-spec main(any()) -> {integer(), boolean()}. +main(X) -> + {begin + _pipe = 1, + _pipe@1 = wibble(_pipe), + wibble(_pipe@1) + end, false}. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__tuples__tuple_with_record_update.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__tuples__tuple_with_record_update.snap new file mode 100644 index 000000000..883868ac7 --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__tuples__tuple_with_record_update.snap @@ -0,0 +1,26 @@ +--- +source: compiler-core/src/erlang/tests/tuples.rs +expression: "\npub type Wibble { Wibble (a: Int, b: Int) }\npub fn main() {\n let base = Wibble(1, 2)\n #(Wibble(..base, a: 2), False)\n}\n" +--- +----- SOURCE CODE + +pub type Wibble { Wibble (a: Int, b: Int) } +pub fn main() { + let base = Wibble(1, 2) + #(Wibble(..base, a: 2), False) +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([main/0]). +-export_type([wibble/0]). + +-type wibble() :: {wibble, integer(), integer()}. + +-file("project/test/my/mod.gleam", 3). +-spec main() -> {wibble(), boolean()}. +main() -> + Base = {wibble, 1, 2}, + {{wibble, 2, erlang:element(3, Base)}, false}. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_named_args_count_once.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_named_args_count_once.snap index 3f318f4c4..c363a1e4b 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_named_args_count_once.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_named_args_count_once.snap @@ -15,8 +15,7 @@ expression: "\n pub type Wibble(a, b) {\n Wibble(a, b)\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([wibble/0]). -export_type([wibble/2]). @@ -25,9 +24,11 @@ expression: "\n pub type Wibble(a, b) {\n Wibble(a, b)\n -file("project/test/my/mod.gleam", 6). -spec wibble() -> wibble(K, K). wibble() -> - erlang:error(#{gleam_error => todo, - message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"wibble"/utf8>>, - line => 7}). + erlang:error(#{ + gleam_error => todo, + message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"wibble"/utf8>>, + line => 7 + }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_nested_named_args_count_once.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_nested_named_args_count_once.snap index 075d30620..14fe6c1e2 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_nested_named_args_count_once.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_nested_named_args_count_once.snap @@ -15,8 +15,7 @@ expression: "\n pub type Wibble(a, b) {\n Wibble(a, b)\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([wibble/0]). -export_type([wibble/2]). @@ -25,9 +24,11 @@ expression: "\n pub type Wibble(a, b) {\n Wibble(a, b)\n -file("project/test/my/mod.gleam", 6). -spec wibble() -> wibble(K, wibble(K, any())). wibble() -> - erlang:error(#{gleam_error => todo, - message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"wibble"/utf8>>, - line => 7}). + erlang:error(#{ + gleam_error => todo, + message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"wibble"/utf8>>, + line => 7 + }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_nested_result_type_count_once.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_nested_result_type_count_once.snap index e55d7026d..40cad5b65 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_nested_result_type_count_once.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_nested_result_type_count_once.snap @@ -15,8 +15,7 @@ expression: "\n pub type Wibble(a) {\n Oops\n }\n\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([wibble/0]). -export_type([wibble/1]). @@ -25,9 +24,11 @@ expression: "\n pub type Wibble(a) {\n Oops\n }\n\n -file("project/test/my/mod.gleam", 6). -spec wibble() -> {ok, any()} | {error, wibble(any())}. wibble() -> - erlang:error(#{gleam_error => todo, - message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"wibble"/utf8>>, - line => 7}). + erlang:error(#{ + gleam_error => todo, + message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"wibble"/utf8>>, + line => 7 + }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_tuple_type_params_count_twice.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_tuple_type_params_count_twice.snap index cdb883c54..a26f90cbb 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_tuple_type_params_count_twice.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__custom_type_tuple_type_params_count_twice.snap @@ -15,8 +15,7 @@ expression: "\n pub type Wibble(a, b) {\n Wibble(a, b)\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([wibble/0]). -export_type([wibble/2]). @@ -25,9 +24,11 @@ expression: "\n pub type Wibble(a, b) {\n Wibble(a, b)\n -file("project/test/my/mod.gleam", 6). -spec wibble() -> {K, wibble(K, any())}. wibble() -> - erlang:error(#{gleam_error => todo, - message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"wibble"/utf8>>, - line => 7}). + erlang:error(#{ + gleam_error => todo, + message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"wibble"/utf8>>, + line => 7 + }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__nested_result_type_count_once.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__nested_result_type_count_once.snap index e49c35014..381807308 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__nested_result_type_count_once.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__nested_result_type_count_once.snap @@ -11,16 +11,17 @@ expression: "\n pub fn wibble() -> Result(a, Result(a, b)) {\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([wibble/0]). -file("project/test/my/mod.gleam", 2). -spec wibble() -> {ok, any()} | {error, {ok, any()} | {error, any()}}. wibble() -> - erlang:error(#{gleam_error => todo, - message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"wibble"/utf8>>, - line => 3}). + erlang:error(#{ + gleam_error => todo, + message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"wibble"/utf8>>, + line => 3 + }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__result_type_count_once.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__result_type_count_once.snap index 19b7a68b7..07f3918da 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__result_type_count_once.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__result_type_count_once.snap @@ -11,16 +11,17 @@ expression: "\n pub fn wibble() -> Result(a, a) {\n todo\n ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([wibble/0]). -file("project/test/my/mod.gleam", 2). -spec wibble() -> {ok, any()} | {error, any()}. wibble() -> - erlang:error(#{gleam_error => todo, - message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"wibble"/utf8>>, - line => 3}). + erlang:error(#{ + gleam_error => todo, + message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"wibble"/utf8>>, + line => 3 + }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__result_type_inferred_count_once.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__result_type_inferred_count_once.snap index 2033e3641..fea06aa15 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__result_type_inferred_count_once.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__result_type_inferred_count_once.snap @@ -19,8 +19,7 @@ expression: "\n pub fn wibble() {\n let assert Ok(_) = wobble( ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([wobble/0, wibble/0]). -export_type([wobble/1]). @@ -29,29 +28,34 @@ expression: "\n pub fn wibble() {\n let assert Ok(_) = wobble( -file("project/test/my/mod.gleam", 10). -spec wobble() -> {ok, any()} | {error, wobble(any())}. wobble() -> - erlang:error(#{gleam_error => todo, - message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"wobble"/utf8>>, - line => 11}). + erlang:error(#{ + gleam_error => todo, + message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"wobble"/utf8>>, + line => 11 + }). -file("project/test/my/mod.gleam", 2). -spec wibble() -> {ok, any()} | {error, wobble(any())}. wibble() -> - _assert_subject = wobble(), - case _assert_subject of - {ok, _} -> _assert_subject; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"wibble"/utf8>>, - line => 3, - value => _assert_fail, - start => 39, - 'end' => 66, - pattern_start => 50, - pattern_end => 55}) + case wobble() of + {ok, _} = _value -> + _value; + + _value@1 -> + erlang:error(#{ + gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"wibble"/utf8>>, + line => 3, + value => _value@1, + start => 39, + 'end' => 66, + pattern_start => 50, + pattern_end => 55 + }) end. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__tuple_type_params_count_twice.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__tuple_type_params_count_twice.snap index 65c995a61..65776c9e9 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__tuple_type_params_count_twice.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__type_params__tuple_type_params_count_twice.snap @@ -11,16 +11,17 @@ expression: "\n pub fn wibble() -> #(a, b) {\n todo\n } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([wibble/0]). -file("project/test/my/mod.gleam", 2). -spec wibble() -> {any(), any()}. wibble() -> - erlang:error(#{gleam_error => todo, - message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"wibble"/utf8>>, - line => 3}). + erlang:error(#{ + gleam_error => todo, + message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"wibble"/utf8>>, + line => 3 + }). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___arity_1.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___arity_1.snap index d63ccb020..f207e6ae8 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___arity_1.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___arity_1.snap @@ -17,8 +17,7 @@ fn pair(f) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 7). @@ -30,4 +29,6 @@ pair(F) -> -file("project/test/my/mod.gleam", 2). -spec main() -> {integer(), integer()}. main() -> - pair(fun() -> 123 end). + pair(fun() -> + 123 + end). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___arity_2.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___arity_2.snap index 3594c4350..1f09fe2a9 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___arity_2.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___arity_2.snap @@ -17,8 +17,7 @@ fn pair(x, f) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 7). @@ -30,4 +29,6 @@ pair(X, F) -> -file("project/test/my/mod.gleam", 2). -spec main() -> {float(), integer()}. main() -> - pair(1.0, fun() -> 123 end). + pair(1.0, fun() -> + 123 + end). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___arity_3.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___arity_3.snap index 7911b9441..6592633a1 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___arity_3.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___arity_3.snap @@ -17,8 +17,7 @@ fn trip(x, y, f) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 7). @@ -30,4 +29,6 @@ trip(X, Y, F) -> -file("project/test/my/mod.gleam", 2). -spec main() -> {float(), binary(), integer()}. main() -> - trip(1.0, <<""/utf8>>, fun() -> 123 end). + trip(1.0, <<""/utf8>>, fun() -> + 123 + end). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___no_callback_body.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___no_callback_body.snap index 427ee32b1..bb57fa58e 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___no_callback_body.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___no_callback_body.snap @@ -12,17 +12,22 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). -spec main() -> any(). main() -> - Thingy = fun(F) -> F() end, - Thingy(fun() -> erlang:error(#{gleam_error => todo, - message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, - file => <>, - module => <<"my/mod"/utf8>>, - function => <<"main"/utf8>>, - line => 4}) end). + Thingy = fun(F) -> + F() + end, + Thingy(fun() -> + erlang:error(#{ + gleam_error => todo, + message => <<"`todo` expression evaluated. This code has not yet been implemented."/utf8>>, + file => <<"project/test/my/mod.gleam"/utf8>>, + module => <<"my/mod"/utf8>>, + function => <<"main"/utf8>>, + line => 4 + }) + end). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___pipeline_that_returns_fn.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___pipeline_that_returns_fn.snap index 1277cf87d..a60471287 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___pipeline_that_returns_fn.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__use___pipeline_that_returns_fn.snap @@ -16,14 +16,15 @@ pub fn add(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([add/1, main/0]). -file("project/test/my/mod.gleam", 7). -spec add(integer()) -> fun((fun(() -> integer())) -> integer()). add(X) -> - fun(F) -> F() + X end. + fun(F) -> + F() + X + end. -file("project/test/my/mod.gleam", 2). -spec main() -> integer(). @@ -31,4 +32,6 @@ main() -> begin _pipe = 1, add(_pipe) - end(fun() -> 1 end). + end(fun() -> + 1 + end). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__anon_external_fun_name_escaping.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__anon_external_fun_name_escaping.snap index b2e4118d6..a779f67b8 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__anon_external_fun_name_escaping.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__anon_external_fun_name_escaping.snap @@ -13,8 +13,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 5). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__blocks_are_scopes.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__blocks_are_scopes.snap index 70e6c056e..ee5bc46d9 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__blocks_are_scopes.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__blocks_are_scopes.snap @@ -15,8 +15,7 @@ pub fn main() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__discarded.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__discarded.snap index 8e8b36301..f0bb84038 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__discarded.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__discarded.snap @@ -11,8 +11,7 @@ pub fn go() { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/0]). -file("project/test/my/mod.gleam", 1). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__module_const_vars.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__module_const_vars.snap index c37017d29..84d099282 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__module_const_vars.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__module_const_vars.snap @@ -17,8 +17,7 @@ pub fn use_compound() { compound.1(compound.0) } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([use_int_alias/0, use_int_identity_alias/0, use_compound/0]). -file("project/test/my/mod.gleam", 3). @@ -39,6 +38,4 @@ use_int_identity_alias() -> -file("project/test/my/mod.gleam", 10). -spec use_compound() -> integer(). use_compound() -> - (erlang:element(2, {42, fun int_identity/1, fun int_identity/1}))( - erlang:element(1, {42, fun int_identity/1, fun int_identity/1}) - ). + (erlang:element(2, {42, fun int_identity/1, fun int_identity/1}))(erlang:element(1, {42, fun int_identity/1, fun int_identity/1})). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_and_call.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_and_call.snap index c7aa02b85..d0c676325 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_and_call.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_and_call.snap @@ -11,8 +11,7 @@ pub fn main(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_let.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_let.snap index a8352b658..11dca604f 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_let.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_let.snap @@ -16,8 +16,7 @@ pub fn go(a) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([go/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_param.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_param.snap index 95e42dd98..33914a93c 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_param.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_param.snap @@ -10,12 +10,13 @@ fn(board) { board } ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 1). -spec main(I) -> I. main(Board) -> - fun(Board@1) -> Board@1 end, + fun(Board@1) -> + Board@1 + end, Board. diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_pipe.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_pipe.snap index 25648ad33..dac0cbb5d 100644 --- a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_pipe.snap +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__shadow_pipe.snap @@ -12,8 +12,7 @@ pub fn main(x) { ----- COMPILED ERLANG -module(my@mod). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "project/test/my/mod.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/1]). -file("project/test/my/mod.gleam", 2). diff --git a/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__simple_variable.snap b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__simple_variable.snap new file mode 100644 index 000000000..056a7c70c --- /dev/null +++ b/compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__variables__simple_variable.snap @@ -0,0 +1,30 @@ +--- +source: compiler-core/src/erlang/tests/variables.rs +expression: "\npub fn wibble() {\n let x = 1\n let y = {\n let a = 1\n a\n }\n y\n}\n" +--- +----- SOURCE CODE + +pub fn wibble() { + let x = 1 + let y = { + let a = 1 + a + } + y +} + + +----- COMPILED ERLANG +-module(my@mod). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). +-export([wibble/0]). + +-file("project/test/my/mod.gleam", 2). +-spec wibble() -> integer(). +wibble() -> + X = 1, + Y = begin + A = 1, + A + end, + Y. diff --git a/compiler-core/src/erlang/tests/tuples.rs b/compiler-core/src/erlang/tests/tuples.rs new file mode 100644 index 000000000..96cb643c8 --- /dev/null +++ b/compiler-core/src/erlang/tests/tuples.rs @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2026 The Gleam contributors + +use crate::assert_erl; + +#[test] +fn simple_tuple() { + assert_erl!( + " +pub fn main() { + #(1, 2, False) +} +" + ) +} + +#[test] +fn tuple_with_record_update() { + assert_erl!( + " +pub type Wibble { Wibble (a: Int, b: Int) } +pub fn main() { + let base = Wibble(1, 2) + #(Wibble(..base, a: 2), False) +} +" + ) +} + +#[test] +fn tuple_with_pipeline() { + assert_erl!( + " +pub fn main(x) { + #(1 |> wibble |> wibble, False) +} + +fn wibble(n) { n } +" + ) +} + +#[test] +fn tuple_index() { + assert_erl!( + " +pub fn main() { + let a = #(1, 2, 3) + a.0 +} +" + ) +} + +#[test] +fn tuple_index_2() { + assert_erl!( + " +pub fn main() { + #(1, 2, 3).1 +} +" + ) +} diff --git a/compiler-core/src/erlang/tests/variables.rs b/compiler-core/src/erlang/tests/variables.rs index 14e06c4c5..505efb335 100644 --- a/compiler-core/src/erlang/tests/variables.rs +++ b/compiler-core/src/erlang/tests/variables.rs @@ -3,6 +3,22 @@ use crate::assert_erl; +#[test] +fn simple_variable() { + assert_erl!( + r#" +pub fn wibble() { + let x = 1 + let y = { + let a = 1 + a + } + y +} +"# + ); +} + #[test] fn shadow_let() { // https://github.com/gleam-lang/gleam/issues/333 diff --git a/compiler-core/src/exhaustiveness.rs b/compiler-core/src/exhaustiveness.rs index e90950e71..81ae0fdce 100644 --- a/compiler-core/src/exhaustiveness.rs +++ b/compiler-core/src/exhaustiveness.rs @@ -4172,9 +4172,6 @@ mod representable_with_bits_test { #[test] fn zero_representable_with_bits_test() { - for i in 0..12 { - println!("{i}: {}", BigInt::from(i).bits()); - } assert!(!representable_with_bits(&BigInt::ZERO, 0, false)); assert!(!representable_with_bits(&BigInt::ZERO, 0, true)); diff --git a/compiler-core/src/lib.rs b/compiler-core/src/lib.rs index 296fecdb3..d9f3d3b42 100644 --- a/compiler-core/src/lib.rs +++ b/compiler-core/src/lib.rs @@ -85,7 +85,6 @@ pub mod metadata; pub mod package_interface; pub mod parse; pub mod paths; -pub mod pretty; pub mod requirement; pub mod strings; pub mod type_; diff --git a/compiler-core/src/pretty.rs b/compiler-core/src/pretty.rs deleted file mode 100644 index c1ce9d9c8..000000000 --- a/compiler-core/src/pretty.rs +++ /dev/null @@ -1,922 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2018 The Gleam contributors - -//! This module implements the functionality described in -//! ["Strictly Pretty" (2000) by Christian Lindig][0], with a few -//! extensions. -//! -//! This module is heavily influenced by Elixir's Inspect.Algebra and -//! JavaScript's Prettier. -//! -//! [0]: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.34.2200 -//! -//! ## Extensions -//! -//! - `ForcedBreak` from Elixir. -//! - `FlexBreak` from Elixir. -//! -//! The way this module works is fairly simple conceptually, however the actual -//! behaviour in practice can be hard to wrap one's head around. -//! -//! The basic premise is the `Document` type, which is a tree structure, -//! containing some text as well as information on how it can be formatted. -//! Once the document is constructed, it can be printed using the -//! `to_pretty_string` function. -//! -//! It will then traverse the tree, and construct -//! a string, attempting to wrap lines to that they do not exceed the line length -//! limit specified. Where and when it wraps lines is determined by the structure -//! of the `Document` itself. -//! -#![allow(clippy::wrong_self_convention)] - -#[cfg(test)] -mod tests; - -use std::{cell::RefCell, rc::Rc}; - -use ecow::{EcoString, eco_format}; -use itertools::Itertools; -use num_bigint::BigInt; -use unicode_segmentation::UnicodeSegmentation; - -use crate::{Result, io::Utf8Writer}; - -/// Join multiple documents together in a vector. This macro calls the `to_doc` -/// method on each element, providing a concise way to write a document sequence. -/// For example: -/// -/// ```rust:norun -/// docvec!["Hello", line(), "world!"] -/// ``` -/// -/// Note: each document in a docvec is not separated in any way: the formatter -/// will never break a line unless a `Document::Break` or `Document::Line` -/// is used. Therefore, `docvec!["a", "b", "c"]` is equivalent to -/// `"abc".to_doc()`. -/// -#[macro_export] -macro_rules! docvec { - () => { - Document::Vec(Vec::new()) - }; - - // A docvec![] with a single element - ($first:expr $(,)?) => { - Document::Vec(vec![$first.to_doc()]) - }; - - // A docvec![] with multiple elements. - ($first:expr, $($rest:expr),+ $(,)?) => { - // A document that looks like this: `Vec[Vec[..rest], ..other_rest]` - // is exactly the same as a flat: `Vec[..rest, ..other_rest]`. - // So in case a `docvec!` starts with a `Vec` we flatten it out to avoid - // having deeply nested documents. - match $first.to_doc() { - Document::Vec(mut vec) => { - $( - vec.push($rest.to_doc()); - )* - Document::Vec(vec) - }, - first => Document::Vec(vec![first, $($rest.to_doc()),+]) - } - }; -} - -/// Coerce a value into a Document. -/// Note we do not implement this for String as a slight pressure to favour str -/// over String. -pub trait Documentable<'a> { - fn to_doc(self) -> Document<'a>; -} - -impl<'a> Documentable<'a> for char { - fn to_doc(self) -> Document<'a> { - Document::eco_string(eco_format!("{self}")) - } -} - -impl<'a> Documentable<'a> for &'a str { - fn to_doc(self) -> Document<'a> { - Document::str(self) - } -} - -impl<'a> Documentable<'a> for EcoString { - fn to_doc(self) -> Document<'a> { - Document::eco_string(self) - } -} - -impl<'a> Documentable<'a> for &EcoString { - fn to_doc(self) -> Document<'a> { - Document::eco_string(self.clone()) - } -} - -impl<'a> Documentable<'a> for isize { - fn to_doc(self) -> Document<'a> { - Document::eco_string(eco_format!("{self}")) - } -} - -impl<'a> Documentable<'a> for i64 { - fn to_doc(self) -> Document<'a> { - Document::eco_string(eco_format!("{self}")) - } -} - -impl<'a> Documentable<'a> for usize { - fn to_doc(self) -> Document<'a> { - Document::eco_string(eco_format!("{self}")) - } -} - -impl<'a> Documentable<'a> for f64 { - fn to_doc(self) -> Document<'a> { - Document::eco_string(eco_format!("{self:?}")) - } -} - -impl<'a> Documentable<'a> for u64 { - fn to_doc(self) -> Document<'a> { - Document::eco_string(eco_format!("{self:?}")) - } -} - -impl<'a> Documentable<'a> for u32 { - fn to_doc(self) -> Document<'a> { - Document::eco_string(eco_format!("{self}")) - } -} - -impl<'a> Documentable<'a> for u16 { - fn to_doc(self) -> Document<'a> { - Document::eco_string(eco_format!("{self}")) - } -} - -impl<'a> Documentable<'a> for u8 { - fn to_doc(self) -> Document<'a> { - Document::eco_string(eco_format!("{self}")) - } -} - -impl<'a> Documentable<'a> for BigInt { - fn to_doc(self) -> Document<'a> { - Document::eco_string(eco_format!("{self}")) - } -} - -impl<'a> Documentable<'a> for Document<'a> { - fn to_doc(self) -> Document<'a> { - self - } -} - -impl<'a> Documentable<'a> for Vec> { - fn to_doc(self) -> Document<'a> { - Document::Vec(self) - } -} - -impl<'a, D: Documentable<'a>> Documentable<'a> for Option { - fn to_doc(self) -> Document<'a> { - self.map(Documentable::to_doc).unwrap_or_else(nil) - } -} - -/// Joins an iterator into a single document, in the same way as `docvec!`. -pub fn concat<'a>(docs: impl IntoIterator>) -> Document<'a> { - Document::Vec(docs.into_iter().collect()) -} - -/// Joins an iterator into a single document, interspersing each element with -/// another document. This is useful for example in argument lists, where a -/// list of arguments must all be separated with a comma. -pub fn join<'a>( - docs: impl IntoIterator>, - separator: Document<'a>, -) -> Document<'a> { - concat(Itertools::intersperse(docs.into_iter(), separator)) -} - -/// A trait that allows for objects to observe the cursor position as it is being formatted. -/// This is useful for any operations that need to track the exact position a document is -/// being written to in a buffer such as for source mapping. -pub trait CursorPositionObserver: std::fmt::Debug { - fn observe_cursor_position(&mut self, line: isize, width: isize); -} - -/// A pretty printable document. A tree structure, made up of text and other -/// elements which determine how it can be formatted. -/// -/// The variants of this enum should probably not be constructed directly, -/// rather use the helper functions of the same names to construct them. -/// For example, use `line()` instead of `Document::Line(1)`. -/// -#[derive(Debug, Clone)] -pub enum Document<'a> { - /// A mandatory linebreak. This is always printed as a string of newlines, - /// equal in length to the number specified. - Line(usize), - - /// Forces the breaks of the wrapped document to be considered as not - /// fitting on a single line. Used in combination with a `Group` it can be - /// used to force its `Break`s to always break. - ForceBroken(Box), - - /// Ignore the next break, forcing it to render as unbroken. - NextBreakFits(Box, NextBreakFitsMode), - - /// A document after which the formatter can insert a newline. This determines - /// where line breaks can occur, outside of hardcoded `Line`s. - /// See `break_` and `flex_break` for usage. - Break { - broken: &'a str, - unbroken: &'a str, - kind: BreakKind, - }, - - /// Join multiple documents together. The documents are not separated in any - /// way: the formatter will only print newlines if `Document::Break` or - /// `Document::Line` is used. - Vec(Vec), - - /// Nests the given document by the given indent, depending on the specified - /// condition. See `Document::nest`, `Document::set_nesting` and - /// `Document::nest_if_broken` for usages. - Nest(isize, NestMode, NestCondition, Box), - - /// Groups a document. When pretty printing a group, the formatter will - /// first attempt to fit the entire group on one line. If it fails, all - /// `break_` documents in the group will render broken. - /// - /// Nested groups are handled separately to their parents, so if the - /// outermost group is broken, any sub-groups might be rendered broken - /// or unbroken, depending on whether they fit on a single line. - Group(Box), - - /// Renders a string slice. This will always render the string verbatim, - /// without any line breaks or other modifications to it. - Str { - string: &'a str, - /// The number of extended grapheme clusters in the string. - /// This is what the pretty printer uses as the width of the string as it - /// is closes to what a human would consider the "length" of a string. - /// - /// Since computing the number of grapheme clusters requires walking over - /// the string we precompute it to avoid iterating through a string over - /// and over again in the pretty printing algorithm. - /// - graphemes: isize, - }, - - /// Renders an `EcoString`. This will always render the string verbatim, - /// without any line breaks or other modifications to it. - EcoString { - string: EcoString, - /// The number of extended grapheme clusters in the string. - /// This is what the pretty printer uses as the width of the string as it - /// is closes to what a human would consider the "length" of a string. - /// - /// Since computing the number of grapheme clusters requires walking over - /// the string we precompute it to avoid iterating through a string over - /// and over again in the pretty printing algorithm. - /// - graphemes: isize, - }, - - /// A string that is not taken into account when determining line length. - /// This is useful for additional formatting text which won't be rendered - /// in the final output, such as ANSI codes or HTML elements. - ZeroWidthString { string: EcoString }, - - /// A node that gets notified of the cursor position as it is being formatted. - /// This allows for processes outside of the final output to be notified of - /// the cursor position and perform actions based on it, such as recording - /// the span of the node in the generated source code for a source mapping. - CursorPositionObserver { - observer: Rc>, - }, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum Mode { - /// The mode used when a group doesn't fit on a single line: when `Broken` - /// the `Break`s inside it will be rendered as newlines, splitting the - /// group. - Broken, - - /// The default mode used when a group can fit on a single line: all its - /// `Break`s will be rendered as their unbroken string and kept on a single - /// line. - Unbroken, - - /// This mode is used by the `NextBreakFit` document to force a break to be - /// considered as broken. - ForcedBroken, - - /// This mode is used to disable a `NextBreakFit` document. - ForcedUnbroken, -} - -/// A flag that can be used to enable or disable a `NextBreakFit` document. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum NextBreakFitsMode { - Enabled, - Disabled, -} - -/// A flag that can be used to conditionally disable a `Nest` document. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum NestCondition { - /// This always applies the nesting. This is a sensible default that will - /// work for most of the cases. - Always, - /// Only applies the nesting if the wrapping `Group` couldn't fit on a - /// single line and has been broken. - IfBroken, -} - -/// Used to change the way nesting of documents work. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum NestMode { - /// If the nesting mode is `Increase`, the current indentation will be - /// increased by the specified value. - Increase, - /// If the nesting mode is `Set`, the current indentation is going to be set - /// to exactly the specified value. - /// - /// `doc.nest(2).set_nesting(0)` - /// "wibble - /// wobble <- no indentation is added! - /// wubble" - Set, -} - -fn fits( - limit: isize, - mut current_width: isize, - mut docs: im::Vector<(isize, Mode, &Document<'_>)>, -) -> bool { - // The `fits` function is going to take each document from the `docs` queue - // and check if those can fit on a single line. In order to do so documents - // are going to be pushed in front of this queue and have to be accompanied - // by additional information: - // - the document indentation, that can be increased by the `Nest` block. - // - the current mode; this is needed to know if a group is being broken or - // not and treat `Break`s differently as a consequence. You can see how - // the behaviour changes in [ref:break-fit]. - // - // The loop might be broken earlier without checking all documents under one - // of two conditions: - // - the documents exceed the line `limit` and surely won't fit - // [ref:document-unfit]. - // - the documents are sure to fit the line - for example, if we meet a - // broken `Break` [ref:break-fit] or a newline [ref:newline-fit]. - loop { - // [tag:document-unfit] If we've exceeded the maximum width allowed for - // a line, it means that the document won't fit on a single line, we can - // break the loop. - if current_width > limit { - return false; - }; - - // We start by checking the first document of the queue. If there's no - // documents then we can safely say that it fits (if reached this point - // it means that the limit wasn't exceeded). - let (indent, mode, document) = match docs.pop_front() { - Some(x) => x, - None => return true, - }; - - match document { - // If a document is marked as `ForceBroken` we can immediately say - // that it doesn't fit, so that every break is going to be - // forcefully broken. - Document::ForceBroken(doc) => match mode { - // If the mode is `ForcedBroken` it means that we have to ignore - // this break [ref:forced-broken], so we go check the inner - // document ignoring the effects of this one. - Mode::ForcedBroken => docs.push_front((indent, mode, doc)), - Mode::Broken | Mode::Unbroken | Mode::ForcedUnbroken => return false, - }, - - // [tag:newline-fit] When we run into a line we know that the - // document has a bit that fits in the current line; if it didn't - // fit (that is, it exceeded the maximum allowed width) the loop - // would have been broken by one of the earlier checks. - Document::Line(_) => return true, - - // If the nesting level is increased we go on checking the wrapped - // document and increase its indentation level based on the nesting - // condition. - Document::Nest(i, nest_mode, condition, doc) => match condition { - NestCondition::IfBroken => docs.push_front((indent, mode, doc)), - NestCondition::Always => { - let new_indent = match nest_mode { - NestMode::Increase => indent + i, - NestMode::Set => *i, - }; - docs.push_front((new_indent, mode, doc)) - } - }, - - // As a general rule, a group fits if it can stay on a single line - // without its breaks being broken down. - Document::Group(doc) => match mode { - // If an outer group was broken, we still try to fit the inner - // group on a single line, that's why for the inner document - // we change the mode back to `Unbroken`. - Mode::Broken => docs.push_front((indent, Mode::Unbroken, doc)), - // Any other mode is preserved as-is: if the mode is forced it - // has to be left unchanged, and if the mode is already unbroken - // there's no need to change it. - Mode::Unbroken | Mode::ForcedBroken | Mode::ForcedUnbroken => { - docs.push_front((indent, mode, doc)) - } - }, - - // When we run into a string we increase the current_width; looping - // back we will check if we've exceeded the maximum allowed width. - Document::Str { graphemes, .. } | Document::EcoString { graphemes, .. } => { - current_width += graphemes - } - - // Zero width strings do nothing: they do not contribute to line length - Document::ZeroWidthString { .. } | Document::CursorPositionObserver { .. } => {} - - // If we get to a break we need to first see if it has to be - // rendered as its unbroken or broken string, depending on the mode. - Document::Break { unbroken, .. } => match mode { - // [tag:break-fit] If the break has to be broken we're done! - // We haven't exceeded the maximum length (otherwise the loop - // iteration would have stopped with one of the earlier checks), - // and - since it needs to be broken - we'll have to go on a new - // line anyway. - // This means that the document inspected so far will fit on a - // single line, thus we return true. - Mode::Broken | Mode::ForcedBroken => return true, - // If the break is not broken then it will be rendered inline as - // its unbroken string, so we treat it exactly as if it were a - // normal string. - Mode::Unbroken | Mode::ForcedUnbroken => current_width += unbroken.len() as isize, - }, - - // The `NextBreakFits` can alter the current mode to `ForcedBroken` - // or `ForcedUnbroken` based on its enabled flag. - Document::NextBreakFits(doc, enabled) => match enabled { - // [tag:disable-next-break] If it is disabled then we check the - // wrapped document changing the mode to `ForcedUnbroken`. - NextBreakFitsMode::Disabled => docs.push_front((indent, Mode::ForcedUnbroken, doc)), - NextBreakFitsMode::Enabled => match mode { - // If we're in `ForcedUnbroken` mode it means that the check - // was disabled by a document wrapping this one - // [ref:disable-next-break]; that's why we do nothing and - // check the wrapped document as if it were a normal one. - Mode::ForcedUnbroken => docs.push_front((indent, mode, doc)), - // [tag:forced-broken] Any other mode is turned into - // `ForcedBroken` so that when we run into a break, the - // response to the question "Does the document fit?" will be - // yes [ref:break-fit]. - // This is why this is called `NextBreakFit` I think. - Mode::Broken | Mode::Unbroken | Mode::ForcedBroken => { - docs.push_front((indent, Mode::ForcedBroken, doc)) - } - }, - }, - - // If there's a sequence of documents we will check each one, one - // after the other to see if - as a whole - they can fit on a single - // line. - Document::Vec(vec) => { - // The array needs to be reversed to preserve the order of the - // documents since each one is pushed _to the front_ of the - // queue of documents to check. - for doc in vec.iter().rev() { - docs.push_front((indent, mode, doc)); - } - } - } - } -} - -/// The kind of line break this `Document::Break` is. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum BreakKind { - /// A `flex_break`. - Flex, - /// A `break_`. - Strict, -} - -fn format( - writer: &mut impl Utf8Writer, - limit: isize, - mut docs: im::Vector<(isize, Mode, &Document<'_>)>, -) -> Result<()> { - let mut line: isize = 0; - let mut width: isize = 0; - // As long as there are documents to print we'll take each one by one and - // output the corresponding string to the given writer. - // - // Each document in the `docs` queue also has an accompanying indentation - // and mode: - // - the indentation is used to keep track of the current indentation, - // you might notice in [ref:format-nest] that it adds documents to the - // queue increasing their current indentation. - // - the mode is used to keep track of the state of the documents inside a - // group. For example, if a group doesn't fit on a single line its - // documents will be split into multiple lines and the mode set to - // `Broken` to keep track of this. - while let Some((indent, mode, document)) = docs.pop_front() { - match document { - // When we run into a line we print the given number of newlines and - // add the indentation required by the given document. - Document::Line(count) => { - for _ in 0..*count { - writer.str_write("\n")?; - } - line += *count as isize; - for _ in 0..indent { - writer.str_write(" ")?; - } - width = indent; - } - - // Flex breaks are NOT conditional to the mode: if the mode is - // already `Unbroken`, then the break is left unbroken (like strict - // breaks); any other mode is ignored. - // A flexible break will only be split if the following documents - // can't fit on the same line; otherwise, it is just displayed as an - // unbroken `Break`. - Document::Break { - broken, - unbroken, - kind: BreakKind::Flex, - } => { - let unbroken_width = width + unbroken.len() as isize; - // Every time we need to check again if the remaining piece can - // fit. If it does, the flexible break is not broken. - if mode == Mode::Unbroken || fits(limit, unbroken_width, docs.clone()) { - writer.str_write(unbroken)?; - width = unbroken_width; - } else { - writer.str_write(broken)?; - writer.str_write("\n")?; - line += 1; - for _ in 0..indent { - writer.str_write(" ")?; - } - width = indent; - } - } - - // Strict breaks are conditional to the mode. They differ from - // flexible break because, if a group gets split - that is the mode - // is `Broken` or `ForceBroken` - ALL of the breaks in that group - // will be split. You can notice the difference with flexible breaks - // because here we only check the mode and then take action; before - // we would try and see if the remaining documents fit on a single - // line before deciding if the (flexible) break can be split or not. - Document::Break { - broken, - unbroken, - kind: BreakKind::Strict, - } => match mode { - // If the mode requires the break to be broken, then its broken - // string is printed, then we start a newline and indent it - // according to the current indentation level. - Mode::Broken | Mode::ForcedBroken => { - writer.str_write(broken)?; - writer.str_write("\n")?; - line += 1; - for _ in 0..indent { - writer.str_write(" ")?; - } - width = indent; - } - // If the mode doesn't require the break to be broken, then its - // unbroken string is printed as if it were a normal string; - // also updating the width of the current line. - Mode::Unbroken | Mode::ForcedUnbroken => { - writer.str_write(unbroken)?; - width += unbroken.len() as isize - } - }, - - // Strings are printed as they are and the current width is - // increased accordingly. - Document::EcoString { string, graphemes } => { - width += graphemes; - writer.str_write(string)?; - } - - Document::Str { string, graphemes } => { - width += graphemes; - writer.str_write(string)?; - } - - Document::ZeroWidthString { string } => { - // We write the string, but do not increment the length - writer.str_write(string)?; - } - - // If multiple documents need to be printed, then they are all - // pushed to the front of the queue and will be printed one by one. - Document::Vec(vec) => { - // Just like `fits`, the elements will be pushed _on the front_ - // of the queue. In order to keep their original order they need - // to be pushed in reverse order. - for doc in vec.iter().rev() { - docs.push_front((indent, mode, doc)); - } - } - - // A `Nest` document doesn't result in anything being printed, its - // only effect is to increase the current nesting level for the - // wrapped document [tag:format-nest]. - Document::Nest(i, nest_mode, condition, doc) => match (condition, mode) { - // The nesting is only applied under two conditions: - // - either the nesting condition is `Always`. - // - or the condition is `IfBroken` and the group was actually - // broken (that is, the current mode is `Broken`). - (NestCondition::Always, _) | (NestCondition::IfBroken, Mode::Broken) => { - let new_indent = match nest_mode { - NestMode::Increase => indent + i, - NestMode::Set => *i, - }; - docs.push_front((new_indent, mode, doc)) - } - // If none of the above conditions is met, then the nesting is - // not applied. - _ => docs.push_front((indent, mode, doc)), - }, - - Document::Group(doc) => { - // When we see a group we first try and see if it can fit on a - // single line without breaking any break; that is why we use - // the `Unbroken` mode here: we want to try to fit everything on - // a single line. - let group_docs = im::vector![(indent, Mode::Unbroken, doc.as_ref())]; - if fits(limit, width, group_docs) { - // If everything can stay on a single line we print the - // wrapped document with the `Unbroken` mode, leaving all - // the group's break as unbroken. - docs.push_front((indent, Mode::Unbroken, doc)); - } else { - // Otherwise, we need to break the group. We print the - // wrapped document changing its mode to `Broken` so that - // all its breaks will be split on newlines. - docs.push_front((indent, Mode::Broken, doc)); - } - } - - // `ForceBroken` and `NextBreakFits` only change the way the `fit` - // function works but do not actually change the formatting of a - // document by themselves. That's why when we run into those we - // just go on printing the wrapped document without altering the - // current mode. - Document::ForceBroken(document) | Document::NextBreakFits(document, _) => { - docs.push_front((indent, mode, document)); - } - - Document::CursorPositionObserver { observer } => { - // Notify the observer of the current cursor position - observer.borrow_mut().observe_cursor_position(line, width); - } - } - } - Ok(()) -} - -/// Renders an empty document. -pub fn nil<'a>() -> Document<'a> { - Document::Vec(vec![]) -} - -/// Renders a single newline. -pub fn line<'a>() -> Document<'a> { - Document::Line(1) -} - -/// Renders a string of newlines, equal in length to the number provided. -pub fn lines<'a>(i: usize) -> Document<'a> { - Document::Line(i) -} - -/// A document after which the formatter can insert a newline. This determines -/// where line breaks can occur, outside of hardcoded `Line`s. -/// -/// If the formatter determines that a group cannot fit on a single line, -/// all breaks in the group will be rendered as broken. Otherwise, they -/// will be rendered as unbroken. -/// -/// A broken `Break` renders the `broken` string, followed by a newline. -/// An unbroken `Break` renders the `unbroken` string by itself. -/// -/// For example: -/// ```rust:norun -/// let document = docvec!["Hello", break_("", ", "), "world!"]; -/// assert_eq!(document.to_pretty_string(20), "Hello, world!"); -/// assert_eq!(document.to_pretty_string(10), "Hello\nworld!"); -/// ``` -/// -pub fn break_<'a>(broken: &'a str, unbroken: &'a str) -> Document<'a> { - Document::Break { - broken, - unbroken, - kind: BreakKind::Strict, - } -} - -/// A document after which the formatter can insert a newline, similar to -/// `break_()`. The difference is that when a group is rendered broken, all -/// breaks are rendered broken. However, `flex_break` decides whether to -/// break or not for every individual `flex_break`. -/// -/// For example: -/// ```rust:norun -/// let with_breaks = docvec!["Hello", break_("", ", "), "pretty", break_("", ", "), "printed!"]; -/// assert_eq!(with_breaks.to_pretty_string(20), "Hello\npretty\nprinted!"); -/// -/// let with_flex_breaks = docvec!["Hello", flex_break("", ", "), "pretty", flex_break("", ", "), "printed!"]; -/// assert_eq!(with_flex_breaks.to_pretty_string(20), "Hello, pretty\nprinted!"); -/// ``` -/// -pub fn flex_break<'a>(broken: &'a str, unbroken: &'a str) -> Document<'a> { - Document::Break { - broken, - unbroken, - kind: BreakKind::Flex, - } -} - -/// A string that is not taken into account when determining line length. -/// This is useful for additional formatting text which won't be rendered -/// in the final output, such as ANSI codes or HTML elements. -/// -/// For example: -/// ```rust:norun -/// let document = docvec!["Hello", zero_width_string("This is a very long string"), break_("", ""), "world"]; -/// assert_eq!(document.to_pretty_string(20), "HelloThis is a very long stringworld"); -/// ``` -/// -pub fn zero_width_string<'a>(string: EcoString) -> Document<'a> { - Document::ZeroWidthString { string } -} - -impl<'a> Document<'a> { - /// Creates a document from a string slice. - pub fn str(string: &'a str) -> Self { - Document::Str { - graphemes: string.graphemes(true).count() as isize, - string, - } - } - - /// Creates a document from an owned `EcoString`. - pub fn eco_string(string: EcoString) -> Self { - Document::EcoString { - graphemes: string.graphemes(true).count() as isize, - string, - } - } - - /// Groups a document. When pretty printing a group, the formatter will - /// first attempt to fit the entire group on one line. If it fails, all - /// `break_` documents in the group will render broken. - /// - /// Nested groups are handled separately to their parents, so if the - /// outermost group is broken, any sub-groups might be rendered broken - /// or unbroken, depending on whether they fit on a single line. - pub fn group(self) -> Self { - match self { - // Grouping a group doesn't change how it will be formatted so we - // can avoid boxing it. - Document::Group(_) - // Grouping a literal string will never change how it's formatted, - // we can avoid boxing it. - | Document::Str { .. } - | Document::EcoString { .. } - | Document::ZeroWidthString { .. } - | Document::CursorPositionObserver { .. } => self, - - Document::Line(_) - | Document::ForceBroken(_) - | Document::NextBreakFits(..) - | Document::Break { .. } - | Document::Vec(_) - | Document::Nest(..) => Self::Group(Box::new(self)), - } - } - - /// Sets the indentation level of a document. - pub fn set_nesting(self, indent: isize) -> Self { - Self::Nest(indent, NestMode::Set, NestCondition::Always, Box::new(self)) - } - - /// Nests a document by a certain indentation. When rending linebreaks, the - /// formatter will print a new line followed by the current indentation. - pub fn nest(self, indent: isize) -> Self { - Self::Nest( - indent, - NestMode::Increase, - NestCondition::Always, - Box::new(self), - ) - } - - /// Nests a document by a certain indentation, but only if the current - /// group is broken. - pub fn nest_if_broken(self, indent: isize) -> Self { - Self::Nest( - indent, - NestMode::Increase, - NestCondition::IfBroken, - Box::new(self), - ) - } - - /// Forces all `break_` and `flex_break` documents in the current group - /// to render broken. - pub fn force_break(self) -> Self { - Self::ForceBroken(Box::new(self)) - } - - /// Force the next `Break` to render unbroken, regardless of whether it - /// fits on the line or not. - pub fn next_break_fits(self, mode: NextBreakFitsMode) -> Self { - Self::NextBreakFits(Box::new(self), mode) - } - - /// Appends one document to another. Equivalent to `docvec![self, second]`, - /// except that it `self` is already a `Document::Vec`, it will append - /// directly to it instead of allocating a new vector. - /// - /// Useful when chaining multiple documents together in a fashion where - /// they cannot be put all into one `docvec!` macro. - pub fn append(self, second: impl Documentable<'a>) -> Self { - match self { - Self::Vec(mut vec) => { - vec.push(second.to_doc()); - Self::Vec(vec) - } - Self::Line(..) - | Self::ForceBroken(..) - | Self::NextBreakFits(..) - | Self::Break { .. } - | Self::Nest(..) - | Self::Group(..) - | Self::Str { .. } - | Self::EcoString { .. } - | Self::ZeroWidthString { .. } - | Self::CursorPositionObserver { .. } => Self::Vec(vec![self, second.to_doc()]), - } - } - - /// Prints a document into a `String`, attempting to limit lines to `limit` - /// characters in length. - pub fn to_pretty_string(self, limit: isize) -> String { - let mut buffer = String::new(); - self.pretty_print(limit, &mut buffer) - .expect("Writing to string buffer failed"); - buffer - } - - /// Surrounds a document in two delimiters. Equivalent to - /// `docvec![option, self, closed]`. - pub fn surround(self, open: impl Documentable<'a>, closed: impl Documentable<'a>) -> Self { - open.to_doc().append(self).append(closed) - } - - /// Prints a document into `writer`, attempting to limit lines to `limit` - /// characters in length. - pub fn pretty_print(&self, limit: isize, writer: &mut impl Utf8Writer) -> Result<()> { - let docs = im::vector![(0, Mode::Unbroken, self)]; - format(writer, limit, docs)?; - Ok(()) - } - - /// Returns true when the document contains no printable characters - /// (whitespace and newlines are considered printable characters). - pub fn is_empty(&self) -> bool { - use Document::*; - match self { - Line(n) => *n == 0, - EcoString { string, .. } => string.is_empty(), - Str { string, .. } => string.is_empty(), - // assuming `broken` and `unbroken` are equivalent - Break { broken, .. } => broken.is_empty(), - ForceBroken(d) | Nest(_, _, _, d) | Group(d) | NextBreakFits(d, _) => d.is_empty(), - Vec(docs) => docs.iter().all(|d| d.is_empty()), - // Zero-width strings don't count towards line length, but they are - // still printed and so are not empty. (Unless their string contents - // is also empty) - ZeroWidthString { string } => string.is_empty(), - CursorPositionObserver { .. } => true, - } - } -} diff --git a/compiler-core/src/pretty/tests.rs b/compiler-core/src/pretty/tests.rs deleted file mode 100644 index 7294dba78..000000000 --- a/compiler-core/src/pretty/tests.rs +++ /dev/null @@ -1,354 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2020 The Gleam contributors - -use super::Document::*; -use super::Mode::*; -use super::*; - -use im::vector; -use pretty_assertions::assert_eq; - -#[test] -fn fits_test() { - // Negative limits never fit - assert!(!fits(-1, 0, vector![])); - - // If no more documents it always fits - assert!(fits(0, 0, vector![])); - - // ForceBreak never fits - let doc = ForceBroken(Box::new(nil())); - assert!(!fits(100, 0, vector![(0, Unbroken, &doc)])); - let doc = ForceBroken(Box::new(nil())); - assert!(!fits(100, 0, vector![(0, Broken, &doc)])); - - // Break in Broken fits always - assert!(fits( - 1, - 0, - vector![( - 0, - Broken, - &Break { - broken: "12", - unbroken: "", - kind: BreakKind::Strict, - } - )] - )); - - // Break in Unbroken mode fits if `unbroken` fits - assert!(fits( - 3, - 0, - vector![( - 0, - Unbroken, - &Break { - broken: "", - unbroken: "123", - kind: BreakKind::Strict, - } - )] - )); - assert!(!fits( - 2, - 0, - vector![( - 0, - Unbroken, - &Break { - broken: "", - unbroken: "123", - kind: BreakKind::Strict, - } - )] - )); - - // Line always fits - assert!(fits(0, 0, vector![(0, Broken, &Line(100))])); - assert!(fits(0, 0, vector![(0, Unbroken, &Line(100))])); - - // String fits if smaller than limit - let doc = Document::str("Hello"); - assert!(fits(5, 0, vector![(0, Broken, &doc)])); - let doc = Document::str("Hello"); - assert!(fits(5, 0, vector![(0, Unbroken, &doc)])); - let doc = Document::str("Hello"); - assert!(!fits(4, 0, vector![(0, Broken, &doc)])); - let doc = Document::str("Hello"); - assert!(!fits(4, 0, vector![(0, Unbroken, &doc)])); - - // Cons fits if combined smaller than limit - let doc = Document::str("1").append(Document::str("2")); - assert!(fits(2, 0, vector![(0, Broken, &doc)])); - let doc = Document::str("1").append(Document::str("2")); - assert!(fits(2, 0, vector![(0, Unbroken, &doc,)])); - let doc = Document::str("1").append(Document::str("2")); - assert!(!fits(1, 0, vector![(0, Broken, &doc)])); - let doc = Document::str("1").append(Document::str("2")); - assert!(!fits(1, 0, vector![(0, Unbroken, &doc)])); - - // Nest fits if combined smaller than limit - let doc = Nest( - 1, - NestMode::Increase, - NestCondition::Always, - Box::new(Document::str("12")), - ); - assert!(fits(2, 0, vector![(0, Broken, &doc)])); - assert!(fits(2, 0, vector![(0, Unbroken, &doc)])); - assert!(!fits(1, 0, vector![(0, Broken, &doc)])); - assert!(!fits(1, 0, vector![(0, Unbroken, &doc)])); - - // Nest fits if combined smaller than limit - let doc = Nest( - 0, - NestMode::Increase, - NestCondition::Always, - Box::new(Document::str("12")), - ); - assert!(fits(2, 0, vector![(0, Broken, &doc)])); - assert!(fits(2, 0, vector![(0, Unbroken, &doc)])); - assert!(!fits(1, 0, vector![(0, Broken, &doc)])); - assert!(!fits(1, 0, vector![(0, Unbroken, &doc)])); - - let doc = ZeroWidthString { - string: "this is a very long string that doesn't count towards line width".into(), - }; - assert!(fits(10, 0, vector![(0, Unbroken, &doc)])); - assert!(fits(10, 9, vector![(0, Unbroken, &doc)])); - let string_doc = "hello!".to_doc(); - assert!(fits( - 10, - 0, - vector![(0, Unbroken, &string_doc), (0, Unbroken, &doc)] - )); -} - -#[test] -fn format_test() { - let doc = Document::str("Hi"); - assert_eq!("Hi", doc.to_pretty_string(10)); - - let doc = Document::str("Hi").append(Document::str(", world!")); - assert_eq!("Hi, world!", doc.clone().to_pretty_string(10)); - - let doc = &Break { - broken: "broken", - unbroken: "unbroken", - kind: BreakKind::Strict, - } - .group(); - assert_eq!("unbroken", doc.clone().to_pretty_string(10)); - - let doc = &Break { - broken: "broken", - unbroken: "unbroken", - kind: BreakKind::Strict, - } - .group(); - assert_eq!("broken\n", doc.clone().to_pretty_string(5)); - - let doc = Nest( - 2, - NestMode::Increase, - NestCondition::Always, - Box::new(Document::str("1").append(Line(1).append(Document::str("2")))), - ); - assert_eq!("1\n 2", doc.to_pretty_string(1)); - - let doc = Group(Box::new(ForceBroken(Box::new(Break { - broken: "broken", - unbroken: "unbroken", - kind: BreakKind::Strict, - })))); - assert_eq!("broken\n".to_string(), doc.to_pretty_string(100)); - - let doc = ForceBroken(Box::new(Break { - broken: "broken", - unbroken: "unbroken", - kind: BreakKind::Flex, - })); - assert_eq!("unbroken".to_string(), doc.to_pretty_string(100)); - - let doc = Vec(vec![ - Break { - broken: "broken", - unbroken: "unbroken", - kind: BreakKind::Strict, - }, - zero_width_string("".into()), - Break { - broken: "broken", - unbroken: "unbroken", - kind: BreakKind::Strict, - }, - ]); - assert_eq!( - "unbrokenunbroken", - doc.to_pretty_string(20) - ); -} - -#[test] -fn forcing_test() { - let docs = join( - [ - "hello".to_doc(), - "a".to_doc(), - "b".to_doc(), - "c".to_doc(), - "d".to_doc(), - ], - break_("", " "), - ); - - assert_eq!( - "hello\na\nb\nc\nd", - docs.clone().force_break().group().to_pretty_string(80) - ); - assert_eq!( - "hello a b c d", - docs.clone() - .force_break() - .next_break_fits(NextBreakFitsMode::Enabled) - .group() - .to_pretty_string(80) - ); - assert_eq!( - "hello\na\nb\nc\nd", - docs.clone() - .force_break() - .next_break_fits(NextBreakFitsMode::Enabled) - .next_break_fits(NextBreakFitsMode::Disabled) - .group() - .to_pretty_string(80) - ); -} - -#[test] -fn nest_if_broken_test() { - assert_eq!( - "hello\n world", - concat(["hello".to_doc(), break_("", " "), "world".to_doc()]) - .nest_if_broken(2) - .group() - .to_pretty_string(10) - ); - - let list_doc = concat([ - concat([ - break_("[", "["), - "a,".to_doc(), - break_("", " "), - "b".to_doc(), - ]) - .nest(2), - break_(",", ""), - "]".to_doc(), - ]) - .group(); - - let arguments_doc = concat([ - break_("", ""), - "one".to_doc(), - ",".to_doc(), - break_("", " "), - list_doc.group().next_break_fits(NextBreakFitsMode::Enabled), - ]) - .nest_if_broken(2) - .group(); - - let function_call_doc = concat([ - "some_function_call(".to_doc(), - arguments_doc, - break_("", ""), - ")".to_doc(), - ]) - .group(); - - assert_eq!( - "some_function_call(\n one,\n [\n a,\n b,\n ]\n)", - function_call_doc.clone().to_pretty_string(2) - ); - assert_eq!( - "some_function_call(\n one,\n [a, b]\n)", - function_call_doc.clone().to_pretty_string(20) - ); - assert_eq!( - "some_function_call(one, [\n a,\n b,\n])", - function_call_doc.clone().to_pretty_string(25) - ); - assert_eq!( - "some_function_call(one, [a, b])", - function_call_doc.clone().to_pretty_string(80) - ); -} - -#[test] -fn let_left_side_fits_test() { - let elements = break_("", "").append("1").nest(2).append(break_("", "")); - let list = "[".to_doc().append(elements).append("]").group(); - let doc = list.clone().append(" = ").append(list); - - assert_eq!( - "[1] = [ - 1 -]", - doc.clone().to_pretty_string(7) - ); - - assert_eq!( - "[ - 1 -] = [ - 1 -]", - doc.clone().to_pretty_string(2) - ); - - assert_eq!("[1] = [1]", doc.clone().to_pretty_string(16)); -} - -#[test] -fn empty_documents() { - // nil - assert!(nil().is_empty()); - - // lines - assert!(lines(0).is_empty()); - assert!(!line().is_empty()); - - // force break - assert!(nil().force_break().is_empty()); - assert!(!"ok".to_doc().force_break().is_empty()); - - // strings - assert!("".to_doc().is_empty()); - assert!(!"wibble".to_doc().is_empty()); - assert!(!" ".to_doc().is_empty()); - assert!(!"\n".to_doc().is_empty()); - - // containers - assert!("".to_doc().nest(2).is_empty()); - assert!(!"wibble".to_doc().nest(2).is_empty()); - assert!("".to_doc().group().is_empty()); - assert!(!"wibble".to_doc().group().is_empty()); - assert!(break_("", "").is_empty()); - assert!(!break_("wibble", "wibble").is_empty()); - assert!(!break_("wibble\nwobble", "wibble wobble").is_empty()); - assert!("".to_doc().append("".to_doc()).is_empty()); - assert!(!"wibble".to_doc().append("".to_doc()).is_empty()); - assert!(!"".to_doc().append("wibble".to_doc()).is_empty()); - assert!(!zero_width_string("wibble".into()).is_empty()); -} - -#[test] -fn set_nesting() { - let doc = Vec(vec!["wibble".to_doc(), break_("", " "), "wobble".to_doc()]).group(); - assert_eq!( - "wibble\nwobble", - doc.set_nesting(0).nest(2).to_pretty_string(1) - ); -} diff --git a/compiler-core/src/type_/expression.rs b/compiler-core/src/type_/expression.rs index 050b3872b..4cb045987 100644 --- a/compiler-core/src/type_/expression.rs +++ b/compiler-core/src/type_/expression.rs @@ -2784,9 +2784,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> { // We cannot support all values in guard expressions as the BEAM does not let (definition_location, origin) = match &constructor.variant { - ValueConstructorVariant::LocalVariable { - location, origin, .. - } => (*location, origin.clone()), + ValueConstructorVariant::LocalVariable { location, origin } => { + (*location, origin.clone()) + } ValueConstructorVariant::ModuleFn { .. } | ValueConstructorVariant::Record { .. } => { return Err(Error::NonLocalClauseGuardVariable { location, name }); diff --git a/compiler-core/templates/echo.erl b/compiler-core/templates/echo.erl index 498a3f08f..483de2b2f 100644 --- a/compiler-core/templates/echo.erl +++ b/compiler-core/templates/echo.erl @@ -26,7 +26,7 @@ -define(grey, "\e[90m"). -define(reset_color, "\e[39m"). -echo(Value, Message, Line) -> +echo(Value, Message, Filepath, Line) -> StringLine = erlang:integer_to_list(Line), StringValue = echo@inspect(Value), StringMessage = @@ -38,7 +38,7 @@ echo(Value, Message, Line) -> io:put_chars( standard_error, [ - ?grey, ?FILEPATH, $:, StringLine, ?reset_color, StringMessage, $\n, + ?grey, Filepath, $:, StringLine, ?reset_color, StringMessage, $\n, StringValue, $\n ] ), diff --git a/erlang-abstract-format/Cargo.toml b/erlang-abstract-format/Cargo.toml new file mode 100644 index 000000000..a1cca371b --- /dev/null +++ b/erlang-abstract-format/Cargo.toml @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2026 The Gleam contributors + +[package] +name = "erlang-abstract-format" +version = "1.0.0" +edition = "2024" + +[dependencies] +# Encoding values in the erlang term format +erlang-term-format = { path = "../erlang-term-format" } +itertools.workspace = true +num-bigint.workspace = true +num-traits.workspace = true +regex.workspace = true +ecow.workspace = true diff --git a/erlang-abstract-format/src/lib.rs b/erlang-abstract-format/src/lib.rs new file mode 100644 index 000000000..acc476da3 --- /dev/null +++ b/erlang-abstract-format/src/lib.rs @@ -0,0 +1,3645 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2026 The Gleam contributors + +use ecow::EcoString; +use itertools::Itertools; +use num_bigint::BigInt; +use num_traits::Zero; +use regex::Regex; +use std::sync::OnceLock; + +macro_rules! pretty_printing_error { + ($this:expr, $expected:literal) => { + unreachable!("{}", $this.pretty_error_message($expected)) + }; +} + +/// This represent an erlang module name. +/// Gleam modules use `/` as a separator, but when turned into erlang `@` is +/// used as a separator instead. +/// +/// If we were to allow strings directly, a very common mistake to make would be +/// to pass a Gleam module name to a function that's expecting an Erlang module +/// name! +/// +/// With this those bugs cannot happen, and since this is a newtype wrapper its +/// not adding any overhead over using plain strings. +/// +pub struct ErlangModuleName(EcoString); + +impl ErlangModuleName { + #[inline] + /// Creates a new erlang module name from a Gleam module name. + pub fn new(gleam_module_name: EcoString) -> Self { + Self(gleam_module_name.replace("/", "@")) + } +} + +impl From<&EcoString> for ErlangModuleName { + fn from(value: &EcoString) -> Self { + Self::new(value.clone()) + } +} + +impl From for ErlangModuleName { + fn from(value: EcoString) -> Self { + Self::new(value) + } +} + +impl From<&str> for ErlangModuleName { + fn from(value: &str) -> Self { + Self::new(value.into()) + } +} + +#[must_use] +/// Represents an open function that has yet to be closed. +/// A function definition is started with `Eaf::start_function` and _must_ be +/// closed using `Eaf::end_function`. +pub struct Function { + clauses: erlang_term_format::List, + statements: erlang_term_format::List, +} + +#[must_use] +/// Represents an open function call that has yet to be closed. +pub struct Call { + arguments: erlang_term_format::List, +} + +#[must_use] +/// Represents an open case expression that has yet to be closed. +pub struct Case { + branches: erlang_term_format::List, +} + +#[must_use] +/// Represents an open case clause pattern that has yet to be generated. +pub struct ClausePattern { + pattern: erlang_term_format::List, + guards: erlang_term_format::List, + body: erlang_term_format::List, +} + +#[must_use] +/// Represents a set of clause guards that has yet to be closed. +pub struct ClauseGuards { + guards: erlang_term_format::List, + body: erlang_term_format::List, +} + +#[must_use] +/// Represents an open clause body that has yet to be closed. +pub struct ClauseBody { + body: erlang_term_format::List, +} + +#[must_use] +/// Represents an open tuple that has yet to be closed. +pub struct Tuple { + items: erlang_term_format::List, +} + +#[must_use] +/// Represents an open map that has yet to be closed. +pub struct Map { + items: erlang_term_format::List, +} + +#[must_use] +/// Represents an open bit array that has yet to be closed. +pub struct BitArray { + segments: erlang_term_format::List, +} + +#[must_use] +/// Represents an open bit array pattern that has yet to be closed. +pub struct BitArrayPattern { + segments: erlang_term_format::List, +} + +#[must_use] +/// Represents an open tuple type that has yet to be closed. +pub struct TupleType { + items: erlang_term_format::List, +} + +#[must_use] +/// Represents an open tuple pattern that has yet to be closed. +pub struct TuplePattern { + items: erlang_term_format::List, +} + +#[must_use] +/// Represents an open doc/moduledoc attribute. +pub struct DocAttribute { + items: erlang_term_format::List, +} + +#[must_use] +/// Represents an open record attribute. +pub struct RecordAttribute { + fields: erlang_term_format::List, +} + +#[must_use] +/// Represents an open function type annotation that has yet to be closed after +/// generating the arguments types and the return type. +pub struct FunctionType { + types: erlang_term_format::List, +} + +#[must_use] +/// Represents an open named type that has yet to be closed after generating +/// the types it takes as an argument (if any). +pub struct NamedType { + types: erlang_term_format::List, +} + +#[must_use] +/// Represents an open alternative type that has yet to be closed after +/// generating all of its alternatives. +pub struct UnionType { + alternatives: erlang_term_format::List, +} + +#[must_use] +/// Represents an open function type annotation that has yet to be closed after +/// generating the arguments types and the return type. +pub struct FunctionSpec { + representations: erlang_term_format::List, +} + +#[must_use] +/// Represents an open block that has yet to be closed after generating the +/// statements that go inside it. +pub struct Block { + statements: erlang_term_format::List, +} + +#[must_use] +/// Represents an open list of arguments' types in a function type annotation +/// that has yet to be closed. +pub struct FunctionTypeArguments { + types: erlang_term_format::List, + arguments: erlang_term_format::List, +} + +/// All the possible specifiers that can be used in a bit array segment. +pub enum BitArraySegmentSpecifier { + Utf8, + Utf16, + Utf32, + Integer, + Float, + Binary, + Bitstring, + Signed, + Unsigned, + Little, + Big, + Native, + Unit(u8), +} + +/// Defines the operations to describe the content of an Erlang module. +/// This might look strange in places, for example why is there a `start_tuple` +/// and `end_tuple` function, but lists are built using `cons_list` and not a +/// `start_list` and `end_list` function? +/// +/// That's because this API has been made primarily to be able to generate +/// the Erlang Abstract Format data structure. All the methods almost map 1:1 +/// to how Erlang constructs are represented in that format. +/// +/// You might want to keep a reference to it open as you go over this module, +/// it's gonna be handy: +/// https://www.erlang.org/doc/apps/erts/absform.html +/// +pub trait Eaf { + /// Creates a new `Eaf` data structure to generate Erlang code. + /// If a module name is provided this will also automatically take care of + /// generating the appropriate `-module` annotation at the very beginning. + /// + /// It's optional because it might not always be needed. For example when + /// producing `-record` annotations there's no need to have a module name. + /// + fn new(module_name: Option) -> Self; + + /// Consumes the given `Eaf` turning it into some other representation. + /// For example that might be a binary representation, or a textual pretty + /// printed one. + /// + fn into_output(self) -> Output; + + /// Adds to the module an export attribute for the given exported functions. + /// + /// For example: + /// + /// ```ignore + /// eaf.export_attribute(vec![("wibble", 1), ("wobble", 2)]); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// -export([wibble/1, wobble/2]). + /// ``` + /// + fn export_attribute>( + &mut self, + exported: impl IntoIterator, + ); + + /// Adds to the module an export_type attribute for the given exported types. + /// + /// For example: + /// + /// ```ignore + /// eaf.export_attribute(vec![("wibble", 1), ("wobble", 2)]); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// -export_type([wibble/1, wobble/2]). + /// ``` + /// + fn export_type_attribute>( + &mut self, + exported: impl IntoIterator, + ); + + /// Starts a `-doc` attribute. + /// What is generated after calling this function will end up inside the + /// `-doc` attribute. + /// You'll most likely always put a string or the atom "false" inside it. + /// + /// For example: + /// + /// ```ignore + /// let doc = eaf.start_doc_attribute(); + /// eaf.atom("false"); + /// eaf.close_doc_attribute(doc); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// -doc(false). + /// ``` + /// + fn start_doc_attribute(&mut self) -> DocAttribute; + + /// Starts a `-moduledoc` attribute. + /// What is generated after calling this function will end up inside the + /// `-moduledoc` attribute. + /// You'll most likely always put a string or the atom "false" inside it. + /// + /// For example: + /// + /// ```ignore + /// let doc = eaf.start_moduledoc_attribute(); + /// eaf.atom("false"); + /// eaf.close_doc_attribute(doc); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// -moduledoc(false). + /// ``` + /// + fn start_moduledoc_attribute(&mut self) -> DocAttribute; + + /// This closes the currently open doc/moduledoc attribute. + /// Code generated after this is not gonna be part of it. + /// + fn end_doc_attribute(&mut self, attribute: DocAttribute); + + /// This generates the code for a `-compile([]).` attribute where all the + /// strings produces by the given iterator are going to be passed as atom + /// literals. + /// + /// For example: + /// + /// ```ignore + /// eaf.compile_attribute(vec!["no_warn", "inline"]); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// -compile([no_warn, inline]). + /// ``` + /// + fn compile_attribute<'a>(&mut self, arguments: impl IntoIterator); + + /// This generates a `-file` attribute. + /// For example: + /// + /// ```ignore + /// eaf.file_attribute("wibble.gleam", 2.into()); + /// ``` + /// + /// Correspods to: + /// + /// ```erl + /// -file("wibble.gleam", 2) + /// ``` + /// + fn file_attribute(&mut self, file: &str, line: u32); + + /// Starts a `-record` attribute. + /// After this you're supposed to generate a sequence of `record_field`, and + /// once you're done you should end it with `edn_record_attribute`. + /// + /// For example: + /// + /// ```ignore + /// let record = eaf.start_record_attribute("wobble"); + /// eaf.record_field(); + /// eaf.atom("wibble"); + /// eaf.literal_atom_type("ok"); + /// eaf.close_record_attribute(record); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// -record(wobble, { wibble :: ok }). + /// ``` + /// + fn start_record_attribute(&mut self, record_name: &str) -> RecordAttribute; + + /// This closes the currently open record attribute. + /// Code generated after this is not gonna be part of it. + /// + fn end_record_attribute(&mut self, record: RecordAttribute); + + /// This creates a record field inside a record attribute. + /// After this you're supposed to generate two things: + /// - an atom representing the name of the field + /// - a type representing the type of the field + /// + /// For an example on how to use this you can check the + /// `start_record_attribute` docs. + fn record_field(&mut self); + + /// This starts a function type spec. + /// Everything that is generated after this call is interpreted as the + /// annotated type of the function. So this should be followed by a single + /// function type. + /// + /// After that is complete, this has to be closed using `end_function_spec`. + /// + /// For example: + /// + /// ```ignore + /// let spec = eaf.start_function_spec("wibble", 1) + /// let function_type = eaf.start_function_type(); + /// eaf.int_type(); + /// let function_type eaf.end_function_type_arguments(function_type); + /// eaf.variable_type("A"); + /// eaf.end_function_type(function_type); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// -spec wibble(integer(), A) -> A. + /// ``` + /// + fn start_function_spec(&mut self, name: &str, arity: usize) -> FunctionSpec; + + /// This closes the currently open function spec. + /// Code generated after this is not gonna be part of this function spec. + /// + fn end_function_spec(&mut self, function_spec: FunctionSpec); + + /// This starts an Erlang type spec. + /// After this call you're expected to generate a single type; that's going + /// to be the definition of the type. + /// + /// For example: + /// + /// ```ignore + /// let spec = eaf.start_type_spec(false, "wibble", ["A"]); + /// + /// let union = eaf.start_union_type(); + /// eaf.literal_atom_type("nil"); + /// + /// let list = eaf.start_named_type("list"); + /// eaf.type_variable("A") + /// eaf.close_named_type(); + /// + /// eaf.end_uniont_type(union); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// -spec wibble(A) :: nil | list(A). + /// ``` + /// + fn type_spec>( + &mut self, + opaque: bool, + name: &str, + type_parameters: impl IntoIterator, + ); + + /// This starts a function type. + /// Any code generated after this is gonna be an argument type of the open + /// function type until `end_function_type_arguments` is called. + /// After that you should generate a single type that's gonna be the return + /// type, and then end the function. + /// + /// For example: + /// + /// ```ignore + /// let function_type = eaf.start_function_type(); + /// eaf.int_type(); + /// eaf.variable_type("A"); + /// let function_type eaf.end_function_type_arguments(function_type); + /// eaf.variable_type("A"); + /// eaf.end_function_type(function_type); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// (integer(), A) -> A. + /// ``` + /// + fn start_function_type(&mut self) -> FunctionTypeArguments; + + /// This closes the currently open function type arguments list. + /// This means that the next type that is generated is going to be the + /// return type of the open function type. + /// + /// After that you should call `end_function_type` to close the function + /// type. + /// + fn end_function_type_arguments(&mut self, function_type: FunctionTypeArguments) + -> FunctionType; + + /// This takes a function type and closes it. + /// Code generated after this is not gonna be part of this function type. + /// + fn end_function_type(&mut self, function_type: FunctionType); + + /// This starts a named type (either defined previously in this module, or + /// a built-in Erlang type) with the given name. + /// Any code generated after this is gonna be an argument of the open + /// named type type until `end_named_type` is called. + /// + /// For example: + /// + /// ```ignore + /// let integer = eaf.start_named_type("integer"); + /// eaf.end_named_type(integer); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// integer(). + /// ``` + /// + fn start_named_type(&mut self, name: &str) -> NamedType; + + /// This starts a remote named type with the given module and name. + /// Any code generated after this is gonna be an argument of the open + /// named type type until `end_named_type` is called. + /// + /// For example: + /// + /// ```ignore + /// let type_ = eaf.start_remote_named_type("wibble", "wobble"); + /// eaf.end_named_type(type_); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// wibble:wobble(). + /// ``` + /// + fn start_remote_named_type(&mut self, module: ErlangModuleName, name: &str) -> NamedType; + + /// This takes a named type and closes it. + /// Code generated after this is not gonna be part of this named type. + /// + fn end_named_type(&mut self, named_type: NamedType); + + /// This starts a tuple type. + /// Any code generated after this is gonna be one of the tuple items. + /// + /// For example: + /// + /// ```ignore + /// let tuple = eaf.start_tuple_type(); + /// eaf.literal_atom_type("nil"); + /// eaf.literal_atom_type("ok"); + /// eaf.end_tuple_type(tuple); + /// ``` + /// + /// Corresponds to the following Erlang type: + /// + /// ```erl + /// {nil, ok}. + /// ``` + /// + fn start_tuple_type(&mut self) -> TupleType; + + /// This takes a tuple type and closes it. + /// Code generated after this is not gonna be part of this tuple type. + /// + fn end_tuple_type(&mut self, tuple: TupleType); + + /// This starts a union type. + /// Any code generated after this is gonna be a possible alternative of this + /// type. + /// + /// For example: + /// + /// ```ignore + /// let ok_or_error = eaf.start_union_type(); + /// eaf.literal_atom_type("ok"); + /// eaf.literal_atom_type("error"); + /// eaf.end_union_type(ok_or_error); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// ok | error. + /// ``` + /// + fn start_union_type(&mut self) -> UnionType; + + /// This takes a union type and closes it. + /// Code generated after this is not gonna be part of this union type. + /// + fn end_union_type(&mut self, union_type: UnionType); + + /// This generated the code for a type variable with the given name. + /// + /// For example, if we were to define the type of the identity function we + /// could do it like this: + /// + /// ```ignore + /// let function = eaf.start_function_type(); + /// eaf.type_variable("A"); + /// let function = eaf.end_function_type_arguments(); + /// eaf.type_variable("A"); + /// eaf.end_function(function); + /// ``` + /// + /// And it corresponds to: + /// + /// ```erl + /// (A) -> A. + /// ``` + /// + fn type_variable(&mut self, name: &str); + + /// This generated the code for a literal atom type. + /// + /// For example, the annotation of a function returning the atom `nil` is + /// be defined like this: + /// + /// ```ignore + /// let function = eaf.start_function_type(); + /// let function = eaf.end_function_type_arguments(); + /// eaf.literal_atom_type("nil"); + /// eaf.end_function(function); + /// ``` + /// + /// And it corresponds to: + /// + /// ```erl + /// % type of a function returning nil! + /// () -> nil. + /// ``` + /// + fn literal_atom_type(&mut self, name: &str); + + /// This starts a module function definition. + /// Any code generated after this is gonna be a statement of the open + /// function until `end_function` is called. + /// + /// For example: + /// + /// ```ignore + /// let function = eaf.start_function("first_name", 0, vec![]); + /// eaf.string("Giacomo"); + /// eaf.end_function(function); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// first_name() -> ~"Giacomo". + /// ``` + /// + fn start_function>( + &mut self, + name: &str, + arity: usize, + arguments_names: impl IntoIterator, + ) -> Function; + + /// This starts an expression defining an anonymous function. + /// Any code generated after this is gonna be a statement inside the + /// anonymous function's body until `end_anonymous_function` is called. + /// + /// For example: + /// + /// ```ignore + /// let function = eaf.start_anonymous_function([]); + /// eaf.string("Erlang rocks"); + /// eaf.end_anonymous_function(function); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// fun() -> ~"Erlang rocks" end. + /// ``` + /// + fn start_anonymous_function>( + &mut self, + arguments_names: impl IntoIterator, + ) -> Function; + + /// This takes a function and closes it. + /// Code generated after this is not gonna be part of this function. + /// + fn end_function(&mut self, function: Function); + + /// This starts a block expression. + /// Any code generated after this is gonna be a statement inside the open + /// block. + /// + /// For example: + /// + /// ```ignore + /// let block = eaf.start_block(); + /// eaf.string("Giacomo"); + /// eaf.int(1); + /// eaf.end_block(block); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// begin + /// ~"Giacomo", + /// 1 + /// end. + /// ``` + /// + fn start_block(&mut self) -> Block; + + /// This takes a block and closes it. + /// Code generated after this is not gonna be part of this block. + /// + fn end_block(&mut self, block: Block); + + /// This starts a remote call. + /// Any code generated after this is gonna be an argument of the open + /// function call `end_call` is called. + /// + /// For example: + /// + /// ```ignore + /// let call = eaf.start_remote_call("io", "format"); + /// eaf.string("Giacomo"); + /// eaf.end_call(call); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// io:format(~"Giacomo"). + /// ``` + /// + fn start_remote_call(&mut self, module: ErlangModuleName, function: &str) -> Call; + + /// This starts a function call. + /// The expression generated immediately after this is going to be the thing + /// that is called, followed by its arguments. + /// + /// For example: + /// + /// ```ignore + /// let call = eaf.start_call(); + /// eaf.atom("wibble") + /// eaf.string("Hello"); + /// eaf.string("Giacomo"); + /// eaf.end_call(call); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// wibble(~"Hello", ~"Giacomo"). + /// ``` + /// + fn start_call(&mut self) -> Call; + + /// This takes an open call and closes it. + /// Code generated after this is not gonna be an argument to this call. + /// + fn end_call(&mut self, call: Call); + + /// This starts a tuple. + /// Any code generated after this is gonna be an item of the tuple. + /// + /// For example: + /// + /// ```ignore + /// let tuple = eaf.start_tuple(); + /// eaf.string("Hello"); + /// eaf.int(1); + /// eaf.end_tuple(tuple); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// { ~"Hello", 1 }. + /// ``` + /// + fn start_tuple(&mut self) -> Tuple; + + /// This takes an open tuple and closes it. + /// Code generated after this is not gonna be an item of the tuple. + /// + fn end_tuple(&mut self, tuple: Tuple); + + /// This starts an Erlang map. + /// After this call you can add fields to the map using the `map_field` + /// function. + /// + /// For example: + /// + /// ```ignore + /// let map = eaf.start_map(); + /// + /// eaf.map_field(); + /// eaf.atom("gleam_error") + /// eaf.atom("todo"); + /// + /// eaf.map_field(); + /// eaf.atom("line"); + /// eaf.int(6.into()); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// #{ + /// gleam_error => todo, + /// line => 6 + /// }. + /// ``` + /// + fn start_map(&mut self) -> Map; + + /// This takes an open map and closes it. + /// Code generated after this is not gonna be a map field. + /// + fn end_map(&mut self, map: Map); + + /// This is used to add new fields to an open map. + /// After calling this you must generate exactly two values: the first one + /// is going to be the key, while the second one is going to be the + /// associated value. + fn map_field(&mut self); + + /// This starts an Erlang bitstring (that's a Gleam's BitArray). + /// Any code generated after this is gonna be a segment of the bitstring. + /// + /// For example: + /// + /// ```ignore + /// let bit_array = eaf.start_bit_array(); + /// + /// eaf.bit_array_segment(); + /// eaf.int(1); + /// eaf.atom("default"); + /// eaf.atom("default"); + /// + /// eaf.bit_array_segment(); + /// eaf.string("hello"); + /// eaf.atom("deafult"); + /// eaf.atom("default"); + /// + /// eaf.end_bit_array(bit_array); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// <<1, ~"hello">>. + /// ``` + /// + fn start_bit_array(&mut self) -> BitArray; + + /// This takes an open bit array and closes it. + /// Code generated after this is not gonna be a segment of the bit array. + /// + fn end_bit_array(&mut self, bit_array: BitArray); + + /// This starts a new bit array segment. Make sure to call it after + /// `start_bit_array`! + /// Bit array segments are a bit tricky, after calling this you're supposed + /// to generate three distinct bits in the following order: + /// + /// 1. The expression representing the bit array segment + /// 2. The expression representing the segment size (or the atom `default` + /// if you want to use... you guessed it, the default) + /// 3. A list of type specifiers (those are atoms like `utf8`, `binary`, + /// ...) or the atom `default` if you're ok with Erlang's default value, + /// those are generated using the `bit_array_segment_specifiers` function. + /// + /// After generating those three bits the segment is automatically over and + /// you can go on to the next one! + /// + /// If this API seems a bit tricky and easy to get wrong, it is! But this is + /// a low level API based on the shape of the Erlang Abstract Format itself, + /// we don't make the rules. + /// + /// If you wanna check an example of how this is used you can have a read at + /// the ones in `start_bit_array`. + fn bit_array_segment(&mut self); + + /// This generates a specifiers list for the currently open bit array + /// segment. + /// You always have to call this function, even if the segment has no + /// specifiers; in that case you can pass this an empty list and the + /// Erlang's default will be applied. + /// + fn bit_array_segment_specifiers( + &mut self, + specifiers: impl IntoIterator, + ); + + /// This creates a list. + /// The next two generated values are going to be respectively the first + /// item and the tail of the list. + /// + /// For example: + /// + /// ```ignore + /// eaf.cons_list(); + /// eaf.variable("Hello"); + /// eaf.cons_list(); + /// eaf.string("Giacomo"); + /// eaf.empty_list(); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// [Hello | [ ~"Giacomo" | []]]. + /// % Which, with some syntax sugar, is how we represent a list with two + /// % elements: + /// % [Hello, ~"Giacomo"] + /// ``` + /// + fn cons_list(&mut self); + + /// This creates an empty list. + /// + fn empty_list(&mut self); + + /// This starts a new case expression. + /// After this function is called you're supposed to first generate a single + /// expression; that's going to be the case subject being matched on. + /// + /// After that you're supposed to generate the case branches using the + /// `start_case_clause` function. + /// + /// For example: + /// + /// ```ignore + /// let case = eaf.start_case(); + /// eaf.variable("wibble"); + /// + /// let clause = eaf.start_case_clause(); + /// eaf.discard_pattern(); + /// let clause = eaf.end_clause_pattern(); + /// let clause = eaf.end_clause_guards(); + /// eaf.int(1.into()); + /// eaf.end_clause_body(); + /// + /// eaf.end_case(case); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// case Wibble of + /// _ -> 1 + /// end. + /// ``` + /// + fn start_case(&mut self) -> Case; + + /// This ends an open case expression. + /// Any code generated after this is not going to be part of it. + /// + fn end_case(&mut self, case: Case); + + /// This starts a new case clause inside a case expression. + /// After this is called you must generate a single pattern and then call + /// `end_clause_pattern`. + /// + /// For an example on how to generate a full case clause check the + /// `start_case` documentation. + fn start_case_clause(&mut self) -> ClausePattern; + + /// This ends the case clause's pattern. After this you should generate the + /// clause guards and then call `end_clause_guards`. + /// If the clause you're generating has no guards you can immediately call + /// that function without generating anything inbetween. + fn end_clause_pattern(&mut self, clause_pattern: ClausePattern) -> ClauseGuards; + + /// This ends the case clause's guards. Anything that is generated after + /// this is going to be a statement inside the current case clause until + /// `end_clause_body` is called. + fn end_clause_guards(&mut self, clause_guards: ClauseGuards) -> ClauseBody; + + /// This takes an open clause body and ends it. + /// After this you can start generating new case clauses, or end the + /// currently open case expression if this was the last clause! + fn end_clause_body(&mut self, clause_body: ClauseBody); + + /// This creates a variable expression with the given name. + /// For example: + /// + /// ```erl + /// wibble(X) -> X. + /// % ^ This here! + /// ``` + /// + fn variable(&mut self, name: &str); + + /// This generated the code that is going to apply the given unary operator + /// to the expression that is going to be generated next. + /// For example: + /// + /// ```ignore + /// eaf.unary_operator("-"); + /// eaf.variable("X"); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// -X. + /// ``` + /// + fn unary_operator(&mut self, operator: &str); + + /// This generated the code that is going to apply the given binary operator + /// to the two expressions generated after it. + /// For example: + /// + /// ```ignore + /// eaf.binary_operator("+"); + /// eaf.variable("X"); + /// eaf.int(1); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// X + 1. + /// ``` + /// + fn binary_operator(&mut self, operator: &'static str); + + /// This generates the code for a function reference. + /// For example: + /// + /// ```ignore + /// eaf.function_reference(None, "wibble", 1); + /// eaf.function_reference(Some("io"), "format", 2); + /// ``` + /// + /// Correspond to: + /// + /// ```erl + /// fun wibble/1, + /// fun io:format/2. + /// ``` + /// + fn function_reference(&mut self, module: Option, name: &str, arity: usize); + + /// This is used to create the code that corresponds to an assignment. + /// A call to this function should always be followed by the generation of + /// a pattern (the left-hand side of the assignment), and of an expression + /// (the right-hand side of the assignment). + /// + /// For example: + /// + /// ```ignore + /// eaf.match_operator(); + /// eaf.variable_pattern("X"); + /// eaf.int(1); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// X = 1. + /// ``` + /// + fn match_operator(&mut self); + + /// This is used to create the code that corresponds to a match pattern. + /// A call to this function should always be followed by the generation of + /// a pattern (the left-hand side of the assignment), and of another pattern + /// (the right-hand side of the assignment). + /// + /// For example: + /// + /// ```ignore + /// eaf.match_pattern(); + /// eaf.int_pattern(1); + /// eaf.variable_pattern("X"); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// 1 = X. + /// ``` + /// + /// You could use this to compare equality of arbitrary complex patterns: + /// `{1, A, [_, _]} = {X, Y, [A | _]}` however you'll most likely ever need + /// this only when generating code for Gleam's "as" patterns where the right + /// hand side is just a variable pattern. + /// + fn match_pattern(&mut self); + + /// This creates a variable pattern with the given name. + /// For example: + /// + /// ```erl + /// wibble() -> + /// X = 1. + /// % ^ This here! + /// ``` + /// + fn variable_pattern(&mut self, name: &str); + + /// This creates a discard pattern. + /// For example: + /// + /// ```erl + /// wibble() -> + /// _ = 1. + /// % ^ This here! + /// ``` + /// + fn discard_pattern(&mut self); + + /// This creates an integer pattern. + /// For example: + /// + /// ```erl + /// wibble() -> + /// 1 = X. + /// % ^ This here! + /// ``` + /// + fn int_pattern(&mut self, number: BigInt); + + /// This creates an integer pattern. + /// For example: + /// + /// ```erl + /// wibble() -> + /// 1 = X. + /// % ^ This here! + /// ``` + /// + fn float_pattern(&mut self, number: f64); + + /// This creates a string pattern. + /// For example: + /// + /// ```erl + /// wibble() -> + /// <<"Hello"/utf8>> = X. + /// % ^^^^^^^^^^^^^^^^ This here! + /// ``` + /// + fn string_pattern(&mut self, content: &str); + + /// This creates an atom pattern. + /// For example: + /// + /// ```erl + /// wibble() -> + /// ok = X. + /// % ^^ This here! + /// ``` + /// + fn atom_pattern(&mut self, name: &str); + + /// This starts a tuple pattern. + /// Any code generated after this is gonna be an item of the tuple pattern. + /// + /// For example: + /// + /// ```ignore + /// let tuple = eaf.start_tuple_pattern(); + /// eaf.int_pattern(1); + /// eaf.discard_pattern(); + /// eaf.end_tuple(tuple); + /// ``` + /// + /// Corresponds to the following pattern: + /// + /// ```erl + /// {~"Hello", _}. + /// ``` + /// + fn start_tuple_pattern(&mut self) -> TuplePattern; + + /// This takes an open tuple pattern and closes it. + /// Any code generated after this is not gonna be part of that pattern. + fn end_tuple_pattern(&mut self, tuple: TuplePattern); + + /// This starts an Erlang bitstring (that's a Gleam's BitArray) pattern. + /// Any code generated after this is gonna be a segment of the pattern. + /// + /// For example: + /// + /// ```ignore + /// let bit_array = eaf.start_bit_array_pattern(); + /// + /// eaf.bit_array_pattern_segment(); + /// eaf.int_pattern(1); + /// eaf.atom("default"); + /// eaf.atom("default"); + /// + /// eaf.bit_array_pattern_segment(); + /// eaf.discard_pattern(); + /// eaf.atom("deafult"); + /// eaf.atom("default"); + /// + /// eaf.end_bit_array_pattern(bit_array); + /// ``` + /// + /// Corresponds to the following pattern: + /// + /// ```erl + /// <<1, _>>. + /// ``` + /// + fn start_bit_array_pattern(&mut self) -> BitArrayPattern; + + /// This takes an open bit array pattern and closes it. + /// Code generated after this is not gonna be a segment of the bit array. + /// + fn end_bit_array_pattern(&mut self, bit_array: BitArrayPattern); + + /// This creates a list pattern. + /// The next two generated values are going to be respectively the pattern + /// for the first item and the pattern for the tail of the list. + /// + /// For example: + /// + /// ```ignore + /// eaf.cons_list_pattern(); + /// eaf.discard_pattern(); + /// eaf.cons_list_pattern(); + /// eaf.string("Louis"); + /// eaf.empty_list_pattern(); + /// ``` + /// + /// Corresponds to the following pattern: + /// + /// ```erl + /// [_ | [ ~"Louis" | []]]. + /// % Which, with some syntax sugar, is how we represent a pattern matching + /// % on a list with two elements, where the second element is the string + /// % ~"Louis": + /// % [_, ~"Louis"] + /// ``` + /// + fn cons_list_pattern(&mut self); + + /// This creates a pattern matching on the empty list. + /// + fn empty_list_pattern(&mut self); + + /// This creates a string literal, where the string is represented as a + /// bit array with the utf8 bytes making up the string. + /// This is how Gleam string literals are represented in Erlang. + /// + /// For example: + /// + /// ```ignore + /// eaf.string("ksiąskę"); + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// ~"ksiąskę". + /// % Which is the same as <<"ksiąskę"/utf8>> + /// % Or the same as writing the bytes directly: + /// % <<107, 115, 105, 196, 133, 115, 107, 196, 153>> + /// ``` + /// + fn string(&mut self, string: &str); + + /// This creates an integer literal from the given value. + /// + /// For example: + /// + /// ```ignore + /// eaf.int(BigInt::from(2)) + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// 2. + /// ``` + /// + fn int(&mut self, value: BigInt); + + /// This creates a float literal from the given value. + /// + /// For example: + /// + /// ```ignore + /// eaf.float(1.2) + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// 1.2. + /// ``` + /// + fn float(&mut self, value: f64); + + /// This creates a literal atom with the given name. + /// + /// For example: + /// + /// ```ignore + /// eaf.atom("wibble") + /// ``` + /// + /// Corresponds to: + /// + /// ```erl + /// wibble. + /// ``` + /// + fn atom(&mut self, name: &str); +} + +/// A structure that implements the EAF trait but rather than producing the +/// Erlang abstract format binary, it will produce a nice and readable Erlang +/// source string that can be used for testing. +#[derive(Debug)] +pub struct PrettyEaf { + code: String, + /// This keeps track of what we're generating + position: Vec, + /// The current indentation to use when generating stuff like case + /// expressions, block statements, etc. + indentation: usize, +} + +/// This is used to keep track of the current position when generating pretty +/// printed code from an `Eaf`. +#[derive(Debug)] +pub enum PrettyEafPosition { + /// We're generating a top level documentation attribute like `-doc(false)`, + /// or `-moduledoc(~"wibble wobble")`. + DocAttribute, + + /// We're generating a function spec like `-spec wibble(atom()) -> atom()`. + FunctionSpec, + + /// We're generating code for a type spec like + /// `-type wibble() :: {ok, integer()}`. + TypeSpec { expected: TypeSpecExpectedItem }, + + /// We're generating a function type, there's a couple of things that make + /// it up that we will need to generate: its arguments and the return type. + /// Which one we're expecting to see is described by the `expected` field. + FunctionType { + expected: ExpectedFunctionTypeItem, + /// If a function type doesn't appear at the top level as a spec + /// annotation, then we must wrap it in a `fun(...)`. For example: + /// + /// ```erl + /// % in a spec annotation it simply comes after the function name: + /// -spec wibble () -> integer(). + /// wibble() -> 11. + /// + /// % but inside another type it has to be wrapped in `fun(...)`: + /// -spec wobble () -> fun(() -> integer()) + /// wobble() -> fun wibble/0. + /// ``` + /// + /// This is `true` if the type has to be wrapped in `fun(...)` + needs_wrapping: bool, + }, + + /// We're generating a named type like `integer()`, or `list(atom())`. + NamedType { + /// This is `true` is the first type argument of the named type has not + /// been generated yet. + first: bool, + }, + + /// We're generating a union type like `integer() | atom()`. + UnionType { + /// This is `true` is the first alternative of the union type has not + /// been generated yet. + first: bool, + }, + + /// We're generating a tuple type like `{integer(), atom()}`. + TupleType { + /// This is `true` is the first item of the tuple type has not been + /// generated yet. + first: bool, + }, + + /// We're generating the statements of a function. + FunctionStatement { + /// This is `true` if the first statement has not been generated yet. + first: bool, + }, + + /// We're generating the statements of an anonymous function. + AnonymousFunctionStatement { + /// This is `true` if the first statement has not been generated yet. + first: bool, + }, + + /// We're generating code for a match operator like `X = 1`. + /// This is something that happens in multiple steps: first the pattern on + /// the left hand side, second the expression on the right. + MatchOperator { + /// This keeps track of what we need to generate next. + expected: ExpectedMatchSide, + }, + + /// We're generating code for a match pattern like `[1, A | _] = List`. + /// This is something that happens in multiple steps: first the pattern on + /// the left hand side, second the pattern on the right hand side. + MatchPattern { + /// This keeps track of what we need to generate next. + expected: ExpectedMatchPatternSide, + }, + + /// We're generating a list. + List { + /// This is telling us if we're generating a list expression, or a list + /// pattern. + kind: ListKind, + /// The list item we're expecting to see next. + expected: ExpectedListItem, + }, + + /// We're generating code for a unary operator. We're waiting for the + /// expression to apply the operator to. + UnaryOperator { + /// This is true if the operator is `-`. + is_number_negation: bool, + }, + + /// We're generating a tuple. + Tuple { + /// This is `true` is the first tuple item has not been generated yet. + first: bool, + }, + + /// We're generating a tuple pattern. + TuplePattern { + /// This is `true` if the first pattern of the tuple has not been + /// generated ywt. + first: bool, + }, + + /// We're generating the segments of a bit array. + BitArray { + /// Whether we're dealing with a bit array pattern, or a bit array + /// expression. + kind: BitArrayKind, + + /// This is `true` if the first segment has not been generated yet. + first: bool, + }, + + /// We're generating code for a segment of a bit array, like `10:1/signed`. + BitArraySegment { + expected: BitArraySegmentExpectedItem, + /// This is `true` if the value of the bit array segment needs to be wrapped + /// in parentheses. For example function calls need to be wrapped, or they + /// would result in invalid Erlang being produced. + /// + /// ```erl + /// <> % This is a syntax error! + /// <<(x())/binary>> % This is fine. + /// ``` + /// + segment_value_needs_wrapping: bool, + segment_size_needs_wrapping: bool, + }, + + /// We're generating a `begin ... end` block. + Block { + /// This is `true` is the first statement of the block has not been + /// generated yet. + first: bool, + }, + + /// We're generating code for a function call like `wibble(1, 2)`. + /// This needs to happen in steps: first we generate the function being + /// called (that could be any arbitrary expression after all), then we + /// generate the arguments it's being called with. + FunctionCall { + expected: ExpectedCallItem, + /// This is `true` if the thing that is being called needs to be wrapped + /// in parentheses. This appears to be needed in just one case: if we + /// are calling another function call expression. For example: + /// + /// ```erl + /// wibble()() % this is invalid Erlang + /// (wibble())() % this is valid Erlang + /// ``` + /// + /// Actually this seems to be needed for OTP versions up to 28, in OTP + /// 29 we can simply write `wibble()()`. However, since we have to + /// support OTP 28 we will add the wrapping when needed. + /// + called_item_needs_wrapping: bool, + }, + + /// We're generating code for a binary operator like `1 + 3`. + BinaryOperator { + expected: ExpectedBinaryOperatorSide, + /// Wether this binary operation needs to be wrapped in parentheses or + /// not. + needs_wrapping: bool, + operator: &'static str, + }, + + /// We're generating code for a case expression. + Case { expected: ExpectedCaseItem }, + /// We're generating code for a case clause. + CaseClause { expected: ExpectedCaseClauseItem }, + /// We're generating the key-value pairs of a map. + Map { + /// This is `true` if no key-value pair has been generated yet. + first: bool, + }, + /// We're generating a key-value pair inside a map. + MapField { expected: MapFieldExpectedItem }, + /// We're generating the fields of a record attribute. + RecordAttribute { + /// This is `true` if no field has been generated yet. + first: bool, + }, + /// We're generating the field of a record attribute. That needs to happen + /// in two steps: first we generate the name, second we generate the type of + /// the field. + RecordField { expected: ExpectedRecordFieldItem }, +} + +#[derive(Debug, Eq, PartialEq)] +pub enum ListKind { + /// We're generating a list pattern. + Pattern, + /// We're generating a list expression. + Expression, +} + +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +pub enum BitArrayKind { + /// We're generating a bit array pattern. + Pattern, + /// We're generating a bit array expression. + Expression, +} + +/// A map field is made of two things: a key, and a value. It's not an item that +/// is closed explicitly with a `end_map_field` function. It is implicitly over +/// after two expressions are generated. So we need to keep track of what we're +/// expecting to be generated next. +#[derive(Debug)] +pub enum MapFieldExpectedItem { + Key, + Value, +} + +/// A record field is made of two things: a name, and a type. It's not an item +/// that is closed explicitly with a `end_record_field` function. +/// It is implicitly over after those two things are generated. +/// So we need to keep track of which we're expecting to be generated next. +#[derive(Debug)] +pub enum ExpectedRecordFieldItem { + Name, + Type, +} + +/// Generating a case clause is done in three separate steps: first we generate +/// a single pattern, then we have to generate the guards for the clause, +/// finally we will be generating the statements making up the clause's body. +/// +#[derive(Debug)] +pub enum ExpectedCaseClauseItem { + Pattern, + Guards { + /// This is true if no guard has been generated yet. + first: bool, + }, + Body { + /// This is true if no body statement has been generated yet. + first: bool, + }, +} + +/// Generating a case expression is done in two steps: first we generate the +/// subject being matched on, then we generate the branches of the case +/// expression. +/// +#[derive(Debug)] +pub enum ExpectedCaseItem { + /// We're waiting for the expression to be matched on to be generated. + Subject, + /// We've generated the expression to be matched on, and now are waiting for + /// the case branches to be generated. + Branches { + /// This is `true` is no branch has been generated yet. + first: bool, + }, +} + +/// When generating a binary operator, that is made of three parts: the operator +/// and the left and right hand sides. +/// The way the Erlang Abstract Format works, we first generate the operator, +/// and then the two sides. +/// This is used to keep track which side we're expecting to see and properly +/// pretty print the output. +/// +#[derive(Debug)] +pub enum ExpectedBinaryOperatorSide { + Left, + Right, + BinaryOperatorIsOver, +} + +/// When generating a bit array segment we need to generate exactly three +/// things: the value, the size, and the type specifiers. +/// This keeps track of which one we're expecting to be generated next. +/// +#[derive(Debug)] +pub enum BitArraySegmentExpectedItem { + Value { + /// This is telling us if the value of the segment has to be a pattern + /// or an expression. + kind: BitArrayKind, + }, + Size, + Specifiers, +} + +/// When generating a function call, that is made of two parts: the function to +/// be called (that could be a simple literal atom, denoting a function from the +/// current module, or any expression), and its arguments. +/// +#[derive(Debug)] +pub enum ExpectedCallItem { + /// We're waiting for the function to be called to be generated + FunctionToBeCalled, + /// The function to be called was generated, now we're waiting for its + /// arguments. + Arguments { first: bool }, +} + +/// When generating a function type, that is made of two parts: the type +/// arguments of the function, and the return type. +/// +#[derive(Debug)] +pub enum ExpectedFunctionTypeItem { + Arguments { first: bool }, + ReturnType, +} + +/// Type specs don't have a "end_" function. They are implicitly over once a +/// type is generated. This is used to keep track of what we're expecting to +/// see. +/// +#[derive(Debug)] +pub enum TypeSpecExpectedItem { + TypeDefinition, + TypeSpecIsOver, +} + +/// A match operator is made of two sides: `X = 1`. A pattern and an expression. +/// +#[derive(Debug)] +pub enum ExpectedMatchSide { + /// We're waiting for the pattern on the left hand side of an assignment to + /// be generated. + Pattern, + /// We're waiting for the expression on the right hand side of an assignment + /// to be generated. + Expression, +} + +/// An as pattern is made of two sides: `[1, _ | _] = List`. +/// A pattern and a variable pattern for the name. +/// +#[derive(Debug)] +pub enum ExpectedMatchPatternSide { + /// We're waiting for the pattern on the left hand side of the match pattern + /// to be generated. + Left, + /// We're waiting for the pattern on the right hand side of the match + /// pattern to be generated. + Right, +} + +/// Lists are built by cons cells, so when building a list we will do something +/// like this: `[a | [b | []]]`. +/// This is telling us if we're expecting the first item, the second list, or if +/// the list is actually over. +/// +#[derive(Debug)] +pub enum ExpectedListItem { + First, + Rest, + ListIsOver, +} + +static UNICODE_ESCAPE_SEQUENCE_PATTERN: OnceLock = OnceLock::new(); + +/// How does pretty printing work? Here's a high level overview of how it works: +/// +/// - when a new element is generated we call the `new_x` method. +/// If I'm generating an integer (or any expression) I call `new_expression`; +/// if I'm generating a pattern I call `new_pattern`. +/// - The `new_x` functions make sure that we're allowed to generate that +/// element in the current context (for example if I'm generating a tuple type +/// I can't start generating expression)! +/// - The `new_x` functions also make sure to add any code that is needed before +/// this new expression we're about to generate given the current context. +/// For example, say we're generating the items of a tuple, and we add another +/// one: first the call to `new_expression` is going to make sure to add +/// a comma to separate the previous item from the new one. +/// +/// - Then we can start pushing the code needed to generate whatever it is we +/// are generating. If it's something simple like an integer we can just push +/// its string representation. +/// - There's also plenty of elements that are not "self-closing" and will be +/// generated in multiple steps (like function calls, tuples with multiple +/// items, binary operators, ...). In that case we can push a new `position` +/// to update the current context and keep track of what we're doing! +/// - Whenever we reach a `end_x` function we can pop the position we pushed on +/// the stack. That's the moment we can add whatever is needed to "close" one +/// of those complex elements. For example if I'm done generating a function's +/// body I can add a full stop at the end of it; if I'm done generating a +/// tuple I can add the final `}` after all the elements, and so on... +/// +/// - There's one final tricky bit. Not all elements that are generated in +/// multiple steps have a `end_x` function (for example binary operators and +/// assignments). Those will end after a specific sequence of elements is +/// generated. +/// For example, if I call `self.match_operator` I know that it will be over +/// after the next pattern and expression are generated: +/// +/// ```ignore +/// // X = 1 +/// eaf.match_operator() +/// eaf.variable_pattern("X") +/// eaf.int(1) +/// ``` +/// +/// Notice how here we don't have a `start_match_operator` and +/// `end_match_operator`. As you'll see in the implementation these will +/// require a bit of extra book-keeping in the `new_x` functions. +/// +impl Eaf for PrettyEaf { + fn new(module: Option) -> Self { + Self { + code: if let Some(module) = module { + format!("-module({}).\n", quote_atom_name(&module.0)) + } else { + String::new() + }, + indentation: 0, + position: vec![], + } + } + + fn into_output(mut self) -> String { + self.close_currently_open_item(); + self.code.push('\n'); + self.code + } + + fn export_attribute<'a, Name: AsRef>( + &mut self, + exported: impl IntoIterator, + ) { + // If there's no item in the iterator we don't add the attribute at all. + let mut exported = exported.into_iter().peekable(); + if exported.peek().is_none() { + return; + } + + self.new_top_level_form(); + self.code.push_str(&format!( + "-export([{}]).\n", + exported + .map(|(name, arity)| { format!("{}/{}", quote_atom_name(name.as_ref()), arity) }) + .join(", ") + )); + } + + fn export_type_attribute<'a, Name: AsRef>( + &mut self, + exported: impl IntoIterator, + ) { + // If there's no item in the iterator we don't add the attribute at all. + let mut exported = exported.into_iter().peekable(); + if exported.peek().is_none() { + return; + } + + self.new_top_level_form(); + self.code.push_str(&format!( + "-export_type([{}]).\n", + exported + .map(|(name, arity)| { format!("{}/{}", quote_atom_name(name.as_ref()), arity) }) + .join(", ") + )); + } + + fn start_doc_attribute(&mut self) -> DocAttribute { + self.new_top_level_form(); + self.code.push_str("-doc("); + self.position.push(PrettyEafPosition::DocAttribute); + DocAttribute { + items: PrettyEaf::dummy_list(), + } + } + + fn start_moduledoc_attribute(&mut self) -> DocAttribute { + self.new_top_level_form(); + self.code.push_str("-moduledoc("); + self.position.push(PrettyEafPosition::DocAttribute); + DocAttribute { + items: PrettyEaf::dummy_list(), + } + } + + fn end_doc_attribute(&mut self, attribute: DocAttribute) { + self.close_currently_open_item(); + attribute.items.consume(); + } + + fn compile_attribute<'a>(&mut self, arguments: impl IntoIterator) { + self.new_top_level_form(); + self.code.push_str(&format!( + "-compile([{}]).\n", + arguments.into_iter().join(", ") + )) + } + + fn file_attribute(&mut self, file: &str, line: u32) { + self.new_top_level_form(); + self.code + .push_str(&format!("\n-file(\"{}\", {}).", file, line)); + } + + fn start_record_attribute(&mut self, record_name: &str) -> RecordAttribute { + self.new_top_level_form(); + self.code + .push_str(&format!("-record({}, {{", quote_atom_name(record_name))); + self.indentation += INDENT; + self.position + .push(PrettyEafPosition::RecordAttribute { first: true }); + + RecordAttribute { + fields: PrettyEaf::dummy_list(), + } + } + + fn end_record_attribute(&mut self, record: RecordAttribute) { + self.close_currently_open_item(); + record.fields.consume(); + } + + fn record_field(&mut self) { + self.new_record_field(); + self.position.push(PrettyEafPosition::RecordField { + expected: ExpectedRecordFieldItem::Name, + }); + } + + fn start_function_spec(&mut self, name: &str, _arity: usize) -> FunctionSpec { + self.new_top_level_form(); + self.code + .push_str(&format!("\n-spec {}", quote_atom_name(name))); + self.position.push(PrettyEafPosition::FunctionSpec); + FunctionSpec { + representations: PrettyEaf::dummy_list(), + } + } + + fn end_function_spec(&mut self, function_spec: FunctionSpec) { + self.close_currently_open_item(); + function_spec.representations.consume(); + } + + fn type_spec>( + &mut self, + opaque: bool, + name: &str, + type_variables: impl IntoIterator, + ) { + self.new_top_level_form(); + self.code.push('\n'); + self.code + .push_str(if opaque { "-opaque " } else { "-type " }); + self.code.push_str("e_atom_name(name)); + self.code.push('('); + + let mut first = true; + for type_variable in type_variables { + if first { + first = false + } else { + self.code.push_str(", ") + } + self.code.push_str(type_variable.as_ref()) + } + self.code.push_str(") :: "); + self.position.push(PrettyEafPosition::TypeSpec { + expected: TypeSpecExpectedItem::TypeDefinition, + }); + } + + fn start_function_type(&mut self) -> FunctionTypeArguments { + self.new_type(); + + let needs_wrapping = if let Some(PrettyEafPosition::FunctionSpec) = self.position.last() { + self.code.push('('); + false + } else { + self.code.push_str("fun(("); + true + }; + + self.position.push(PrettyEafPosition::FunctionType { + expected: ExpectedFunctionTypeItem::Arguments { first: true }, + needs_wrapping, + }); + + FunctionTypeArguments { + types: PrettyEaf::dummy_list(), + arguments: PrettyEaf::dummy_list(), + } + } + + fn end_function_type_arguments( + &mut self, + function_type: FunctionTypeArguments, + ) -> FunctionType { + self.close_currently_open_item(); + function_type.arguments.consume(); + FunctionType { + types: function_type.types, + } + } + + fn end_function_type(&mut self, function_type: FunctionType) { + self.close_currently_open_item(); + function_type.types.consume(); + } + + fn start_named_type(&mut self, name: &str) -> NamedType { + self.new_type(); + self.position + .push(PrettyEafPosition::NamedType { first: true }); + self.code.push_str("e_atom_name(name)); + self.code.push('('); + + NamedType { + types: PrettyEaf::dummy_list(), + } + } + + fn start_remote_named_type(&mut self, module: ErlangModuleName, name: &str) -> NamedType { + self.new_type(); + self.position + .push(PrettyEafPosition::NamedType { first: true }); + self.code.push_str("e_atom_name(&module.0)); + self.code.push(':'); + self.code.push_str("e_atom_name(name)); + self.code.push('('); + + NamedType { + types: PrettyEaf::dummy_list(), + } + } + + fn end_named_type(&mut self, named_type: NamedType) { + self.close_currently_open_item(); + named_type.types.consume(); + } + + fn start_tuple_type(&mut self) -> TupleType { + self.new_type(); + self.position + .push(PrettyEafPosition::TupleType { first: true }); + self.code.push('{'); + + TupleType { + items: PrettyEaf::dummy_list(), + } + } + + fn end_tuple_type(&mut self, tuple: TupleType) { + self.close_currently_open_item(); + tuple.items.consume(); + } + + fn start_union_type(&mut self) -> UnionType { + self.new_type(); + self.position + .push(PrettyEafPosition::UnionType { first: true }); + + UnionType { + alternatives: PrettyEaf::dummy_list(), + } + } + + fn end_union_type(&mut self, union_type: UnionType) { + self.close_currently_open_item(); + union_type.alternatives.consume(); + } + + fn type_variable(&mut self, name: &str) { + self.new_type(); + self.code.push_str(name); + } + + fn literal_atom_type(&mut self, name: &str) { + self.new_type(); + self.code.push_str("e_atom_name(name)); + } + + fn start_function>( + &mut self, + name: &str, + _arity: usize, + arguments_names: impl IntoIterator, + ) -> Function { + self.new_top_level_form(); + self.code.push_str("e_atom_name(name)); + self.code.push('('); + + let mut first = true; + for argument in arguments_names { + if !first { + self.code.push_str(", ") + } else { + first = false; + } + self.code.push_str(argument.as_ref()) + } + + self.code.push_str(") ->"); + self.indentation += INDENT; + self.position + .push(PrettyEafPosition::FunctionStatement { first: true }); + + Function { + clauses: PrettyEaf::dummy_list(), + statements: PrettyEaf::dummy_list(), + } + } + + fn start_anonymous_function>( + &mut self, + arguments_names: impl IntoIterator, + ) -> Function { + self.new_expression(); + self.code.push_str("fun("); + + let mut first = true; + for argument in arguments_names { + if !first { + self.code.push_str(", ") + } else { + first = false; + } + self.code.push_str(argument.as_ref()) + } + + self.code.push_str(") ->"); + self.indentation += INDENT; + self.position + .push(PrettyEafPosition::AnonymousFunctionStatement { first: true }); + + Function { + clauses: PrettyEaf::dummy_list(), + statements: PrettyEaf::dummy_list(), + } + } + + fn end_function(&mut self, function: Function) { + self.close_currently_open_item(); + function.clauses.consume(); + function.statements.consume(); + } + + fn start_block(&mut self) -> Block { + self.new_expression(); + self.code.push_str("begin"); + self.indentation += INDENT; + self.position.push(PrettyEafPosition::Block { first: true }); + + Block { + statements: PrettyEaf::dummy_list(), + } + } + + fn end_block(&mut self, block: Block) { + self.close_currently_open_item(); + block.statements.consume(); + } + + fn start_remote_call(&mut self, module: ErlangModuleName, function: &str) -> Call { + self.pop_leftover_items(); + + // If this function call we're generating is itself being called then + // it is going to need to be wrapped in parentheses to be valid in + // OTP 28: it is not ok to write `wibble()()`, but we have to write + // `(wibble())()`. + if let Some(PrettyEafPosition::FunctionCall { + expected: ExpectedCallItem::FunctionToBeCalled, + called_item_needs_wrapping, + }) = self.position.last_mut() + { + *called_item_needs_wrapping = true; + }; + + self.new_expression(); + self.code.push_str(&format!( + "{}:{}", + quote_atom_name(&module.0), + quote_atom_name(function), + )); + self.position.push(PrettyEafPosition::FunctionCall { + expected: ExpectedCallItem::Arguments { first: true }, + called_item_needs_wrapping: false, + }); + Call { + arguments: PrettyEaf::dummy_list(), + } + } + + fn start_call(&mut self) -> Call { + self.pop_leftover_items(); + + // If this function call we're generating is itself being called then + // it is going to need to be wrapped in parentheses to be valid in + // OTP 28: it is not ok to write `wibble()()`, but we have to write + // `(wibble())()`. + if let Some(PrettyEafPosition::FunctionCall { + expected: ExpectedCallItem::FunctionToBeCalled, + called_item_needs_wrapping, + }) = self.position.last_mut() + { + *called_item_needs_wrapping = true; + }; + + self.new_expression(); + self.position.push(PrettyEafPosition::FunctionCall { + expected: ExpectedCallItem::FunctionToBeCalled, + called_item_needs_wrapping: false, + }); + Call { + arguments: PrettyEaf::dummy_list(), + } + } + + fn end_call(&mut self, call: Call) { + self.close_currently_open_item(); + call.arguments.consume(); + } + + fn start_tuple(&mut self) -> Tuple { + self.new_expression(); + self.code.push('{'); + self.position.push(PrettyEafPosition::Tuple { first: true }); + + Tuple { + items: PrettyEaf::dummy_list(), + } + } + + fn end_tuple(&mut self, tuple: Tuple) { + self.close_currently_open_item(); + tuple.items.consume(); + } + + fn start_map(&mut self) -> Map { + self.new_expression(); + self.code.push_str("#{"); + self.indentation += INDENT; + self.position.push(PrettyEafPosition::Map { first: true }); + Map { + items: PrettyEaf::dummy_list(), + } + } + + fn end_map(&mut self, map: Map) { + self.close_currently_open_item(); + map.items.consume(); + } + + fn map_field(&mut self) { + self.new_map_field(); + self.position.push(PrettyEafPosition::MapField { + expected: MapFieldExpectedItem::Key, + }); + } + + fn start_bit_array(&mut self) -> BitArray { + self.do_not_wrap_if_segment_value_or_size(); + self.new_expression(); + self.code.push_str("<<"); + self.position.push(PrettyEafPosition::BitArray { + kind: BitArrayKind::Expression, + first: true, + }); + + BitArray { + segments: PrettyEaf::dummy_list(), + } + } + + fn end_bit_array(&mut self, bit_array: BitArray) { + self.close_currently_open_item(); + bit_array.segments.consume(); + } + + fn bit_array_segment(&mut self) { + let kind = self.new_bit_array_segment(); + self.position.push(PrettyEafPosition::BitArraySegment { + expected: BitArraySegmentExpectedItem::Value { kind }, + // We assume all values are going to have to be wrapped, better + // be safe than sorry! + // We will turn this off only for certain expressions we know + // are safe to not wrap, like bare integers and strings. + segment_value_needs_wrapping: true, + segment_size_needs_wrapping: true, + }) + } + + fn bit_array_segment_specifiers( + &mut self, + specifiers: impl IntoIterator, + ) { + self.pop_leftover_items(); + let Some(PrettyEafPosition::BitArraySegment { + expected: BitArraySegmentExpectedItem::Specifiers, + segment_value_needs_wrapping, + segment_size_needs_wrapping, + }) = self.position.last_mut() + else { + pretty_printing_error!(self, "bit array segment specifier"); + }; + + if *segment_value_needs_wrapping { + self.code.push(')'); + *segment_value_needs_wrapping = false; + } else if *segment_size_needs_wrapping { + self.code.push(')'); + *segment_size_needs_wrapping = false; + } + + let mut first_specifier = true; + let specifiers = specifiers.into_iter().sorted_by(|one, other| { + if let BitArraySegmentSpecifier::Unit(_) = one { + std::cmp::Ordering::Greater + } else if let BitArraySegmentSpecifier::Unit(_) = other { + std::cmp::Ordering::Less + } else { + std::cmp::Ordering::Equal + } + }); + + for specifier in specifiers { + let string = match specifier { + BitArraySegmentSpecifier::Utf8 => "utf8", + BitArraySegmentSpecifier::Utf16 => "utf16", + BitArraySegmentSpecifier::Utf32 => "utf32", + BitArraySegmentSpecifier::Integer => "integer", + BitArraySegmentSpecifier::Float => "float", + BitArraySegmentSpecifier::Binary => "binary", + BitArraySegmentSpecifier::Bitstring => "bitstring", + BitArraySegmentSpecifier::Signed => "signed", + BitArraySegmentSpecifier::Unsigned => "unsigned", + BitArraySegmentSpecifier::Little => "little", + BitArraySegmentSpecifier::Big => "big", + BitArraySegmentSpecifier::Native => "native", + BitArraySegmentSpecifier::Unit(unit) => &format!("unit:{unit}"), + }; + if first_specifier { + first_specifier = false; + self.code.push('/'); + } else { + self.code.push('-') + } + self.code.push_str(string); + } + + self.position.pop(); + } + + fn cons_list(&mut self) { + self.cons_list_of_kind(ListKind::Expression); + } + + fn empty_list(&mut self) { + self.empty_list_of_kind(ListKind::Expression); + } + + fn start_case(&mut self) -> Case { + self.new_expression(); + self.code.push_str("case "); + self.position.push(PrettyEafPosition::Case { + expected: ExpectedCaseItem::Subject, + }); + + Case { + branches: PrettyEaf::dummy_list(), + } + } + + fn end_case(&mut self, case: Case) { + self.close_currently_open_item(); + case.branches.consume(); + } + + fn start_case_clause(&mut self) -> ClausePattern { + self.new_case_clause(); + self.position.push(PrettyEafPosition::CaseClause { + expected: ExpectedCaseClauseItem::Pattern, + }); + ClausePattern { + pattern: PrettyEaf::dummy_list(), + guards: PrettyEaf::dummy_list(), + body: PrettyEaf::dummy_list(), + } + } + + fn end_clause_pattern(&mut self, clause_pattern: ClausePattern) -> ClauseGuards { + self.close_currently_open_item(); + self.position.push(PrettyEafPosition::CaseClause { + expected: ExpectedCaseClauseItem::Guards { first: true }, + }); + clause_pattern.pattern.consume(); + ClauseGuards { + guards: clause_pattern.guards, + body: clause_pattern.body, + } + } + + fn end_clause_guards(&mut self, clause_guards: ClauseGuards) -> ClauseBody { + self.close_currently_open_item(); + self.indentation += INDENT; + self.position.push(PrettyEafPosition::CaseClause { + expected: ExpectedCaseClauseItem::Body { first: true }, + }); + + clause_guards.guards.consume(); + ClauseBody { + body: clause_guards.body, + } + } + + fn end_clause_body(&mut self, clause_body: ClauseBody) { + self.close_currently_open_item(); + clause_body.body.consume(); + } + + fn variable(&mut self, name: &str) { + self.do_not_wrap_if_segment_value_or_size(); + self.new_expression(); + self.code.push_str(name); + } + + fn unary_operator(&mut self, operator: &str) { + self.new_expression(); + self.code.push_str(operator); + self.code.push(' '); + self.position.push(PrettyEafPosition::UnaryOperator { + is_number_negation: operator == "-", + }) + } + + fn binary_operator(&mut self, operator: &'static str) { + self.new_expression(); + + // If this new binary operator we're generating is part of a bigger + // binary operator (it doesn't matter if on the left or right-hand + // side), then we want to wrap it in parentheses to avoid precedence + // confusion! + let needs_wrapping = match self.position.last() { + Some(PrettyEafPosition::BinaryOperator { .. }) => { + self.code.push('('); + true + } + Some(_) | None => false, + }; + + self.position.push(PrettyEafPosition::BinaryOperator { + expected: ExpectedBinaryOperatorSide::Left, + needs_wrapping, + operator, + }) + } + + fn function_reference(&mut self, module: Option, name: &str, arity: usize) { + self.new_expression(); + self.code.push_str("fun "); + if let Some(module) = module { + self.code.push_str("e_atom_name(&module.0)); + self.code.push(':'); + } + self.code.push_str("e_atom_name(name)); + self.code.push('/'); + self.code.push_str(&format!("{arity}")); + } + + fn match_operator(&mut self) { + self.new_expression(); + self.position.push(PrettyEafPosition::MatchOperator { + expected: ExpectedMatchSide::Pattern, + }); + } + + fn match_pattern(&mut self) { + self.new_pattern(); + self.position.push(PrettyEafPosition::MatchPattern { + expected: ExpectedMatchPatternSide::Left, + }) + } + + fn variable_pattern(&mut self, name: &str) { + self.do_not_wrap_if_segment_value_or_size(); + self.new_pattern(); + self.code.push_str(name); + } + + fn discard_pattern(&mut self) { + self.do_not_wrap_if_segment_value_or_size(); + self.new_pattern(); + self.code.push('_'); + } + + fn int_pattern(&mut self, number: BigInt) { + self.do_not_wrap_if_segment_value_or_size(); + self.new_pattern(); + self.code.push_str(&format!("{number}")); + } + + fn float_pattern(&mut self, number: f64) { + self.do_not_wrap_if_segment_value_or_size(); + self.new_pattern(); + + self.code.push_str(&format_float(number)) + } + + fn string_pattern(&mut self, content: &str) { + self.do_not_wrap_if_segment_value_or_size(); + self.new_pattern(); + self.do_print_string_content(content); + } + + fn atom_pattern(&mut self, name: &str) { + self.new_pattern(); + self.code.push_str("e_atom_name(name)); + } + + fn start_tuple_pattern(&mut self) -> TuplePattern { + self.new_pattern(); + self.code.push('{'); + self.position + .push(PrettyEafPosition::TuplePattern { first: true }); + TuplePattern { + items: PrettyEaf::dummy_list(), + } + } + + fn end_tuple_pattern(&mut self, tuple: TuplePattern) { + self.close_currently_open_item(); + tuple.items.consume(); + } + + fn start_bit_array_pattern(&mut self) -> BitArrayPattern { + self.new_pattern(); + self.code.push_str("<<"); + self.position.push(PrettyEafPosition::BitArray { + kind: BitArrayKind::Pattern, + first: true, + }); + + BitArrayPattern { + segments: PrettyEaf::dummy_list(), + } + } + + fn end_bit_array_pattern(&mut self, bit_array: BitArrayPattern) { + self.close_currently_open_item(); + bit_array.segments.consume(); + } + + fn cons_list_pattern(&mut self) { + self.cons_list_of_kind(ListKind::Pattern); + } + + fn empty_list_pattern(&mut self) { + self.empty_list_of_kind(ListKind::Pattern); + } + + fn string(&mut self, content: &str) { + self.do_not_wrap_if_segment_value_or_size(); + self.new_expression(); + self.do_print_string_content(content); + } + + fn int(&mut self, number: BigInt) { + self.do_not_wrap_if_segment_value_or_size(); + self.new_expression(); + self.code.push_str(&format!("{number}")); + } + + fn float(&mut self, number: f64) { + self.do_not_wrap_if_segment_value_or_size(); + self.new_expression(); + self.code.push_str(&format_float(number)); + } + + fn atom(&mut self, name: &str) { + // There's one special case where we actually don't want to push the + // atom's text at all. That's when we're generating the `default` atom + // as the size of a bit array segment. + // That's how we can tell in the Erlang Abstract Format that the size + // should be the default value, but it's not actually spelled out in + // textual Erlang code. + if let Some(PrettyEafPosition::BitArraySegment { + expected: expected @ BitArraySegmentExpectedItem::Size, + segment_value_needs_wrapping, + segment_size_needs_wrapping, + }) = self.position.last_mut() + { + // We are new expecting to see the specifiers list + *expected = BitArraySegmentExpectedItem::Specifiers; + if *segment_value_needs_wrapping { + self.code.push(')'); + *segment_value_needs_wrapping = false; + } + // We have the default atom as a size, that means we don't have to + // print anything at all! The size doesn't need any wrapping because + // there's no size at all. + *segment_size_needs_wrapping = false; + } else { + self.new_expression(); + self.code.push_str("e_atom_name(name)); + } + } +} + +fn format_float(number: f64) -> String { + if number.is_zero() { + if number.is_sign_negative() { + String::from("-0.0") + } else { + String::from("+0.0") + } + } else if number.fract().is_zero() { + format!("{number:.1}") + } else { + format!("{number}") + } +} + +const INDENT: usize = 4; + +impl PrettyEaf { + fn dummy_list() -> erlang_term_format::List { + erlang_term_format::List::new(0) + } + + /// This has to be called before generating any new top level form: those + /// are specs like `-spec`, `-type`, `-opaque`, doc attributes like + /// `-doc` and `-moduledoc`, and function definitions. + /// This allows the code generator to: + /// - check for inconsistencies and panic (for example if we're generating + /// a top level form not at the top level scope). + /// - update the current context. + /// - add all the code that needs to go before this expression we're about + /// to generate, based on the current context. + /// + fn new_top_level_form(&mut self) { + self.pop_leftover_items(); + if !self.position.is_empty() { + pretty_printing_error!(self, "new top level form"); + } + } + + /// This has to be called before generating any expression! + /// This allows the code generator to: + /// - check for inconsistencies and panic (for example if we're generating + /// expressions in the wrong place). + /// - update the current context. + /// - add all the code that needs to go before this expression we're about + /// to generate, based on the current context. + /// + fn new_expression(&mut self) { + self.pop_leftover_items(); + let Some(position) = self.position.last_mut() else { + pretty_printing_error!(self, "new expression"); + }; + + match position { + PrettyEafPosition::DocAttribute => (), + + PrettyEafPosition::RecordField { + expected: expected @ ExpectedRecordFieldItem::Name, + } => *expected = ExpectedRecordFieldItem::Type, + + PrettyEafPosition::Case { + expected: expected @ ExpectedCaseItem::Subject, + } => *expected = ExpectedCaseItem::Branches { first: true }, + + PrettyEafPosition::FunctionCall { + expected: expected @ ExpectedCallItem::FunctionToBeCalled, + called_item_needs_wrapping, + } => { + if *called_item_needs_wrapping { + self.code.push('('); + }; + *expected = ExpectedCallItem::Arguments { first: true } + } + + PrettyEafPosition::FunctionCall { + expected: ExpectedCallItem::Arguments { first }, + called_item_needs_wrapping, + } => { + if *called_item_needs_wrapping { + *called_item_needs_wrapping = false; + self.code.push(')'); + } + if *first { + self.code.push('(') + } else { + self.code.push_str(", "); + } + *first = false; + } + PrettyEafPosition::Tuple { first } => { + if !*first { + self.code.push_str(", "); + } + *first = false; + } + + // We're expecting the list's head. We don't have to add + // anything! + PrettyEafPosition::List { + expected: expected @ ExpectedListItem::First, + kind: ListKind::Expression, + } => *expected = ExpectedListItem::Rest, + + PrettyEafPosition::List { + expected: expected @ ExpectedListItem::Rest, + kind: ListKind::Expression, + } => { + *expected = ExpectedListItem::ListIsOver; + self.code.push_str(" | ") + } + + PrettyEafPosition::BinaryOperator { + expected: expected @ ExpectedBinaryOperatorSide::Left, + .. + } => *expected = ExpectedBinaryOperatorSide::Right, + + PrettyEafPosition::BinaryOperator { + expected: expected @ ExpectedBinaryOperatorSide::Right, + operator, + .. + } => { + *expected = ExpectedBinaryOperatorSide::BinaryOperatorIsOver; + self.code.push(' '); + self.code.push_str(operator); + self.code.push(' '); + } + + PrettyEafPosition::FunctionStatement { first } + | PrettyEafPosition::AnonymousFunctionStatement { first } + | PrettyEafPosition::Block { first } + | PrettyEafPosition::CaseClause { + expected: ExpectedCaseClauseItem::Body { first }, + } => { + if !*first { + self.code.push(','); + } + self.code.push('\n'); + self.code.push_str(&" ".repeat(self.indentation)); + *first = false; + } + + PrettyEafPosition::BitArraySegment { + expected: + expected @ BitArraySegmentExpectedItem::Value { + kind: BitArrayKind::Expression, + }, + segment_value_needs_wrapping, + .. + } => { + if *segment_value_needs_wrapping { + self.code.push('('); + } + *expected = BitArraySegmentExpectedItem::Size + } + + PrettyEafPosition::BitArraySegment { + expected: expected @ BitArraySegmentExpectedItem::Size, + segment_value_needs_wrapping, + segment_size_needs_wrapping, + } => { + if *segment_value_needs_wrapping { + self.code.push(')'); + // We've finished wrapping the value, we set this to + // false so we don't add other parentheses when we get + // to the specifiers list! + *segment_value_needs_wrapping = false; + } + *expected = BitArraySegmentExpectedItem::Specifiers; + self.code.push(':'); + if *segment_size_needs_wrapping { + self.code.push('('); + } + } + + PrettyEafPosition::CaseClause { + expected: + ExpectedCaseClauseItem::Guards { + first: first @ true, + }, + } => { + *first = false; + self.code.push_str(" when "); + } + + PrettyEafPosition::MapField { expected } => match expected { + MapFieldExpectedItem::Key => *expected = MapFieldExpectedItem::Value, + // We've generated a key and now the value is being generated. + // So we need to add the `=>` separating key and value and we + // can pop this position that is now complete. + MapFieldExpectedItem::Value => { + self.code.push_str(" => "); + self.position.pop(); + } + }, + + // We were expecting an expression and someone is about to generate + // it, we can pop this off the stack and need to add the ` = ` + // separating the previous pattern from this new expression. + PrettyEafPosition::MatchOperator { + expected: ExpectedMatchSide::Expression, + } => { + self.code.push_str(" = "); + self.position.pop(); + } + // We were expecting an expression and someone generated it, we can + // now pop this off the stack. + PrettyEafPosition::UnaryOperator { .. } => { + self.position.pop(); + } + + // Expressions are not allowed in any of these positions. + PrettyEafPosition::Case { + expected: ExpectedCaseItem::Branches { .. }, + } + | PrettyEafPosition::List { + expected: ExpectedListItem::ListIsOver, + kind: ListKind::Expression, + } + | PrettyEafPosition::BitArray { .. } + | PrettyEafPosition::MatchOperator { + expected: ExpectedMatchSide::Pattern, + } + | PrettyEafPosition::CaseClause { + expected: ExpectedCaseClauseItem::Pattern, + } + | PrettyEafPosition::TuplePattern { .. } + | PrettyEafPosition::MatchPattern { .. } + | PrettyEafPosition::FunctionSpec + | PrettyEafPosition::TypeSpec { .. } + | PrettyEafPosition::NamedType { .. } + | PrettyEafPosition::FunctionType { .. } + | PrettyEafPosition::UnionType { .. } + | PrettyEafPosition::RecordField { + expected: ExpectedRecordFieldItem::Type, + } + | PrettyEafPosition::TupleType { .. } + | PrettyEafPosition::Map { .. } + | PrettyEafPosition::RecordAttribute { .. } + | PrettyEafPosition::CaseClause { + expected: ExpectedCaseClauseItem::Guards { first: false }, + } + | PrettyEafPosition::BitArraySegment { + expected: BitArraySegmentExpectedItem::Specifiers, + .. + } + | PrettyEafPosition::BitArraySegment { + expected: + BitArraySegmentExpectedItem::Value { + kind: BitArrayKind::Pattern, + }, + .. + } + | PrettyEafPosition::BinaryOperator { + expected: ExpectedBinaryOperatorSide::BinaryOperatorIsOver, + .. + } + | PrettyEafPosition::List { + kind: ListKind::Pattern, + .. + } => pretty_printing_error!(self, "new expression"), + } + } + + /// This has to be called before generating any type! + /// This allows the code generator to: + /// - check for inconsistencies and panic (for example if we're generating + /// types in the wrong place). + /// - update the current context. + /// - add all the code that needs to go before this type we're about + /// to generate, based on the current context. + /// + fn new_type(&mut self) { + self.pop_leftover_items(); + let Some(position) = self.position.last_mut() else { + pretty_printing_error!(self, "new type"); + }; + + match position { + PrettyEafPosition::FunctionSpec => {} + PrettyEafPosition::FunctionType { + expected: ExpectedFunctionTypeItem::ReturnType, + needs_wrapping: _, + } => {} + + PrettyEafPosition::TypeSpec { + expected: expected @ TypeSpecExpectedItem::TypeDefinition, + } => { + *expected = TypeSpecExpectedItem::TypeSpecIsOver; + } + + PrettyEafPosition::FunctionType { + expected: ExpectedFunctionTypeItem::Arguments { first }, + needs_wrapping: _, + } + | PrettyEafPosition::TupleType { first } + | PrettyEafPosition::NamedType { first } => { + if !*first { + self.code.push_str(", ") + } + *first = false + } + + PrettyEafPosition::UnionType { first } => { + if !*first { + self.code.push_str(" | ") + } + *first = false + } + + PrettyEafPosition::RecordField { + expected: ExpectedRecordFieldItem::Type, + } => { + self.code.push_str(" :: "); + self.position.pop(); + } + + PrettyEafPosition::FunctionCall { .. } + | PrettyEafPosition::Block { .. } + | PrettyEafPosition::Tuple { .. } + | PrettyEafPosition::BitArray { .. } + | PrettyEafPosition::BitArraySegment { .. } + | PrettyEafPosition::List { .. } + | PrettyEafPosition::FunctionStatement { .. } + | PrettyEafPosition::AnonymousFunctionStatement { .. } + | PrettyEafPosition::DocAttribute + | PrettyEafPosition::UnaryOperator { .. } + | PrettyEafPosition::Case { .. } + | PrettyEafPosition::BinaryOperator { .. } + | PrettyEafPosition::CaseClause { .. } + | PrettyEafPosition::Map { .. } + | PrettyEafPosition::MapField { .. } + | PrettyEafPosition::RecordField { + expected: ExpectedRecordFieldItem::Name, + } + | PrettyEafPosition::MatchOperator { + expected: ExpectedMatchSide::Expression, + } + | PrettyEafPosition::RecordAttribute { .. } + | PrettyEafPosition::TypeSpec { + expected: TypeSpecExpectedItem::TypeSpecIsOver, + } + | PrettyEafPosition::MatchOperator { + expected: ExpectedMatchSide::Pattern, + } + | PrettyEafPosition::MatchPattern { .. } + | PrettyEafPosition::TuplePattern { .. } => { + pretty_printing_error!(self, "new type") + } + } + } + + /// This has to be called before generating any pattern! + /// This allows the code generator to: + /// - check for inconsistencies and panic (for example if we're generating + /// patterns in the wrong place). + /// - update the current context. + /// - add all the code that needs to go before this type we're about + /// to generate, based on the current context. + /// + fn new_pattern(&mut self) { + self.pop_leftover_items(); + let Some(position) = self.position.last_mut() else { + pretty_printing_error!(self, "new pattern"); + }; + + match position { + // We're expecting the list's head. We don't have to add + // anything! + PrettyEafPosition::List { + kind: ListKind::Pattern, + expected: expected @ ExpectedListItem::First, + } => *expected = ExpectedListItem::Rest, + + PrettyEafPosition::List { + kind: ListKind::Pattern, + expected: expected @ ExpectedListItem::Rest, + } => { + *expected = ExpectedListItem::ListIsOver; + self.code.push_str(" | ") + } + + PrettyEafPosition::BitArraySegment { + segment_value_needs_wrapping, + segment_size_needs_wrapping: _, + expected: + expected @ BitArraySegmentExpectedItem::Value { + kind: BitArrayKind::Pattern, + }, + } => { + if *segment_value_needs_wrapping { + self.code.push('('); + } + *expected = BitArraySegmentExpectedItem::Size + } + + // We were waiting for the pattern to be generated, now we're done + // and can start generating an expression for the right-hand side. + PrettyEafPosition::MatchOperator { + expected: expected @ ExpectedMatchSide::Pattern, + } => { + *expected = ExpectedMatchSide::Expression; + } + + // We were waiting for the pattern and a pattern has been generated. + // We don't change this ourselves since the pattern has to be closed + // explicitly calling `end_clause_pattern`. + // We don't have to do anything here! + PrettyEafPosition::CaseClause { + expected: ExpectedCaseClauseItem::Pattern, + } => (), + PrettyEafPosition::TuplePattern { first } => { + if *first { + *first = false; + } else { + self.code.push_str(", ") + } + } + PrettyEafPosition::MatchPattern { expected } => match expected { + ExpectedMatchPatternSide::Left => *expected = ExpectedMatchPatternSide::Right, + // The right hand side is about to be generated so we have to + // push the ` = ` to separate it from the left hand side, and we + // can remove this position since the match pattern has now been + // completed. + ExpectedMatchPatternSide::Right => { + self.code.push_str(" = "); + self.position.pop(); + } + }, + + PrettyEafPosition::FunctionCall { .. } + | PrettyEafPosition::Block { .. } + | PrettyEafPosition::FunctionStatement { .. } + | PrettyEafPosition::AnonymousFunctionStatement { .. } + | PrettyEafPosition::List { + kind: ListKind::Expression, + .. + } + | PrettyEafPosition::BitArray { .. } + | PrettyEafPosition::BitArraySegment { + expected: + BitArraySegmentExpectedItem::Size + | BitArraySegmentExpectedItem::Specifiers + | BitArraySegmentExpectedItem::Value { + kind: BitArrayKind::Expression, + }, + .. + } + | PrettyEafPosition::UnaryOperator { .. } + | PrettyEafPosition::BinaryOperator { .. } + | PrettyEafPosition::Case { .. } + | PrettyEafPosition::Map { .. } + | PrettyEafPosition::MapField { .. } + | PrettyEafPosition::MatchOperator { + expected: ExpectedMatchSide::Expression, + } + | PrettyEafPosition::Tuple { .. } + | PrettyEafPosition::FunctionType { .. } + | PrettyEafPosition::FunctionSpec + | PrettyEafPosition::TypeSpec { .. } + | PrettyEafPosition::NamedType { .. } + | PrettyEafPosition::UnionType { .. } + | PrettyEafPosition::TupleType { .. } + | PrettyEafPosition::RecordField { .. } + | PrettyEafPosition::DocAttribute + | PrettyEafPosition::RecordAttribute { .. } + | PrettyEafPosition::List { + kind: ListKind::Pattern, + expected: ExpectedListItem::ListIsOver, + } + | PrettyEafPosition::CaseClause { + expected: ExpectedCaseClauseItem::Guards { .. }, + } + | PrettyEafPosition::CaseClause { + expected: ExpectedCaseClauseItem::Body { .. }, + } => { + pretty_printing_error!(self, "new pattern"); + } + } + } + + fn close_currently_open_item(&mut self) { + self.pop_leftover_items(); + let Some(position) = self.position.pop() else { + return; + }; + + match position { + // When we're done generating statements for a function we need to + // add one final `.` to the last statement. Then we also want to + // add an empty line to make our code breath a bit better. + PrettyEafPosition::FunctionStatement { .. } => { + self.indentation -= INDENT; + self.code.push_str(".\n") + } + // When we're done generating statements for an anonymous function + // we need to add the closing `end` after the last statement on a + // new line. + PrettyEafPosition::AnonymousFunctionStatement { .. } => { + self.indentation -= INDENT; + self.code.push('\n'); + self.code.push_str(&" ".repeat(self.indentation)); + self.code.push_str("end") + } + // When we're done generating statements for a block we need to add + // the closing `end`, and reduce the nesting level. + PrettyEafPosition::Block { .. } => { + self.indentation -= INDENT; + self.code.push('\n'); + self.code.push_str(&" ".repeat(self.indentation)); + self.code.push_str("end"); + } + // When we're done generating code for a function spec we want to + // add a `.` and go to a new line so we can start generating the + // function itself. + PrettyEafPosition::FunctionSpec => self.code.push_str(".\n"), + // When we're done generating the arguments of a function we need + // to add the closed parentheses for the function call! + PrettyEafPosition::FunctionCall { + expected: ExpectedCallItem::Arguments { first }, + called_item_needs_wrapping, + } => { + if called_item_needs_wrapping { + self.code.push(')') + } + + // If the function is closed with no arguments being generated + // then we will need to add both the open and closed + // parentheses. That's because the open paren is added when the + // first argument is generated. + if first { + self.code.push_str("()") + } else { + self.code.push(')') + } + } + + // When we're done generating the items of a tuple we need + // to add the closed curly brace to actually close the tuple. + PrettyEafPosition::TupleType { .. } + | PrettyEafPosition::Tuple { .. } + | PrettyEafPosition::TuplePattern { .. } => self.code.push('}'), + // When we're done generating a bit array we can add its closing + // element. + PrettyEafPosition::BitArray { .. } => self.code.push_str(">>"), + + // When the function type arguments are over we add what we need for + // the return type. + PrettyEafPosition::FunctionType { + expected: ExpectedFunctionTypeItem::Arguments { .. }, + needs_wrapping, + } => { + // After popping the argument, we now need to wait for the + // return type! + self.position.push(PrettyEafPosition::FunctionType { + expected: ExpectedFunctionTypeItem::ReturnType, + needs_wrapping, + }); + self.code.push_str(") -> ") + } + // When a named type is over we need to add the closing parentheses. + PrettyEafPosition::NamedType { .. } => self.code.push(')'), + // If we close a function type we need to check what the current + // state is. If we were generating this for a type spec we're done. + // But if we were generating this as a type inside another we need to + // add one further parentheses to close the `fun(...)` around the + // function type. + // + // ```erl + // % in a spec annotation it simply comes after the function name: + // -spec wibble () -> integer(). + // wibble() -> 11. + // + // % but inside another type it has to be wrapped in `fun(...)`: + // -spec wobble () -> fun(() -> integer()) + // % ^ We're adding this bit here! + // wobble() -> fun wibble/0. + // ``` + PrettyEafPosition::FunctionType { + expected: ExpectedFunctionTypeItem::ReturnType, + needs_wrapping, + } => { + if needs_wrapping { + self.code.push(')') + } + } + // There's nothing left to do when a union type ends. + PrettyEafPosition::UnionType { .. } => (), + // When a doc attribute is closed we need to add the closed + // parentheses and a newline. + PrettyEafPosition::DocAttribute => self.code.push_str(").\n"), + // When a case expression is over, we need to add the closing `end`. + PrettyEafPosition::Case { + expected: ExpectedCaseItem::Branches { .. }, + } => { + self.indentation -= INDENT; + self.code.push('\n'); + self.code.push_str(&" ".repeat(self.indentation)); + self.code.push_str("end"); + } + + PrettyEafPosition::CaseClause { expected } => match expected { + ExpectedCaseClauseItem::Pattern => (), + // When the guards of a case clause are over we need to add the + // arrow before the body is generated. + ExpectedCaseClauseItem::Guards { .. } => self.code.push_str(" ->"), + ExpectedCaseClauseItem::Body { .. } => { + self.indentation -= INDENT; + } + }, + // We're done with a map, we can add the closed parentheses and + // reduce nesting. + PrettyEafPosition::Map { .. } => { + self.indentation -= INDENT; + self.code.push('\n'); + self.code.push_str(&" ".repeat(self.indentation)); + self.code.push('}'); + } + PrettyEafPosition::RecordAttribute { .. } => { + self.indentation -= INDENT; + self.code.push('\n'); + self.code.push_str(&" ".repeat(self.indentation)); + self.code.push_str("})."); + } + + PrettyEafPosition::MapField { .. } + | PrettyEafPosition::RecordField { .. } + | PrettyEafPosition::MatchPattern { .. } + | PrettyEafPosition::UnaryOperator { .. } + | PrettyEafPosition::List { .. } + | PrettyEafPosition::BinaryOperator { .. } + | PrettyEafPosition::MatchOperator { .. } + | PrettyEafPosition::TypeSpec { .. } + | PrettyEafPosition::BitArraySegment { .. } + | PrettyEafPosition::Case { + expected: ExpectedCaseItem::Subject, + } + | PrettyEafPosition::FunctionCall { + // If we try and close a function for which no called item was + // generated, then that's an error! + expected: ExpectedCallItem::FunctionToBeCalled, + .. + } => pretty_printing_error!(self, "pop leftover item"), + } + } + + /// Given the content of something that has to end up inside an Erlang + /// literal string `~"..."` this escapes its content based on + /// position-specific rules: depending where we will be putting the string + /// (and so depending where it comes from) it might need different things to + /// be escaped! + /// + /// For example, if we're given the content of a literal Gleam string, we + /// know that some charachters like double quotes are going to be escaped + /// already: + /// + /// ```gleam + /// let some_gleam_string = "wibble\"wobble" + /// ``` + /// + /// After all, if those weren't escaped our Gleam program would have a + /// syntax error and not compile! + /// + /// However, there's other pieces of syntax that might be turned into + /// literal Erlang strings: doc comments. In that case those can contain + /// unescaped characters. For example: + /// + /// ```gleam + /// /// This is a doc comment that has unescaped double quotes "" + /// ``` + /// + /// If we were to just take that comment's content and put it in an Erlang + /// string with no escaping that would produce invalid code! + /// + fn escape_string_content(&self, content: &str) -> String { + let position = self + .position + .last() + .expect("escaping string in the top level scope"); + + match position { + PrettyEafPosition::FunctionSpec + | PrettyEafPosition::TypeSpec { .. } + | PrettyEafPosition::FunctionType { .. } + | PrettyEafPosition::NamedType { .. } + | PrettyEafPosition::UnionType { .. } + | PrettyEafPosition::RecordAttribute { .. } + | PrettyEafPosition::TupleType { .. } => { + pretty_printing_error!(self, "escaping string") + } + + PrettyEafPosition::FunctionCall { .. } + | PrettyEafPosition::FunctionStatement { .. } + | PrettyEafPosition::AnonymousFunctionStatement { .. } + | PrettyEafPosition::List { .. } + | PrettyEafPosition::UnaryOperator { .. } + | PrettyEafPosition::Tuple { .. } + | PrettyEafPosition::TuplePattern { .. } + | PrettyEafPosition::BitArray { .. } + | PrettyEafPosition::BitArraySegment { .. } + | PrettyEafPosition::Block { .. } + | PrettyEafPosition::BinaryOperator { .. } + | PrettyEafPosition::Case { .. } + | PrettyEafPosition::CaseClause { .. } + | PrettyEafPosition::Map { .. } + | PrettyEafPosition::MapField { .. } + | PrettyEafPosition::MatchPattern { .. } + | PrettyEafPosition::RecordField { .. } + | PrettyEafPosition::MatchOperator { .. } => { + // When pretty printing we want the resulting code to be regular + // executable Erlang code. + // If we're tasked with escaping the content of a literal string + // expression we need to turn Gleam's `\u` sequences into + // Erlang's `\x`. + UNICODE_ESCAPE_SEQUENCE_PATTERN + .get_or_init(|| { + Regex::new(r#"(\\+)(u)"#) + .expect("Unicode escape sequence regex cannot be constructed") + }) + // `\\u`-s should not be affected, so that "\\u..." is not converted to + // "\\x...". That's why capturing groups is used to exclude cases that + // shouldn't be replaced. + .replace_all(content, |caps: ®ex::Captures<'_>| { + let slashes = caps.get(1).map_or("", |match_| match_.as_str()); + if slashes.len().is_multiple_of(2) { + format!("{slashes}u") + } else { + format!("{slashes}x") + } + }) + .into() + } + + PrettyEafPosition::DocAttribute => { + // Escaping strings generated inside doc attributes is a little + // different: since their content doesn't come from a Gleam + // literal string but freeform text, their content might contain + // all sorts of unescaped characters. + content.replace("\\", "\\\\").replace("\"", "\\\"") + } + } + } + + #[must_use] + fn new_bit_array_segment(&mut self) -> BitArrayKind { + self.pop_leftover_items(); + let Some(PrettyEafPosition::BitArray { first, kind }) = self.position.last_mut() else { + pretty_printing_error!(self, "bit array segment") + }; + + if *first { + *first = false; + } else { + self.code.push_str(", "); + } + + *kind + } + + fn new_case_clause(&mut self) { + self.pop_leftover_items(); + let Some(PrettyEafPosition::Case { + expected: ExpectedCaseItem::Branches { first }, + }) = self.position.last_mut() + else { + pretty_printing_error!(self, "case clause") + }; + + if *first { + *first = false; + self.code.push_str(" of\n"); + self.indentation += INDENT; + } else { + self.code.push_str(";\n\n"); + } + self.code.push_str(&" ".repeat(self.indentation)) + } + + fn new_map_field(&mut self) { + self.pop_leftover_items(); + let Some(PrettyEafPosition::Map { first }) = self.position.last_mut() else { + pretty_printing_error!(self, "map field"); + }; + + if *first { + *first = false; + self.code.push('\n'); + } else { + self.code.push_str(",\n") + } + self.code.push_str(&" ".repeat(self.indentation)) + } + + /// You can call this before generating any expression (before the + /// `new_expression` call) if we can skip wrapping it in parentheses when it + /// appears as a bitstring segment value. + /// This is opt-out rather than opt-in: it's always safe to wrap everything, + /// but it leads to slightly uglier code for some values like bare integers. + /// For example: + /// + /// ```erl + /// <<(1)/signed>> + /// % ^ ^ Those are not needed at all! + /// ``` + /// + /// So for those values that you know are safe and would look better you can + /// use this function. + /// + fn do_not_wrap_if_segment_value_or_size(&mut self) { + self.pop_leftover_items(); + // If we're about to generate a bit array segment value, or a size, + // then we can skip the wrapping, otherwise this is not needed at all! + match self.position.last_mut() { + Some(PrettyEafPosition::BitArraySegment { + segment_value_needs_wrapping, + expected: BitArraySegmentExpectedItem::Value { .. }, + .. + }) => *segment_value_needs_wrapping = false, + Some(PrettyEafPosition::BitArraySegment { + segment_size_needs_wrapping, + expected: BitArraySegmentExpectedItem::Size, + .. + }) => *segment_size_needs_wrapping = false, + _ => (), + } + } + + /// This can be used to output the content of a string wether that is a + /// pattern or an expression! + fn do_print_string_content(&mut self, content: &str) { + let content = self.escape_string_content(content); + // If we're generating a string as a bit array segment value we want to + // output slightly different code: rather than a bit array we want to + // output a regular string with no modifiers which are going to be added + // later as the segment is created + if let Some(PrettyEafPosition::BitArraySegment { + // the call to `new_expression` at the beginning is going to advance + // the state to expect the `::Size`, that means the code we are + // outputting now was expected to be the the `::Value` of the bit + // array segment! + // We can't move the `new_expression` call down, that _must_ be the + // first thing we do, so we check to see if the size if the next + // thing we're expecting to see. + expected: BitArraySegmentExpectedItem::Size, + segment_value_needs_wrapping: _, + segment_size_needs_wrapping: _, + }) = self.position.last() + { + self.code.push_str(&format!("\"{content}\"")) + } else { + self.code.push_str(&format!("<<\"{content}\"/utf8>>",)); + } + } + + fn cons_list_of_kind(&mut self, list_kind: ListKind) { + self.pop_leftover_items(); + match self.position.last_mut() { + // If we were expecting the rest of a list and we generate a new + // cons cell we can keep adding commas to separate items: we want + // to show `[1, 2, 3]` rather than `[1 | [2 | [3 | []]]]` + Some(PrettyEafPosition::List { + kind, + expected: expected @ ExpectedListItem::Rest, + }) if *kind == list_kind => { + *expected = ExpectedListItem::First; + self.code.push_str(", "); + } + // Otherwise we have to properly start a new list: push the `[` and + // wait for the first item to be generated. + Some(_) | None => { + match list_kind { + ListKind::Pattern => self.new_pattern(), + ListKind::Expression => self.new_expression(), + } + self.code.push('['); + self.position.push(PrettyEafPosition::List { + kind: list_kind, + expected: ExpectedListItem::First, + }); + } + } + } + + fn empty_list_of_kind(&mut self, list_kind: ListKind) { + self.pop_leftover_items(); + match self.position.last_mut() { + // If we were building a cons list and were expecting the end of the + // list then we have to special case this: we don't want to render + // it as: `[1, 2 | []]`, but as `[1, 2]`. + Some(PrettyEafPosition::List { + kind, + expected: ExpectedListItem::Rest, + }) if *kind == list_kind => { + // Crucially we don't want to call `new_expression` here: we + // don't want the default handling. + self.code.push(']'); + // The list is over, so we pop it away. + self.position.pop(); + } + Some(_) | None => { + match list_kind { + ListKind::Pattern => self.new_pattern(), + ListKind::Expression => self.new_expression(), + } + self.code.push_str("[]"); + } + } + } + + /// This has to be called before any `new_x` function. This takes care of + /// removing all leftover items that do not self close. + /// + /// That happens when there's some node that requires code to be pushed + /// _after_ it is over and it is not closed manually with a `end_x` + /// function. + fn pop_leftover_items(&mut self) { + let Some(position) = self.position.last() else { + return; + }; + + match position { + PrettyEafPosition::TypeSpec { + expected: TypeSpecExpectedItem::TypeSpecIsOver, + } => { + self.code.push_str(".\n"); + self.position.pop(); + self.pop_leftover_items(); + } + + // The expression we're generating is preceded by a list + // that has been closed. Lists are a bit tricky because they + // are built as a list of cons cells, so we can't really + // tell when a list is over until we get to the next + // expression. + PrettyEafPosition::List { + expected: ExpectedListItem::ListIsOver, + .. + } => { + self.code.push(']'); + // We remove this leftover list... + self.position.pop(); + // ...and then we can keep going until there's no leftover + // items left. + self.pop_leftover_items(); + } + + // Like with lists, we don't really know when a binary operator is + // over until we get to the following operation (or we try closing + // the current item and notice there's a closed operator left). + // Also, just like lists, we might still need to add some + // parentheses _after_ the operator is over. + PrettyEafPosition::BinaryOperator { + expected: ExpectedBinaryOperatorSide::BinaryOperatorIsOver, + needs_wrapping, + .. + } => { + // If needed add the closing parentheses... + if *needs_wrapping { + self.code.push(')'); + } + // ...we remove this leftover binary operator... + self.position.pop(); + // ...and then we can keep going until there's no leftover items + // left. + self.pop_leftover_items(); + } + + // All of these items are not leftovers. They are either still open, + // require manual closing, or things that don't need closing at all! + PrettyEafPosition::NamedType { .. } + | PrettyEafPosition::UnionType { .. } + | PrettyEafPosition::TupleType { .. } + | PrettyEafPosition::FunctionStatement { .. } + | PrettyEafPosition::AnonymousFunctionStatement { .. } + | PrettyEafPosition::DocAttribute + | PrettyEafPosition::FunctionSpec + | PrettyEafPosition::Tuple { .. } + | PrettyEafPosition::TuplePattern { .. } + | PrettyEafPosition::BitArray { .. } + | PrettyEafPosition::Map { .. } + | PrettyEafPosition::Block { .. } + | PrettyEafPosition::UnaryOperator { .. } + | PrettyEafPosition::FunctionType { + expected: + ExpectedFunctionTypeItem::Arguments { .. } | ExpectedFunctionTypeItem::ReturnType, + .. + } + | PrettyEafPosition::TypeSpec { + expected: TypeSpecExpectedItem::TypeDefinition, + } + | PrettyEafPosition::MapField { + expected: MapFieldExpectedItem::Key | MapFieldExpectedItem::Value, + } + | PrettyEafPosition::List { + expected: ExpectedListItem::First | ExpectedListItem::Rest, + .. + } + | PrettyEafPosition::BitArraySegment { + expected: + BitArraySegmentExpectedItem::Size + | BitArraySegmentExpectedItem::Specifiers + | BitArraySegmentExpectedItem::Value { .. }, + .. + } + | PrettyEafPosition::FunctionCall { + expected: ExpectedCallItem::Arguments { .. } | ExpectedCallItem::FunctionToBeCalled, + .. + } + | PrettyEafPosition::MatchPattern { + expected: ExpectedMatchPatternSide::Left | ExpectedMatchPatternSide::Right, + } + | PrettyEafPosition::Case { + expected: ExpectedCaseItem::Subject | ExpectedCaseItem::Branches { .. }, + } + | PrettyEafPosition::CaseClause { + expected: + ExpectedCaseClauseItem::Pattern + | ExpectedCaseClauseItem::Guards { .. } + | ExpectedCaseClauseItem::Body { .. }, + } + | PrettyEafPosition::BinaryOperator { + expected: ExpectedBinaryOperatorSide::Left | ExpectedBinaryOperatorSide::Right, + .. + } + | PrettyEafPosition::RecordAttribute { .. } + | PrettyEafPosition::MatchOperator { + expected: ExpectedMatchSide::Expression | ExpectedMatchSide::Pattern, + } + | PrettyEafPosition::RecordField { .. } => (), + } + } + + fn new_record_field(&mut self) { + self.pop_leftover_items(); + let Some(PrettyEafPosition::RecordAttribute { first }) = self.position.last_mut() else { + panic!("tried generating record field outside of record attribute"); + }; + + if *first { + *first = false; + } else { + self.code.push(','); + } + self.code.push('\n'); + self.code.push_str(&" ".repeat(self.indentation)); + } + + fn pretty_error_message(&self, expected: &str) -> String { + let position = self.position.last(); + format!("tried {expected}, position: {position:?}") + } +} + +/// This wraps an atom name in between single quotes if needed. +fn quote_atom_name(name: &str) -> String { + if is_erlang_reserved_word(name) { + // Escape because of keyword collision + format!("'{name}'") + } else if atom_name_regex().is_match(name) { + String::from(name) + } else { + // Escape because of characters contained + format!("'{name}'") + } +} + +static ATOM_NAME_REGEX: OnceLock = OnceLock::new(); + +fn atom_name_regex() -> &'static Regex { + ATOM_NAME_REGEX.get_or_init(|| Regex::new(r"^[a-z][a-z0-9_@]*$").expect("atom RE regex")) +} + +fn is_erlang_reserved_word(name: &str) -> bool { + matches!( + name, + "!" | "receive" + | "bnot" + | "div" + | "rem" + | "band" + | "bor" + | "bxor" + | "bsl" + | "bsr" + | "not" + | "and" + | "or" + | "xor" + | "orelse" + | "andalso" + | "when" + | "end" + | "fun" + | "try" + | "catch" + | "after" + | "begin" + | "let" + | "query" + | "cond" + | "if" + | "of" + | "case" + | "maybe" + | "else" + ) +} diff --git a/erlang-term-format/Cargo.toml b/erlang-term-format/Cargo.toml index e26fccc81..2572ed748 100644 --- a/erlang-term-format/Cargo.toml +++ b/erlang-term-format/Cargo.toml @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2026 The Gleam contributors + [package] name = "erlang-term-format" version = "1.0.0" diff --git a/erlang-term-format/src/lib.rs b/erlang-term-format/src/lib.rs index fb502b7fb..7b4ac0254 100644 --- a/erlang-term-format/src/lib.rs +++ b/erlang-term-format/src/lib.rs @@ -1,4 +1,8 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2026 The Gleam contributors + use num_bigint::{BigInt, Sign}; +use num_traits::ToPrimitive; #[cfg(test)] #[macro_use] @@ -7,18 +11,37 @@ extern crate pretty_assertions; /// A data structure used to encode values into the Erlang Term Format: /// https://www.erlang.org/doc/apps/erts/erl_ext_dist.html. /// -/// Hello!! -/// +#[derive(Debug)] pub struct Etf { bytes: Vec, } +impl Default for Etf { + fn default() -> Self { + Self::new() + } +} + #[must_use] +#[derive(Debug)] pub struct List { size_index: usize, used: bool, } +impl List { + pub fn new(size_index: usize) -> Self { + Self { + size_index, + used: false, + } + } + + pub fn consume(mut self) { + self.used = true; + } +} + impl Drop for List { fn drop(&mut self) { assert!(self.used, "list not closed"); @@ -43,6 +66,83 @@ impl Etf { self.bytes.extend(bytes); } + /// Pushes a single raw byte. + /// + pub fn raw_byte(&mut self, byte: u8) { + self.push(byte); + } + + /// Pushes the etf of an empty list. + /// - If you need to build lists with a number of items that is not known in + /// advance you can use `start_list` and `end_list`. + /// + /// https://www.erlang.org/doc/apps/erts/erl_ext_dist.html#nil_ext + pub fn empty_list(&mut self) { + self.nil() + } + + /// Start building a list with a number of item that is not known in + /// advance. + /// + /// Once you've then pushed all the items, you _must_ complete the list by + /// calling `end_list` with the number of items that were pushed. + /// + /// ```ignore + /// // [1, 2, 3] + /// let list = etf.start_list() + /// etf.small_integer(1); + /// etf.small_integer(2); + /// etf.small_integer(3); + /// etf.end_list(list, 3) + /// ``` + /// + /// https://www.erlang.org/doc/apps/erts/erl_ext_dist.html#list_ext + pub fn start_list(&mut self) -> List { + self.push(108); + let size_index = self.bytes.len(); + self.push(0); + self.push(0); + self.push(0); + self.push(0); + List::new(size_index) + } + + pub fn end_list(&mut self, list: List, items: u32) { + self.nil(); + self.bytes[list.size_index..list.size_index + 4].copy_from_slice(&items.to_be_bytes()); + list.consume(); + } + + /// Pushes the most compact etf representation of the given atom. + pub fn atom(&mut self, atom: &str) { + if atom.len() <= 255 { + self.small_atom_utf8(atom); + } else { + self.atom_utf8(atom); + } + } + + /// Pushes the most compact etf representation of the given bigint number. + pub fn bigint(&mut self, value: BigInt) { + if let Some(value) = value.to_u8() { + self.small_integer(value); + } else if let Some(value) = value.to_i32() { + self.integer(value); + } else { + self.small_big(value); + } + } + + /// Pushes the most compact etf representation of the given usize number. + /// + pub fn usize(&mut self, value: usize) { + if let Some(value) = value.to_u8() { + self.small_integer(value); + } else { + self.integer(value as i32); + } + } + /// https://www.erlang.org/doc/apps/erts/erl_ext_dist.html#small_integer_ext fn small_integer(&mut self, value: u8) { self.push(97); @@ -56,7 +156,7 @@ impl Etf { } /// https://www.erlang.org/doc/apps/erts/erl_ext_dist.html#new_float_ext - fn new_float(&mut self, value: f64) { + pub fn new_float(&mut self, value: f64) { self.push(70); self.extend(value.to_be_bytes()); } @@ -78,30 +178,10 @@ impl Etf { self.push(106); } - /// https://www.erlang.org/doc/apps/erts/erl_ext_dist.html#list_ext - fn start_list(&mut self) -> List { - self.push(108); - let size_index = self.bytes.len(); - self.push(0); - self.push(0); - self.push(0); - self.push(0); - List { - size_index, - used: false, - } - } - - fn end_list(&mut self, mut list: List, items: u32) { - self.nil(); - self.bytes[list.size_index..list.size_index + 4].copy_from_slice(&items.to_be_bytes()); - list.used = true; - } - /// https://www.erlang.org/doc/apps/erts/erl_ext_dist.html#binary_ext - fn binary(&mut self, bytes: Vec) { + pub fn binary(&mut self, bytes_count: u32, bytes: impl IntoIterator) { self.push(109); - self.extend((bytes.len() as u32).to_be_bytes()); + self.extend(bytes_count.to_be_bytes()); self.extend(bytes); } @@ -118,7 +198,7 @@ impl Etf { } /// https://www.erlang.org/doc/apps/erts/erl_ext_dist.html#large_big_ext - fn large_big(&mut self, number: BigInt) { + pub fn large_big(&mut self, number: BigInt) { let (sign, bytes) = number.to_bytes_le(); self.push(111); self.extend((bytes.len() as u32).to_be_bytes()); @@ -155,14 +235,14 @@ mod tests { #[test] fn small_atom() { let mut etf = Etf::new(); - etf.small_atom_utf8("atom"); + etf.atom("atom"); assert_eq!(etf.into_vec(), [131, 119, 4, 97, 116, 111, 109]) } #[test] fn small_atom_utf8() { let mut etf = Etf::new(); - etf.small_atom_utf8("ksiąskę"); + etf.atom("ksiąskę"); assert_eq!( etf.into_vec(), [131, 119, 9, 107, 115, 105, 196, 133, 115, 107, 196, 153] @@ -172,7 +252,7 @@ mod tests { #[test] fn atom() { let mut etf = Etf::new(); - etf.atom_utf8(&"ą".repeat(128)); + etf.atom(&"ą".repeat(128)); assert_eq!( etf.into_vec(), [ @@ -279,13 +359,13 @@ mod tests { #[test] fn empty_binary() { let mut etf = Etf::new(); - etf.binary(vec![]); + etf.binary(0, vec![]); assert_eq!(etf.into_vec(), [131, 109, 0, 0, 0, 0]) } #[test] fn binary() { let mut etf = Etf::new(); - etf.binary(vec![1, 2, 3]); + etf.binary(3, vec![1, 2, 3]); assert_eq!(etf.into_vec(), [131, 109, 0, 0, 0, 3, 1, 2, 3]) } diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__alias_unqualified_import.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__alias_unqualified_import.snap index 105b8f1c5..af7040e5d 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__alias_unqualified_import.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__alias_unqualified_import.snap @@ -10,8 +10,7 @@ expression: "./cases/alias_unqualified_import" //// /out/lib/the_package/_gleam_artefacts/one.erl -module(one). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/one.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([id/1]). -export_type([empty/0]). @@ -23,6 +22,7 @@ id(X) -> X. + //// /out/lib/the_package/_gleam_artefacts/two.cache <.cache binary> @@ -31,8 +31,7 @@ id(X) -> //// /out/lib/the_package/_gleam_artefacts/two.erl -module(two). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/two.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([make/0]). -file("src/two.gleam", 7). @@ -41,6 +40,7 @@ make() -> one:id(empty). + //// /out/lib/the_package/ebin/importy.app {application, importy, [ {vsn, "0.1.0"}, diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__empty_module_warning.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__empty_module_warning.snap index 1a228799f..fa09e49a0 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__empty_module_warning.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__empty_module_warning.snap @@ -10,6 +10,8 @@ expression: "./cases/empty_module_warning" //// /out/lib/the_package/_gleam_artefacts/empty.erl -module(empty). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). + //// /out/lib/the_package/_gleam_artefacts/internal.cache @@ -20,25 +22,17 @@ expression: "./cases/empty_module_warning" //// /out/lib/the_package/_gleam_artefacts/internal.erl -module(internal). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/internal.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([private_function/0]). --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -file("src/internal.gleam", 5). -?DOC(false). -spec private_function() -> nil. +-doc(false). private_function() -> nil. + //// /out/lib/the_package/_gleam_artefacts/private.cache <.cache binary> @@ -47,6 +41,8 @@ private_function() -> //// /out/lib/the_package/_gleam_artefacts/private.erl -module(private). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). + //// /out/lib/the_package/_gleam_artefacts/public.cache @@ -57,8 +53,7 @@ private_function() -> //// /out/lib/the_package/_gleam_artefacts/public.erl -module(public). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/public.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("src/public.gleam", 4). @@ -67,6 +62,7 @@ main() -> <<"This module has public definitions"/utf8>>. + //// /out/lib/the_package/ebin/empty_module_warning.app {application, empty_module_warning, [ {vsn, "1.0.0"}, diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_app_generation.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_app_generation.snap index cccc8f1dd..358025136 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_app_generation.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_app_generation.snap @@ -10,6 +10,8 @@ expression: "./cases/erlang_app_generation" //// /out/lib/the_package/_gleam_artefacts/main.erl -module(main). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). + //// /out/lib/the_package/ebin/my_erlang_application.app diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_app_generation_with_argument.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_app_generation_with_argument.snap index ec44e0fd6..50b9eb12f 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_app_generation_with_argument.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_app_generation_with_argument.snap @@ -10,6 +10,8 @@ expression: "./cases/erlang_app_generation_with_argument" //// /out/lib/the_package/_gleam_artefacts/main.erl -module(main). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). + //// /out/lib/the_package/ebin/my_erlang_application.app diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_bug_752.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_bug_752.snap index ea43c2c57..e1ce88847 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_bug_752.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_bug_752.snap @@ -10,15 +10,13 @@ expression: "./cases/erlang_bug_752" //// /out/lib/the_package/_gleam_artefacts/one.erl -module(one). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/one.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([one/1]). -type one(I) :: {one, I}. - //// /out/lib/the_package/_gleam_artefacts/two.cache <.cache binary> @@ -27,15 +25,13 @@ expression: "./cases/erlang_bug_752" //// /out/lib/the_package/_gleam_artefacts/two.erl -module(two). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/two.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([two/1]). -type two(K) :: {two, one:one(integer())} | {gleam_phantom, K}. - //// /out/lib/the_package/ebin/importy.app {application, importy, [ {vsn, "0.1.0"}, @@ -48,4 +44,6 @@ expression: "./cases/erlang_bug_752" //// /out/lib/the_package/include/two_Two.hrl --record(two, {thing :: one:one(integer())}). +-record(two, { + thing :: one:one(integer()) +}). diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_empty.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_empty.snap index 3ac000bf8..15a2d941e 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_empty.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_empty.snap @@ -10,6 +10,8 @@ expression: "./cases/erlang_empty" //// /out/lib/the_package/_gleam_artefacts/empty.erl -module(empty). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). + //// /out/lib/the_package/ebin/hello_joe.app diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_escape_names.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_escape_names.snap index 838d0df5d..b5b83ac15 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_escape_names.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_escape_names.snap @@ -10,8 +10,7 @@ expression: "./cases/erlang_escape_names" //// /out/lib/the_package/_gleam_artefacts/one.erl -module(one). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/one.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export(['receive'/1]). -file("src/one.gleam", 5). @@ -20,6 +19,7 @@ expression: "./cases/erlang_escape_names" X. + //// /out/lib/the_package/_gleam_artefacts/two.cache <.cache binary> @@ -28,8 +28,7 @@ expression: "./cases/erlang_escape_names" //// /out/lib/the_package/_gleam_artefacts/two.erl -module(two). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/two.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([qualified_call/0, qualified_value/0, unqualified_call/0, unqualified_value/0]). -file("src/two.gleam", 7). @@ -53,6 +52,7 @@ unqualified_value() -> fun one:'receive'/1. + //// /out/lib/the_package/ebin/importy.app {application, importy, [ {vsn, "0.1.0"}, diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_import.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_import.snap index 0a52b7c37..f1c07dfb9 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_import.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_import.snap @@ -10,8 +10,7 @@ expression: "./cases/erlang_import" //// /out/lib/the_package/_gleam_artefacts/one.erl -module(one). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/one.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([unbox/1]). -file("src/one.gleam", 6). @@ -21,6 +20,7 @@ unbox(X) -> I. + //// /out/lib/the_package/_gleam_artefacts/two.cache <.cache binary> @@ -29,15 +29,13 @@ unbox(X) -> //// /out/lib/the_package/_gleam_artefacts/two.erl -module(two). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/two.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([box/0]). -type box() :: {box, integer()}. - //// /out/lib/the_package/ebin/importy.app {application, importy, [ {vsn, "0.1.0"}, diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_import_shadowing_prelude.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_import_shadowing_prelude.snap index 5326188ca..8b983cda5 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_import_shadowing_prelude.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_import_shadowing_prelude.snap @@ -10,15 +10,13 @@ expression: "./cases/erlang_import_shadowing_prelude" //// /out/lib/the_package/_gleam_artefacts/one.erl -module(one). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/one.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([error/0]). -type error() :: error. - //// /out/lib/the_package/_gleam_artefacts/two.cache <.cache binary> @@ -27,8 +25,7 @@ expression: "./cases/erlang_import_shadowing_prelude" //// /out/lib/the_package/_gleam_artefacts/two.erl -module(two). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/two.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("src/two.gleam", 7). @@ -37,6 +34,7 @@ main() -> error. + //// /out/lib/the_package/ebin/importy.app {application, importy, [ {vsn, "0.1.0"}, diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_nested.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_nested.snap index 9a734a24e..4eb1eb5ea 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_nested.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_nested.snap @@ -10,8 +10,7 @@ expression: "./cases/erlang_nested" //// /out/lib/the_package/_gleam_artefacts/one@two.erl -module(one@two). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/one/two.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("src/one/two.gleam", 4). @@ -20,6 +19,7 @@ main() -> <<"Hi there"/utf8>>. + //// /out/lib/the_package/ebin/importy.app {application, importy, [ {vsn, "0.1.0"}, diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_nested_qualified_constant.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_nested_qualified_constant.snap index da90cede2..efd53078a 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_nested_qualified_constant.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__erlang_nested_qualified_constant.snap @@ -10,15 +10,13 @@ expression: "./cases/erlang_nested_qualified_constant" //// /out/lib/the_package/_gleam_artefacts/one@two.erl -module(one@two). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/one/two.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([a/0]). -type a() :: a. - //// /out/lib/the_package/_gleam_artefacts/two.cache <.cache binary> @@ -27,6 +25,8 @@ expression: "./cases/erlang_nested_qualified_constant" //// /out/lib/the_package/_gleam_artefacts/two.erl -module(two). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). + //// /out/lib/the_package/ebin/importy.app diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__hello_joe.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__hello_joe.snap index c38e97538..80b2dea92 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__hello_joe.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__hello_joe.snap @@ -10,8 +10,7 @@ expression: "./cases/hello_joe" //// /out/lib/the_package/_gleam_artefacts/hello_joe.erl -module(hello_joe). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/hello_joe.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([main/0]). -file("src/hello_joe.gleam", 4). @@ -20,6 +19,7 @@ main() -> <<"Hello, Joe!"/utf8>>. + //// /out/lib/the_package/ebin/hello_joe.app {application, hello_joe, [ {vsn, "0.1.0"}, diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__import_shadowed_name_warning.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__import_shadowed_name_warning.snap index 77c1472c7..3d913b070 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__import_shadowed_name_warning.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__import_shadowed_name_warning.snap @@ -10,15 +10,13 @@ expression: "./cases/import_shadowed_name_warning" //// /out/lib/the_package/_gleam_artefacts/one.erl -module(one). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/one.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([port_/0]). -type port_() :: any(). - //// /out/lib/the_package/_gleam_artefacts/two.cache <.cache binary> @@ -27,20 +25,10 @@ expression: "./cases/import_shadowed_name_warning" //// /out/lib/the_package/_gleam_artefacts/two.erl -module(two). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/two.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([use_type/1]). -export_type([shadowing/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC(" https://github.com/gleam-lang/otp/pull/22\n"). +-moduledoc(<<" https://github.com/gleam-lang/otp/pull/22"/utf8>>). -type shadowing() :: port. @@ -50,6 +38,7 @@ use_type(Port) -> wibble:wobble(Port). + //// /out/lib/the_package/ebin/importy.app {application, importy, [ {vsn, "0.1.0"}, diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__imported_constants.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__imported_constants.snap index 961733526..e9e0e5b68 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__imported_constants.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__imported_constants.snap @@ -10,8 +10,7 @@ expression: "./cases/imported_constants" //// /out/lib/the_package/_gleam_artefacts/one.erl -module(one). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/one.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([a/0, b/0, user/0]). -type a() :: a. @@ -22,7 +21,6 @@ expression: "./cases/imported_constants" - //// /out/lib/the_package/_gleam_artefacts/two.cache <.cache binary> @@ -31,18 +29,9 @@ expression: "./cases/imported_constants" //// /out/lib/the_package/_gleam_artefacts/two.erl -module(two). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/two.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([qualified_fn_a/0, qualified_fn_b/0, unqualified_fn_a/0, unqualified_fn_b/0, aliased_fn_a/0, aliased_fn_b/0, accessors/1, destructure_qualified/1, destructure_unqualified/1, destructure_aliased/1]). --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -file("src/two.gleam", 9). -spec qualified_fn_a() -> one:a(). qualified_fn_a() -> @@ -74,19 +63,17 @@ aliased_fn_b() -> {b, a, a}. -file("src/two.gleam", 48). -?DOC( - " For these statements we use the accessors for the record from the other\n" - " module\n" -). -spec accessors(one:user()) -> {binary(), integer()}. +-doc(<<" For these statements we use the accessors for the record from the other + module"/utf8>>). accessors(User) -> Name = erlang:element(2, User), Score = erlang:element(3, User), {Name, Score}. -file("src/two.gleam", 55). -?DOC(" For these statements we use destructure the record\n"). -spec destructure_qualified(one:user()) -> {binary(), integer()}. +-doc(<<" For these statements we use destructure the record"/utf8>>). destructure_qualified(User) -> {user, Name, Score} = User, {Name, Score}. @@ -104,6 +91,7 @@ destructure_aliased(User) -> {Name, Score}. + //// /out/lib/the_package/ebin/importy.app {application, importy, [ {vsn, "0.1.0"}, @@ -116,4 +104,7 @@ destructure_aliased(User) -> //// /out/lib/the_package/include/one_User.hrl --record(user, {name :: binary(), score :: integer()}). +-record(user, { + name :: binary(), + score :: integer() +}). diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__imported_external_fns.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__imported_external_fns.snap index 089e8475c..48f6ca10c 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__imported_external_fns.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__imported_external_fns.snap @@ -10,8 +10,7 @@ expression: "./cases/imported_external_fns" //// /out/lib/the_package/_gleam_artefacts/one.erl -module(one). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/one.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([thing/0, escaped_thing/0]). -file("src/one.gleam", 5). @@ -25,6 +24,7 @@ escaped_thing() -> 'the.thing':'make.new'(). + //// /out/lib/the_package/_gleam_artefacts/three.cache <.cache binary> @@ -33,8 +33,7 @@ escaped_thing() -> //// /out/lib/the_package/_gleam_artefacts/three.erl -module(three). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/three.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([thing/0, escaped_thing/0]). -file("src/three.gleam", 5). @@ -48,6 +47,7 @@ escaped_thing() -> 'the.thing':'make.new'(). + //// /out/lib/the_package/_gleam_artefacts/two.cache <.cache binary> @@ -56,8 +56,7 @@ escaped_thing() -> //// /out/lib/the_package/_gleam_artefacts/two.erl -module(two). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/two.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([the_consts/0, fn_reference_qualified/0, fn_reference_qualified_aliased/0, fn_reference_unqualified/0, fn_reference_unqualified_aliased/0, fn_call_qualified/0, fn_call_qualified_aliased/0, fn_call_unqualified/0, fn_call_unqualified_aliased/0, argument_reference_qualified/0, argument_reference_qualified_aliased/0, argument_reference_unqualified/0, argument_reference_unqualified_aliased/0]). -file("src/two.gleam", 27). @@ -146,6 +145,7 @@ argument_reference_unqualified_aliased() -> x(fun 'the.thing':'make.new'/0). + //// /out/lib/the_package/ebin/importy.app {application, importy, [ {vsn, "0.1.0"}, diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__imported_record_constructors.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__imported_record_constructors.snap index 940f6f232..e87e85bb2 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__imported_record_constructors.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__imported_record_constructors.snap @@ -10,8 +10,7 @@ expression: "./cases/imported_record_constructors" //// /out/lib/the_package/_gleam_artefacts/one@one.erl -module(one@one). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/one/one.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([a/0, b/0, user/0]). -type a() :: a. @@ -22,7 +21,6 @@ expression: "./cases/imported_record_constructors" - //// /out/lib/the_package/_gleam_artefacts/one@two.cache <.cache binary> @@ -31,8 +29,7 @@ expression: "./cases/imported_record_constructors" //// /out/lib/the_package/_gleam_artefacts/one@two.erl -module(one@two). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/one/two.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export_type([a/0, b/0, user/0]). -type a() :: a. @@ -43,7 +40,6 @@ expression: "./cases/imported_record_constructors" - //// /out/lib/the_package/_gleam_artefacts/two.cache <.cache binary> @@ -52,18 +48,9 @@ expression: "./cases/imported_record_constructors" //// /out/lib/the_package/_gleam_artefacts/two.erl -module(two). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/two.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([qualified_fn_a/0, qualified_fn_b/0, qualified_aliased_fn_a/0, qualified_aliased_fn_b/0, unqualified_fn_a/0, unqualified_fn_b/0, aliased_fn_a/0, aliased_fn_b/0, accessors/1, destructure_qualified/1, destructure_qualified_aliased/1, destructure_unqualified/1, destructure_aliased/1, update_qualified/1, update_qualified_aliased/1, update_unqualified/1, update_aliased/1]). --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -file("src/two.gleam", 10). -spec qualified_fn_a() -> one@one:a(). qualified_fn_a() -> @@ -105,19 +92,17 @@ aliased_fn_b() -> {b, a, a}. -file("src/two.gleam", 61). -?DOC( - " For these statements we use the accessors for the record from the other\n" - " module\n" -). -spec accessors(one@one:user()) -> {binary(), integer()}. +-doc(<<" For these statements we use the accessors for the record from the other + module"/utf8>>). accessors(User) -> Name = erlang:element(2, User), Score = erlang:element(3, User), {Name, Score}. -file("src/two.gleam", 68). -?DOC(" For these statements we use destructure the record\n"). -spec destructure_qualified(one@one:user()) -> {binary(), integer()}. +-doc(<<" For these statements we use destructure the record"/utf8>>). destructure_qualified(User) -> {user, Name, Score} = User, {Name, Score}. @@ -141,8 +126,8 @@ destructure_aliased(User) -> {Name, Score}. -file("src/two.gleam", 89). -?DOC(" For these statements we use update the record\n"). -spec update_qualified(one@one:user()) -> one@one:user(). +-doc(<<" For these statements we use update the record"/utf8>>). update_qualified(User) -> {user, <<"wibble"/utf8>>, erlang:element(3, User)}. @@ -162,6 +147,7 @@ update_aliased(User) -> {user, <<"wibble"/utf8>>, erlang:element(3, User)}. + //// /out/lib/the_package/ebin/importy.app {application, importy, [ {vsn, "0.1.0"}, @@ -175,8 +161,14 @@ update_aliased(User) -> //// /out/lib/the_package/include/one@one_User.hrl --record(user, {name :: binary(), score :: integer()}). +-record(user, { + name :: binary(), + score :: integer() +}). //// /out/lib/the_package/include/one@two_User.hrl --record(user, {name :: binary(), score :: integer()}). +-record(user, { + name :: binary(), + score :: integer() +}). diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__not_overwriting_erlang_module.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__not_overwriting_erlang_module.snap index bdd3bee74..89f1f9303 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__not_overwriting_erlang_module.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__not_overwriting_erlang_module.snap @@ -10,6 +10,8 @@ expression: "./cases/not_overwriting_erlang_module" //// /out/lib/the_package/_gleam_artefacts/app@code.erl -module(app@code). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). + //// /out/lib/the_package/ebin/importy.app diff --git a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__variable_or_module.snap b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__variable_or_module.snap index 181ea6568..134880852 100644 --- a/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__variable_or_module.snap +++ b/test-package-compiler/src/snapshots/test_package_compiler__generated_tests__variable_or_module.snap @@ -10,8 +10,7 @@ expression: "./cases/variable_or_module" //// /out/lib/the_package/_gleam_artefacts/main.erl -module(main). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/main.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([module_function/1, record_field/1]). -file("src/main.gleam", 7). @@ -25,6 +24,7 @@ record_field(Power) -> erlang:element(2, Power). + //// /out/lib/the_package/_gleam_artefacts/power.cache <.cache binary> @@ -33,8 +33,7 @@ record_field(Power) -> //// /out/lib/the_package/_gleam_artefacts/power.erl -module(power). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/power.gleam"). +-compile([no_auto_import, nowarn_ignored, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -export([to_int/1]). -export_type([power/0]). @@ -46,6 +45,7 @@ to_int(P) -> erlang:element(2, P) * 9000. + //// /out/lib/the_package/ebin/importy.app {application, importy, [ {vsn, "0.1.0"}, @@ -58,4 +58,6 @@ to_int(P) -> //// /out/lib/the_package/include/power_Power.hrl --record(power, {value :: integer()}). +-record(power, { + value :: integer() +}).