mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Merge remote-tracking branch 'origin/main' into inspect-builtin
This commit is contained in:
commit
15a6bc34f4
183 changed files with 1793 additions and 1694 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -4099,6 +4099,7 @@ dependencies = [
|
|||
"roc_debug_flags",
|
||||
"roc_error_macros",
|
||||
"roc_module",
|
||||
"roc_parse",
|
||||
"roc_region",
|
||||
"roc_serialize",
|
||||
"static_assertions",
|
||||
|
|
84
FAQ.md
84
FAQ.md
|
@ -31,61 +31,6 @@ fantastical, and it has incredible potential for puns. Here are some different w
|
|||
|
||||
Fun fact: "roc" translates to 鹏 in Chinese, [which means](https://www.mdbg.net/chinese/dictionary?page=worddict&wdrst=0&wdqb=%E9%B9%8F) "a large fabulous bird."
|
||||
|
||||
## Why make a new editor instead of making an LSP plugin for VSCode, Vim or Emacs?
|
||||
|
||||
The Roc editor is one of the key areas where we want to innovate. Constraining ourselves to a plugin for existing editors would severely limit our possibilities for innovation.
|
||||
|
||||
A key part of our editor will be the use of plugins that are shipped with libraries. Think of a regex visualizer, parser debugger, or color picker. For library authors, it would be most convenient to write these plugins in Roc. Trying to dynamically load library plugins (written in Roc) in for example VSCode seems very difficult.
|
||||
|
||||
## Is there syntax highlighting for Vim/Emacs/VS Code or a LSP?
|
||||
|
||||
Not currently. Although they will presumably exist someday, while Roc is in the early days there's actually a conscious
|
||||
effort to focus on the Roc Editor _instead of_ adding Roc support to other editors - specifically in order to give the Roc
|
||||
Editor the best possible chance at kickstarting a virtuous cycle of plugin authorship.
|
||||
|
||||
This is an unusual approach, but there are more details in [this 2021 interview](https://youtu.be/ITrDd6-PbvY?t=212).
|
||||
|
||||
In the meantime, using CoffeeScript syntax highlighting for .roc files turns out to work surprisingly well!
|
||||
|
||||
## Why won't the editor be able to edit non-roc files like .md, .gitignore, .yml, ... ?
|
||||
|
||||
The downside of having the Roc editor support files other than .roc is that it seems extremely difficult to avoid scope creep if we allow it. For example, it starts with just editing json as plaintext but then it's annoying that there's no syntax highlighting, so maybe we add the capability to do syntax highlighting for json but of course then some people want it for toml, .md, etc, so we need to add a way to specify custom syntax highlighting rules for all of those.
|
||||
|
||||
Then of course people don't want to be copy/pasting syntax highlighting rules from online, so maybe someone develops a third party "plugin manager" for the editor to distribute these syntax highlighting definitions.
|
||||
So maybe we add sharing syntax highlighting as a first-class thing, so people don't have to download a separate tool to use their editor normally but then some people who are using it for .json and .yaml start using it for .css too. Syntax highlighting is okay but it's annoying that they don't get error reporting when they mess up syntax or type an invalid selector or import and pretty soon there's demand for the Roc editor to do all the hardest parts of VS code.
|
||||
|
||||
We have to draw the line somewhere in there...but where to draw it?
|
||||
It seems like drawing a bright line at .roc files is the most straightforward. It means the roc editor is the absolute best at editing .roc files and it isn't a weak editor for anything else because it doesn't try to be an editor for anything else and it means the scope is very clear.
|
||||
|
||||
## Why is there no way to specify "import everything this module exposes" in `imports`?
|
||||
|
||||
In [Elm](https://elm-lang.org), it's possible to import a module in a way that brings everything that module
|
||||
exposes into scope. It can be convenient, but like all programming language features, it has downsides.
|
||||
|
||||
A minor reason Roc doesn't have this feature is that exposing everything can make it more difficult
|
||||
outside the editor (e.g. on a website) to tell where something comes from, especially if multiple imports are
|
||||
using this. ("I don't see `blah` defined in this module, so it must be coming from an import...but which of
|
||||
these several import-exposing-everything modules could it be? I'll have to check all of them, or
|
||||
download this code base and open it up in the editor so I can jump to definition!")
|
||||
|
||||
The main reason for this design, though, is compiler performance.
|
||||
|
||||
Currently, the name resolution step in compilation can be parallelized across modules, because it's possible to
|
||||
tell if there's a naming error within a module using only the contents of that module. If "expose everything" is
|
||||
allowed, then it's no longer clear whether anything is a naming error or not, until all the "expose everything"
|
||||
modules have been processed, so we know exactly which names they expose. Because that feature doesn't exist in Roc,
|
||||
all modules can do name resolution in parallel.
|
||||
|
||||
Of note, allowing this feature would only slow down modules that used it; modules that didn't use it would still be
|
||||
parallelizable. However, when people find out ways to speed up their builds (in any language), advice starts to
|
||||
circulate about how to unlock those speed boosts. If Roc had this feature, it's predictable that a commonly-accepted
|
||||
piece of advice would eventually circulate: "don't use this feature because it slows down your builds."
|
||||
|
||||
If a feature exists in a language, but the common recommendation is never to use it, that's cause for reconsidering
|
||||
whether the feature should be in the language at all. In the case of this feature, I think it's simpler if the
|
||||
language doesn't have it; that way nobody has to learn (or spend time spreading the word) about the
|
||||
performance-boosting advice not to use it.
|
||||
|
||||
## Why can't functions be compared for equality using the `==` operator?
|
||||
|
||||
Function equality has been proven to be undecidable in the general case because of the [halting problem](https://en.wikipedia.org/wiki/Halting_problem).
|
||||
|
@ -126,6 +71,35 @@ The first of these problems could be addressed by having function equality alway
|
|||
Each of these designs makes Roc a language that's some combination of more error-prone, more confusing, and more
|
||||
brittle to change. Disallowing function equality at compile time eliminates all of these drawbacks.
|
||||
|
||||
## Why is there no way to specify "import everything this module exposes" in `imports`?
|
||||
|
||||
In [Elm](https://elm-lang.org), it's possible to import a module in a way that brings everything that module
|
||||
exposes into scope. It can be convenient, but like all programming language features, it has downsides.
|
||||
|
||||
A minor reason Roc doesn't have this feature is that exposing everything can make it more difficult
|
||||
outside the editor (e.g. on a website) to tell where something comes from, especially if multiple imports are
|
||||
using this. ("I don't see `blah` defined in this module, so it must be coming from an import...but which of
|
||||
these several import-exposing-everything modules could it be? I'll have to check all of them, or
|
||||
download this code base and open it up in the editor so I can jump to definition!")
|
||||
|
||||
The main reason for this design, though, is compiler performance.
|
||||
|
||||
Currently, the name resolution step in compilation can be parallelized across modules, because it's possible to
|
||||
tell if there's a naming error within a module using only the contents of that module. If "expose everything" is
|
||||
allowed, then it's no longer clear whether anything is a naming error or not, until all the "expose everything"
|
||||
modules have been processed, so we know exactly which names they expose. Because that feature doesn't exist in Roc,
|
||||
all modules can do name resolution in parallel.
|
||||
|
||||
Of note, allowing this feature would only slow down modules that used it; modules that didn't use it would still be
|
||||
parallelizable. However, when people find out ways to speed up their builds (in any language), advice starts to
|
||||
circulate about how to unlock those speed boosts. If Roc had this feature, it's predictable that a commonly-accepted
|
||||
piece of advice would eventually circulate: "don't use this feature because it slows down your builds."
|
||||
|
||||
If a feature exists in a language, but the common recommendation is never to use it, that's cause for reconsidering
|
||||
whether the feature should be in the language at all. In the case of this feature, I think it's simpler if the
|
||||
language doesn't have it; that way nobody has to learn (or spend time spreading the word) about the
|
||||
performance-boosting advice not to use it.
|
||||
|
||||
## Why doesn't Roc have a `Maybe` or `Option` or `Optional` type, or `null` or `nil` or `undefined`?
|
||||
|
||||
It's common for programming languages to have a [null reference](https://en.wikipedia.org/wiki/Null_pointer)
|
||||
|
|
|
@ -10,9 +10,9 @@ Model position : {
|
|||
openSet : Set position,
|
||||
costs : Dict position F64,
|
||||
cameFrom : Dict position position,
|
||||
} | position has Hash & Eq
|
||||
} where position implements Hash & Eq
|
||||
|
||||
initialModel : position -> Model position | position has Hash & Eq
|
||||
initialModel : position -> Model position where position implements Hash & Eq
|
||||
initialModel = \start -> {
|
||||
evaluated: Set.empty {},
|
||||
openSet: Set.single start,
|
||||
|
@ -20,7 +20,7 @@ initialModel = \start -> {
|
|||
cameFrom: Dict.empty {},
|
||||
}
|
||||
|
||||
cheapestOpen : (position -> F64), Model position -> Result position {} | position has Hash & Eq
|
||||
cheapestOpen : (position -> F64), Model position -> Result position {} where position implements Hash & Eq
|
||||
cheapestOpen = \costFn, model ->
|
||||
model.openSet
|
||||
|> Set.toList
|
||||
|
@ -35,13 +35,13 @@ cheapestOpen = \costFn, model ->
|
|||
|> Result.map .position
|
||||
|> Result.mapErr (\_ -> {})
|
||||
|
||||
reconstructPath : Dict position position, position -> List position | position has Hash & Eq
|
||||
reconstructPath : Dict position position, position -> List position where position implements Hash & Eq
|
||||
reconstructPath = \cameFrom, goal ->
|
||||
when Dict.get cameFrom goal is
|
||||
Err _ -> []
|
||||
Ok next -> List.append (reconstructPath cameFrom next) goal
|
||||
|
||||
updateCost : position, position, Model position -> Model position | position has Hash & Eq
|
||||
updateCost : position, position, Model position -> Model position where position implements Hash & Eq
|
||||
updateCost = \current, neighbor, model ->
|
||||
newCameFrom =
|
||||
Dict.insert model.cameFrom neighbor current
|
||||
|
@ -70,7 +70,7 @@ updateCost = \current, neighbor, model ->
|
|||
else
|
||||
model
|
||||
|
||||
astar : (position, position -> F64), (position -> Set position), position, Model position -> Result (List position) {} | position has Hash & Eq
|
||||
astar : (position, position -> F64), (position -> Set position), position, Model position -> Result (List position) {} where position implements Hash & Eq
|
||||
astar = \costFn, moveFn, goal, model ->
|
||||
when cheapestOpen (\source -> costFn source goal) model is
|
||||
Err {} -> Err {}
|
||||
|
|
|
@ -4,6 +4,7 @@ use roc_command_utils::{cargo, clang, rustup, zig};
|
|||
use roc_error_macros::internal_error;
|
||||
use roc_mono::ir::OptLevel;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::DirEntry;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -785,11 +786,25 @@ fn get_target_str(target: &Triple) -> &str {
|
|||
}
|
||||
}
|
||||
|
||||
fn nix_path_opt() -> Option<String> {
|
||||
env::var_os("NIX_GLIBC_PATH").map(|path| path.into_string().unwrap())
|
||||
fn nix_paths() -> Vec<String> {
|
||||
let mut paths = vec![];
|
||||
|
||||
if let Some(nix_libgcc_s_path) = env::var_os("NIX_LIBGCC_S_PATH") {
|
||||
paths.push(nix_libgcc_s_path.into_string().unwrap())
|
||||
}
|
||||
|
||||
if let Some(nix_glibc_path) = nix_glibc_path_opt() {
|
||||
paths.push(nix_glibc_path.into_string().unwrap())
|
||||
}
|
||||
|
||||
paths
|
||||
}
|
||||
|
||||
fn library_path<const N: usize>(segments: [&str; N]) -> Option<PathBuf> {
|
||||
fn nix_glibc_path_opt() -> Option<OsString> {
|
||||
env::var_os("NIX_GLIBC_PATH")
|
||||
}
|
||||
|
||||
fn build_path<const N: usize>(segments: [&str; N]) -> Option<PathBuf> {
|
||||
let mut guess_path = PathBuf::new();
|
||||
for s in segments {
|
||||
guess_path.push(s);
|
||||
|
@ -812,22 +827,21 @@ fn library_path<const N: usize>(segments: [&str; N]) -> Option<PathBuf> {
|
|||
/// match will be returned.
|
||||
///
|
||||
/// If there are no matches, [`None`] will be returned.
|
||||
fn look_for_library(lib_dirs: &[&[&str]], lib_filename: &str) -> Option<PathBuf> {
|
||||
fn look_for_library(lib_dirs: &[PathBuf], lib_filename: &str) -> Option<PathBuf> {
|
||||
lib_dirs
|
||||
.iter()
|
||||
.map(|lib_dir| {
|
||||
lib_dir.iter().fold(PathBuf::new(), |mut path, segment| {
|
||||
path.push(segment);
|
||||
path
|
||||
})
|
||||
})
|
||||
.map(|mut path| {
|
||||
path.push(lib_filename);
|
||||
path
|
||||
.map(|path| {
|
||||
let mut path_cl = path.clone();
|
||||
path_cl.push(lib_filename);
|
||||
path_cl
|
||||
})
|
||||
.find(|path| path.exists())
|
||||
}
|
||||
|
||||
fn strs_to_path(strs: &[&str]) -> PathBuf {
|
||||
strs.iter().collect()
|
||||
}
|
||||
|
||||
fn link_linux(
|
||||
target: &Triple,
|
||||
output_path: PathBuf,
|
||||
|
@ -862,50 +876,37 @@ fn link_linux(
|
|||
));
|
||||
}
|
||||
|
||||
// Some things we'll need to build a list of dirs to check for libraries
|
||||
let maybe_nix_path = nix_path_opt();
|
||||
let usr_lib_arch = ["/usr", "lib", &architecture];
|
||||
let lib_arch = ["/lib", &architecture];
|
||||
let nix_path_segments;
|
||||
let lib_dirs_if_nix: [&[&str]; 5];
|
||||
let lib_dirs_if_nonix: [&[&str]; 4];
|
||||
let nix_paths_vec_string = nix_paths();
|
||||
let nix_paths_vec: Vec<PathBuf> = nix_paths_vec_string.iter().map(PathBuf::from).collect();
|
||||
let usr_lib_arch_path = strs_to_path(&["/usr", "lib", &architecture]);
|
||||
let lib_arch_path = strs_to_path(&["/lib", &architecture]);
|
||||
|
||||
// Build the aformentioned list
|
||||
let lib_dirs: &[&[&str]] =
|
||||
// give preference to nix_path if it's defined, this prevents bugs
|
||||
if let Some(nix_path) = &maybe_nix_path {
|
||||
nix_path_segments = [nix_path.as_str()];
|
||||
lib_dirs_if_nix = [
|
||||
&nix_path_segments,
|
||||
&usr_lib_arch,
|
||||
&lib_arch,
|
||||
&["/usr", "lib"],
|
||||
&["/usr", "lib64"],
|
||||
];
|
||||
&lib_dirs_if_nix
|
||||
} else {
|
||||
lib_dirs_if_nonix = [
|
||||
&usr_lib_arch,
|
||||
&lib_arch,
|
||||
&["/usr", "lib"],
|
||||
&["/usr", "lib64"],
|
||||
];
|
||||
&lib_dirs_if_nonix
|
||||
};
|
||||
let mut lib_dirs: Vec<PathBuf> = vec![];
|
||||
|
||||
// start with nix paths, this prevents version incompatibility
|
||||
if !nix_paths_vec.is_empty() {
|
||||
lib_dirs.extend(nix_paths_vec)
|
||||
}
|
||||
|
||||
lib_dirs.extend([
|
||||
usr_lib_arch_path,
|
||||
lib_arch_path,
|
||||
strs_to_path(&["/usr", "lib"]),
|
||||
strs_to_path(&["/usr", "lib64"]),
|
||||
]);
|
||||
|
||||
// Look for the libraries we'll need
|
||||
|
||||
let libgcc_name = "libgcc_s.so.1";
|
||||
let libgcc_path = look_for_library(lib_dirs, libgcc_name);
|
||||
let libgcc_path = look_for_library(&lib_dirs, libgcc_name);
|
||||
|
||||
let crti_name = "crti.o";
|
||||
let crti_path = look_for_library(lib_dirs, crti_name);
|
||||
let crti_path = look_for_library(&lib_dirs, crti_name);
|
||||
|
||||
let crtn_name = "crtn.o";
|
||||
let crtn_path = look_for_library(lib_dirs, crtn_name);
|
||||
let crtn_path = look_for_library(&lib_dirs, crtn_name);
|
||||
|
||||
let scrt1_name = "Scrt1.o";
|
||||
let scrt1_path = look_for_library(lib_dirs, scrt1_name);
|
||||
let scrt1_path = look_for_library(&lib_dirs, scrt1_name);
|
||||
|
||||
// Unwrap all the paths at once so we can inform the user of all missing libs at once
|
||||
let (libgcc_path, crti_path, crtn_path, scrt1_path) =
|
||||
|
@ -925,7 +926,13 @@ fn link_linux(
|
|||
|
||||
let dirs = lib_dirs
|
||||
.iter()
|
||||
.map(|segments| segments.join("/"))
|
||||
.map(|path_buf| {
|
||||
path_buf
|
||||
.as_path()
|
||||
.to_str()
|
||||
.unwrap_or("FAILED TO CONVERT PATH TO STR")
|
||||
.to_string()
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
eprintln!("We looked in the following directories:\n{dirs}");
|
||||
|
@ -936,13 +943,16 @@ fn link_linux(
|
|||
let ld_linux = match target.architecture {
|
||||
Architecture::X86_64 => {
|
||||
// give preference to nix_path if it's defined, this prevents bugs
|
||||
if let Some(nix_path) = nix_path_opt() {
|
||||
library_path([&nix_path, "ld-linux-x86-64.so.2"])
|
||||
if let Some(nix_glibc_path) = nix_glibc_path_opt() {
|
||||
build_path([
|
||||
&nix_glibc_path.into_string().unwrap(),
|
||||
"ld-linux-x86-64.so.2",
|
||||
])
|
||||
} else {
|
||||
library_path(["/lib64", "ld-linux-x86-64.so.2"])
|
||||
build_path(["/lib64", "ld-linux-x86-64.so.2"])
|
||||
}
|
||||
}
|
||||
Architecture::Aarch64(_) => library_path(["/lib", "ld-linux-aarch64.so.1"]),
|
||||
Architecture::Aarch64(_) => build_path(["/lib", "ld-linux-aarch64.so.1"]),
|
||||
_ => internal_error!(
|
||||
"TODO gracefully handle unsupported linux architecture: {:?}",
|
||||
target.architecture
|
||||
|
|
|
@ -12,7 +12,7 @@ interface Bool
|
|||
## be a `NaN` ([Not a Number](https://en.wikipedia.org/wiki/NaN)), and the
|
||||
## [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754) floating point standard
|
||||
## specifies that two `NaN`s are not equal.
|
||||
Eq has
|
||||
Eq implements
|
||||
## Returns `Bool.true` if the input values are equal. This is
|
||||
## equivalent to the logic
|
||||
## [XNOR](https://en.wikipedia.org/wiki/Logical_equality) gate. The infix
|
||||
|
@ -30,11 +30,11 @@ Eq has
|
|||
## for more detail.
|
||||
## 5. Functions cannot be compared for structural equality, therefore Roc
|
||||
## cannot derive `isEq` for types that contain functions.
|
||||
isEq : a, a -> Bool | a has Eq
|
||||
isEq : a, a -> Bool where a implements Eq
|
||||
|
||||
## Represents the boolean true and false using an opaque type.
|
||||
## `Bool` implements the `Eq` ability.
|
||||
Bool := [True, False] has [Eq { isEq: boolIsEq }]
|
||||
Bool := [True, False] implements [Eq { isEq: boolIsEq }]
|
||||
|
||||
boolIsEq = \@Bool b1, @Bool b2 -> structuralEq b1 b2
|
||||
|
||||
|
@ -116,7 +116,7 @@ not : Bool -> Bool
|
|||
## expect (Bool.false != Bool.false) == Bool.false
|
||||
## expect "Apples" != "Oranges"
|
||||
## ```
|
||||
isNotEq : a, a -> Bool | a has Eq
|
||||
isNotEq : a, a -> Bool where a implements Eq
|
||||
isNotEq = \a, b -> structuralNotEq a b
|
||||
|
||||
# INTERNAL COMPILER USE ONLY: used to lower calls to `isEq` to structural
|
||||
|
|
|
@ -73,30 +73,30 @@ DecodeResult val : { result : Result val DecodeError, rest : List U8 }
|
|||
## Decodes a `List U8` of utf-8 bytes where `val` is the type of the decoded
|
||||
## value, and `fmt` is a [Decoder] which implements the [DecoderFormatting]
|
||||
## ability
|
||||
Decoder val fmt := List U8, fmt -> DecodeResult val | fmt has DecoderFormatting
|
||||
Decoder val fmt := List U8, fmt -> DecodeResult val where fmt implements DecoderFormatting
|
||||
|
||||
## Definition of the [Decoding] ability
|
||||
Decoding has
|
||||
decoder : Decoder val fmt | val has Decoding, fmt has DecoderFormatting
|
||||
Decoding implements
|
||||
decoder : Decoder val fmt where val implements Decoding, fmt implements DecoderFormatting
|
||||
|
||||
## Definition of the [DecoderFormatting] ability
|
||||
DecoderFormatting has
|
||||
u8 : Decoder U8 fmt | fmt has DecoderFormatting
|
||||
u16 : Decoder U16 fmt | fmt has DecoderFormatting
|
||||
u32 : Decoder U32 fmt | fmt has DecoderFormatting
|
||||
u64 : Decoder U64 fmt | fmt has DecoderFormatting
|
||||
u128 : Decoder U128 fmt | fmt has DecoderFormatting
|
||||
i8 : Decoder I8 fmt | fmt has DecoderFormatting
|
||||
i16 : Decoder I16 fmt | fmt has DecoderFormatting
|
||||
i32 : Decoder I32 fmt | fmt has DecoderFormatting
|
||||
i64 : Decoder I64 fmt | fmt has DecoderFormatting
|
||||
i128 : Decoder I128 fmt | fmt has DecoderFormatting
|
||||
f32 : Decoder F32 fmt | fmt has DecoderFormatting
|
||||
f64 : Decoder F64 fmt | fmt has DecoderFormatting
|
||||
dec : Decoder Dec fmt | fmt has DecoderFormatting
|
||||
bool : Decoder Bool fmt | fmt has DecoderFormatting
|
||||
string : Decoder Str fmt | fmt has DecoderFormatting
|
||||
list : Decoder elem fmt -> Decoder (List elem) fmt | fmt has DecoderFormatting
|
||||
DecoderFormatting implements
|
||||
u8 : Decoder U8 fmt where fmt implements DecoderFormatting
|
||||
u16 : Decoder U16 fmt where fmt implements DecoderFormatting
|
||||
u32 : Decoder U32 fmt where fmt implements DecoderFormatting
|
||||
u64 : Decoder U64 fmt where fmt implements DecoderFormatting
|
||||
u128 : Decoder U128 fmt where fmt implements DecoderFormatting
|
||||
i8 : Decoder I8 fmt where fmt implements DecoderFormatting
|
||||
i16 : Decoder I16 fmt where fmt implements DecoderFormatting
|
||||
i32 : Decoder I32 fmt where fmt implements DecoderFormatting
|
||||
i64 : Decoder I64 fmt where fmt implements DecoderFormatting
|
||||
i128 : Decoder I128 fmt where fmt implements DecoderFormatting
|
||||
f32 : Decoder F32 fmt where fmt implements DecoderFormatting
|
||||
f64 : Decoder F64 fmt where fmt implements DecoderFormatting
|
||||
dec : Decoder Dec fmt where fmt implements DecoderFormatting
|
||||
bool : Decoder Bool fmt where fmt implements DecoderFormatting
|
||||
string : Decoder Str fmt where fmt implements DecoderFormatting
|
||||
list : Decoder elem fmt -> Decoder (List elem) fmt where fmt implements DecoderFormatting
|
||||
|
||||
## `record state stepField finalizer` decodes a record field-by-field.
|
||||
##
|
||||
|
@ -104,7 +104,7 @@ DecoderFormatting has
|
|||
## `Skip` if the field is not a part of the decoded record.
|
||||
##
|
||||
## `finalizer` should produce the record value from the decoded `state`.
|
||||
record : state, (state, Str -> [Keep (Decoder state fmt), Skip]), (state -> Result val DecodeError) -> Decoder val fmt | fmt has DecoderFormatting
|
||||
record : state, (state, Str -> [Keep (Decoder state fmt), Skip]), (state -> Result val DecodeError) -> Decoder val fmt where fmt implements DecoderFormatting
|
||||
|
||||
## `tuple state stepElem finalizer` decodes a tuple element-by-element.
|
||||
##
|
||||
|
@ -113,7 +113,7 @@ DecoderFormatting has
|
|||
## index passed to `stepElem` is 0-indexed.
|
||||
##
|
||||
## `finalizer` should produce the tuple value from the decoded `state`.
|
||||
tuple : state, (state, Nat -> [Next (Decoder state fmt), TooLong]), (state -> Result val DecodeError) -> Decoder val fmt | fmt has DecoderFormatting
|
||||
tuple : state, (state, Nat -> [Next (Decoder state fmt), TooLong]), (state -> Result val DecodeError) -> Decoder val fmt where fmt implements DecoderFormatting
|
||||
|
||||
## Build a custom [Decoder] function. For example the implementation of
|
||||
## `decodeBool` could be defined as follows;
|
||||
|
@ -125,11 +125,11 @@ DecoderFormatting has
|
|||
## ['t', 'r', 'u', 'e', ..] -> { result: Ok Bool.true, rest: List.drop bytes 4 }
|
||||
## _ -> { result: Err TooShort, rest: bytes }
|
||||
## ```
|
||||
custom : (List U8, fmt -> DecodeResult val) -> Decoder val fmt | fmt has DecoderFormatting
|
||||
custom : (List U8, fmt -> DecodeResult val) -> Decoder val fmt where fmt implements DecoderFormatting
|
||||
custom = \decode -> @Decoder decode
|
||||
|
||||
## Decode a `List U8` utf-8 bytes using a specific [Decoder] function
|
||||
decodeWith : List U8, Decoder val fmt, fmt -> DecodeResult val | fmt has DecoderFormatting
|
||||
decodeWith : List U8, Decoder val fmt, fmt -> DecodeResult val where fmt implements DecoderFormatting
|
||||
decodeWith = \bytes, @Decoder decode, fmt -> decode bytes fmt
|
||||
|
||||
## Decode a `List U8` utf-8 bytes and return a [DecodeResult](#DecodeResult)
|
||||
|
@ -141,7 +141,7 @@ decodeWith = \bytes, @Decoder decode, fmt -> decode bytes fmt
|
|||
##
|
||||
## actual.result == expected
|
||||
## ```
|
||||
fromBytesPartial : List U8, fmt -> DecodeResult val | val has Decoding, fmt has DecoderFormatting
|
||||
fromBytesPartial : List U8, fmt -> DecodeResult val where val implements Decoding, fmt implements DecoderFormatting
|
||||
fromBytesPartial = \bytes, fmt -> decodeWith bytes decoder fmt
|
||||
|
||||
## Decode a `List U8` utf-8 bytes and return a [Result] with no leftover bytes
|
||||
|
@ -155,7 +155,7 @@ fromBytesPartial = \bytes, fmt -> decodeWith bytes decoder fmt
|
|||
##
|
||||
## actual == expected
|
||||
## ```
|
||||
fromBytes : List U8, fmt -> Result val [Leftover (List U8)]DecodeError | val has Decoding, fmt has DecoderFormatting
|
||||
fromBytes : List U8, fmt -> Result val [Leftover (List U8)]DecodeError where val implements Decoding, fmt implements DecoderFormatting
|
||||
fromBytes = \bytes, fmt ->
|
||||
when fromBytesPartial bytes fmt is
|
||||
{ result, rest } ->
|
||||
|
|
|
@ -95,13 +95,13 @@ Dict k v := {
|
|||
# TODO: As an optimization, we can make all of these lists in one allocation
|
||||
# TODO: Grow data with the rest of the hashmap. This will require creating a list of garbage data.
|
||||
# TODO: Change remove to use tombstones. Store the tombstones in a bitmap.
|
||||
# TODO: define Eq and Hash that are unordered. Only if value has hash/eq?
|
||||
# TODO: define Eq and Hash that are unordered. Only if value implements hash/eq?
|
||||
metadata : List I8,
|
||||
dataIndices : List Nat,
|
||||
data : List (k, v),
|
||||
size : Nat,
|
||||
} | k has Hash & Eq
|
||||
has [
|
||||
} where k implements Hash & Eq
|
||||
implements [
|
||||
Eq {
|
||||
isEq,
|
||||
},
|
||||
|
@ -110,7 +110,7 @@ Dict k v := {
|
|||
},
|
||||
]
|
||||
|
||||
isEq : Dict k v, Dict k v -> Bool | k has Hash & Eq, v has Eq
|
||||
isEq : Dict k v, Dict k v -> Bool where k implements Hash & Eq, v implements Eq
|
||||
isEq = \xs, ys ->
|
||||
if len xs != len ys then
|
||||
Bool.false
|
||||
|
@ -123,14 +123,14 @@ isEq = \xs, ys ->
|
|||
_ ->
|
||||
Break Bool.false
|
||||
|
||||
hashDict : hasher, Dict k v -> hasher | k has Hash & Eq, v has Hash, hasher has Hasher
|
||||
hashDict : hasher, Dict k v -> hasher where k implements Hash & Eq, v implements Hash, hasher implements Hasher
|
||||
hashDict = \hasher, dict -> Hash.hashUnordered hasher (toList dict) List.walk
|
||||
|
||||
## Return an empty dictionary.
|
||||
## ```
|
||||
## emptyDict = Dict.empty {}
|
||||
## ```
|
||||
empty : {} -> Dict k v | k has Hash & Eq
|
||||
empty : {} -> Dict k v where k implements Hash & Eq
|
||||
empty = \{} ->
|
||||
@Dict {
|
||||
metadata: List.repeat emptySlot 8,
|
||||
|
@ -156,7 +156,7 @@ capacity = \@Dict { dataIndices } ->
|
|||
## Return a dictionary with space allocated for a number of entries. This
|
||||
## may provide a performance optimization if you know how many entries will be
|
||||
## inserted.
|
||||
withCapacity : Nat -> Dict k v | k has Hash & Eq
|
||||
withCapacity : Nat -> Dict k v where k implements Hash & Eq
|
||||
withCapacity = \_ ->
|
||||
# TODO: power of 2 * 8 and actual implementation
|
||||
empty {}
|
||||
|
@ -167,7 +167,7 @@ withCapacity = \_ ->
|
|||
## Dict.single "A" "B"
|
||||
## |> Bool.isEq (Dict.insert (Dict.empty {}) "A" "B")
|
||||
## ```
|
||||
single : k, v -> Dict k v | k has Hash & Eq
|
||||
single : k, v -> Dict k v where k implements Hash & Eq
|
||||
single = \k, v ->
|
||||
insert (empty {}) k v
|
||||
|
||||
|
@ -180,7 +180,7 @@ single = \k, v ->
|
|||
## |> Dict.insert 4 "Four"
|
||||
## |> Bool.isEq (Dict.fromList [(1, "One"), (2, "Two"), (3, "Three"), (4, "Four")])
|
||||
## ```
|
||||
fromList : List (k, v) -> Dict k v | k has Hash & Eq
|
||||
fromList : List (k, v) -> Dict k v where k implements Hash & Eq
|
||||
fromList = \data ->
|
||||
# TODO: make this efficient. Should just set data and then set all indicies in the hashmap.
|
||||
List.walk data (empty {}) (\dict, (k, v) -> insert dict k v)
|
||||
|
@ -221,7 +221,7 @@ isEmpty = \@Dict { size } ->
|
|||
##
|
||||
## expect Dict.len clearSongs == 0
|
||||
## ```
|
||||
clear : Dict k v -> Dict k v | k has Hash & Eq
|
||||
clear : Dict k v -> Dict k v where k implements Hash & Eq
|
||||
clear = \@Dict { metadata, dataIndices, data } ->
|
||||
cap = List.len dataIndices
|
||||
|
||||
|
@ -241,7 +241,7 @@ clear = \@Dict { metadata, dataIndices, data } ->
|
|||
## Convert each value in the dictionary to something new, by calling a conversion
|
||||
## function on each of them which receives both the key and the old value. Then return a
|
||||
## new dictionary containing the same keys and the converted values.
|
||||
map : Dict k a, (k, a -> b) -> Dict k b | k has Hash & Eq, b has Hash & Eq
|
||||
map : Dict k a, (k, a -> b) -> Dict k b where k implements Hash & Eq, b implements Hash & Eq
|
||||
map = \dict, transform ->
|
||||
init = withCapacity (capacity dict)
|
||||
|
||||
|
@ -253,7 +253,7 @@ map = \dict, transform ->
|
|||
## (using [Dict.insertAll]) into one dictionary.
|
||||
##
|
||||
## You may know a similar function named `concatMap` in other languages.
|
||||
joinMap : Dict a b, (a, b -> Dict x y) -> Dict x y | a has Hash & Eq, x has Hash & Eq
|
||||
joinMap : Dict a b, (a, b -> Dict x y) -> Dict x y where a implements Hash & Eq, x implements Hash & Eq
|
||||
joinMap = \dict, transform ->
|
||||
init = withCapacity (capacity dict) # Might be a pessimization
|
||||
|
||||
|
@ -271,7 +271,7 @@ joinMap = \dict, transform ->
|
|||
## |> Dict.walk 0 (\count, _, qty -> count + qty)
|
||||
## |> Bool.isEq 36
|
||||
## ```
|
||||
walk : Dict k v, state, (state, k, v -> state) -> state | k has Hash & Eq
|
||||
walk : Dict k v, state, (state, k, v -> state) -> state where k implements Hash & Eq
|
||||
walk = \@Dict { data }, initialState, transform ->
|
||||
List.walk data initialState (\state, (k, v) -> transform state k v)
|
||||
|
||||
|
@ -303,7 +303,7 @@ walk = \@Dict { data }, initialState, transform ->
|
|||
##
|
||||
## expect someoneIsAnAdult == Bool.true
|
||||
## ```
|
||||
walkUntil : Dict k v, state, (state, k, v -> [Continue state, Break state]) -> state | k has Hash & Eq
|
||||
walkUntil : Dict k v, state, (state, k, v -> [Continue state, Break state]) -> state where k implements Hash & Eq
|
||||
walkUntil = \@Dict { data }, initialState, transform ->
|
||||
List.walkUntil data initialState (\state, (k, v) -> transform state k v)
|
||||
|
||||
|
@ -318,7 +318,7 @@ walkUntil = \@Dict { data }, initialState, transform ->
|
|||
## expect Dict.get dictionary 1 == Ok "Apple"
|
||||
## expect Dict.get dictionary 2000 == Err KeyNotFound
|
||||
## ```
|
||||
get : Dict k v, k -> Result v [KeyNotFound] | k has Hash & Eq
|
||||
get : Dict k v, k -> Result v [KeyNotFound] where k implements Hash & Eq
|
||||
get = \@Dict { metadata, dataIndices, data }, key ->
|
||||
hashKey =
|
||||
createLowLevelHasher PseudoRandSeed
|
||||
|
@ -346,7 +346,7 @@ get = \@Dict { metadata, dataIndices, data }, key ->
|
|||
## |> Dict.contains 1234
|
||||
## |> Bool.isEq Bool.true
|
||||
## ```
|
||||
contains : Dict k v, k -> Bool | k has Hash & Eq
|
||||
contains : Dict k v, k -> Bool where k implements Hash & Eq
|
||||
contains = \@Dict { metadata, dataIndices, data }, key ->
|
||||
hashKey =
|
||||
createLowLevelHasher PseudoRandSeed
|
||||
|
@ -371,7 +371,7 @@ contains = \@Dict { metadata, dataIndices, data }, key ->
|
|||
## |> Dict.get "Apples"
|
||||
## |> Bool.isEq (Ok 12)
|
||||
## ```
|
||||
insert : Dict k v, k, v -> Dict k v | k has Hash & Eq
|
||||
insert : Dict k v, k, v -> Dict k v where k implements Hash & Eq
|
||||
insert = \@Dict { metadata, dataIndices, data, size }, key, value ->
|
||||
hashKey =
|
||||
createLowLevelHasher PseudoRandSeed
|
||||
|
@ -417,7 +417,7 @@ insert = \@Dict { metadata, dataIndices, data, size }, key, value ->
|
|||
## |> Dict.len
|
||||
## |> Bool.isEq 0
|
||||
## ```
|
||||
remove : Dict k v, k -> Dict k v | k has Hash & Eq
|
||||
remove : Dict k v, k -> Dict k v where k implements Hash & Eq
|
||||
remove = \@Dict { metadata, dataIndices, data, size }, key ->
|
||||
# TODO: change this from swap remove to tombstone and test is performance is still good.
|
||||
hashKey =
|
||||
|
@ -461,7 +461,7 @@ remove = \@Dict { metadata, dataIndices, data, size }, key ->
|
|||
## expect Dict.update (Dict.single "a" Bool.false) "a" alterValue == Dict.single "a" Bool.true
|
||||
## expect Dict.update (Dict.single "a" Bool.true) "a" alterValue == Dict.empty {}
|
||||
## ```
|
||||
update : Dict k v, k, ([Present v, Missing] -> [Present v, Missing]) -> Dict k v | k has Hash & Eq
|
||||
update : Dict k v, k, ([Present v, Missing] -> [Present v, Missing]) -> Dict k v where k implements Hash & Eq
|
||||
update = \dict, key, alter ->
|
||||
# TODO: look into optimizing by merging substeps and reducing lookups.
|
||||
possibleValue =
|
||||
|
@ -484,7 +484,7 @@ update = \dict, key, alter ->
|
|||
## |> Dict.toList
|
||||
## |> Bool.isEq [(1, "One"), (2, "Two"), (3, "Three"), (4, "Four")]
|
||||
## ```
|
||||
toList : Dict k v -> List (k, v) | k has Hash & Eq
|
||||
toList : Dict k v -> List (k, v) where k implements Hash & Eq
|
||||
toList = \@Dict { data } ->
|
||||
data
|
||||
|
||||
|
@ -499,7 +499,7 @@ toList = \@Dict { data } ->
|
|||
## |> Dict.keys
|
||||
## |> Bool.isEq [1,2,3,4]
|
||||
## ```
|
||||
keys : Dict k v -> List k | k has Hash & Eq
|
||||
keys : Dict k v -> List k where k implements Hash & Eq
|
||||
keys = \@Dict { data } ->
|
||||
List.map data (\(k, _) -> k)
|
||||
|
||||
|
@ -514,7 +514,7 @@ keys = \@Dict { data } ->
|
|||
## |> Dict.values
|
||||
## |> Bool.isEq ["One","Two","Three","Four"]
|
||||
## ```
|
||||
values : Dict k v -> List v | k has Hash & Eq
|
||||
values : Dict k v -> List v where k implements Hash & Eq
|
||||
values = \@Dict { data } ->
|
||||
List.map data (\(_, v) -> v)
|
||||
|
||||
|
@ -542,7 +542,7 @@ values = \@Dict { data } ->
|
|||
## expect
|
||||
## Dict.insertAll first second == expected
|
||||
## ```
|
||||
insertAll : Dict k v, Dict k v -> Dict k v | k has Hash & Eq
|
||||
insertAll : Dict k v, Dict k v -> Dict k v where k implements Hash & Eq
|
||||
insertAll = \xs, ys ->
|
||||
walk ys xs insert
|
||||
|
||||
|
@ -564,7 +564,7 @@ insertAll = \xs, ys ->
|
|||
##
|
||||
## expect Dict.keepShared first second == first
|
||||
## ```
|
||||
keepShared : Dict k v, Dict k v -> Dict k v | k has Hash & Eq
|
||||
keepShared : Dict k v, Dict k v -> Dict k v where k implements Hash & Eq
|
||||
keepShared = \xs, ys ->
|
||||
walk
|
||||
xs
|
||||
|
@ -596,11 +596,11 @@ keepShared = \xs, ys ->
|
|||
##
|
||||
## expect Dict.removeAll first second == expected
|
||||
## ```
|
||||
removeAll : Dict k v, Dict k v -> Dict k v | k has Hash & Eq
|
||||
removeAll : Dict k v, Dict k v -> Dict k v where k implements Hash & Eq
|
||||
removeAll = \xs, ys ->
|
||||
walk ys xs (\state, k, _ -> remove state k)
|
||||
|
||||
swapAndUpdateDataIndex : Dict k v, Nat, Nat -> Dict k v | k has Hash & Eq
|
||||
swapAndUpdateDataIndex : Dict k v, Nat, Nat -> Dict k v where k implements Hash & Eq
|
||||
swapAndUpdateDataIndex = \@Dict { metadata, dataIndices, data, size }, removedIndex, lastIndex ->
|
||||
(key, _) = listGetUnsafe data lastIndex
|
||||
hashKey =
|
||||
|
@ -664,7 +664,7 @@ nextEmptyOrDeletedHelper = \metadata, probe, offset ->
|
|||
|
||||
# TODO: investigate if this needs to be split into more specific helper functions.
|
||||
# There is a chance that returning specific sub-info like the value would be faster.
|
||||
findIndexHelper : List I8, List Nat, List (k, v), I8, k, Probe, Nat -> Result Nat [NotFound] | k has Hash & Eq
|
||||
findIndexHelper : List I8, List Nat, List (k, v), I8, k, Probe, Nat -> Result Nat [NotFound] where k implements Hash & Eq
|
||||
findIndexHelper = \metadata, dataIndices, data, h2Key, key, probe, offset ->
|
||||
# For finding a value, we must search past all deleted element tombstones.
|
||||
index = Num.addWrap (mul8 probe.slotIndex) offset
|
||||
|
@ -696,7 +696,7 @@ findIndexHelper = \metadata, dataIndices, data, h2Key, key, probe, offset ->
|
|||
# This is how we grow the container.
|
||||
# If we aren't to the load factor yet, just ignore this.
|
||||
# The container must have an updated size including any elements about to be inserted.
|
||||
maybeRehash : Dict k v -> Dict k v | k has Hash & Eq
|
||||
maybeRehash : Dict k v -> Dict k v where k implements Hash & Eq
|
||||
maybeRehash = \@Dict { metadata, dataIndices, data, size } ->
|
||||
cap = List.len dataIndices
|
||||
maxLoadCap =
|
||||
|
@ -709,7 +709,7 @@ maybeRehash = \@Dict { metadata, dataIndices, data, size } ->
|
|||
@Dict { metadata, dataIndices, data, size }
|
||||
|
||||
# TODO: switch rehash to iterate data and eventually clear out tombstones as well.
|
||||
rehash : Dict k v -> Dict k v | k has Hash & Eq
|
||||
rehash : Dict k v -> Dict k v where k implements Hash & Eq
|
||||
rehash = \@Dict { metadata, dataIndices, data, size } ->
|
||||
newLen = 2 * List.len dataIndices
|
||||
newDict =
|
||||
|
@ -722,7 +722,7 @@ rehash = \@Dict { metadata, dataIndices, data, size } ->
|
|||
|
||||
rehashHelper newDict metadata dataIndices data 0
|
||||
|
||||
rehashHelper : Dict k v, List I8, List Nat, List (k, v), Nat -> Dict k v | k has Hash & Eq
|
||||
rehashHelper : Dict k v, List I8, List Nat, List (k, v), Nat -> Dict k v where k implements Hash & Eq
|
||||
rehashHelper = \dict, oldMetadata, oldDataIndices, oldData, index ->
|
||||
when List.get oldMetadata index is
|
||||
Ok md ->
|
||||
|
@ -743,7 +743,7 @@ rehashHelper = \dict, oldMetadata, oldDataIndices, oldData, index ->
|
|||
# Walked entire list, complete now.
|
||||
dict
|
||||
|
||||
insertForRehash : Dict k v, k, Nat -> Dict k v | k has Hash & Eq
|
||||
insertForRehash : Dict k v, k, Nat -> Dict k v where k implements Hash & Eq
|
||||
insertForRehash = \@Dict { metadata, dataIndices, data, size }, key, dataIndex ->
|
||||
hashKey =
|
||||
createLowLevelHasher PseudoRandSeed
|
||||
|
@ -1010,7 +1010,7 @@ expect
|
|||
# TODO: wyhash is slow for large keys, use something like cityhash if the keys are too long.
|
||||
# TODO: Add a builtin to distinguish big endian systems and change loading orders.
|
||||
# TODO: Switch out Wymum on systems with slow 128bit multiplication.
|
||||
LowLevelHasher := { originalSeed : U64, state : U64 } has [
|
||||
LowLevelHasher := { originalSeed : U64, state : U64 } implements [
|
||||
Hasher {
|
||||
addBytes,
|
||||
addU8,
|
||||
|
|
|
@ -47,40 +47,40 @@ interface Encode
|
|||
Bool.{ Bool },
|
||||
]
|
||||
|
||||
Encoder fmt := List U8, fmt -> List U8 | fmt has EncoderFormatting
|
||||
Encoder fmt := List U8, fmt -> List U8 where fmt implements EncoderFormatting
|
||||
|
||||
Encoding has
|
||||
toEncoder : val -> Encoder fmt | val has Encoding, fmt has EncoderFormatting
|
||||
Encoding implements
|
||||
toEncoder : val -> Encoder fmt where val implements Encoding, fmt implements EncoderFormatting
|
||||
|
||||
EncoderFormatting has
|
||||
u8 : U8 -> Encoder fmt | fmt has EncoderFormatting
|
||||
u16 : U16 -> Encoder fmt | fmt has EncoderFormatting
|
||||
u32 : U32 -> Encoder fmt | fmt has EncoderFormatting
|
||||
u64 : U64 -> Encoder fmt | fmt has EncoderFormatting
|
||||
u128 : U128 -> Encoder fmt | fmt has EncoderFormatting
|
||||
i8 : I8 -> Encoder fmt | fmt has EncoderFormatting
|
||||
i16 : I16 -> Encoder fmt | fmt has EncoderFormatting
|
||||
i32 : I32 -> Encoder fmt | fmt has EncoderFormatting
|
||||
i64 : I64 -> Encoder fmt | fmt has EncoderFormatting
|
||||
i128 : I128 -> Encoder fmt | fmt has EncoderFormatting
|
||||
f32 : F32 -> Encoder fmt | fmt has EncoderFormatting
|
||||
f64 : F64 -> Encoder fmt | fmt has EncoderFormatting
|
||||
dec : Dec -> Encoder fmt | fmt has EncoderFormatting
|
||||
bool : Bool -> Encoder fmt | fmt has EncoderFormatting
|
||||
string : Str -> Encoder fmt | fmt has EncoderFormatting
|
||||
list : List elem, (elem -> Encoder fmt) -> Encoder fmt | fmt has EncoderFormatting
|
||||
record : List { key : Str, value : Encoder fmt } -> Encoder fmt | fmt has EncoderFormatting
|
||||
tuple : List (Encoder fmt) -> Encoder fmt | fmt has EncoderFormatting
|
||||
tag : Str, List (Encoder fmt) -> Encoder fmt | fmt has EncoderFormatting
|
||||
EncoderFormatting implements
|
||||
u8 : U8 -> Encoder fmt where fmt implements EncoderFormatting
|
||||
u16 : U16 -> Encoder fmt where fmt implements EncoderFormatting
|
||||
u32 : U32 -> Encoder fmt where fmt implements EncoderFormatting
|
||||
u64 : U64 -> Encoder fmt where fmt implements EncoderFormatting
|
||||
u128 : U128 -> Encoder fmt where fmt implements EncoderFormatting
|
||||
i8 : I8 -> Encoder fmt where fmt implements EncoderFormatting
|
||||
i16 : I16 -> Encoder fmt where fmt implements EncoderFormatting
|
||||
i32 : I32 -> Encoder fmt where fmt implements EncoderFormatting
|
||||
i64 : I64 -> Encoder fmt where fmt implements EncoderFormatting
|
||||
i128 : I128 -> Encoder fmt where fmt implements EncoderFormatting
|
||||
f32 : F32 -> Encoder fmt where fmt implements EncoderFormatting
|
||||
f64 : F64 -> Encoder fmt where fmt implements EncoderFormatting
|
||||
dec : Dec -> Encoder fmt where fmt implements EncoderFormatting
|
||||
bool : Bool -> Encoder fmt where fmt implements EncoderFormatting
|
||||
string : Str -> Encoder fmt where fmt implements EncoderFormatting
|
||||
list : List elem, (elem -> Encoder fmt) -> Encoder fmt where fmt implements EncoderFormatting
|
||||
record : List { key : Str, value : Encoder fmt } -> Encoder fmt where fmt implements EncoderFormatting
|
||||
tuple : List (Encoder fmt) -> Encoder fmt where fmt implements EncoderFormatting
|
||||
tag : Str, List (Encoder fmt) -> Encoder fmt where fmt implements EncoderFormatting
|
||||
|
||||
custom : (List U8, fmt -> List U8) -> Encoder fmt | fmt has EncoderFormatting
|
||||
custom : (List U8, fmt -> List U8) -> Encoder fmt where fmt implements EncoderFormatting
|
||||
custom = \encoder -> @Encoder encoder
|
||||
|
||||
appendWith : List U8, Encoder fmt, fmt -> List U8 | fmt has EncoderFormatting
|
||||
appendWith : List U8, Encoder fmt, fmt -> List U8 where fmt implements EncoderFormatting
|
||||
appendWith = \lst, @Encoder doEncoding, fmt -> doEncoding lst fmt
|
||||
|
||||
append : List U8, val, fmt -> List U8 | val has Encoding, fmt has EncoderFormatting
|
||||
append : List U8, val, fmt -> List U8 where val implements Encoding, fmt implements EncoderFormatting
|
||||
append = \lst, val, fmt -> appendWith lst (toEncoder val) fmt
|
||||
|
||||
toBytes : val, fmt -> List U8 | val has Encoding, fmt has EncoderFormatting
|
||||
toBytes : val, fmt -> List U8 where val implements Encoding, fmt implements EncoderFormatting
|
||||
toBytes = \val, fmt -> appendWith [] (toEncoder val) fmt
|
||||
|
|
|
@ -29,39 +29,39 @@ interface Hash
|
|||
]
|
||||
|
||||
## A value that can hashed.
|
||||
Hash has
|
||||
Hash implements
|
||||
## Hashes a value into a [Hasher].
|
||||
## Note that [hash] does not produce a hash value itself; the hasher must be
|
||||
## [complete]d in order to extract the hash value.
|
||||
hash : hasher, a -> hasher | a has Hash, hasher has Hasher
|
||||
hash : hasher, a -> hasher where a implements Hash, hasher implements Hasher
|
||||
|
||||
## Describes a hashing algorithm that is fed bytes and produces an integer hash.
|
||||
##
|
||||
## The [Hasher] ability describes general-purpose hashers. It only allows
|
||||
## emission of 64-bit unsigned integer hashes. It is not suitable for
|
||||
## cryptographically-secure hashing.
|
||||
Hasher has
|
||||
Hasher implements
|
||||
## Adds a list of bytes to the hasher.
|
||||
addBytes : a, List U8 -> a | a has Hasher
|
||||
addBytes : a, List U8 -> a where a implements Hasher
|
||||
|
||||
## Adds a single U8 to the hasher.
|
||||
addU8 : a, U8 -> a | a has Hasher
|
||||
addU8 : a, U8 -> a where a implements Hasher
|
||||
|
||||
## Adds a single U16 to the hasher.
|
||||
addU16 : a, U16 -> a | a has Hasher
|
||||
addU16 : a, U16 -> a where a implements Hasher
|
||||
|
||||
## Adds a single U32 to the hasher.
|
||||
addU32 : a, U32 -> a | a has Hasher
|
||||
addU32 : a, U32 -> a where a implements Hasher
|
||||
|
||||
## Adds a single U64 to the hasher.
|
||||
addU64 : a, U64 -> a | a has Hasher
|
||||
addU64 : a, U64 -> a where a implements Hasher
|
||||
|
||||
## Adds a single U128 to the hasher.
|
||||
addU128 : a, U128 -> a | a has Hasher
|
||||
addU128 : a, U128 -> a where a implements Hasher
|
||||
|
||||
## Completes the hasher, extracting a hash value from its
|
||||
## accumulated hash state.
|
||||
complete : a -> U64 | a has Hasher
|
||||
complete : a -> U64 where a implements Hasher
|
||||
|
||||
## Adds a string into a [Hasher] by hashing its UTF-8 bytes.
|
||||
hashStrBytes = \hasher, s ->
|
||||
|
@ -73,33 +73,33 @@ hashList = \hasher, lst ->
|
|||
hash accumHasher elem
|
||||
|
||||
## Adds a single [Bool] to a hasher.
|
||||
hashBool : a, Bool -> a | a has Hasher
|
||||
hashBool : a, Bool -> a where a implements Hasher
|
||||
hashBool = \hasher, b ->
|
||||
asU8 = if b then 1 else 0
|
||||
addU8 hasher asU8
|
||||
|
||||
## Adds a single I8 to a hasher.
|
||||
hashI8 : a, I8 -> a | a has Hasher
|
||||
hashI8 : a, I8 -> a where a implements Hasher
|
||||
hashI8 = \hasher, n -> addU8 hasher (Num.toU8 n)
|
||||
|
||||
## Adds a single I16 to a hasher.
|
||||
hashI16 : a, I16 -> a | a has Hasher
|
||||
hashI16 : a, I16 -> a where a implements Hasher
|
||||
hashI16 = \hasher, n -> addU16 hasher (Num.toU16 n)
|
||||
|
||||
## Adds a single I32 to a hasher.
|
||||
hashI32 : a, I32 -> a | a has Hasher
|
||||
hashI32 : a, I32 -> a where a implements Hasher
|
||||
hashI32 = \hasher, n -> addU32 hasher (Num.toU32 n)
|
||||
|
||||
## Adds a single I64 to a hasher.
|
||||
hashI64 : a, I64 -> a | a has Hasher
|
||||
hashI64 : a, I64 -> a where a implements Hasher
|
||||
hashI64 = \hasher, n -> addU64 hasher (Num.toU64 n)
|
||||
|
||||
## Adds a single I128 to a hasher.
|
||||
hashI128 : a, I128 -> a | a has Hasher
|
||||
hashI128 : a, I128 -> a where a implements Hasher
|
||||
hashI128 = \hasher, n -> addU128 hasher (Num.toU128 n)
|
||||
|
||||
## Adds a single Nat to a hasher.
|
||||
hashNat : a, Nat -> a | a has Hasher
|
||||
hashNat : a, Nat -> a where a implements Hasher
|
||||
hashNat = \hasher, n ->
|
||||
isPlatform32bit =
|
||||
x : Nat
|
||||
|
@ -117,7 +117,7 @@ hashNat = \hasher, n ->
|
|||
i128OfDec : Dec -> I128
|
||||
|
||||
## Adds a single [Dec] to a hasher.
|
||||
hashDec : a, Dec -> a | a has Hasher
|
||||
hashDec : a, Dec -> a where a implements Hasher
|
||||
hashDec = \hasher, n -> hashI128 hasher (i128OfDec n)
|
||||
|
||||
## Adds a container of [Hash]able elements to a [Hasher] by hashing each element.
|
||||
|
|
|
@ -43,52 +43,52 @@ interface Inspect
|
|||
KeyValWalker state collection key val : collection, state, (state, key, val -> state) -> state
|
||||
ElemWalker state collection elem : collection, state, (state, elem -> state) -> state
|
||||
|
||||
InspectFormatter has
|
||||
init : {} -> f | f has InspectFormatter
|
||||
InspectFormatter implements
|
||||
init : {} -> f where f implements InspectFormatter
|
||||
|
||||
tag : Str, List (Inspector f) -> Inspector f | f has InspectFormatter
|
||||
tuple : List (Inspector f) -> Inspector f | f has InspectFormatter
|
||||
record : List { key : Str, value : Inspector f } -> Inspector f | f has InspectFormatter
|
||||
bool : Bool -> Inspector f | f has InspectFormatter
|
||||
str : Str -> Inspector f | f has InspectFormatter
|
||||
tag : Str, List (Inspector f) -> Inspector f where f implements InspectFormatter
|
||||
tuple : List (Inspector f) -> Inspector f where f implements InspectFormatter
|
||||
record : List { key : Str, value : Inspector f } -> Inspector f where f implements InspectFormatter
|
||||
bool : Bool -> Inspector f where f implements InspectFormatter
|
||||
str : Str -> Inspector f where f implements InspectFormatter
|
||||
|
||||
list : list, ElemWalker state list elem, (elem -> Inspector f) -> Inspector f | f has InspectFormatter
|
||||
set : set, ElemWalker state set elem, (elem -> Inspector f) -> Inspector f | f has InspectFormatter
|
||||
dict : dict, KeyValWalker state dict key value, (key -> Inspector f), (value -> Inspector f) -> Inspector f | f has InspectFormatter
|
||||
list : list, ElemWalker state list elem, (elem -> Inspector f) -> Inspector f where f implements InspectFormatter
|
||||
set : set, ElemWalker state set elem, (elem -> Inspector f) -> Inspector f where f implements InspectFormatter
|
||||
dict : dict, KeyValWalker state dict key value, (key -> Inspector f), (value -> Inspector f) -> Inspector f where f implements InspectFormatter
|
||||
|
||||
# Note opaque is used for both opaque types and functions.
|
||||
# The auto deriver for functions probably could put the function type.
|
||||
# For regular opaque types, I think we can use the type name, though that may lead to some reflection related issues that still need to be discussed.
|
||||
# As a simple baseline, it can just use the exact words `opaque` and `function` for now.
|
||||
# In text, this would render as `<opaque>`, `<function>`, etc
|
||||
opaque : Str -> Inspector f | f has InspectFormatter
|
||||
opaque : Str -> Inspector f where f implements InspectFormatter
|
||||
|
||||
u8 : U8 -> Inspector f | f has InspectFormatter
|
||||
i8 : I8 -> Inspector f | f has InspectFormatter
|
||||
u16 : U16 -> Inspector f | f has InspectFormatter
|
||||
i16 : I16 -> Inspector f | f has InspectFormatter
|
||||
u32 : U32 -> Inspector f | f has InspectFormatter
|
||||
i32 : I32 -> Inspector f | f has InspectFormatter
|
||||
u64 : U64 -> Inspector f | f has InspectFormatter
|
||||
i64 : I64 -> Inspector f | f has InspectFormatter
|
||||
u128 : U128 -> Inspector f | f has InspectFormatter
|
||||
i128 : I128 -> Inspector f | f has InspectFormatter
|
||||
f32 : F32 -> Inspector f | f has InspectFormatter
|
||||
f64 : F64 -> Inspector f | f has InspectFormatter
|
||||
dec : Dec -> Inspector f | f has InspectFormatter
|
||||
u8 : U8 -> Inspector f where f implements InspectFormatter
|
||||
i8 : I8 -> Inspector f where f implements InspectFormatter
|
||||
u16 : U16 -> Inspector f where f implements InspectFormatter
|
||||
i16 : I16 -> Inspector f where f implements InspectFormatter
|
||||
u32 : U32 -> Inspector f where f implements InspectFormatter
|
||||
i32 : I32 -> Inspector f where f implements InspectFormatter
|
||||
u64 : U64 -> Inspector f where f implements InspectFormatter
|
||||
i64 : I64 -> Inspector f where f implements InspectFormatter
|
||||
u128 : U128 -> Inspector f where f implements InspectFormatter
|
||||
i128 : I128 -> Inspector f where f implements InspectFormatter
|
||||
f32 : F32 -> Inspector f where f implements InspectFormatter
|
||||
f64 : F64 -> Inspector f where f implements InspectFormatter
|
||||
dec : Dec -> Inspector f where f implements InspectFormatter
|
||||
|
||||
Inspector f := f -> f | f has InspectFormatter
|
||||
Inspector f := f -> f where f implements InspectFormatter
|
||||
|
||||
custom : (f -> f) -> Inspector f | f has InspectFormatter
|
||||
custom : (f -> f) -> Inspector f where f implements InspectFormatter
|
||||
custom = @Inspector
|
||||
|
||||
apply : Inspector f, f -> f | f has InspectFormatter
|
||||
apply : Inspector f, f -> f where f implements InspectFormatter
|
||||
apply = \@Inspector fn, fmt -> fn fmt
|
||||
|
||||
Inspect has
|
||||
toInspector : val -> Inspector f | val has Inspect, f has InspectFormatter
|
||||
Inspect implements
|
||||
toInspector : val -> Inspector f where val implements Inspect, f implements InspectFormatter
|
||||
|
||||
inspect : val -> f | val has Inspect, f has InspectFormatter
|
||||
inspect : val -> f where val implements Inspect, f implements InspectFormatter
|
||||
inspect = \val ->
|
||||
(@Inspector valFn) = toInspector val
|
||||
valFn (init {})
|
||||
|
|
|
@ -422,7 +422,7 @@ join = \lists ->
|
|||
|
||||
List.walk lists (List.withCapacity totalLength) (\state, list -> List.concat state list)
|
||||
|
||||
contains : List a, a -> Bool | a has Eq
|
||||
contains : List a, a -> Bool where a implements Eq
|
||||
contains = \list, needle ->
|
||||
List.any list (\x -> x == needle)
|
||||
|
||||
|
@ -1104,7 +1104,7 @@ intersperse = \list, sep ->
|
|||
## is considered to "start with" an empty list.
|
||||
##
|
||||
## If the first list is empty, this only returns `Bool.true` if the second list is empty.
|
||||
startsWith : List elem, List elem -> Bool | elem has Eq
|
||||
startsWith : List elem, List elem -> Bool where elem implements Eq
|
||||
startsWith = \list, prefix ->
|
||||
# TODO once we have seamless slices, verify that this wouldn't
|
||||
# have better performance with a function like List.compareSublists
|
||||
|
@ -1116,7 +1116,7 @@ startsWith = \list, prefix ->
|
|||
## is considered to "end with" an empty list.
|
||||
##
|
||||
## If the first list is empty, this only returns `Bool.true` if the second list is empty.
|
||||
endsWith : List elem, List elem -> Bool | elem has Eq
|
||||
endsWith : List elem, List elem -> Bool where elem implements Eq
|
||||
endsWith = \list, suffix ->
|
||||
# TODO once we have seamless slices, verify that this wouldn't
|
||||
# have better performance with a function like List.compareSublists
|
||||
|
@ -1146,7 +1146,7 @@ split = \elements, userSplitIndex ->
|
|||
## ```
|
||||
## List.splitFirst [Foo, Z, Bar, Z, Baz] Z == Ok { before: [Foo], after: [Bar, Z, Baz] }
|
||||
## ```
|
||||
splitFirst : List elem, elem -> Result { before : List elem, after : List elem } [NotFound] | elem has Eq
|
||||
splitFirst : List elem, elem -> Result { before : List elem, after : List elem } [NotFound] where elem implements Eq
|
||||
splitFirst = \list, delimiter ->
|
||||
when List.findFirstIndex list (\elem -> elem == delimiter) is
|
||||
Ok index ->
|
||||
|
@ -1162,7 +1162,7 @@ splitFirst = \list, delimiter ->
|
|||
## ```
|
||||
## List.splitLast [Foo, Z, Bar, Z, Baz] Z == Ok { before: [Foo, Z, Bar], after: [Baz] }
|
||||
## ```
|
||||
splitLast : List elem, elem -> Result { before : List elem, after : List elem } [NotFound] | elem has Eq
|
||||
splitLast : List elem, elem -> Result { before : List elem, after : List elem } [NotFound] where elem implements Eq
|
||||
splitLast = \list, delimiter ->
|
||||
when List.findLastIndex list (\elem -> elem == delimiter) is
|
||||
Ok index ->
|
||||
|
|
|
@ -29,8 +29,8 @@ interface Set
|
|||
|
||||
## Provides a [set](https://en.wikipedia.org/wiki/Set_(abstract_data_type))
|
||||
## type which stores a collection of unique values, without any ordering
|
||||
Set k := Dict.Dict k {} | k has Hash & Eq
|
||||
has [
|
||||
Set k := Dict.Dict k {} where k implements Hash & Eq
|
||||
implements [
|
||||
Eq {
|
||||
isEq,
|
||||
},
|
||||
|
@ -39,7 +39,7 @@ Set k := Dict.Dict k {} | k has Hash & Eq
|
|||
},
|
||||
]
|
||||
|
||||
isEq : Set k, Set k -> Bool | k has Hash & Eq
|
||||
isEq : Set k, Set k -> Bool where k implements Hash & Eq
|
||||
isEq = \xs, ys ->
|
||||
if len xs != len ys then
|
||||
Bool.false
|
||||
|
@ -50,7 +50,7 @@ isEq = \xs, ys ->
|
|||
else
|
||||
Break Bool.false
|
||||
|
||||
hashSet : hasher, Set k -> hasher | k has Hash & Eq, hasher has Hasher
|
||||
hashSet : hasher, Set k -> hasher where k implements Hash & Eq, hasher implements Hasher
|
||||
hashSet = \hasher, @Set inner -> Hash.hash hasher inner
|
||||
|
||||
## Creates a new empty `Set`.
|
||||
|
@ -60,13 +60,13 @@ hashSet = \hasher, @Set inner -> Hash.hash hasher inner
|
|||
##
|
||||
## expect countValues == 0
|
||||
## ```
|
||||
empty : {} -> Set k | k has Hash & Eq
|
||||
empty : {} -> Set k where k implements Hash & Eq
|
||||
empty = \{} -> @Set (Dict.empty {})
|
||||
|
||||
## Return a dictionary with space allocated for a number of entries. This
|
||||
## may provide a performance optimization if you know how many entries will be
|
||||
## inserted.
|
||||
withCapacity : Nat -> Set k | k has Hash & Eq
|
||||
withCapacity : Nat -> Set k where k implements Hash & Eq
|
||||
withCapacity = \cap ->
|
||||
@Set (Dict.withCapacity cap)
|
||||
|
||||
|
@ -77,7 +77,7 @@ withCapacity = \cap ->
|
|||
##
|
||||
## expect countValues == 1
|
||||
## ```
|
||||
single : k -> Set k | k has Hash & Eq
|
||||
single : k -> Set k where k implements Hash & Eq
|
||||
single = \key ->
|
||||
Dict.single key {} |> @Set
|
||||
|
||||
|
@ -93,7 +93,7 @@ single = \key ->
|
|||
##
|
||||
## expect countValues == 3
|
||||
## ```
|
||||
insert : Set k, k -> Set k | k has Hash & Eq
|
||||
insert : Set k, k -> Set k where k implements Hash & Eq
|
||||
insert = \@Set dict, key ->
|
||||
Dict.insert dict key {} |> @Set
|
||||
|
||||
|
@ -178,7 +178,7 @@ expect
|
|||
## expect has10 == Bool.false
|
||||
## expect has20 == Bool.true
|
||||
## ```
|
||||
remove : Set k, k -> Set k | k has Hash & Eq
|
||||
remove : Set k, k -> Set k where k implements Hash & Eq
|
||||
remove = \@Set dict, key ->
|
||||
Dict.remove dict key |> @Set
|
||||
|
||||
|
@ -197,7 +197,7 @@ remove = \@Set dict, key ->
|
|||
## expect hasApple == Bool.true
|
||||
## expect hasBanana == Bool.false
|
||||
## ```
|
||||
contains : Set k, k -> Bool | k has Hash & Eq
|
||||
contains : Set k, k -> Bool where k implements Hash & Eq
|
||||
contains = \@Set dict, key ->
|
||||
Dict.contains dict key
|
||||
|
||||
|
@ -210,7 +210,7 @@ contains = \@Set dict, key ->
|
|||
##
|
||||
## expect Set.toList numbers == values
|
||||
## ```
|
||||
toList : Set k -> List k | k has Hash & Eq
|
||||
toList : Set k -> List k where k implements Hash & Eq
|
||||
toList = \@Set dict ->
|
||||
Dict.keys dict
|
||||
|
||||
|
@ -224,7 +224,7 @@ toList = \@Set dict ->
|
|||
##
|
||||
## expect Set.fromList [Pear, Apple, Banana] == values
|
||||
## ```
|
||||
fromList : List k -> Set k | k has Hash & Eq
|
||||
fromList : List k -> Set k where k implements Hash & Eq
|
||||
fromList = \list ->
|
||||
initial = @Set (Dict.withCapacity (List.len list))
|
||||
|
||||
|
@ -240,7 +240,7 @@ fromList = \list ->
|
|||
##
|
||||
## expect Set.union set1 set2 == Set.fromList [Left, Right]
|
||||
## ```
|
||||
union : Set k, Set k -> Set k | k has Hash & Eq
|
||||
union : Set k, Set k -> Set k where k implements Hash & Eq
|
||||
union = \@Set dict1, @Set dict2 ->
|
||||
Dict.insertAll dict1 dict2 |> @Set
|
||||
|
||||
|
@ -253,7 +253,7 @@ union = \@Set dict1, @Set dict2 ->
|
|||
##
|
||||
## expect Set.intersection set1 set2 == Set.single Left
|
||||
## ```
|
||||
intersection : Set k, Set k -> Set k | k has Hash & Eq
|
||||
intersection : Set k, Set k -> Set k where k implements Hash & Eq
|
||||
intersection = \@Set dict1, @Set dict2 ->
|
||||
Dict.keepShared dict1 dict2 |> @Set
|
||||
|
||||
|
@ -267,7 +267,7 @@ intersection = \@Set dict1, @Set dict2 ->
|
|||
##
|
||||
## expect Set.difference first second == Set.fromList [Up, Down]
|
||||
## ```
|
||||
difference : Set k, Set k -> Set k | k has Hash & Eq
|
||||
difference : Set k, Set k -> Set k where k implements Hash & Eq
|
||||
difference = \@Set dict1, @Set dict2 ->
|
||||
Dict.removeAll dict1 dict2 |> @Set
|
||||
|
||||
|
@ -290,14 +290,14 @@ difference = \@Set dict1, @Set dict2 ->
|
|||
##
|
||||
## expect result == 2
|
||||
## ```
|
||||
walk : Set k, state, (state, k -> state) -> state | k has Hash & Eq
|
||||
walk : Set k, state, (state, k -> state) -> state where k implements Hash & Eq
|
||||
walk = \@Set dict, state, step ->
|
||||
Dict.walk dict state (\s, k, _ -> step s k)
|
||||
|
||||
## Convert each value in the set to something new, by calling a conversion
|
||||
## function on each of them which receives the old value. Then return a
|
||||
## new set containing the converted values.
|
||||
map : Set a, (a -> b) -> Set b | a has Hash & Eq, b has Hash & Eq
|
||||
map : Set a, (a -> b) -> Set b where a implements Hash & Eq, b implements Hash & Eq
|
||||
map = \set, transform ->
|
||||
init = withCapacity (capacity set)
|
||||
|
||||
|
@ -309,7 +309,7 @@ map = \set, transform ->
|
|||
## (using [Set.union]) into one set.
|
||||
##
|
||||
## You may know a similar function named `concatMap` in other languages.
|
||||
joinMap : Set a, (a -> Set b) -> Set b | a has Hash & Eq, b has Hash & Eq
|
||||
joinMap : Set a, (a -> Set b) -> Set b where a implements Hash & Eq, b implements Hash & Eq
|
||||
joinMap = \set, transform ->
|
||||
init = withCapacity (capacity set) # Might be a pessimization
|
||||
|
||||
|
@ -331,7 +331,7 @@ joinMap = \set, transform ->
|
|||
##
|
||||
## expect result == FoundTheAnswer
|
||||
## ```
|
||||
walkUntil : Set k, state, (state, k -> [Continue state, Break state]) -> state | k has Hash & Eq
|
||||
walkUntil : Set k, state, (state, k -> [Continue state, Break state]) -> state where k implements Hash & Eq
|
||||
walkUntil = \@Set dict, state, step ->
|
||||
Dict.walkUntil dict state (\s, k, _ -> step s k)
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ interface TotallyNotJson
|
|||
## An opaque type with the `EncoderFormatting` and
|
||||
## `DecoderFormatting` abilities.
|
||||
Json := { fieldNameMapping : FieldNameMapping }
|
||||
has [
|
||||
implements [
|
||||
EncoderFormatting {
|
||||
u8: encodeU8,
|
||||
u16: encodeU16,
|
||||
|
|
|
@ -80,7 +80,7 @@ impl AbilityMemberData<Resolved> {
|
|||
|
||||
/// Solved lambda sets for an ability member specialization. For example, if we have
|
||||
///
|
||||
/// Default has default : {} -[[] + a:default:1]-> a | a has Default
|
||||
/// Default implements default : {} -[[] + a:default:1]-> a where a implements Default
|
||||
///
|
||||
/// A := {}
|
||||
/// default = \{} -[[closA]]-> @A {}
|
||||
|
@ -144,7 +144,7 @@ pub struct IAbilitiesStore<Phase: ResolvePhase> {
|
|||
///
|
||||
/// For example, in the program
|
||||
///
|
||||
/// Hash has hash : a -> U64 | a has Hash
|
||||
/// Hash implements hash : a -> U64 where a implements Hash
|
||||
///
|
||||
/// Id := {} implements [Hash {hash: myHash}]
|
||||
/// myHash = \@Id n -> n
|
||||
|
@ -155,7 +155,7 @@ pub struct IAbilitiesStore<Phase: ResolvePhase> {
|
|||
/// Information about all members composing abilities.
|
||||
ability_members: MutMap<Symbol, AbilityMemberData<Phase>>,
|
||||
|
||||
/// Maps a tuple (member, type) specifying that `type` has an implementation of an ability
|
||||
/// Maps a tuple (member, type) specifying that `type` implements an ability
|
||||
/// member `member`, to how that implementation is defined.
|
||||
declared_implementations: MutMap<ImplKey, MemberImpl>,
|
||||
|
||||
|
@ -284,7 +284,7 @@ impl<Phase: ResolvePhase> IAbilitiesStore<Phase> {
|
|||
}
|
||||
|
||||
/// Finds the implementation key for a symbol specializing the ability member, if it specializes any.
|
||||
/// For example, suppose `hashId : Id -> U64` specializes `hash : a -> U64 | a has Hash`.
|
||||
/// For example, suppose `hashId : Id -> U64` specializes `hash : a -> U64 where a implements Hash`.
|
||||
/// Calling this with `hashId` would retrieve (hash, hashId).
|
||||
pub fn impl_key(&self, specializing_symbol: Symbol) -> Option<&ImplKey> {
|
||||
self.specialization_to_root.get(&specializing_symbol)
|
||||
|
@ -392,7 +392,7 @@ pub enum MarkError {
|
|||
impl IAbilitiesStore<Resolved> {
|
||||
/// Finds the symbol name and ability member definition for a symbol specializing the ability
|
||||
/// member, if it specializes any.
|
||||
/// For example, suppose `hashId : Id -> U64` specializes `hash : a -> U64 | a has Hash`.
|
||||
/// For example, suppose `hashId : Id -> U64` specializes `hash : a -> U64 where a implements Hash`.
|
||||
/// Calling this with `hashId` would retrieve the ability member data for `hash`, and what type
|
||||
/// `hashId` is specializing for.
|
||||
pub fn impl_key_and_def(
|
||||
|
@ -414,7 +414,7 @@ impl IAbilitiesStore<Resolved> {
|
|||
}
|
||||
|
||||
/// Returns an iterator over pairs ((ability member, type), implementation) specifying that
|
||||
/// the give type has an implementation of an ability member.
|
||||
/// the given type implements an ability member.
|
||||
pub fn iter_declared_implementations(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (ImplKey, &MemberImpl)> + '_ {
|
||||
|
|
|
@ -122,7 +122,7 @@ pub struct NamedVariable {
|
|||
pub first_seen: Region,
|
||||
}
|
||||
|
||||
/// A type variable bound to an ability, like "a has Hash".
|
||||
/// A type variable bound to an ability, like "a implements Hash".
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct AbleVariable {
|
||||
pub variable: Variable,
|
||||
|
@ -296,7 +296,7 @@ pub(crate) fn canonicalize_annotation(
|
|||
|
||||
let (annotation, region) = match annotation {
|
||||
TypeAnnotation::Where(annotation, clauses) => {
|
||||
// Add each "has" clause. The association of a variable to an ability will be saved on
|
||||
// Add each "implements" clause. The association of a variable to an ability will be saved on
|
||||
// `introduced_variables`, which we'll process later.
|
||||
for clause in clauses.iter() {
|
||||
let opt_err = canonicalize_has_clause(
|
||||
|
@ -1029,8 +1029,8 @@ fn can_annotation_help(
|
|||
Where(_annotation, clauses) => {
|
||||
debug_assert!(!clauses.is_empty());
|
||||
|
||||
// Has clauses are allowed only on the top level of a signature, which we handle elsewhere.
|
||||
env.problem(roc_problem::can::Problem::IllegalHasClause {
|
||||
// Implements clauses are allowed only on the top level of a signature, which we handle elsewhere.
|
||||
env.problem(roc_problem::can::Problem::IllegalImplementsClause {
|
||||
region: Region::across_all(clauses.iter().map(|clause| &clause.region)),
|
||||
});
|
||||
|
||||
|
@ -1053,13 +1053,13 @@ fn canonicalize_has_clause(
|
|||
scope: &mut Scope,
|
||||
var_store: &mut VarStore,
|
||||
introduced_variables: &mut IntroducedVariables,
|
||||
clause: &Loc<roc_parse::ast::HasClause<'_>>,
|
||||
clause: &Loc<roc_parse::ast::ImplementsClause<'_>>,
|
||||
pending_abilities_in_scope: &PendingAbilitiesInScope,
|
||||
references: &mut VecSet<Symbol>,
|
||||
) -> Result<(), Type> {
|
||||
let Loc {
|
||||
region,
|
||||
value: roc_parse::ast::HasClause { var, abilities },
|
||||
value: roc_parse::ast::ImplementsClause { var, abilities },
|
||||
} = clause;
|
||||
let region = *region;
|
||||
|
||||
|
@ -1085,13 +1085,13 @@ fn canonicalize_has_clause(
|
|||
// or an ability that was imported from elsewhere
|
||||
&& !scope.abilities_store.is_ability(symbol)
|
||||
{
|
||||
env.problem(roc_problem::can::Problem::HasClauseIsNotAbility { region });
|
||||
env.problem(roc_problem::can::Problem::ImplementsClauseIsNotAbility { region });
|
||||
return Err(Type::Error);
|
||||
}
|
||||
symbol
|
||||
}
|
||||
_ => {
|
||||
env.problem(roc_problem::can::Problem::HasClauseIsNotAbility { region });
|
||||
env.problem(roc_problem::can::Problem::ImplementsClauseIsNotAbility { region });
|
||||
return Err(Type::Error);
|
||||
}
|
||||
};
|
||||
|
@ -1100,7 +1100,7 @@ fn canonicalize_has_clause(
|
|||
let already_seen = can_abilities.insert(ability);
|
||||
|
||||
if already_seen {
|
||||
env.problem(roc_problem::can::Problem::DuplicateHasAbility { ability, region });
|
||||
env.problem(roc_problem::can::Problem::DuplicateImplementsAbility { ability, region });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -191,7 +191,7 @@ enum PendingTypeDef<'a> {
|
|||
name: Loc<Symbol>,
|
||||
vars: Vec<Loc<Lowercase>>,
|
||||
ann: &'a Loc<ast::TypeAnnotation<'a>>,
|
||||
derived: Option<&'a Loc<ast::HasAbilities<'a>>>,
|
||||
derived: Option<&'a Loc<ast::ImplementsAbilities<'a>>>,
|
||||
},
|
||||
|
||||
Ability {
|
||||
|
@ -497,7 +497,7 @@ fn canonicalize_claimed_ability_impl<'a>(
|
|||
//
|
||||
// interface F imports [] exposes []
|
||||
//
|
||||
// Hello := {} has [Encoding.{ toEncoder }]
|
||||
// Hello := {} implements [Encoding.{ toEncoder }]
|
||||
//
|
||||
// toEncoder = \@Hello {} -> ...
|
||||
//
|
||||
|
@ -509,7 +509,7 @@ fn canonicalize_claimed_ability_impl<'a>(
|
|||
//
|
||||
// interface F imports [Encoding.{ toEncoder }] exposes []
|
||||
//
|
||||
// Hello := {} has [Encoding.{ toEncoder }]
|
||||
// Hello := {} implements [Encoding.{ toEncoder }]
|
||||
//
|
||||
// toEncoder = \@Hello {} -> ...
|
||||
//
|
||||
|
@ -527,9 +527,9 @@ fn canonicalize_claimed_ability_impl<'a>(
|
|||
// definition symbol, for example when the ability is defined in the same
|
||||
// module as an implementer:
|
||||
//
|
||||
// Eq has eq : a, a -> U64 | a has Eq
|
||||
// Eq implements eq : a, a -> U64 where a implements Eq
|
||||
//
|
||||
// A := U8 has [Eq {eq}]
|
||||
// A := U8 implements [Eq {eq}]
|
||||
//
|
||||
// So, do a final check that the implementation symbol is not resolved directly
|
||||
// to the member.
|
||||
|
@ -689,7 +689,7 @@ fn canonicalize_opaque<'a>(
|
|||
name_str: &'a str,
|
||||
ann: &'a Loc<ast::TypeAnnotation<'a>>,
|
||||
vars: &[Loc<Lowercase>],
|
||||
has_abilities: Option<&'a Loc<ast::HasAbilities<'a>>>,
|
||||
has_abilities: Option<&'a Loc<ast::ImplementsAbilities<'a>>>,
|
||||
) -> Result<CanonicalizedOpaque<'a>, ()> {
|
||||
let alias = canonicalize_alias(
|
||||
env,
|
||||
|
@ -712,7 +712,7 @@ fn canonicalize_opaque<'a>(
|
|||
for has_ability in has_abilities.items {
|
||||
let region = has_ability.region;
|
||||
let (ability, opt_impls) = match has_ability.value.extract_spaces().item {
|
||||
ast::HasAbility::HasAbility { ability, impls } => (ability, impls),
|
||||
ast::ImplementsAbility::ImplementsAbility { ability, impls } => (ability, impls),
|
||||
_ => internal_error!("spaces not extracted"),
|
||||
};
|
||||
|
||||
|
@ -766,8 +766,8 @@ fn canonicalize_opaque<'a>(
|
|||
// Did the user claim this implementation for a specialization of a different
|
||||
// type? e.g.
|
||||
//
|
||||
// A has [Hash {hash: myHash}]
|
||||
// B has [Hash {hash: myHash}]
|
||||
// A implements [Hash {hash: myHash}]
|
||||
// B implements [Hash {hash: myHash}]
|
||||
//
|
||||
// If so, that's an error and we drop the impl for this opaque type.
|
||||
let member_impl = match scope.abilities_store.impl_key(impl_symbol) {
|
||||
|
@ -1198,7 +1198,7 @@ fn canonicalize_type_defs<'a>(
|
|||
Loc<Symbol>,
|
||||
Vec<Loc<Lowercase>>,
|
||||
&'a Loc<ast::TypeAnnotation<'a>>,
|
||||
Option<&'a Loc<ast::HasAbilities<'a>>>,
|
||||
Option<&'a Loc<ast::ImplementsAbilities<'a>>>,
|
||||
),
|
||||
Ability(Loc<Symbol>, Vec<PendingAbilityMember<'a>>),
|
||||
}
|
||||
|
@ -1404,7 +1404,7 @@ fn resolve_abilities(
|
|||
[] => {
|
||||
// There are no variables bound to the parent ability - then this member doesn't
|
||||
// need to be a part of the ability.
|
||||
env.problem(Problem::AbilityMemberMissingHasClause {
|
||||
env.problem(Problem::AbilityMemberMissingImplementsClause {
|
||||
member: member_sym,
|
||||
ability,
|
||||
region: member_name_region,
|
||||
|
@ -1414,7 +1414,7 @@ fn resolve_abilities(
|
|||
}
|
||||
[..] => {
|
||||
// There is more than one variable bound to the member signature, so something like
|
||||
// Eq has eq : a, b -> Bool | a has Eq, b has Eq
|
||||
// Eq implements eq : a, b -> Bool where a implements Eq, b implements Eq
|
||||
// We have no way of telling what type implements a particular instance of Eq in
|
||||
// this case (a or b?), so disallow it.
|
||||
let span_has_clauses = Region::across_all(
|
||||
|
@ -1427,7 +1427,7 @@ fn resolve_abilities(
|
|||
env.problem(Problem::AbilityMemberMultipleBoundVars {
|
||||
member: member_sym,
|
||||
ability,
|
||||
span_has_clauses,
|
||||
span_implements_clauses: span_has_clauses,
|
||||
bound_var_names,
|
||||
});
|
||||
// Pretend the member isn't a part of the ability
|
||||
|
@ -2558,7 +2558,7 @@ fn to_pending_alias_or_opaque<'a>(
|
|||
name: &'a Loc<&'a str>,
|
||||
vars: &'a [Loc<ast::Pattern<'a>>],
|
||||
ann: &'a Loc<ast::TypeAnnotation<'a>>,
|
||||
opt_derived: Option<&'a Loc<ast::HasAbilities<'a>>>,
|
||||
opt_derived: Option<&'a Loc<ast::ImplementsAbilities<'a>>>,
|
||||
kind: AliasKind,
|
||||
) -> PendingTypeDef<'a> {
|
||||
let region = Region::span_across(&name.region, &ann.region);
|
||||
|
@ -2677,7 +2677,7 @@ fn to_pending_type_def<'a>(
|
|||
Ability {
|
||||
header: TypeHeader { name, vars },
|
||||
members,
|
||||
loc_has: _,
|
||||
loc_implements: _,
|
||||
} => {
|
||||
let name = match scope
|
||||
.introduce_without_shadow_symbol(&Ident::from(name.value), name.region)
|
||||
|
|
|
@ -76,7 +76,7 @@ pub enum Pattern {
|
|||
Underscore,
|
||||
|
||||
/// An identifier that marks a specialization of an ability member.
|
||||
/// For example, given an ability member definition `hash : a -> U64 | a has Hash`,
|
||||
/// For example, given an ability member definition `hash : a -> U64 where a implements Hash`,
|
||||
/// there may be the specialization `hash : Bool -> U64`. In this case we generate a
|
||||
/// new symbol for the specialized "hash" identifier.
|
||||
AbilityMemberSpecialization {
|
||||
|
|
|
@ -33,7 +33,7 @@ pub struct Scope {
|
|||
imports: Vec<(Ident, Symbol, Region)>,
|
||||
|
||||
/// Shadows of an ability member, for example a local specialization of `eq` for the ability
|
||||
/// member `Eq has eq : a, a -> Bool | a has Eq` gets a shadow symbol it can use for its
|
||||
/// member `Eq implements eq : a, a -> Bool where a implements Eq` gets a shadow symbol it can use for its
|
||||
/// implementation.
|
||||
///
|
||||
/// Only one shadow of an ability member is permitted per scope.
|
||||
|
|
|
@ -674,7 +674,7 @@ pub enum FoundSymbol {
|
|||
Symbol(Symbol),
|
||||
}
|
||||
|
||||
/// Given an ability Foo has foo : ..., returns (T, foo1) if the symbol at the given region is a
|
||||
/// Given an ability Foo implements foo : ..., returns (T, foo1) if the symbol at the given region is a
|
||||
/// symbol foo1 that specializes foo for T. Otherwise if the symbol is foo but the specialization
|
||||
/// is unknown, (Foo, foo) is returned. Otherwise [None] is returned.
|
||||
pub fn find_symbol_at(
|
||||
|
|
|
@ -63,7 +63,7 @@ fn wrap_in_decode_custom_decode_with(
|
|||
|
||||
// Decode.decodeWith bytes inner_decoder fmt : DecodeResult val
|
||||
let (decode_with_call, decode_with_result_var) = {
|
||||
// Decode.decodeWith : List U8, Decoder val fmt, fmt -> DecodeResult val | fmt has DecoderFormatting
|
||||
// Decode.decodeWith : List U8, Decoder val fmt, fmt -> DecodeResult val where fmt implements DecoderFormatting
|
||||
let decode_with_type = env.import_builtin_symbol_var(Symbol::DECODE_DECODE_WITH);
|
||||
|
||||
// Decode.decodeWith : bytes, inner_decoder, fmt -> DecoderResult (List val)
|
||||
|
@ -80,7 +80,7 @@ fn wrap_in_decode_custom_decode_with(
|
|||
)),
|
||||
);
|
||||
|
||||
// List U8, Decoder val fmt, fmt -> DecodeResult val | fmt has DecoderFormatting
|
||||
// List U8, Decoder val fmt, fmt -> DecodeResult val where fmt implements DecoderFormatting
|
||||
// ~ bytes, Decoder (List elem) fmt, fmt -> DecoderResult (List val)
|
||||
env.unify(decode_with_type, this_decode_with_fn_var);
|
||||
|
||||
|
@ -169,7 +169,7 @@ fn wrap_in_decode_custom_decode_with(
|
|||
|
||||
// Decode.custom \bytes, fmt -> Decode.decodeWith bytes inner_decoder fmt
|
||||
let (decode_custom_call, decoder_var) = {
|
||||
// (List U8, fmt -> DecodeResult val) -> Decoder val fmt | fmt has DecoderFormatting
|
||||
// (List U8, fmt -> DecodeResult val) -> Decoder val fmt where fmt implements DecoderFormatting
|
||||
let decode_custom_type = env.import_builtin_symbol_var(Symbol::DECODE_CUSTOM);
|
||||
|
||||
// (List U8, fmt -> DecodeResult (List elem)) -> Decoder (List elem) fmt
|
||||
|
@ -185,7 +185,7 @@ fn wrap_in_decode_custom_decode_with(
|
|||
)),
|
||||
);
|
||||
|
||||
// (List U8, fmt -> DecodeResult val) -> Decoder val fmt | fmt has DecoderFormatting
|
||||
// (List U8, fmt -> DecodeResult val) -> Decoder val fmt where fmt implements DecoderFormatting
|
||||
// ~ (List U8, fmt -> DecodeResult (List elem)) -> Decoder (List elem) fmt
|
||||
env.unify(decode_custom_type, this_decode_custom_fn_var);
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ use crate::util::Env;
|
|||
pub(crate) fn decoder(env: &mut Env<'_>, _def_symbol: Symbol) -> (Expr, Variable) {
|
||||
// Build
|
||||
//
|
||||
// def_symbol : Decoder (List elem) fmt | elem has Decoding, fmt has DecoderFormatting
|
||||
// def_symbol : Decoder (List elem) fmt where elem implements Decoding, fmt implements DecoderFormatting
|
||||
// def_symbol = Decode.custom \bytes, fmt -> Decode.decodeWith bytes (Decode.list Decode.decoder) fmt
|
||||
//
|
||||
// NB: reduction to `Decode.list Decode.decoder` is not possible to the HRR.
|
||||
|
@ -27,10 +27,10 @@ pub(crate) fn decoder(env: &mut Env<'_>, _def_symbol: Symbol) -> (Expr, Variable
|
|||
// List elem
|
||||
let elem_var = env.subs.fresh_unnamed_flex_var();
|
||||
|
||||
// Decode.decoder : Decoder elem fmt | elem has Decoding, fmt has EncoderFormatting
|
||||
// Decode.decoder : Decoder elem fmt where elem implements Decoding, fmt implements EncoderFormatting
|
||||
let (elem_decoder, elem_decoder_var) = {
|
||||
// build `Decode.decoder : Decoder elem fmt` type
|
||||
// Decoder val fmt | val has Decoding, fmt has EncoderFormatting
|
||||
// Decoder val fmt where val implements Decoding, fmt implements EncoderFormatting
|
||||
let elem_decoder_var = env.import_builtin_symbol_var(Symbol::DECODE_DECODER);
|
||||
|
||||
// set val ~ elem
|
||||
|
@ -52,7 +52,7 @@ pub(crate) fn decoder(env: &mut Env<'_>, _def_symbol: Symbol) -> (Expr, Variable
|
|||
};
|
||||
|
||||
// Build `Decode.list Decode.decoder` type
|
||||
// Decoder val fmt -[uls]-> Decoder (List val) fmt | fmt has DecoderFormatting
|
||||
// Decoder val fmt -[uls]-> Decoder (List val) fmt where fmt implements DecoderFormatting
|
||||
let decode_list_fn_var = env.import_builtin_symbol_var(Symbol::DECODE_LIST);
|
||||
|
||||
// Decoder elem fmt -a-> b
|
||||
|
@ -68,7 +68,7 @@ pub(crate) fn decoder(env: &mut Env<'_>, _def_symbol: Symbol) -> (Expr, Variable
|
|||
)),
|
||||
);
|
||||
|
||||
// Decoder val fmt -[uls]-> Decoder (List val) fmt | fmt has DecoderFormatting
|
||||
// Decoder val fmt -[uls]-> Decoder (List val) fmt where fmt implements DecoderFormatting
|
||||
// ~ Decoder elem fmt -a -> b
|
||||
env.unify(decode_list_fn_var, this_decode_list_fn_var);
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ use super::wrap_in_decode_custom_decode_with;
|
|||
/// we'd like to generate an impl like
|
||||
///
|
||||
/// ```roc
|
||||
/// decoder : Decoder {first: a, second: b} fmt | a has Decoding, b has Decoding, fmt has DecoderFormatting
|
||||
/// decoder : Decoder {first: a, second: b} fmt where a implements Decoding, b implements Decoding, fmt implements DecoderFormatting
|
||||
/// decoder =
|
||||
/// initialState : {f0: Result a [NoField], f1: Result b [NoField]}
|
||||
/// initialState = {f0: Err NoField, f1: Err NoField}
|
||||
|
|
|
@ -28,7 +28,7 @@ use super::wrap_in_decode_custom_decode_with;
|
|||
/// we'd like to generate an impl like
|
||||
///
|
||||
/// ```roc
|
||||
/// decoder : Decoder (a, b) fmt | a has Decoding, b has Decoding, fmt has DecoderFormatting
|
||||
/// decoder : Decoder (a, b) fmt where a implements Decoding, b implements Decoding, fmt implements DecoderFormatting
|
||||
/// decoder =
|
||||
/// initialState : {e0: Result a [NoElem], e1: Result b [NoElem]}
|
||||
/// initialState = {e0: Err NoElem, e1: Err NoElem}
|
||||
|
|
|
@ -121,7 +121,7 @@ fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
);
|
||||
|
||||
// build `toEncoder elem` type
|
||||
// val -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// val -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let to_encoder_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER);
|
||||
|
||||
// elem -[clos]-> t1
|
||||
|
@ -136,11 +136,11 @@ fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
)),
|
||||
);
|
||||
|
||||
// val -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// val -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
// ~ elem -[clos]-> t1
|
||||
env.unify(to_encoder_fn_var, elem_to_encoder_fn_var);
|
||||
|
||||
// toEncoder : (typeof rcd.a) -[clos]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// toEncoder : (typeof rcd.a) -[clos]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let to_encoder_var = AbilityMember(Symbol::ENCODE_TO_ENCODER, None, elem_to_encoder_fn_var);
|
||||
let to_encoder_fn = Box::new((
|
||||
to_encoder_fn_var,
|
||||
|
@ -201,7 +201,7 @@ fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
});
|
||||
|
||||
// build `Encode.list lst (\elem -> Encode.toEncoder elem)` type
|
||||
// List e, (e -> Encoder fmt) -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// List e, (e -> Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let encode_list_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_LIST);
|
||||
|
||||
// List elem, to_elem_encoder_fn_var -[clos]-> t1
|
||||
|
@ -218,11 +218,11 @@ fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
)),
|
||||
);
|
||||
|
||||
// List e, (e -> Encoder fmt) -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// List e, (e -> Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
// ~ List elem, to_elem_encoder_fn_var -[clos]-> t1
|
||||
env.unify(encode_list_fn_var, this_encode_list_fn_var);
|
||||
|
||||
// Encode.list : List elem, to_elem_encoder_fn_var -[clos]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// Encode.list : List elem, to_elem_encoder_fn_var -[clos]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let encode_list = AbilityMember(Symbol::ENCODE_LIST, None, this_encode_list_fn_var);
|
||||
let encode_list_fn = Box::new((
|
||||
this_encode_list_fn_var,
|
||||
|
@ -340,7 +340,7 @@ fn to_encoder_record(
|
|||
};
|
||||
|
||||
// build `toEncoder rcd.a` type
|
||||
// val -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// val -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let to_encoder_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER);
|
||||
|
||||
// (typeof rcd.a) -[clos]-> t1
|
||||
|
@ -355,11 +355,11 @@ fn to_encoder_record(
|
|||
)),
|
||||
);
|
||||
|
||||
// val -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// val -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
// ~ (typeof rcd.a) -[clos]-> t1
|
||||
env.unify(to_encoder_fn_var, this_to_encoder_fn_var);
|
||||
|
||||
// toEncoder : (typeof rcd.a) -[clos]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// toEncoder : (typeof rcd.a) -[clos]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let to_encoder_var = AbilityMember(Symbol::ENCODE_TO_ENCODER, None, to_encoder_fn_var);
|
||||
let to_encoder_fn = Box::new((
|
||||
to_encoder_fn_var,
|
||||
|
@ -420,7 +420,7 @@ fn to_encoder_record(
|
|||
};
|
||||
|
||||
// build `Encode.record [ { key: .., value: ..}, .. ]` type
|
||||
// List { key : Str, value : Encoder fmt } -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// List { key : Str, value : Encoder fmt } -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let encode_record_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_RECORD);
|
||||
|
||||
// fields_list_var -[clos]-> t1
|
||||
|
@ -437,11 +437,11 @@ fn to_encoder_record(
|
|||
)),
|
||||
);
|
||||
|
||||
// List { key : Str, value : Encoder fmt } -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// List { key : Str, value : Encoder fmt } -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
// ~ fields_list_var -[clos]-> t1
|
||||
env.unify(encode_record_fn_var, this_encode_record_fn_var);
|
||||
|
||||
// Encode.record : fields_list_var -[clos]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// Encode.record : fields_list_var -[clos]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let encode_record_var = AbilityMember(Symbol::ENCODE_RECORD, None, encode_record_fn_var);
|
||||
let encode_record_fn = Box::new((
|
||||
encode_record_fn_var,
|
||||
|
@ -543,7 +543,7 @@ fn to_encoder_tuple(
|
|||
};
|
||||
|
||||
// build `toEncoder tup.0` type
|
||||
// val -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// val -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let to_encoder_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER);
|
||||
|
||||
// (typeof tup.0) -[clos]-> t1
|
||||
|
@ -558,11 +558,11 @@ fn to_encoder_tuple(
|
|||
)),
|
||||
);
|
||||
|
||||
// val -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// val -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
// ~ (typeof tup.0) -[clos]-> t1
|
||||
env.unify(to_encoder_fn_var, this_to_encoder_fn_var);
|
||||
|
||||
// toEncoder : (typeof tup.0) -[clos]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// toEncoder : (typeof tup.0) -[clos]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let to_encoder_var = AbilityMember(Symbol::ENCODE_TO_ENCODER, None, to_encoder_fn_var);
|
||||
let to_encoder_fn = Box::new((
|
||||
to_encoder_fn_var,
|
||||
|
@ -603,7 +603,7 @@ fn to_encoder_tuple(
|
|||
};
|
||||
|
||||
// build `Encode.tuple [ toEncoder tup.0, toEncoder tup.1 ]` type
|
||||
// List (Encoder fmt) -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// List (Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let encode_tuple_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TUPLE);
|
||||
|
||||
// elem_encoders_list_var -[clos]-> t1
|
||||
|
@ -620,11 +620,11 @@ fn to_encoder_tuple(
|
|||
)),
|
||||
);
|
||||
|
||||
// List (Encoder fmt) -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// List (Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
// ~ elem_encoders_list_var -[clos]-> t1
|
||||
env.unify(encode_tuple_fn_var, this_encode_tuple_fn_var);
|
||||
|
||||
// Encode.tuple : elem_encoders_list_var -[clos]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// Encode.tuple : elem_encoders_list_var -[clos]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let encode_tuple_var = AbilityMember(Symbol::ENCODE_TUPLE, None, encode_tuple_fn_var);
|
||||
let encode_tuple_fn = Box::new((
|
||||
encode_tuple_fn_var,
|
||||
|
@ -741,7 +741,7 @@ fn to_encoder_tag_union(
|
|||
.zip(payload_vars.iter())
|
||||
.map(|(&sym, &sym_var)| {
|
||||
// build `toEncoder v1` type
|
||||
// expected: val -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// expected: val -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let to_encoder_fn_var =
|
||||
env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER);
|
||||
|
||||
|
@ -759,11 +759,11 @@ fn to_encoder_tag_union(
|
|||
)),
|
||||
);
|
||||
|
||||
// val -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// val -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
// ~ t1 -[clos]-> t'
|
||||
env.unify(to_encoder_fn_var, this_to_encoder_fn_var);
|
||||
|
||||
// toEncoder : t1 -[clos]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// toEncoder : t1 -[clos]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let to_encoder_var =
|
||||
AbilityMember(Symbol::ENCODE_TO_ENCODER, None, this_to_encoder_fn_var);
|
||||
let to_encoder_fn = Box::new((
|
||||
|
@ -802,7 +802,7 @@ fn to_encoder_tag_union(
|
|||
};
|
||||
|
||||
// build `Encode.tag "A" [ ... ]` type
|
||||
// expected: Str, List (Encoder fmt) -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// expected: Str, List (Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let encode_tag_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TAG);
|
||||
|
||||
// wanted: Str, List whole_encoders_var -[clos]-> t'
|
||||
|
@ -821,11 +821,11 @@ fn to_encoder_tag_union(
|
|||
)),
|
||||
);
|
||||
|
||||
// Str, List (Encoder fmt) -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// Str, List (Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
// ~ Str, List whole_encoders_var -[clos]-> t'
|
||||
env.unify(encode_tag_fn_var, this_encode_tag_fn_var);
|
||||
|
||||
// Encode.tag : Str, List whole_encoders_var -[clos]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// Encode.tag : Str, List whole_encoders_var -[clos]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
let encode_tag_var = AbilityMember(Symbol::ENCODE_TAG, None, this_encode_tag_fn_var);
|
||||
let encode_tag_fn = Box::new((
|
||||
this_encode_tag_fn_var,
|
||||
|
@ -954,15 +954,15 @@ fn wrap_in_encode_custom(
|
|||
let bytes_sym = env.new_symbol("bytes");
|
||||
let bytes_var = Variable::LIST_U8;
|
||||
|
||||
// fmt: fmt | fmt has EncoderFormatting
|
||||
// fmt: fmt where fmt implements EncoderFormatting
|
||||
let fmt_sym = env.new_symbol("fmt");
|
||||
let fmt_var = env.subs.fresh_unnamed_flex_var();
|
||||
|
||||
// build `Encode.appendWith bytes encoder fmt` type
|
||||
// expected: Encode.appendWith : List U8, Encoder fmt, fmt -[appendWith]-> List U8 | fmt has EncoderFormatting
|
||||
// expected: Encode.appendWith : List U8, Encoder fmt, fmt -[appendWith]-> List U8 where fmt implements EncoderFormatting
|
||||
let append_with_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_APPEND_WITH);
|
||||
|
||||
// wanted: Encode.appendWith : List U8, encoder_var, fmt -[clos]-> List U8 | fmt has EncoderFormatting
|
||||
// wanted: Encode.appendWith : List U8, encoder_var, fmt -[clos]-> List U8 where fmt implements EncoderFormatting
|
||||
let this_append_with_args_var_slice =
|
||||
VariableSubsSlice::insert_into_subs(env.subs, [Variable::LIST_U8, encoder_var, fmt_var]);
|
||||
let this_append_with_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]->
|
||||
|
@ -975,11 +975,11 @@ fn wrap_in_encode_custom(
|
|||
)),
|
||||
);
|
||||
|
||||
// List U8, Encoder fmt, fmt -[appendWith]-> List U8 | fmt has EncoderFormatting
|
||||
// ~ List U8, encoder_var, fmt -[clos]-> List U8 | fmt has EncoderFormatting
|
||||
// List U8, Encoder fmt, fmt -[appendWith]-> List U8 where fmt implements EncoderFormatting
|
||||
// ~ List U8, encoder_var, fmt -[clos]-> List U8 where fmt implements EncoderFormatting
|
||||
env.unify(append_with_fn_var, this_append_with_fn_var);
|
||||
|
||||
// Encode.appendWith : List U8, encoder_var, fmt -[appendWith]-> List U8 | fmt has EncoderFormatting
|
||||
// Encode.appendWith : List U8, encoder_var, fmt -[appendWith]-> List U8 where fmt implements EncoderFormatting
|
||||
let append_with_fn = Box::new((
|
||||
this_append_with_fn_var,
|
||||
Loc::at_zero(Var(Symbol::ENCODE_APPEND_WITH, this_append_with_fn_var)),
|
||||
|
@ -1050,7 +1050,7 @@ fn wrap_in_encode_custom(
|
|||
// Build
|
||||
// Encode.custom \bytes, fmt -> Encode.appendWith bytes encoder fmt
|
||||
//
|
||||
// expected: Encode.custom : (List U8, fmt -> List U8) -> Encoder fmt | fmt has EncoderFormatting
|
||||
// expected: Encode.custom : (List U8, fmt -> List U8) -> Encoder fmt where fmt implements EncoderFormatting
|
||||
let custom_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_CUSTOM);
|
||||
|
||||
// wanted: Encode.custom : fn_var -[clos]-> t'
|
||||
|
@ -1066,11 +1066,11 @@ fn wrap_in_encode_custom(
|
|||
)),
|
||||
);
|
||||
|
||||
// (List U8, fmt -> List U8) -[..]-> Encoder fmt | fmt has EncoderFormatting
|
||||
// (List U8, fmt -> List U8) -[..]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
// ~ fn_var -[clos]-> t'
|
||||
env.unify(custom_fn_var, this_custom_fn_var);
|
||||
|
||||
// Encode.custom : (List U8, fmt -> List U8) -> Encoder fmt | fmt has EncoderFormatting
|
||||
// Encode.custom : (List U8, fmt -> List U8) -> Encoder fmt where fmt implements EncoderFormatting
|
||||
let custom_fn = Box::new((
|
||||
this_custom_fn_var,
|
||||
Loc::at_zero(Var(Symbol::ENCODE_CUSTOM, this_custom_fn_var)),
|
||||
|
|
|
@ -75,7 +75,7 @@ fn hash_record(env: &mut Env<'_>, fn_name: Symbol, fields: Vec<Lowercase>) -> (V
|
|||
|
||||
// Now, a hasher for this record is
|
||||
//
|
||||
// hash_rcd : hasher, { f1: t1, ..., fn: tn } -> hasher | hasher has Hasher
|
||||
// hash_rcd : hasher, { f1: t1, ..., fn: tn } -> hasher where hasher implements Hasher
|
||||
// hash_rcd = \hasher, rcd ->
|
||||
// Hash.hash (
|
||||
// Hash.hash
|
||||
|
@ -144,7 +144,7 @@ fn hash_tuple(env: &mut Env<'_>, fn_name: Symbol, arity: u32) -> (Variable, Expr
|
|||
|
||||
// Now, a hasher for this tuple is
|
||||
//
|
||||
// hash_tup : hasher, (t1, ..., tn) -> hasher | hasher has Hasher
|
||||
// hash_tup : hasher, (t1, ..., tn) -> hasher where hasher implements Hasher
|
||||
// hash_tup = \hasher, tup ->
|
||||
// Hash.hash (
|
||||
// Hash.hash
|
||||
|
@ -227,7 +227,7 @@ fn hash_tag_union(
|
|||
|
||||
// Now, a hasher for this tag union is
|
||||
//
|
||||
// hash_union : hasher, [ A t11 .. t1n, ..., Q tq1 .. tqm ] -> hasher | hasher has Hasher
|
||||
// hash_union : hasher, [ A t11 .. t1n, ..., Q tq1 .. tqm ] -> hasher where hasher implements Hasher
|
||||
// hash_union = \hasher, union ->
|
||||
// when union is
|
||||
// A x11 .. x1n -> Hash.hash (... (Hash.hash (Hash.uN hasher 0) x11) ...) x1n
|
||||
|
@ -393,7 +393,7 @@ fn hash_newtype_tag_union(
|
|||
|
||||
// Now, a hasher for this tag union is
|
||||
//
|
||||
// hash_union : hasher, [ A t1 .. tn ] -> hasher | hasher has Hasher
|
||||
// hash_union : hasher, [ A t1 .. tn ] -> hasher where hasher implements Hasher
|
||||
// hash_union = \hasher, A x1 .. xn ->
|
||||
// Hash.hash (... (Hash.hash discrHasher x1) ...) xn
|
||||
let hasher_sym = env.new_symbol("hasher");
|
||||
|
@ -462,7 +462,7 @@ fn call_hash_ability_member(
|
|||
|
||||
// build `member ...` function type. `member` here is `Hash.hash` or `Hash.addU16`.
|
||||
//
|
||||
// hasher, val -[uls]-> hasher | hasher has Hasher, val has Hash
|
||||
// hasher, val -[uls]-> hasher where hasher implements Hasher, val implements Hash
|
||||
let exposed_hash_fn_var = env.import_builtin_symbol_var(member);
|
||||
|
||||
// (typeof body), (typeof field) -[clos]-> hasher_result
|
||||
|
@ -479,11 +479,11 @@ fn call_hash_ability_member(
|
|||
)),
|
||||
);
|
||||
|
||||
// hasher, val -[uls]-> hasher | hasher has Hasher, val has Hash
|
||||
// hasher, val -[uls]-> hasher where hasher implements Hasher, val implements Hash
|
||||
// ~ (typeof body), (typeof field) -[clos]-> hasher_result
|
||||
env.unify(exposed_hash_fn_var, this_hash_fn_var);
|
||||
|
||||
// Hash.hash : hasher, (typeof field) -[clos]-> hasher | hasher has Hasher, (typeof field) has Hash
|
||||
// Hash.hash : hasher, (typeof field) -[clos]-> hasher where hasher implements Hasher, (typeof field) implements Hash
|
||||
let hash_fn_head = Expr::AbilityMember(member, None, this_hash_fn_var);
|
||||
let hash_fn_data = Box::new((
|
||||
this_hash_fn_var,
|
||||
|
|
|
@ -146,7 +146,7 @@ impl Env<'_> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
// Since we're doing `{foo} ~ a | a has Encoding`, we may see "lambda sets to
|
||||
// Since we're doing `{foo} ~ a where a implements Encoding`, we may see "lambda sets to
|
||||
// specialize" for e.g. `{foo}:toEncoder:1`, but these are actually just the
|
||||
// specialization lambda sets, so we don't need to do any extra work!
|
||||
//
|
||||
|
|
|
@ -4,8 +4,8 @@ use crate::{
|
|||
Buf,
|
||||
};
|
||||
use roc_parse::ast::{
|
||||
AssignedField, Collection, Expr, ExtractSpaces, HasAbilities, HasAbility, HasClause, HasImpls,
|
||||
RecordBuilderField, Tag, TypeAnnotation, TypeHeader,
|
||||
AbilityImpls, AssignedField, Collection, Expr, ExtractSpaces, ImplementsAbilities,
|
||||
ImplementsAbility, ImplementsClause, RecordBuilderField, Tag, TypeAnnotation, TypeHeader,
|
||||
};
|
||||
use roc_parse::ident::UppercaseIdent;
|
||||
use roc_region::all::Loc;
|
||||
|
@ -350,16 +350,23 @@ impl<'a> Formattable for TypeAnnotation<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
Where(annot, has_clauses) => {
|
||||
Where(annot, implements_clauses) => {
|
||||
annot.format_with_options(buf, parens, newlines, indent);
|
||||
if has_clauses.iter().any(|has| has.is_multiline()) {
|
||||
if implements_clauses
|
||||
.iter()
|
||||
.any(|implements| implements.is_multiline())
|
||||
{
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
}
|
||||
for (i, has) in has_clauses.iter().enumerate() {
|
||||
buf.push(if i == 0 { '|' } else { ',' });
|
||||
for (i, has) in implements_clauses.iter().enumerate() {
|
||||
buf.push_str(if i == 0 {
|
||||
roc_parse::keyword::WHERE
|
||||
} else {
|
||||
","
|
||||
});
|
||||
buf.spaces(1);
|
||||
has.format_with_options(buf, parens, newlines, indent);
|
||||
}
|
||||
|
@ -645,16 +652,16 @@ impl<'a> Formattable for Tag<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Formattable for HasClause<'a> {
|
||||
impl<'a> Formattable for ImplementsClause<'a> {
|
||||
fn is_multiline(&self) -> bool {
|
||||
// No, always put abilities in a "has" clause on one line
|
||||
// No, always put abilities in an "implements" clause on one line
|
||||
false
|
||||
}
|
||||
|
||||
fn format_with_options(&self, buf: &mut Buf, parens: Parens, newlines: Newlines, indent: u16) {
|
||||
buf.push_str(self.var.value.extract_spaces().item);
|
||||
buf.spaces(1);
|
||||
buf.push_str("has");
|
||||
buf.push_str(roc_parse::keyword::IMPLEMENTS);
|
||||
buf.spaces(1);
|
||||
|
||||
for (i, ab) in self.abilities.iter().enumerate() {
|
||||
|
@ -668,30 +675,30 @@ impl<'a> Formattable for HasClause<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Formattable for HasImpls<'a> {
|
||||
impl<'a> Formattable for AbilityImpls<'a> {
|
||||
fn is_multiline(&self) -> bool {
|
||||
match self {
|
||||
HasImpls::SpaceBefore(_, _) | HasImpls::SpaceAfter(_, _) => true,
|
||||
HasImpls::HasImpls(impls) => is_collection_multiline(impls),
|
||||
AbilityImpls::SpaceBefore(_, _) | AbilityImpls::SpaceAfter(_, _) => true,
|
||||
AbilityImpls::AbilityImpls(impls) => is_collection_multiline(impls),
|
||||
}
|
||||
}
|
||||
|
||||
fn format_with_options(&self, buf: &mut Buf, parens: Parens, newlines: Newlines, indent: u16) {
|
||||
match self {
|
||||
HasImpls::HasImpls(impls) => {
|
||||
AbilityImpls::AbilityImpls(impls) => {
|
||||
if newlines == Newlines::Yes {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
}
|
||||
fmt_collection(buf, indent, Braces::Curly, *impls, Newlines::No);
|
||||
}
|
||||
HasImpls::SpaceBefore(impls, spaces) => {
|
||||
AbilityImpls::SpaceBefore(impls, spaces) => {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
impls.format_with_options(buf, parens, Newlines::No, indent);
|
||||
}
|
||||
HasImpls::SpaceAfter(impls, spaces) => {
|
||||
AbilityImpls::SpaceAfter(impls, spaces) => {
|
||||
impls.format_with_options(buf, parens, newlines, indent);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
}
|
||||
|
@ -699,11 +706,11 @@ impl<'a> Formattable for HasImpls<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Formattable for HasAbility<'a> {
|
||||
impl<'a> Formattable for ImplementsAbility<'a> {
|
||||
fn is_multiline(&self) -> bool {
|
||||
match self {
|
||||
HasAbility::SpaceAfter(..) | HasAbility::SpaceBefore(..) => true,
|
||||
HasAbility::HasAbility { ability, impls } => {
|
||||
ImplementsAbility::SpaceAfter(..) | ImplementsAbility::SpaceBefore(..) => true,
|
||||
ImplementsAbility::ImplementsAbility { ability, impls } => {
|
||||
ability.is_multiline() || impls.map(|i| i.is_multiline()).unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
@ -711,7 +718,7 @@ impl<'a> Formattable for HasAbility<'a> {
|
|||
|
||||
fn format_with_options(&self, buf: &mut Buf, parens: Parens, newlines: Newlines, indent: u16) {
|
||||
match self {
|
||||
HasAbility::HasAbility { ability, impls } => {
|
||||
ImplementsAbility::ImplementsAbility { ability, impls } => {
|
||||
if newlines == Newlines::Yes {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
|
@ -722,13 +729,13 @@ impl<'a> Formattable for HasAbility<'a> {
|
|||
impls.format_with_options(buf, parens, newlines, indent);
|
||||
}
|
||||
}
|
||||
HasAbility::SpaceBefore(ab, spaces) => {
|
||||
ImplementsAbility::SpaceBefore(ab, spaces) => {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
ab.format_with_options(buf, parens, Newlines::No, indent)
|
||||
}
|
||||
HasAbility::SpaceAfter(ab, spaces) => {
|
||||
ImplementsAbility::SpaceAfter(ab, spaces) => {
|
||||
ab.format_with_options(buf, parens, newlines, indent);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
}
|
||||
|
@ -736,32 +743,34 @@ impl<'a> Formattable for HasAbility<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Formattable for HasAbilities<'a> {
|
||||
impl<'a> Formattable for ImplementsAbilities<'a> {
|
||||
fn is_multiline(&self) -> bool {
|
||||
match self {
|
||||
HasAbilities::SpaceAfter(..) | HasAbilities::SpaceBefore(..) => true,
|
||||
HasAbilities::Has(has_abilities) => is_collection_multiline(has_abilities),
|
||||
ImplementsAbilities::SpaceAfter(..) | ImplementsAbilities::SpaceBefore(..) => true,
|
||||
ImplementsAbilities::Implements(has_abilities) => {
|
||||
is_collection_multiline(has_abilities)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn format_with_options(&self, buf: &mut Buf, parens: Parens, newlines: Newlines, indent: u16) {
|
||||
match self {
|
||||
HasAbilities::Has(has_abilities) => {
|
||||
ImplementsAbilities::Implements(has_abilities) => {
|
||||
if newlines == Newlines::Yes {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
}
|
||||
buf.push_str("has");
|
||||
buf.push_str(roc_parse::keyword::IMPLEMENTS);
|
||||
buf.spaces(1);
|
||||
fmt_collection(buf, indent, Braces::Square, *has_abilities, Newlines::No);
|
||||
}
|
||||
HasAbilities::SpaceBefore(has_abilities, spaces) => {
|
||||
ImplementsAbilities::SpaceBefore(has_abilities, spaces) => {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
has_abilities.format_with_options(buf, parens, Newlines::No, indent)
|
||||
}
|
||||
HasAbilities::SpaceAfter(has_abilities, spaces) => {
|
||||
ImplementsAbilities::SpaceAfter(has_abilities, spaces) => {
|
||||
has_abilities.format_with_options(buf, parens, newlines, indent);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ impl<'a> Formattable for TypeDef<'a> {
|
|||
}
|
||||
Ability {
|
||||
header: TypeHeader { name, vars },
|
||||
loc_has: _,
|
||||
loc_implements: _,
|
||||
members,
|
||||
} => {
|
||||
buf.indent(indent);
|
||||
|
@ -133,8 +133,8 @@ impl<'a> Formattable for TypeDef<'a> {
|
|||
fmt_pattern(buf, &var.value, indent, Parens::NotNeeded);
|
||||
buf.indent(indent);
|
||||
}
|
||||
|
||||
buf.push_str(" has");
|
||||
buf.spaces(1);
|
||||
buf.push_str(roc_parse::keyword::IMPLEMENTS);
|
||||
|
||||
if !self.is_multiline() {
|
||||
debug_assert_eq!(members.len(), 1);
|
||||
|
|
|
@ -3,10 +3,10 @@ use bumpalo::Bump;
|
|||
use roc_module::called_via::{BinOp, UnaryOp};
|
||||
use roc_parse::{
|
||||
ast::{
|
||||
AbilityMember, AssignedField, Collection, CommentOrNewline, Defs, Expr, Has, HasAbilities,
|
||||
HasAbility, HasClause, HasImpls, Header, Module, Pattern, RecordBuilderField, Spaced,
|
||||
Spaces, StrLiteral, StrSegment, Tag, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
||||
WhenBranch,
|
||||
AbilityImpls, AbilityMember, AssignedField, Collection, CommentOrNewline, Defs, Expr,
|
||||
Header, Implements, ImplementsAbilities, ImplementsAbility, ImplementsClause, Module,
|
||||
Pattern, RecordBuilderField, Spaced, Spaces, StrLiteral, StrSegment, Tag, TypeAnnotation,
|
||||
TypeDef, TypeHeader, ValueDef, WhenBranch,
|
||||
},
|
||||
header::{
|
||||
AppHeader, ExposedName, HostedHeader, ImportsEntry, InterfaceHeader, KeywordItem,
|
||||
|
@ -507,14 +507,14 @@ impl<'a> RemoveSpaces<'a> for TypeDef<'a> {
|
|||
},
|
||||
Ability {
|
||||
header: TypeHeader { name, vars },
|
||||
loc_has,
|
||||
loc_implements: loc_has,
|
||||
members,
|
||||
} => Ability {
|
||||
header: TypeHeader {
|
||||
name: name.remove_spaces(arena),
|
||||
vars: vars.remove_spaces(arena),
|
||||
},
|
||||
loc_has: loc_has.remove_spaces(arena),
|
||||
loc_implements: loc_has.remove_spaces(arena),
|
||||
members: members.remove_spaces(arena),
|
||||
},
|
||||
}
|
||||
|
@ -569,9 +569,9 @@ impl<'a> RemoveSpaces<'a> for ValueDef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> RemoveSpaces<'a> for Has<'a> {
|
||||
impl<'a> RemoveSpaces<'a> for Implements<'a> {
|
||||
fn remove_spaces(&self, _arena: &'a Bump) -> Self {
|
||||
Has::Has
|
||||
Implements::Implements
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -870,9 +870,9 @@ impl<'a> RemoveSpaces<'a> for TypeAnnotation<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> RemoveSpaces<'a> for HasClause<'a> {
|
||||
impl<'a> RemoveSpaces<'a> for ImplementsClause<'a> {
|
||||
fn remove_spaces(&self, arena: &'a Bump) -> Self {
|
||||
HasClause {
|
||||
ImplementsClause {
|
||||
var: self.var.remove_spaces(arena),
|
||||
abilities: self.abilities.remove_spaces(arena),
|
||||
}
|
||||
|
@ -893,38 +893,43 @@ impl<'a> RemoveSpaces<'a> for Tag<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> RemoveSpaces<'a> for HasImpls<'a> {
|
||||
impl<'a> RemoveSpaces<'a> for AbilityImpls<'a> {
|
||||
fn remove_spaces(&self, arena: &'a Bump) -> Self {
|
||||
match *self {
|
||||
HasImpls::HasImpls(impls) => HasImpls::HasImpls(impls.remove_spaces(arena)),
|
||||
HasImpls::SpaceBefore(has, _) | HasImpls::SpaceAfter(has, _) => {
|
||||
AbilityImpls::AbilityImpls(impls) => {
|
||||
AbilityImpls::AbilityImpls(impls.remove_spaces(arena))
|
||||
}
|
||||
AbilityImpls::SpaceBefore(has, _) | AbilityImpls::SpaceAfter(has, _) => {
|
||||
has.remove_spaces(arena)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> RemoveSpaces<'a> for HasAbility<'a> {
|
||||
impl<'a> RemoveSpaces<'a> for ImplementsAbility<'a> {
|
||||
fn remove_spaces(&self, arena: &'a Bump) -> Self {
|
||||
match *self {
|
||||
HasAbility::HasAbility { ability, impls } => HasAbility::HasAbility {
|
||||
ImplementsAbility::ImplementsAbility { ability, impls } => {
|
||||
ImplementsAbility::ImplementsAbility {
|
||||
ability: ability.remove_spaces(arena),
|
||||
impls: impls.remove_spaces(arena),
|
||||
},
|
||||
HasAbility::SpaceBefore(has, _) | HasAbility::SpaceAfter(has, _) => {
|
||||
}
|
||||
}
|
||||
ImplementsAbility::SpaceBefore(has, _) | ImplementsAbility::SpaceAfter(has, _) => {
|
||||
has.remove_spaces(arena)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> RemoveSpaces<'a> for HasAbilities<'a> {
|
||||
impl<'a> RemoveSpaces<'a> for ImplementsAbilities<'a> {
|
||||
fn remove_spaces(&self, arena: &'a Bump) -> Self {
|
||||
match *self {
|
||||
HasAbilities::Has(derived) => HasAbilities::Has(derived.remove_spaces(arena)),
|
||||
HasAbilities::SpaceBefore(derived, _) | HasAbilities::SpaceAfter(derived, _) => {
|
||||
derived.remove_spaces(arena)
|
||||
ImplementsAbilities::Implements(derived) => {
|
||||
ImplementsAbilities::Implements(derived.remove_spaces(arena))
|
||||
}
|
||||
ImplementsAbilities::SpaceBefore(derived, _)
|
||||
| ImplementsAbilities::SpaceAfter(derived, _) => derived.remove_spaces(arena),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1160,8 +1160,13 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
|
|||
*******************************************************************/
|
||||
|
||||
fn expr_literal(&mut self, lit: &Literal<'a>, storage: &StoredValue) {
|
||||
let invalid_error =
|
||||
|| internal_error!("Literal value {:?} has invalid storage {:?}", lit, storage);
|
||||
let invalid_error = || {
|
||||
internal_error!(
|
||||
"Literal value {:?} implements invalid storage {:?}",
|
||||
lit,
|
||||
storage
|
||||
)
|
||||
};
|
||||
|
||||
match storage {
|
||||
StoredValue::VirtualMachineStack { value_type, .. } => {
|
||||
|
|
|
@ -450,7 +450,7 @@ fn contains_unexposed_type(
|
|||
false
|
||||
}
|
||||
Where(loc_ann, _loc_has_clauses) => {
|
||||
// We assume all the abilities in the `has` clause are from exported modules.
|
||||
// We assume all the abilities in the `implements` clause are from exported modules.
|
||||
// TODO don't assume this! Instead, look them up and verify.
|
||||
contains_unexposed_type(&loc_ann.value, exposed_module_ids, module_ids)
|
||||
}
|
||||
|
@ -553,7 +553,7 @@ fn ability_member_type_to_docs(
|
|||
let has_clauses = has_clauses
|
||||
.iter()
|
||||
.map(|hc| {
|
||||
let ast::HasClause { var, abilities } = hc.value;
|
||||
let ast::ImplementsClause { var, abilities } = hc.value;
|
||||
(
|
||||
var.value.extract_spaces().item.to_string(),
|
||||
abilities
|
||||
|
|
|
@ -2870,7 +2870,7 @@ fn update<'a>(
|
|||
// # Default module
|
||||
// interface Default exposes [default, getDefault]
|
||||
//
|
||||
// Default has default : {} -> a | a has Default
|
||||
// Default implements default : {} -> a where a implements Default
|
||||
//
|
||||
// getDefault = \{} -> default {}
|
||||
//
|
||||
|
@ -4287,7 +4287,7 @@ fn build_header<'a>(
|
|||
// created an IdentId for this, when it was imported exposed
|
||||
// in a dependent module.
|
||||
//
|
||||
// For example, if module A has [B.{ foo }], then
|
||||
// For example, if module A implements [B.{ foo }], then
|
||||
// when we get here for B, `foo` will already have
|
||||
// an IdentId. We must reuse that!
|
||||
let ident_id = ident_ids.get_or_insert(loc_exposed.value.as_str());
|
||||
|
@ -4311,7 +4311,7 @@ fn build_header<'a>(
|
|||
// created an IdentId for this, when it was imported exposed
|
||||
// in a dependent module.
|
||||
//
|
||||
// For example, if module A has [B.{ foo }], then
|
||||
// For example, if module A implements [B.{ foo }], then
|
||||
// when we get here for B, `foo` will already have
|
||||
// an IdentId. We must reuse that!
|
||||
let ident_id = ident_ids.get_or_insert(loc_name.value.as_str());
|
||||
|
|
|
@ -13,7 +13,7 @@ Model position :
|
|||
}
|
||||
|
||||
|
||||
initialModel : position -> Model position | position has Hash & Eq
|
||||
initialModel : position -> Model position where position implements Hash & Eq
|
||||
initialModel = \start ->
|
||||
{ evaluated : Set.empty {}
|
||||
, openSet : Set.single start
|
||||
|
@ -22,7 +22,7 @@ initialModel = \start ->
|
|||
}
|
||||
|
||||
|
||||
cheapestOpen : (position -> F64), Model position -> Result position [KeyNotFound] | position has Hash & Eq
|
||||
cheapestOpen : (position -> F64), Model position -> Result position [KeyNotFound] where position implements Hash & Eq
|
||||
cheapestOpen = \costFunction, model ->
|
||||
|
||||
folder = \resSmallestSoFar, position ->
|
||||
|
@ -47,7 +47,7 @@ cheapestOpen = \costFunction, model ->
|
|||
|
||||
|
||||
|
||||
reconstructPath : Dict position position, position -> List position | position has Hash & Eq
|
||||
reconstructPath : Dict position position, position -> List position where position implements Hash & Eq
|
||||
reconstructPath = \cameFrom, goal ->
|
||||
when Dict.get cameFrom goal is
|
||||
Err KeyNotFound ->
|
||||
|
@ -56,7 +56,7 @@ reconstructPath = \cameFrom, goal ->
|
|||
Ok next ->
|
||||
List.append (reconstructPath cameFrom next) goal
|
||||
|
||||
updateCost : position, position, Model position -> Model position | position has Hash & Eq
|
||||
updateCost : position, position, Model position -> Model position where position implements Hash & Eq
|
||||
updateCost = \current, neighbour, model ->
|
||||
newCameFrom = Dict.insert model.cameFrom neighbour current
|
||||
|
||||
|
@ -80,12 +80,12 @@ updateCost = \current, neighbour, model ->
|
|||
model
|
||||
|
||||
|
||||
findPath : { costFunction: (position, position -> F64), moveFunction: (position -> Set position), start : position, end : position } -> Result (List position) [KeyNotFound] | position has Hash & Eq
|
||||
findPath : { costFunction: (position, position -> F64), moveFunction: (position -> Set position), start : position, end : position } -> Result (List position) [KeyNotFound] where position implements Hash & Eq
|
||||
findPath = \{ costFunction, moveFunction, start, end } ->
|
||||
astar costFunction moveFunction end (initialModel start)
|
||||
|
||||
|
||||
astar : (position, position -> F64), (position -> Set position), position, Model position -> [Err [KeyNotFound], Ok (List position)] | position has Hash & Eq
|
||||
astar : (position, position -> F64), (position -> Set position), position, Model position -> [Err [KeyNotFound], Ok (List position)] where position implements Hash & Eq
|
||||
astar = \costFn, moveFn, goal, model ->
|
||||
when cheapestOpen (\position -> costFn goal position) model is
|
||||
Err _ ->
|
||||
|
|
|
@ -514,12 +514,12 @@ fn load_astar() {
|
|||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"findPath" => "{ costFunction : position, position -> F64, end : position, moveFunction : position -> Set position, start : position } -> Result (List position) [KeyNotFound] | position has Hash & Eq",
|
||||
"initialModel" => "position -> Model position | position has Hash & Eq",
|
||||
"reconstructPath" => "Dict position position, position -> List position | position has Hash & Eq",
|
||||
"updateCost" => "position, position, Model position -> Model position | position has Hash & Eq",
|
||||
"cheapestOpen" => "(position -> F64), Model position -> Result position [KeyNotFound] | position has Hash & Eq",
|
||||
"astar" => "(position, position -> F64), (position -> Set position), position, Model position -> [Err [KeyNotFound], Ok (List position)] | position has Hash & Eq",
|
||||
"findPath" => "{ costFunction : position, position -> F64, end : position, moveFunction : position -> Set position, start : position } -> Result (List position) [KeyNotFound] where position implements Hash & Eq",
|
||||
"initialModel" => "position -> Model position where position implements Hash & Eq",
|
||||
"reconstructPath" => "Dict position position, position -> List position where position implements Hash & Eq",
|
||||
"updateCost" => "position, position, Model position -> Model position where position implements Hash & Eq",
|
||||
"cheapestOpen" => "(position -> F64), Model position -> Result position [KeyNotFound] where position implements Hash & Eq",
|
||||
"astar" => "(position, position -> F64), (position -> Set position), position, Model position -> [Err [KeyNotFound], Ok (List position)] where position implements Hash & Eq",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -357,15 +357,15 @@ impl<'a> TypeHeader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The `has` keyword associated with ability definitions.
|
||||
/// The `implements` keyword associated with ability definitions.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Has<'a> {
|
||||
Has,
|
||||
SpaceBefore(&'a Has<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a Has<'a>, &'a [CommentOrNewline<'a>]),
|
||||
pub enum Implements<'a> {
|
||||
Implements,
|
||||
SpaceBefore(&'a Implements<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a Implements<'a>, &'a [CommentOrNewline<'a>]),
|
||||
}
|
||||
|
||||
/// An ability demand is a value defining the ability; for example `hash : a -> U64 | a has Hash`
|
||||
/// An ability demand is a value defining the ability; for example `hash : a -> U64 where a implements Hash`
|
||||
/// for a `Hash` ability.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct AbilityMember<'a> {
|
||||
|
@ -394,15 +394,15 @@ pub enum TypeDef<'a> {
|
|||
Opaque {
|
||||
header: TypeHeader<'a>,
|
||||
typ: Loc<TypeAnnotation<'a>>,
|
||||
derived: Option<Loc<HasAbilities<'a>>>,
|
||||
derived: Option<Loc<ImplementsAbilities<'a>>>,
|
||||
},
|
||||
|
||||
/// An ability definition. E.g.
|
||||
/// Hash has
|
||||
/// hash : a -> U64 | a has Hash
|
||||
/// Hash implements
|
||||
/// hash : a -> U64 where a implements Hash
|
||||
Ability {
|
||||
header: TypeHeader<'a>,
|
||||
loc_has: Loc<Has<'a>>,
|
||||
loc_implements: Loc<Implements<'a>>,
|
||||
members: &'a [AbilityMember<'a>],
|
||||
},
|
||||
}
|
||||
|
@ -538,54 +538,54 @@ impl<'a> Defs<'a> {
|
|||
pub type AbilityName<'a> = Loc<TypeAnnotation<'a>>;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub struct HasClause<'a> {
|
||||
pub struct ImplementsClause<'a> {
|
||||
pub var: Loc<Spaced<'a, &'a str>>,
|
||||
pub abilities: &'a [AbilityName<'a>],
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub enum HasImpls<'a> {
|
||||
pub enum AbilityImpls<'a> {
|
||||
// `{ eq: myEq }`
|
||||
HasImpls(Collection<'a, Loc<AssignedField<'a, Expr<'a>>>>),
|
||||
AbilityImpls(Collection<'a, Loc<AssignedField<'a, Expr<'a>>>>),
|
||||
|
||||
// We preserve this for the formatter; canonicalization ignores it.
|
||||
SpaceBefore(&'a HasImpls<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a HasImpls<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceBefore(&'a AbilityImpls<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a AbilityImpls<'a>, &'a [CommentOrNewline<'a>]),
|
||||
}
|
||||
|
||||
/// `Eq` or `Eq { eq: myEq }`
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub enum HasAbility<'a> {
|
||||
HasAbility {
|
||||
pub enum ImplementsAbility<'a> {
|
||||
ImplementsAbility {
|
||||
/// Should be a zero-argument `Apply` or an error; we'll check this in canonicalization
|
||||
ability: Loc<TypeAnnotation<'a>>,
|
||||
impls: Option<Loc<HasImpls<'a>>>,
|
||||
impls: Option<Loc<AbilityImpls<'a>>>,
|
||||
},
|
||||
|
||||
// We preserve this for the formatter; canonicalization ignores it.
|
||||
SpaceBefore(&'a HasAbility<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a HasAbility<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceBefore(&'a ImplementsAbility<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a ImplementsAbility<'a>, &'a [CommentOrNewline<'a>]),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub enum HasAbilities<'a> {
|
||||
/// `has [Eq { eq: myEq }, Hash]`
|
||||
Has(Collection<'a, Loc<HasAbility<'a>>>),
|
||||
pub enum ImplementsAbilities<'a> {
|
||||
/// `implements [Eq { eq: myEq }, Hash]`
|
||||
Implements(Collection<'a, Loc<ImplementsAbility<'a>>>),
|
||||
|
||||
// We preserve this for the formatter; canonicalization ignores it.
|
||||
SpaceBefore(&'a HasAbilities<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a HasAbilities<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceBefore(&'a ImplementsAbilities<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a ImplementsAbilities<'a>, &'a [CommentOrNewline<'a>]),
|
||||
}
|
||||
|
||||
impl HasAbilities<'_> {
|
||||
pub fn collection(&self) -> &Collection<Loc<HasAbility>> {
|
||||
impl ImplementsAbilities<'_> {
|
||||
pub fn collection(&self) -> &Collection<Loc<ImplementsAbility>> {
|
||||
let mut it = self;
|
||||
loop {
|
||||
match it {
|
||||
Self::SpaceBefore(inner, _) | Self::SpaceAfter(inner, _) => {
|
||||
it = inner;
|
||||
}
|
||||
Self::Has(collection) => return collection,
|
||||
Self::Implements(collection) => return collection,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -641,8 +641,8 @@ pub enum TypeAnnotation<'a> {
|
|||
/// The `*` type variable, e.g. in (List *)
|
||||
Wildcard,
|
||||
|
||||
/// A "where" clause demanding abilities designated by a `|`, e.g. `a -> U64 | a has Hash`
|
||||
Where(&'a Loc<TypeAnnotation<'a>>, &'a [Loc<HasClause<'a>>]),
|
||||
/// A "where" clause demanding abilities designated by a `where`, e.g. `a -> U64 where a implements Hash`
|
||||
Where(&'a Loc<TypeAnnotation<'a>>, &'a [Loc<ImplementsClause<'a>>]),
|
||||
|
||||
// We preserve this for the formatter; canonicalization ignores it.
|
||||
SpaceBefore(&'a TypeAnnotation<'a>, &'a [CommentOrNewline<'a>]),
|
||||
|
@ -1245,39 +1245,39 @@ impl<'a> Spaceable<'a> for Tag<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Spaceable<'a> for Has<'a> {
|
||||
impl<'a> Spaceable<'a> for Implements<'a> {
|
||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
Has::SpaceBefore(self, spaces)
|
||||
Implements::SpaceBefore(self, spaces)
|
||||
}
|
||||
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
Has::SpaceAfter(self, spaces)
|
||||
Implements::SpaceAfter(self, spaces)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Spaceable<'a> for HasImpls<'a> {
|
||||
impl<'a> Spaceable<'a> for AbilityImpls<'a> {
|
||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
HasImpls::SpaceBefore(self, spaces)
|
||||
AbilityImpls::SpaceBefore(self, spaces)
|
||||
}
|
||||
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
HasImpls::SpaceAfter(self, spaces)
|
||||
AbilityImpls::SpaceAfter(self, spaces)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Spaceable<'a> for HasAbility<'a> {
|
||||
impl<'a> Spaceable<'a> for ImplementsAbility<'a> {
|
||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
HasAbility::SpaceBefore(self, spaces)
|
||||
ImplementsAbility::SpaceBefore(self, spaces)
|
||||
}
|
||||
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
HasAbility::SpaceAfter(self, spaces)
|
||||
ImplementsAbility::SpaceAfter(self, spaces)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Spaceable<'a> for HasAbilities<'a> {
|
||||
impl<'a> Spaceable<'a> for ImplementsAbilities<'a> {
|
||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
HasAbilities::SpaceBefore(self, spaces)
|
||||
ImplementsAbilities::SpaceBefore(self, spaces)
|
||||
}
|
||||
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
HasAbilities::SpaceAfter(self, spaces)
|
||||
ImplementsAbilities::SpaceAfter(self, spaces)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1368,7 +1368,7 @@ impl_extract_spaces!(Pattern);
|
|||
impl_extract_spaces!(Tag);
|
||||
impl_extract_spaces!(AssignedField<T>);
|
||||
impl_extract_spaces!(TypeAnnotation);
|
||||
impl_extract_spaces!(HasAbility);
|
||||
impl_extract_spaces!(ImplementsAbility);
|
||||
|
||||
impl<'a, T: Copy> ExtractSpaces<'a> for Spaced<'a, T> {
|
||||
type Item = T;
|
||||
|
@ -1422,43 +1422,43 @@ impl<'a, T: Copy> ExtractSpaces<'a> for Spaced<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> ExtractSpaces<'a> for HasImpls<'a> {
|
||||
impl<'a> ExtractSpaces<'a> for AbilityImpls<'a> {
|
||||
type Item = Collection<'a, Loc<AssignedField<'a, Expr<'a>>>>;
|
||||
|
||||
fn extract_spaces(&self) -> Spaces<'a, Self::Item> {
|
||||
match self {
|
||||
HasImpls::HasImpls(inner) => Spaces {
|
||||
AbilityImpls::AbilityImpls(inner) => Spaces {
|
||||
before: &[],
|
||||
item: *inner,
|
||||
after: &[],
|
||||
},
|
||||
HasImpls::SpaceBefore(item, before) => match item {
|
||||
HasImpls::HasImpls(inner) => Spaces {
|
||||
AbilityImpls::SpaceBefore(item, before) => match item {
|
||||
AbilityImpls::AbilityImpls(inner) => Spaces {
|
||||
before,
|
||||
item: *inner,
|
||||
after: &[],
|
||||
},
|
||||
HasImpls::SpaceBefore(_, _) => todo!(),
|
||||
HasImpls::SpaceAfter(HasImpls::HasImpls(inner), after) => Spaces {
|
||||
AbilityImpls::SpaceBefore(_, _) => todo!(),
|
||||
AbilityImpls::SpaceAfter(AbilityImpls::AbilityImpls(inner), after) => Spaces {
|
||||
before,
|
||||
item: *inner,
|
||||
after,
|
||||
},
|
||||
HasImpls::SpaceAfter(_, _) => todo!(),
|
||||
AbilityImpls::SpaceAfter(_, _) => todo!(),
|
||||
},
|
||||
HasImpls::SpaceAfter(item, after) => match item {
|
||||
HasImpls::HasImpls(inner) => Spaces {
|
||||
AbilityImpls::SpaceAfter(item, after) => match item {
|
||||
AbilityImpls::AbilityImpls(inner) => Spaces {
|
||||
before: &[],
|
||||
item: *inner,
|
||||
after,
|
||||
},
|
||||
HasImpls::SpaceBefore(HasImpls::HasImpls(inner), before) => Spaces {
|
||||
AbilityImpls::SpaceBefore(AbilityImpls::AbilityImpls(inner), before) => Spaces {
|
||||
before,
|
||||
item: *inner,
|
||||
after,
|
||||
},
|
||||
HasImpls::SpaceBefore(_, _) => todo!(),
|
||||
HasImpls::SpaceAfter(_, _) => todo!(),
|
||||
AbilityImpls::SpaceBefore(_, _) => todo!(),
|
||||
AbilityImpls::SpaceAfter(_, _) => todo!(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -1681,11 +1681,11 @@ impl<'a> Malformed for TypeDef<'a> {
|
|||
} => header.is_malformed() || typ.is_malformed() || derived.is_malformed(),
|
||||
TypeDef::Ability {
|
||||
header,
|
||||
loc_has,
|
||||
loc_implements,
|
||||
members,
|
||||
} => {
|
||||
header.is_malformed()
|
||||
|| loc_has.is_malformed()
|
||||
|| loc_implements.is_malformed()
|
||||
|| members.iter().any(|member| member.is_malformed())
|
||||
}
|
||||
}
|
||||
|
@ -1698,42 +1698,48 @@ impl<'a> Malformed for AbilityMember<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Malformed for Has<'a> {
|
||||
impl<'a> Malformed for Implements<'a> {
|
||||
fn is_malformed(&self) -> bool {
|
||||
match self {
|
||||
Has::Has => false,
|
||||
Has::SpaceBefore(has, _) | Has::SpaceAfter(has, _) => has.is_malformed(),
|
||||
Implements::Implements => false,
|
||||
Implements::SpaceBefore(has, _) | Implements::SpaceAfter(has, _) => has.is_malformed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Malformed for HasAbility<'a> {
|
||||
impl<'a> Malformed for ImplementsAbility<'a> {
|
||||
fn is_malformed(&self) -> bool {
|
||||
match self {
|
||||
HasAbility::HasAbility { ability, impls } => {
|
||||
ImplementsAbility::ImplementsAbility { ability, impls } => {
|
||||
ability.is_malformed() || impls.iter().any(|impl_| impl_.is_malformed())
|
||||
}
|
||||
HasAbility::SpaceBefore(has, _) | HasAbility::SpaceAfter(has, _) => has.is_malformed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Malformed for HasAbilities<'a> {
|
||||
fn is_malformed(&self) -> bool {
|
||||
match self {
|
||||
HasAbilities::Has(abilities) => abilities.iter().any(|ability| ability.is_malformed()),
|
||||
HasAbilities::SpaceBefore(has, _) | HasAbilities::SpaceAfter(has, _) => {
|
||||
ImplementsAbility::SpaceBefore(has, _) | ImplementsAbility::SpaceAfter(has, _) => {
|
||||
has.is_malformed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Malformed for HasImpls<'a> {
|
||||
impl<'a> Malformed for ImplementsAbilities<'a> {
|
||||
fn is_malformed(&self) -> bool {
|
||||
match self {
|
||||
HasImpls::HasImpls(impls) => impls.iter().any(|ability| ability.is_malformed()),
|
||||
HasImpls::SpaceBefore(has, _) | HasImpls::SpaceAfter(has, _) => has.is_malformed(),
|
||||
ImplementsAbilities::Implements(abilities) => {
|
||||
abilities.iter().any(|ability| ability.is_malformed())
|
||||
}
|
||||
ImplementsAbilities::SpaceBefore(has, _) | ImplementsAbilities::SpaceAfter(has, _) => {
|
||||
has.is_malformed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Malformed for AbilityImpls<'a> {
|
||||
fn is_malformed(&self) -> bool {
|
||||
match self {
|
||||
AbilityImpls::AbilityImpls(impls) => impls.iter().any(|ability| ability.is_malformed()),
|
||||
AbilityImpls::SpaceBefore(has, _) | AbilityImpls::SpaceAfter(has, _) => {
|
||||
has.is_malformed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1823,7 +1829,7 @@ impl<'a> Malformed for Tag<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Malformed for HasClause<'a> {
|
||||
impl<'a> Malformed for ImplementsClause<'a> {
|
||||
fn is_malformed(&self) -> bool {
|
||||
self.abilities.iter().any(|ability| ability.is_malformed())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::ast::{
|
||||
AssignedField, Collection, CommentOrNewline, Defs, Expr, ExtractSpaces, Has, HasAbilities,
|
||||
Pattern, RecordBuilderField, Spaceable, Spaces, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
||||
AssignedField, Collection, CommentOrNewline, Defs, Expr, ExtractSpaces, Implements,
|
||||
ImplementsAbilities, Pattern, RecordBuilderField, Spaceable, Spaces, TypeAnnotation, TypeDef,
|
||||
TypeHeader, ValueDef,
|
||||
};
|
||||
use crate::blankspace::{
|
||||
space0_after_e, space0_around_e_no_after_indent_check, space0_around_ee, space0_before_e,
|
||||
|
@ -14,7 +15,7 @@ use crate::parser::{
|
|||
word2, EClosure, EExpect, EExpr, EIf, EInParens, EList, ENumber, EPattern, ERecord, EString,
|
||||
EType, EWhen, Either, ParseResult, Parser,
|
||||
};
|
||||
use crate::pattern::{closure_param, loc_has_parser};
|
||||
use crate::pattern::{closure_param, loc_implements_parser};
|
||||
use crate::state::State;
|
||||
use crate::string_literal::StrLikeLiteral;
|
||||
use crate::type_annotation;
|
||||
|
@ -616,14 +617,14 @@ pub fn parse_single_def<'a>(
|
|||
};
|
||||
|
||||
if let Some((name, name_region, args)) = opt_tag_and_args {
|
||||
if let Ok((_, loc_has, state)) =
|
||||
loc_has_parser().parse(arena, state.clone(), min_indent)
|
||||
if let Ok((_, loc_implements, state)) =
|
||||
loc_implements_parser().parse(arena, state.clone(), min_indent)
|
||||
{
|
||||
let (_, (type_def, def_region), state) = finish_parsing_ability_def_help(
|
||||
min_indent,
|
||||
Loc::at(name_region, name),
|
||||
args,
|
||||
loc_has,
|
||||
loc_implements,
|
||||
arena,
|
||||
state,
|
||||
)?;
|
||||
|
@ -1063,8 +1064,14 @@ fn alias_signature_with_space_before<'a>() -> impl Parser<'a, Loc<TypeAnnotation
|
|||
))
|
||||
}
|
||||
|
||||
fn opaque_signature_with_space_before<'a>(
|
||||
) -> impl Parser<'a, (Loc<TypeAnnotation<'a>>, Option<Loc<HasAbilities<'a>>>), EExpr<'a>> {
|
||||
fn opaque_signature_with_space_before<'a>() -> impl Parser<
|
||||
'a,
|
||||
(
|
||||
Loc<TypeAnnotation<'a>>,
|
||||
Option<Loc<ImplementsAbilities<'a>>>,
|
||||
),
|
||||
EExpr<'a>,
|
||||
> {
|
||||
and!(
|
||||
specialize(
|
||||
EExpr::Type,
|
||||
|
@ -1075,7 +1082,7 @@ fn opaque_signature_with_space_before<'a>(
|
|||
),
|
||||
optional(backtrackable(specialize(
|
||||
EExpr::Type,
|
||||
space0_before_e(type_annotation::has_abilities(), EType::TIndentStart,),
|
||||
space0_before_e(type_annotation::implements_abilities(), EType::TIndentStart,),
|
||||
)))
|
||||
)
|
||||
}
|
||||
|
@ -1279,7 +1286,7 @@ mod ability {
|
|||
Exact(u32),
|
||||
}
|
||||
|
||||
/// Parses an ability demand like `hash : a -> U64 | a has Hash`, in the context of a larger
|
||||
/// Parses an ability demand like `hash : a -> U64 where a implements Hash`, in the context of a larger
|
||||
/// ability definition.
|
||||
/// This is basically the same as parsing a free-floating annotation, but with stricter rules.
|
||||
pub fn parse_demand<'a>(
|
||||
|
@ -1363,7 +1370,7 @@ fn finish_parsing_ability_def_help<'a>(
|
|||
start_column: u32,
|
||||
name: Loc<&'a str>,
|
||||
args: &'a [Loc<Pattern<'a>>],
|
||||
loc_has: Loc<Has<'a>>,
|
||||
loc_implements: Loc<Implements<'a>>,
|
||||
arena: &'a Bump,
|
||||
state: State<'a>,
|
||||
) -> ParseResult<'a, (TypeDef<'a>, Region), EExpr<'a>> {
|
||||
|
@ -1401,7 +1408,7 @@ fn finish_parsing_ability_def_help<'a>(
|
|||
let def_region = Region::span_across(&name.region, &demands.last().unwrap().typ.region);
|
||||
let type_def = TypeDef::Ability {
|
||||
header: TypeHeader { name, vars: args },
|
||||
loc_has,
|
||||
loc_implements,
|
||||
members: demands.into_bump_slice(),
|
||||
};
|
||||
|
||||
|
@ -1634,13 +1641,13 @@ fn parse_expr_end<'a>(
|
|||
value:
|
||||
Expr::Var {
|
||||
module_name: "",
|
||||
ident: "has",
|
||||
ident: crate::keyword::IMPLEMENTS,
|
||||
},
|
||||
..
|
||||
},
|
||||
state,
|
||||
)) if matches!(expr_state.expr.value, Expr::Tag(..)) => {
|
||||
// This is an ability definition, `Ability arg1 ... has ...`.
|
||||
// This is an ability definition, `Ability arg1 ... implements ...`.
|
||||
|
||||
let name = expr_state.expr.map_owned(|e| match e {
|
||||
Expr::Tag(name) => name,
|
||||
|
@ -1661,13 +1668,13 @@ fn parse_expr_end<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
// Attach any spaces to the `has` keyword
|
||||
// Attach any spaces to the `implements` keyword
|
||||
let has = if !expr_state.spaces_after.is_empty() {
|
||||
arena
|
||||
.alloc(Has::Has)
|
||||
.alloc(Implements::Implements)
|
||||
.with_spaces_before(expr_state.spaces_after, has.region)
|
||||
} else {
|
||||
Loc::at(has.region, Has::Has)
|
||||
Loc::at(has.region, Implements::Implements)
|
||||
};
|
||||
|
||||
let args = arguments.into_bump_slice();
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// These keywords are valid in expressions
|
||||
pub const IF: &str = "if";
|
||||
pub const THEN: &str = "then";
|
||||
pub const ELSE: &str = "else";
|
||||
|
@ -9,4 +10,10 @@ pub const EXPECT: &str = "expect";
|
|||
pub const EXPECT_FX: &str = "expect-fx";
|
||||
pub const CRASH: &str = "crash";
|
||||
|
||||
pub const KEYWORDS: [&str; 10] = [IF, THEN, ELSE, WHEN, AS, IS, DBG, EXPECT, EXPECT_FX, CRASH];
|
||||
// These keywords are valid in types
|
||||
pub const IMPLEMENTS: &str = "implements";
|
||||
pub const WHERE: &str = "where";
|
||||
|
||||
pub const KEYWORDS: [&str; 11] = [
|
||||
IF, THEN, ELSE, WHEN, AS, IS, DBG, EXPECT, EXPECT_FX, CRASH, WHERE,
|
||||
];
|
||||
|
|
|
@ -599,7 +599,7 @@ pub enum EType<'a> {
|
|||
TEnd(Position),
|
||||
TFunctionArgument(Position),
|
||||
TWhereBar(Position),
|
||||
THasClause(Position),
|
||||
TImplementsClause(Position),
|
||||
TAbilityImpl(ETypeAbilityImpl<'a>, Position),
|
||||
///
|
||||
TIndentStart(Position),
|
||||
|
@ -1524,6 +1524,23 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn word<'a, ToError, E>(word: &'static str, to_error: ToError) -> impl Parser<'a, (), E>
|
||||
where
|
||||
ToError: Fn(Position) -> E,
|
||||
E: 'a,
|
||||
{
|
||||
debug_assert!(!word.contains('\n'));
|
||||
|
||||
move |_arena: &'a Bump, state: State<'a>, _min_indent: u32| {
|
||||
if state.bytes().starts_with(word.as_bytes()) {
|
||||
let state = state.advance(word.len());
|
||||
Ok((MadeProgress, (), state))
|
||||
} else {
|
||||
Err((NoProgress, to_error(state.pos())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn word1<'a, ToError, E>(word: u8, to_error: ToError) -> impl Parser<'a, (), E>
|
||||
where
|
||||
ToError: Fn(Position) -> E,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::ast::{Has, Pattern, PatternAs, Spaceable};
|
||||
use crate::ast::{Implements, Pattern, PatternAs, Spaceable};
|
||||
use crate::blankspace::{space0_e, spaces, spaces_before};
|
||||
use crate::ident::{lowercase_ident, parse_ident, Accessor, Ident};
|
||||
use crate::keyword;
|
||||
|
@ -116,7 +116,7 @@ fn loc_tag_pattern_args_help<'a>() -> impl Parser<'a, Vec<'a, Loc<Pattern<'a>>>,
|
|||
zero_or_more!(loc_tag_pattern_arg(false))
|
||||
}
|
||||
|
||||
/// Like `loc_tag_pattern_args_help`, but stops if a "has" keyword is seen (indicating an ability).
|
||||
/// Like `loc_tag_pattern_args_help`, but stops if a "implements" keyword is seen (indicating an ability).
|
||||
fn loc_type_def_tag_pattern_args_help<'a>(
|
||||
) -> impl Parser<'a, Vec<'a, Loc<Pattern<'a>>>, EPattern<'a>> {
|
||||
zero_or_more!(loc_tag_pattern_arg(true))
|
||||
|
@ -138,7 +138,7 @@ fn loc_tag_pattern_arg<'a>(
|
|||
|
||||
let Loc { region, value } = loc_pat;
|
||||
|
||||
if stop_on_has_kw && matches!(value, Pattern::Identifier("has")) {
|
||||
if stop_on_has_kw && matches!(value, Pattern::Identifier(crate::keyword::IMPLEMENTS)) {
|
||||
Err((NoProgress, EPattern::End(original_state.pos())))
|
||||
} else {
|
||||
Ok((
|
||||
|
@ -154,12 +154,19 @@ fn loc_tag_pattern_arg<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn loc_has_parser<'a>() -> impl Parser<'a, Loc<Has<'a>>, EPattern<'a>> {
|
||||
pub fn loc_implements_parser<'a>() -> impl Parser<'a, Loc<Implements<'a>>, EPattern<'a>> {
|
||||
then(
|
||||
loc_tag_pattern_arg(false),
|
||||
|_arena, state, progress, pattern| {
|
||||
if matches!(pattern.value, Pattern::Identifier("has")) {
|
||||
Ok((progress, Loc::at(pattern.region, Has::Has), state))
|
||||
if matches!(
|
||||
pattern.value,
|
||||
Pattern::Identifier(crate::keyword::IMPLEMENTS)
|
||||
) {
|
||||
Ok((
|
||||
progress,
|
||||
Loc::at(pattern.region, Implements::Implements),
|
||||
state,
|
||||
))
|
||||
} else {
|
||||
Err((progress, EPattern::End(state.pos())))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ast::{
|
||||
AssignedField, CommentOrNewline, Expr, HasAbilities, HasAbility, HasClause, HasImpls, Pattern,
|
||||
Spaceable, Spaced, Tag, TypeAnnotation, TypeHeader,
|
||||
AbilityImpls, AssignedField, CommentOrNewline, Expr, ImplementsAbilities, ImplementsAbility,
|
||||
ImplementsClause, Pattern, Spaceable, Spaced, Tag, TypeAnnotation, TypeHeader,
|
||||
};
|
||||
use crate::blankspace::{
|
||||
space0_around_ee, space0_before_e, space0_before_optional_after, space0_e,
|
||||
|
@ -12,7 +12,7 @@ use crate::parser::{
|
|||
absolute_column_min_indent, increment_min_indent, then, ERecord, ETypeAbilityImpl,
|
||||
};
|
||||
use crate::parser::{
|
||||
allocated, backtrackable, fail, optional, specialize, specialize_ref, word1, word2, word3,
|
||||
allocated, backtrackable, fail, optional, specialize, specialize_ref, word, word1, word2,
|
||||
EType, ETypeApply, ETypeInParens, ETypeInlineAlias, ETypeRecord, ETypeTagUnion, Parser,
|
||||
Progress::{self, *},
|
||||
};
|
||||
|
@ -426,7 +426,7 @@ fn ability_chain<'a>() -> impl Parser<'a, Vec<'a, Loc<TypeAnnotation<'a>>>, ETyp
|
|||
EType::TIndentEnd,
|
||||
),
|
||||
zero_or_more!(skip_first!(
|
||||
word1(b'&', EType::THasClause),
|
||||
word1(b'&', EType::TImplementsClause),
|
||||
space0_before_optional_after(
|
||||
specialize(EType::TApply, loc!(concrete_type())),
|
||||
EType::TIndentStart,
|
||||
|
@ -444,9 +444,9 @@ fn ability_chain<'a>() -> impl Parser<'a, Vec<'a, Loc<TypeAnnotation<'a>>>, ETyp
|
|||
)
|
||||
}
|
||||
|
||||
fn has_clause<'a>() -> impl Parser<'a, Loc<HasClause<'a>>, EType<'a>> {
|
||||
fn implements_clause<'a>() -> impl Parser<'a, Loc<ImplementsClause<'a>>, EType<'a>> {
|
||||
map!(
|
||||
// Suppose we are trying to parse "a has Hash"
|
||||
// Suppose we are trying to parse "a implements Hash"
|
||||
and!(
|
||||
space0_around_ee(
|
||||
// Parse "a", with appropriate spaces
|
||||
|
@ -458,8 +458,8 @@ fn has_clause<'a>() -> impl Parser<'a, Loc<HasClause<'a>>, EType<'a>> {
|
|||
EType::TIndentEnd
|
||||
),
|
||||
skip_first!(
|
||||
// Parse "has"; we don't care about this keyword
|
||||
word3(b'h', b'a', b's', EType::THasClause),
|
||||
// Parse "implements"; we don't care about this keyword
|
||||
word(crate::keyword::IMPLEMENTS, EType::TImplementsClause),
|
||||
// Parse "Hash & ..."; this may be qualified from another module like "Hash.Hash"
|
||||
absolute_column_min_indent(ability_chain())
|
||||
)
|
||||
|
@ -470,29 +470,33 @@ fn has_clause<'a>() -> impl Parser<'a, Loc<HasClause<'a>>, EType<'a>> {
|
|||
&abilities.last().unwrap().region,
|
||||
);
|
||||
let region = Region::span_across(&var.region, &abilities_region);
|
||||
let has_clause = HasClause {
|
||||
let implements_clause = ImplementsClause {
|
||||
var,
|
||||
abilities: abilities.into_bump_slice(),
|
||||
};
|
||||
Loc::at(region, has_clause)
|
||||
Loc::at(region, implements_clause)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Parse a chain of `has` clauses, e.g. " | a has Hash, b has Eq".
|
||||
/// Returns the clauses and spaces before the starting "|", if there were any.
|
||||
fn has_clause_chain<'a>(
|
||||
) -> impl Parser<'a, (&'a [CommentOrNewline<'a>], &'a [Loc<HasClause<'a>>]), EType<'a>> {
|
||||
/// Parse a chain of `implements` clauses, e.g. " where a implements Hash, b implements Eq".
|
||||
/// Returns the clauses and spaces before the starting "where", if there were any.
|
||||
fn implements_clause_chain<'a>(
|
||||
) -> impl Parser<'a, (&'a [CommentOrNewline<'a>], &'a [Loc<ImplementsClause<'a>>]), EType<'a>> {
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
let (_, (spaces_before, ()), state) =
|
||||
and!(space0_e(EType::TIndentStart), word1(b'|', EType::TWhereBar))
|
||||
let (_, (spaces_before, ()), state) = and!(
|
||||
space0_e(EType::TIndentStart),
|
||||
word(crate::keyword::WHERE, EType::TWhereBar)
|
||||
)
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
// Parse the first clause (there must be one), then the rest
|
||||
let (_, first_clause, state) = has_clause().parse(arena, state, min_indent)?;
|
||||
let (_, first_clause, state) = implements_clause().parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, mut clauses, state) =
|
||||
zero_or_more!(skip_first!(word1(b',', EType::THasClause), has_clause()))
|
||||
let (_, mut clauses, state) = zero_or_more!(skip_first!(
|
||||
word1(b',', EType::TImplementsClause),
|
||||
implements_clause()
|
||||
))
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
// Usually the number of clauses shouldn't be too large, so this is okay
|
||||
|
@ -506,30 +510,30 @@ fn has_clause_chain<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Parse a has-abilities clause, e.g. `has [Eq, Hash]`.
|
||||
pub fn has_abilities<'a>() -> impl Parser<'a, Loc<HasAbilities<'a>>, EType<'a>> {
|
||||
/// Parse a implements-abilities clause, e.g. `implements [Eq, Hash]`.
|
||||
pub fn implements_abilities<'a>() -> impl Parser<'a, Loc<ImplementsAbilities<'a>>, EType<'a>> {
|
||||
increment_min_indent(skip_first!(
|
||||
// Parse "has"; we don't care about this keyword
|
||||
word3(b'h', b'a', b's', EType::THasClause),
|
||||
// Parse "implements"; we don't care about this keyword
|
||||
word(crate::keyword::IMPLEMENTS, EType::TImplementsClause),
|
||||
// Parse "Hash"; this may be qualified from another module like "Hash.Hash"
|
||||
space0_before_e(
|
||||
loc!(map!(
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'[', EType::TStart),
|
||||
loc!(parse_has_ability()),
|
||||
loc!(parse_implements_ability()),
|
||||
word1(b',', EType::TEnd),
|
||||
word1(b']', EType::TEnd),
|
||||
HasAbility::SpaceBefore
|
||||
ImplementsAbility::SpaceBefore
|
||||
),
|
||||
HasAbilities::Has
|
||||
ImplementsAbilities::Implements
|
||||
)),
|
||||
EType::TIndentEnd,
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_has_ability<'a>() -> impl Parser<'a, HasAbility<'a>, EType<'a>> {
|
||||
increment_min_indent(record!(HasAbility::HasAbility {
|
||||
fn parse_implements_ability<'a>() -> impl Parser<'a, ImplementsAbility<'a>, EType<'a>> {
|
||||
increment_min_indent(record!(ImplementsAbility::ImplementsAbility {
|
||||
ability: loc!(specialize(EType::TApply, concrete_type())),
|
||||
impls: optional(backtrackable(space0_before_e(
|
||||
loc!(map!(
|
||||
|
@ -543,7 +547,7 @@ fn parse_has_ability<'a>() -> impl Parser<'a, HasAbility<'a>, EType<'a>> {
|
|||
AssignedField::SpaceBefore
|
||||
)
|
||||
),
|
||||
HasImpls::HasImpls
|
||||
AbilityImpls::AbilityImpls
|
||||
)),
|
||||
EType::TIndentEnd
|
||||
)))
|
||||
|
@ -642,12 +646,13 @@ fn expression<'a>(
|
|||
|
||||
// Finally, try to parse a where clause if there is one.
|
||||
// The where clause must be at least as deep as where the type annotation started.
|
||||
match has_clause_chain().parse(arena, state.clone(), min_indent) {
|
||||
Ok((where_progress, (spaces_before, has_chain), state)) => {
|
||||
let region = Region::span_across(&annot.region, &has_chain.last().unwrap().region);
|
||||
match implements_clause_chain().parse(arena, state.clone(), min_indent) {
|
||||
Ok((where_progress, (spaces_before, implements_chain), state)) => {
|
||||
let region =
|
||||
Region::span_across(&annot.region, &implements_chain.last().unwrap().region);
|
||||
let type_annot = if !spaces_before.is_empty() {
|
||||
// We're transforming the spaces_before the '|'
|
||||
// into spaces_after the thing before the '|'
|
||||
// We're transforming the spaces_before the 'where'
|
||||
// into spaces_after the thing before the 'where'
|
||||
let spaced = arena
|
||||
.alloc(annot.value)
|
||||
.with_spaces_after(spaces_before, annot.region);
|
||||
|
@ -655,7 +660,7 @@ fn expression<'a>(
|
|||
} else {
|
||||
&*arena.alloc(annot)
|
||||
};
|
||||
let where_annot = TypeAnnotation::Where(type_annot, has_chain);
|
||||
let where_annot = TypeAnnotation::Where(type_annot, implements_chain);
|
||||
Ok((
|
||||
where_progress.or(progress),
|
||||
Loc::at(region, where_annot),
|
||||
|
@ -724,7 +729,7 @@ fn parse_type_variable<'a>(
|
|||
min_indent,
|
||||
) {
|
||||
Ok((_, name, state)) => {
|
||||
if name == "has" && stop_at_surface_has {
|
||||
if name == crate::keyword::IMPLEMENTS && stop_at_surface_has {
|
||||
Err((NoProgress, EType::TEnd(state.pos())))
|
||||
} else {
|
||||
let answer = TypeAnnotation::BoundVariable(name);
|
||||
|
|
|
@ -117,17 +117,17 @@ pub enum Problem {
|
|||
name: Symbol,
|
||||
variables_region: Region,
|
||||
},
|
||||
HasClauseIsNotAbility {
|
||||
ImplementsClauseIsNotAbility {
|
||||
region: Region,
|
||||
},
|
||||
IllegalHasClause {
|
||||
IllegalImplementsClause {
|
||||
region: Region,
|
||||
},
|
||||
DuplicateHasAbility {
|
||||
DuplicateImplementsAbility {
|
||||
ability: Symbol,
|
||||
region: Region,
|
||||
},
|
||||
AbilityMemberMissingHasClause {
|
||||
AbilityMemberMissingImplementsClause {
|
||||
member: Symbol,
|
||||
ability: Symbol,
|
||||
region: Region,
|
||||
|
@ -135,7 +135,7 @@ pub enum Problem {
|
|||
AbilityMemberMultipleBoundVars {
|
||||
member: Symbol,
|
||||
ability: Symbol,
|
||||
span_has_clauses: Region,
|
||||
span_implements_clauses: Region,
|
||||
bound_var_names: Vec<Lowercase>,
|
||||
},
|
||||
AbilityNotOnToplevel {
|
||||
|
@ -245,10 +245,10 @@ impl Problem {
|
|||
Problem::NestedDatatype { .. } => RuntimeError,
|
||||
Problem::InvalidExtensionType { .. } => RuntimeError,
|
||||
Problem::AbilityHasTypeVariables { .. } => RuntimeError,
|
||||
Problem::HasClauseIsNotAbility { .. } => RuntimeError,
|
||||
Problem::IllegalHasClause { .. } => RuntimeError,
|
||||
Problem::DuplicateHasAbility { .. } => Warning,
|
||||
Problem::AbilityMemberMissingHasClause { .. } => RuntimeError,
|
||||
Problem::ImplementsClauseIsNotAbility { .. } => RuntimeError,
|
||||
Problem::IllegalImplementsClause { .. } => RuntimeError,
|
||||
Problem::DuplicateImplementsAbility { .. } => Warning,
|
||||
Problem::AbilityMemberMissingImplementsClause { .. } => RuntimeError,
|
||||
Problem::AbilityMemberMultipleBoundVars { .. } => RuntimeError,
|
||||
Problem::AbilityNotOnToplevel { .. } => RuntimeError, // Ideally, could be compiled
|
||||
Problem::AbilityUsedAsType(_, _, _) => RuntimeError,
|
||||
|
@ -379,12 +379,12 @@ impl Problem {
|
|||
variables_region: region,
|
||||
..
|
||||
}
|
||||
| Problem::HasClauseIsNotAbility { region }
|
||||
| Problem::IllegalHasClause { region }
|
||||
| Problem::DuplicateHasAbility { region, .. }
|
||||
| Problem::AbilityMemberMissingHasClause { region, .. }
|
||||
| Problem::ImplementsClauseIsNotAbility { region }
|
||||
| Problem::IllegalImplementsClause { region }
|
||||
| Problem::DuplicateImplementsAbility { region, .. }
|
||||
| Problem::AbilityMemberMissingImplementsClause { region, .. }
|
||||
| Problem::AbilityMemberMultipleBoundVars {
|
||||
span_has_clauses: region,
|
||||
span_implements_clauses: region,
|
||||
..
|
||||
}
|
||||
| Problem::AbilityNotOnToplevel { region }
|
||||
|
|
|
@ -741,7 +741,7 @@ trait DerivableVisitor {
|
|||
) {
|
||||
// TODO: currently, just we suppose the presence of a flex var may
|
||||
// include more or less things which we can derive. But, we should
|
||||
// instead recurse here, and add a `t ~ u | u has Decode` constraint as needed.
|
||||
// instead recurse here, and add a `t ~ u where u implements Decode` constraint as needed.
|
||||
stack.push(ext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3146,7 +3146,7 @@ mod solve_expr {
|
|||
Dict.insert
|
||||
"#
|
||||
),
|
||||
"Dict k v, k, v -> Dict k v | k has Hash & Eq",
|
||||
"Dict k v, k, v -> Dict k v where k implements Hash & Eq",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3407,7 +3407,7 @@ mod solve_expr {
|
|||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r#"
|
||||
reconstructPath : Dict position position, position -> List position | position has Hash & Eq
|
||||
reconstructPath : Dict position position, position -> List position where position implements Hash & Eq
|
||||
reconstructPath = \cameFrom, goal ->
|
||||
when Dict.get cameFrom goal is
|
||||
Err KeyNotFound ->
|
||||
|
@ -3419,7 +3419,7 @@ mod solve_expr {
|
|||
reconstructPath
|
||||
"#
|
||||
),
|
||||
"Dict position position, position -> List position | position has Hash & Eq",
|
||||
"Dict position position, position -> List position where position implements Hash & Eq",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3454,7 +3454,7 @@ mod solve_expr {
|
|||
|
||||
Model position : { openSet : Set position }
|
||||
|
||||
cheapestOpen : Model position -> Result position [KeyNotFound] | position has Hash & Eq
|
||||
cheapestOpen : Model position -> Result position [KeyNotFound] where position implements Hash & Eq
|
||||
cheapestOpen = \model ->
|
||||
|
||||
folder = \resSmallestSoFar, position ->
|
||||
|
@ -3469,14 +3469,14 @@ mod solve_expr {
|
|||
Set.walk model.openSet (Ok { position: boom {}, cost: 0.0 }) folder
|
||||
|> Result.map (\x -> x.position)
|
||||
|
||||
astar : Model position -> Result position [KeyNotFound] | position has Hash & Eq
|
||||
astar : Model position -> Result position [KeyNotFound] where position implements Hash & Eq
|
||||
astar = \model -> cheapestOpen model
|
||||
|
||||
main =
|
||||
astar
|
||||
"#
|
||||
),
|
||||
"Model position -> Result position [KeyNotFound] | position has Hash & Eq",
|
||||
"Model position -> Result position [KeyNotFound] where position implements Hash & Eq",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4118,7 +4118,7 @@ mod solve_expr {
|
|||
|
||||
Key k : Num k
|
||||
|
||||
removeHelpEQGT : Key k, RBTree (Key k) v -> RBTree (Key k) v | k has Hash & Eq
|
||||
removeHelpEQGT : Key k, RBTree (Key k) v -> RBTree (Key k) v where k implements Hash & Eq
|
||||
removeHelpEQGT = \targetKey, dict ->
|
||||
when dict is
|
||||
Node color key value left right ->
|
||||
|
@ -4232,7 +4232,7 @@ mod solve_expr {
|
|||
_ ->
|
||||
Empty
|
||||
|
||||
removeHelp : Key k, RBTree (Key k) v -> RBTree (Key k) v | k has Hash & Eq
|
||||
removeHelp : Key k, RBTree (Key k) v -> RBTree (Key k) v where k implements Hash & Eq
|
||||
removeHelp = \targetKey, dict ->
|
||||
when dict is
|
||||
Empty ->
|
||||
|
@ -4320,7 +4320,7 @@ mod solve_expr {
|
|||
|
||||
RBTree k v : [Node NodeColor k v (RBTree k v) (RBTree k v), Empty]
|
||||
|
||||
removeHelp : Num k, RBTree (Num k) v -> RBTree (Num k) v | k has Hash & Eq
|
||||
removeHelp : Num k, RBTree (Num k) v -> RBTree (Num k) v where k implements Hash & Eq
|
||||
removeHelp = \targetKey, dict ->
|
||||
when dict is
|
||||
Empty ->
|
||||
|
@ -4355,7 +4355,7 @@ mod solve_expr {
|
|||
|
||||
removeHelpPrepEQGT : Key k, RBTree (Key k) v, NodeColor, (Key k), v, RBTree (Key k) v, RBTree (Key k) v -> RBTree (Key k) v
|
||||
|
||||
removeHelpEQGT : Key k, RBTree (Key k) v -> RBTree (Key k) v | k has Hash & Eq
|
||||
removeHelpEQGT : Key k, RBTree (Key k) v -> RBTree (Key k) v where k implements Hash & Eq
|
||||
removeHelpEQGT = \targetKey, dict ->
|
||||
when dict is
|
||||
Node color key value left right ->
|
||||
|
|
|
@ -87,7 +87,7 @@ fn derivable_record_ext_flex_var() {
|
|||
fn derivable_record_ext_flex_able_var() {
|
||||
check_derivable(
|
||||
Decoder,
|
||||
v!({ a: v!(STR), }a has Symbol::DECODE_DECODER ),
|
||||
v!({ a: v!(STR), }a implements Symbol::DECODE_DECODER ),
|
||||
DeriveKey::Decoder(FlatDecodableKey::Record(vec!["a".into()])),
|
||||
);
|
||||
}
|
||||
|
@ -106,8 +106,8 @@ fn list() {
|
|||
derive_test(Decoder, v!(Symbol::LIST_LIST v!(STR)), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for List Str
|
||||
# Decoder (List val) fmt | fmt has DecoderFormatting, val has Decoding
|
||||
# List U8, fmt -[[custom(3)]]-> { rest : List U8, result : [Err [TooShort], Ok (List val)] } | fmt has DecoderFormatting, val has Decoding
|
||||
# Decoder (List val) fmt where fmt implements DecoderFormatting, val implements Decoding
|
||||
# List U8, fmt -[[custom(3)]]-> { rest : List U8, result : [Err [TooShort], Ok (List val)] } where fmt implements DecoderFormatting, val implements Decoding
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[custom(3)]]
|
||||
#Derived.decoder_list =
|
||||
|
@ -124,8 +124,8 @@ fn record_2_fields() {
|
|||
derive_test(Decoder, v!({first: v!(STR), second: v!(STR),}), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for { first : Str, second : Str }
|
||||
# Decoder { first : val, second : val1 } fmt | fmt has DecoderFormatting, val has Decoding, val1 has Decoding
|
||||
# List U8, fmt -[[custom(22)]]-> { rest : List U8, result : [Err [TooShort], Ok { first : val, second : val1 }] } | fmt has DecoderFormatting, val has Decoding, val1 has Decoding
|
||||
# Decoder { first : val, second : val1 } fmt where fmt implements DecoderFormatting, val implements Decoding, val1 implements Decoding
|
||||
# List U8, fmt -[[custom(22)]]-> { rest : List U8, result : [Err [TooShort], Ok { first : val, second : val1 }] } where fmt implements DecoderFormatting, val implements Decoding, val1 implements Decoding
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[custom(22)]]
|
||||
#Derived.decoder_{first,second} =
|
||||
|
@ -181,8 +181,8 @@ fn tuple_2_fields() {
|
|||
derive_test(Decoder, v!((v!(STR), v!(U8),)), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for ( Str, U8 )*
|
||||
# Decoder ( val, val1 )* fmt | fmt has DecoderFormatting, val has Decoding, val1 has Decoding
|
||||
# List U8, fmt -[[custom(22)]]-> { rest : List U8, result : [Err [TooShort], Ok ( val, val1 )a] } | fmt has DecoderFormatting, val has Decoding, val1 has Decoding
|
||||
# Decoder ( val, val1 )* fmt where fmt implements DecoderFormatting, val implements Decoding, val1 implements Decoding
|
||||
# List U8, fmt -[[custom(22)]]-> { rest : List U8, result : [Err [TooShort], Ok ( val, val1 )a] } where fmt implements DecoderFormatting, val implements Decoding, val1 implements Decoding
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[custom(22)]]
|
||||
#Derived.decoder_(arity:2) =
|
||||
|
|
|
@ -139,7 +139,7 @@ fn derivable_record_ext_flex_var() {
|
|||
fn derivable_record_ext_flex_able_var() {
|
||||
check_derivable(
|
||||
ToEncoder,
|
||||
v!({ a: v!(STR), }a has Symbol::ENCODE_TO_ENCODER),
|
||||
v!({ a: v!(STR), }a implements Symbol::ENCODE_TO_ENCODER),
|
||||
DeriveKey::ToEncoder(FlatEncodableKey::Record(vec!["a".into()])),
|
||||
);
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ fn derivable_tag_ext_flex_var() {
|
|||
fn derivable_tag_ext_flex_able_var() {
|
||||
check_derivable(
|
||||
ToEncoder,
|
||||
v!([ A v!(STR) ]a has Symbol::ENCODE_TO_ENCODER),
|
||||
v!([ A v!(STR) ]a implements Symbol::ENCODE_TO_ENCODER),
|
||||
DeriveKey::ToEncoder(FlatEncodableKey::TagUnion(vec![("A".into(), 1)])),
|
||||
);
|
||||
}
|
||||
|
@ -188,8 +188,8 @@ fn empty_record() {
|
|||
derive_test(ToEncoder, v!(EMPTY_RECORD), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for {}
|
||||
# {} -[[toEncoder_{}(0)]]-> Encoder fmt | fmt has EncoderFormatting
|
||||
# {} -[[toEncoder_{}(0)]]-> (List U8, fmt -[[custom(2) {}]]-> List U8) | fmt has EncoderFormatting
|
||||
# {} -[[toEncoder_{}(0)]]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
# {} -[[toEncoder_{}(0)]]-> (List U8, fmt -[[custom(2) {}]]-> List U8) where fmt implements EncoderFormatting
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[toEncoder_{}(0)]]
|
||||
# @<2>: [[custom(2) {}]]
|
||||
|
@ -208,8 +208,8 @@ fn zero_field_record() {
|
|||
derive_test(ToEncoder, v!({}), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for {}
|
||||
# {} -[[toEncoder_{}(0)]]-> Encoder fmt | fmt has EncoderFormatting
|
||||
# {} -[[toEncoder_{}(0)]]-> (List U8, fmt -[[custom(2) {}]]-> List U8) | fmt has EncoderFormatting
|
||||
# {} -[[toEncoder_{}(0)]]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
# {} -[[toEncoder_{}(0)]]-> (List U8, fmt -[[custom(2) {}]]-> List U8) where fmt implements EncoderFormatting
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[toEncoder_{}(0)]]
|
||||
# @<2>: [[custom(2) {}]]
|
||||
|
@ -228,11 +228,11 @@ fn one_field_record() {
|
|||
derive_test(ToEncoder, v!({ a: v!(U8), }), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for { a : U8 }
|
||||
# { a : val } -[[toEncoder_{a}(0)]]-> Encoder fmt | fmt has EncoderFormatting, val has Encoding
|
||||
# { a : val } -[[toEncoder_{a}(0)]]-> (List U8, fmt -[[custom(2) { a : val }]]-> List U8) | fmt has EncoderFormatting, val has Encoding
|
||||
# { a : val } -[[toEncoder_{a}(0)]]-> Encoder fmt where fmt implements EncoderFormatting, val implements Encoding
|
||||
# { a : val } -[[toEncoder_{a}(0)]]-> (List U8, fmt -[[custom(2) { a : val }]]-> List U8) where fmt implements EncoderFormatting, val implements Encoding
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[toEncoder_{a}(0)]]
|
||||
# @<2>: [[custom(2) { a : val }]] | val has Encoding
|
||||
# @<2>: [[custom(2) { a : val }]] where val implements Encoding
|
||||
#Derived.toEncoder_{a} =
|
||||
\#Derived.rcd ->
|
||||
custom
|
||||
|
@ -251,11 +251,11 @@ fn two_field_record() {
|
|||
derive_test(ToEncoder, v!({ a: v!(U8), b: v!(STR), }), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for { a : U8, b : Str }
|
||||
# { a : val, b : val1 } -[[toEncoder_{a,b}(0)]]-> Encoder fmt | fmt has EncoderFormatting, val has Encoding, val1 has Encoding
|
||||
# { a : val, b : val1 } -[[toEncoder_{a,b}(0)]]-> (List U8, fmt -[[custom(2) { a : val, b : val1 }]]-> List U8) | fmt has EncoderFormatting, val has Encoding, val1 has Encoding
|
||||
# { a : val, b : val1 } -[[toEncoder_{a,b}(0)]]-> Encoder fmt where fmt implements EncoderFormatting, val implements Encoding, val1 implements Encoding
|
||||
# { a : val, b : val1 } -[[toEncoder_{a,b}(0)]]-> (List U8, fmt -[[custom(2) { a : val, b : val1 }]]-> List U8) where fmt implements EncoderFormatting, val implements Encoding, val1 implements Encoding
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[toEncoder_{a,b}(0)]]
|
||||
# @<2>: [[custom(2) { a : val, b : val1 }]] | val has Encoding, val1 has Encoding
|
||||
# @<2>: [[custom(2) { a : val, b : val1 }]] where val implements Encoding, val1 implements Encoding
|
||||
#Derived.toEncoder_{a,b} =
|
||||
\#Derived.rcd ->
|
||||
custom
|
||||
|
@ -278,11 +278,11 @@ fn two_field_tuple() {
|
|||
derive_test(ToEncoder, v!((v!(U8), v!(STR),)), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for ( U8, Str )*
|
||||
# ( val, val1 )* -[[toEncoder_(arity:2)(0)]]-> Encoder fmt | fmt has EncoderFormatting, val has Encoding, val1 has Encoding
|
||||
# ( val, val1 )a -[[toEncoder_(arity:2)(0)]]-> (List U8, fmt -[[custom(2) ( val, val1 )a]]-> List U8) | fmt has EncoderFormatting, val has Encoding, val1 has Encoding
|
||||
# ( val, val1 )* -[[toEncoder_(arity:2)(0)]]-> Encoder fmt where fmt implements EncoderFormatting, val implements Encoding, val1 implements Encoding
|
||||
# ( val, val1 )a -[[toEncoder_(arity:2)(0)]]-> (List U8, fmt -[[custom(2) ( val, val1 )a]]-> List U8) where fmt implements EncoderFormatting, val implements Encoding, val1 implements Encoding
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[toEncoder_(arity:2)(0)]]
|
||||
# @<2>: [[custom(2) ( val, val1 )*]] | val has Encoding, val1 has Encoding
|
||||
# @<2>: [[custom(2) ( val, val1 )*]] where val implements Encoding, val1 implements Encoding
|
||||
#Derived.toEncoder_(arity:2) =
|
||||
\#Derived.tup ->
|
||||
custom
|
||||
|
@ -314,8 +314,8 @@ fn tag_one_label_zero_args() {
|
|||
derive_test(ToEncoder, v!([A]), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for [A]
|
||||
# [A] -[[toEncoder_[A 0](0)]]-> Encoder fmt | fmt has EncoderFormatting
|
||||
# [A] -[[toEncoder_[A 0](0)]]-> (List U8, fmt -[[custom(2) [A]]]-> List U8) | fmt has EncoderFormatting
|
||||
# [A] -[[toEncoder_[A 0](0)]]-> Encoder fmt where fmt implements EncoderFormatting
|
||||
# [A] -[[toEncoder_[A 0](0)]]-> (List U8, fmt -[[custom(2) [A]]]-> List U8) where fmt implements EncoderFormatting
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[toEncoder_[A 0](0)]]
|
||||
# @<2>: [[custom(2) [A]]]
|
||||
|
@ -338,11 +338,11 @@ fn tag_one_label_two_args() {
|
|||
derive_test(ToEncoder, v!([A v!(U8) v!(STR)]), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for [A U8 Str]
|
||||
# [A val val1] -[[toEncoder_[A 2](0)]]-> Encoder fmt | fmt has EncoderFormatting, val has Encoding, val1 has Encoding
|
||||
# [A val val1] -[[toEncoder_[A 2](0)]]-> (List U8, fmt -[[custom(4) [A val val1]]]-> List U8) | fmt has EncoderFormatting, val has Encoding, val1 has Encoding
|
||||
# [A val val1] -[[toEncoder_[A 2](0)]]-> Encoder fmt where fmt implements EncoderFormatting, val implements Encoding, val1 implements Encoding
|
||||
# [A val val1] -[[toEncoder_[A 2](0)]]-> (List U8, fmt -[[custom(4) [A val val1]]]-> List U8) where fmt implements EncoderFormatting, val implements Encoding, val1 implements Encoding
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[toEncoder_[A 2](0)]]
|
||||
# @<2>: [[custom(4) [A val val1]]] | val has Encoding, val1 has Encoding
|
||||
# @<2>: [[custom(4) [A val val1]]] where val implements Encoding, val1 implements Encoding
|
||||
#Derived.toEncoder_[A 2] =
|
||||
\#Derived.tag ->
|
||||
custom
|
||||
|
@ -366,11 +366,11 @@ fn tag_two_labels() {
|
|||
|golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for [A U8 Str U16, B Str]
|
||||
# [A val val1 val1, B val1] -[[toEncoder_[A 3,B 1](0)]]-> Encoder fmt | fmt has EncoderFormatting, val has Encoding, val1 has Encoding
|
||||
# [A val val1 val1, B val1] -[[toEncoder_[A 3,B 1](0)]]-> (List U8, fmt -[[custom(6) [A val val1 val1, B val1]]]-> List U8) | fmt has EncoderFormatting, val has Encoding, val1 has Encoding
|
||||
# [A val val1 val1, B val1] -[[toEncoder_[A 3,B 1](0)]]-> Encoder fmt where fmt implements EncoderFormatting, val implements Encoding, val1 implements Encoding
|
||||
# [A val val1 val1, B val1] -[[toEncoder_[A 3,B 1](0)]]-> (List U8, fmt -[[custom(6) [A val val1 val1, B val1]]]-> List U8) where fmt implements EncoderFormatting, val implements Encoding, val1 implements Encoding
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[toEncoder_[A 3,B 1](0)]]
|
||||
# @<2>: [[custom(6) [A val val1 val1, B val1]]] | val has Encoding, val1 has Encoding
|
||||
# @<2>: [[custom(6) [A val val1 val1, B val1]]] where val implements Encoding, val1 implements Encoding
|
||||
#Derived.toEncoder_[A 3,B 1] =
|
||||
\#Derived.tag ->
|
||||
custom
|
||||
|
@ -402,11 +402,11 @@ fn recursive_tag_union() {
|
|||
|golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for [Cons U8 $rec, Nil] as $rec
|
||||
# [Cons val val1, Nil] -[[toEncoder_[Cons 2,Nil 0](0)]]-> Encoder fmt | fmt has EncoderFormatting, val has Encoding, val1 has Encoding
|
||||
# [Cons val val1, Nil] -[[toEncoder_[Cons 2,Nil 0](0)]]-> (List U8, fmt -[[custom(4) [Cons val val1, Nil]]]-> List U8) | fmt has EncoderFormatting, val has Encoding, val1 has Encoding
|
||||
# [Cons val val1, Nil] -[[toEncoder_[Cons 2,Nil 0](0)]]-> Encoder fmt where fmt implements EncoderFormatting, val implements Encoding, val1 implements Encoding
|
||||
# [Cons val val1, Nil] -[[toEncoder_[Cons 2,Nil 0](0)]]-> (List U8, fmt -[[custom(4) [Cons val val1, Nil]]]-> List U8) where fmt implements EncoderFormatting, val implements Encoding, val1 implements Encoding
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[toEncoder_[Cons 2,Nil 0](0)]]
|
||||
# @<2>: [[custom(4) [Cons val val1, Nil]]] | val has Encoding, val1 has Encoding
|
||||
# @<2>: [[custom(4) [Cons val val1, Nil]]] where val implements Encoding, val1 implements Encoding
|
||||
#Derived.toEncoder_[Cons 2,Nil 0] =
|
||||
\#Derived.tag ->
|
||||
custom
|
||||
|
@ -429,11 +429,11 @@ fn list() {
|
|||
derive_test(ToEncoder, v!(Symbol::LIST_LIST v!(STR)), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for List Str
|
||||
# List val -[[toEncoder_list(0)]]-> Encoder fmt | fmt has EncoderFormatting, val has Encoding
|
||||
# List val -[[toEncoder_list(0)]]-> (List U8, fmt -[[custom(4) (List val)]]-> List U8) | fmt has EncoderFormatting, val has Encoding
|
||||
# List val -[[toEncoder_list(0)]]-> Encoder fmt where fmt implements EncoderFormatting, val implements Encoding
|
||||
# List val -[[toEncoder_list(0)]]-> (List U8, fmt -[[custom(4) (List val)]]-> List U8) where fmt implements EncoderFormatting, val implements Encoding
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[toEncoder_list(0)]]
|
||||
# @<2>: [[custom(4) (List val)]] | val has Encoding
|
||||
# @<2>: [[custom(4) (List val)]] where val implements Encoding
|
||||
#Derived.toEncoder_list =
|
||||
\#Derived.lst ->
|
||||
custom
|
||||
|
|
|
@ -102,7 +102,7 @@ fn derivable_record_ext_flex_var() {
|
|||
fn derivable_record_ext_flex_able_var() {
|
||||
check_derivable(
|
||||
Hash,
|
||||
v!({ a: v!(STR), }a has Symbol::DECODE_DECODER ),
|
||||
v!({ a: v!(STR), }a implements Symbol::DECODE_DECODER ),
|
||||
DeriveKey::Hash(FlatHashKey::Record(vec!["a".into()])),
|
||||
);
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ fn derivable_tag_ext_flex_var() {
|
|||
fn derivable_tag_ext_flex_able_var() {
|
||||
check_derivable(
|
||||
Hash,
|
||||
v!([ A v!(STR) ]a has Symbol::ENCODE_TO_ENCODER),
|
||||
v!([ A v!(STR) ]a implements Symbol::ENCODE_TO_ENCODER),
|
||||
DeriveKey::Hash(FlatHashKey::TagUnion(vec![("A".into(), 1)])),
|
||||
);
|
||||
}
|
||||
|
@ -151,8 +151,8 @@ fn empty_record() {
|
|||
derive_test(Hash, v!(EMPTY_RECORD), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for {}
|
||||
# hasher, {} -[[hash_{}(0)]]-> hasher | hasher has Hasher
|
||||
# hasher, {} -[[hash_{}(0)]]-> hasher | hasher has Hasher
|
||||
# hasher, {} -[[hash_{}(0)]]-> hasher where hasher implements Hasher
|
||||
# hasher, {} -[[hash_{}(0)]]-> hasher where hasher implements Hasher
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[hash_{}(0)]]
|
||||
#Derived.hash_{} = \#Derived.hasher, #Derived.rcd -> #Derived.hasher
|
||||
|
@ -166,8 +166,8 @@ fn zero_field_record() {
|
|||
derive_test(Hash, v!({}), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for {}
|
||||
# hasher, {} -[[hash_{}(0)]]-> hasher | hasher has Hasher
|
||||
# hasher, {} -[[hash_{}(0)]]-> hasher | hasher has Hasher
|
||||
# hasher, {} -[[hash_{}(0)]]-> hasher where hasher implements Hasher
|
||||
# hasher, {} -[[hash_{}(0)]]-> hasher where hasher implements Hasher
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[hash_{}(0)]]
|
||||
#Derived.hash_{} = \#Derived.hasher, #Derived.rcd -> #Derived.hasher
|
||||
|
@ -181,8 +181,8 @@ fn one_field_record() {
|
|||
derive_test(Hash, v!({ a: v!(U8), }), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for { a : U8 }
|
||||
# hasher, { a : a } -[[hash_{a}(0)]]-> hasher | a has Hash, hasher has Hasher
|
||||
# hasher, { a : a } -[[hash_{a}(0)]]-> hasher | a has Hash, hasher has Hasher
|
||||
# hasher, { a : a } -[[hash_{a}(0)]]-> hasher where a implements Hash, hasher implements Hasher
|
||||
# hasher, { a : a } -[[hash_{a}(0)]]-> hasher where a implements Hash, hasher implements Hasher
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[hash_{a}(0)]]
|
||||
#Derived.hash_{a} =
|
||||
|
@ -197,8 +197,8 @@ fn two_field_record() {
|
|||
derive_test(Hash, v!({ a: v!(U8), b: v!(STR), }), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for { a : U8, b : Str }
|
||||
# hasher, { a : a, b : a1 } -[[hash_{a,b}(0)]]-> hasher | a has Hash, a1 has Hash, hasher has Hasher
|
||||
# hasher, { a : a, b : a1 } -[[hash_{a,b}(0)]]-> hasher | a has Hash, a1 has Hash, hasher has Hasher
|
||||
# hasher, { a : a, b : a1 } -[[hash_{a,b}(0)]]-> hasher where a implements Hash, a1 implements Hash, hasher implements Hasher
|
||||
# hasher, { a : a, b : a1 } -[[hash_{a,b}(0)]]-> hasher where a implements Hash, a1 implements Hash, hasher implements Hasher
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[hash_{a,b}(0)]]
|
||||
#Derived.hash_{a,b} =
|
||||
|
@ -214,8 +214,8 @@ fn two_element_tuple() {
|
|||
derive_test(Hash, v!((v!(U8), v!(STR),)), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for ( U8, Str )*
|
||||
# hasher, ( a, a1 )* -[[hash_(arity:2)(0)]]-> hasher | a has Hash, a1 has Hash, hasher has Hasher
|
||||
# hasher, ( a, a1 )* -[[hash_(arity:2)(0)]]-> hasher | a has Hash, a1 has Hash, hasher has Hasher
|
||||
# hasher, ( a, a1 )* -[[hash_(arity:2)(0)]]-> hasher where a implements Hash, a1 implements Hash, hasher implements Hasher
|
||||
# hasher, ( a, a1 )* -[[hash_(arity:2)(0)]]-> hasher where a implements Hash, a1 implements Hash, hasher implements Hasher
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[hash_(arity:2)(0)]]
|
||||
#Derived.hash_(arity:2) =
|
||||
|
@ -231,8 +231,8 @@ fn tag_one_label_no_payloads() {
|
|||
derive_test(Hash, v!([A]), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for [A]
|
||||
# hasher, [A] -[[hash_[A 0](0)]]-> hasher | hasher has Hasher
|
||||
# hasher, [A] -[[hash_[A 0](0)]]-> hasher | hasher has Hasher
|
||||
# hasher, [A] -[[hash_[A 0](0)]]-> hasher where hasher implements Hasher
|
||||
# hasher, [A] -[[hash_[A 0](0)]]-> hasher where hasher implements Hasher
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[hash_[A 0](0)]]
|
||||
#Derived.hash_[A 0] = \#Derived.hasher, A -> #Derived.hasher
|
||||
|
@ -246,8 +246,8 @@ fn tag_one_label_newtype() {
|
|||
derive_test(Hash, v!([A v!(U8) v!(STR)]), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for [A U8 Str]
|
||||
# hasher, [A a a1] -[[hash_[A 2](0)]]-> hasher | a has Hash, a1 has Hash, hasher has Hasher
|
||||
# hasher, [A a a1] -[[hash_[A 2](0)]]-> hasher | a has Hash, a1 has Hash, hasher has Hasher
|
||||
# hasher, [A a a1] -[[hash_[A 2](0)]]-> hasher where a implements Hash, a1 implements Hash, hasher implements Hasher
|
||||
# hasher, [A a a1] -[[hash_[A 2](0)]]-> hasher where a implements Hash, a1 implements Hash, hasher implements Hasher
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[hash_[A 2](0)]]
|
||||
#Derived.hash_[A 2] =
|
||||
|
@ -263,8 +263,8 @@ fn tag_two_labels() {
|
|||
derive_test(Hash, v!([A v!(U8) v!(STR) v!(U16), B v!(STR)]), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for [A U8 Str U16, B Str]
|
||||
# a, [A a1 a2 a3, B a3] -[[hash_[A 3,B 1](0)]]-> a | a has Hasher, a1 has Hash, a2 has Hash, a3 has Hash
|
||||
# a, [A a1 a2 a3, B a3] -[[hash_[A 3,B 1](0)]]-> a | a has Hasher, a1 has Hash, a2 has Hash, a3 has Hash
|
||||
# a, [A a1 a2 a3, B a3] -[[hash_[A 3,B 1](0)]]-> a where a implements Hasher, a1 implements Hash, a2 implements Hash, a3 implements Hash
|
||||
# a, [A a1 a2 a3, B a3] -[[hash_[A 3,B 1](0)]]-> a where a implements Hasher, a1 implements Hash, a2 implements Hash, a3 implements Hash
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[hash_[A 3,B 1](0)]]
|
||||
#Derived.hash_[A 3,B 1] =
|
||||
|
@ -285,8 +285,8 @@ fn tag_two_labels_no_payloads() {
|
|||
derive_test(Hash, v!([A, B]), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for [A, B]
|
||||
# a, [A, B] -[[hash_[A 0,B 0](0)]]-> a | a has Hasher
|
||||
# a, [A, B] -[[hash_[A 0,B 0](0)]]-> a | a has Hasher
|
||||
# a, [A, B] -[[hash_[A 0,B 0](0)]]-> a where a implements Hasher
|
||||
# a, [A, B] -[[hash_[A 0,B 0](0)]]-> a where a implements Hasher
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[hash_[A 0,B 0](0)]]
|
||||
#Derived.hash_[A 0,B 0] =
|
||||
|
@ -304,8 +304,8 @@ fn recursive_tag_union() {
|
|||
derive_test(Hash, v!([Nil, Cons v!(U8) v!(^lst) ] as lst), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for [Cons U8 $rec, Nil] as $rec
|
||||
# a, [Cons a1 a2, Nil] -[[hash_[Cons 2,Nil 0](0)]]-> a | a has Hasher, a1 has Hash, a2 has Hash
|
||||
# a, [Cons a1 a2, Nil] -[[hash_[Cons 2,Nil 0](0)]]-> a | a has Hasher, a1 has Hash, a2 has Hash
|
||||
# a, [Cons a1 a2, Nil] -[[hash_[Cons 2,Nil 0](0)]]-> a where a implements Hasher, a1 implements Hash, a2 implements Hash
|
||||
# a, [Cons a1 a2, Nil] -[[hash_[Cons 2,Nil 0](0)]]-> a where a implements Hasher, a1 implements Hash, a2 implements Hash
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[hash_[Cons 2,Nil 0](0)]]
|
||||
#Derived.hash_[Cons 2,Nil 0] =
|
||||
|
|
|
@ -187,7 +187,7 @@ macro_rules! v {
|
|||
use roc_types::subs::{Subs, Content};
|
||||
|subs: &mut Subs| { roc_derive::synth_var(subs, Content::FlexVar(None)) }
|
||||
}};
|
||||
($name:ident has $ability:path) => {{
|
||||
($name:ident implements $ability:path) => {{
|
||||
use roc_types::subs::{Subs, SubsIndex, SubsSlice, Content};
|
||||
|subs: &mut Subs| {
|
||||
let name_index =
|
||||
|
|
|
@ -62,8 +62,13 @@ fn roc_function<'a, 'b>(
|
|||
};
|
||||
|
||||
let context = inkwell::context::Context::create();
|
||||
let (main_fn_name, errors, lib) =
|
||||
helpers::llvm::helper(arena, config, source, arena.alloc(context));
|
||||
let (main_fn_name, errors, lib) = helpers::llvm::helper(
|
||||
arena,
|
||||
config,
|
||||
source,
|
||||
arena.alloc(context),
|
||||
roc_load::FunctionKind::LambdaSet,
|
||||
);
|
||||
|
||||
assert!(errors.is_empty(), "Encountered errors:\n{errors}");
|
||||
|
||||
|
|
|
@ -91,8 +91,13 @@ fn roc_function<'a>(
|
|||
};
|
||||
|
||||
let context = inkwell::context::Context::create();
|
||||
let (main_fn_name, errors, lib) =
|
||||
helpers::llvm::helper(arena, config, source, arena.alloc(context));
|
||||
let (main_fn_name, errors, lib) = helpers::llvm::helper(
|
||||
arena,
|
||||
config,
|
||||
source,
|
||||
arena.alloc(context),
|
||||
roc_load::FunctionKind::LambdaSet,
|
||||
);
|
||||
|
||||
assert!(errors.is_empty(), "Encountered errors:\n{errors}");
|
||||
|
||||
|
|
|
@ -22,10 +22,10 @@ fn hash_specialization() {
|
|||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
MHash has
|
||||
hash : a -> U64 | a has MHash
|
||||
MHash implements
|
||||
hash : a -> U64 where a implements MHash
|
||||
|
||||
Id := U64 has [MHash {hash}]
|
||||
Id := U64 implements [MHash {hash}]
|
||||
|
||||
hash = \@Id n -> n
|
||||
|
||||
|
@ -45,14 +45,14 @@ fn hash_specialization_multiple_add() {
|
|||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
MHash has
|
||||
hash : a -> U64 | a has MHash
|
||||
MHash implements
|
||||
hash : a -> U64 where a implements MHash
|
||||
|
||||
Id := U64 has [ MHash {hash: hashId} ]
|
||||
Id := U64 implements [ MHash {hash: hashId} ]
|
||||
|
||||
hashId = \@Id n -> n
|
||||
|
||||
One := {} has [ MHash {hash: hashOne} ]
|
||||
One := {} implements [ MHash {hash: hashOne} ]
|
||||
|
||||
hashOne = \@One _ -> 1
|
||||
|
||||
|
@ -72,10 +72,10 @@ fn alias_member_specialization() {
|
|||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
MHash has
|
||||
hash : a -> U64 | a has MHash
|
||||
MHash implements
|
||||
hash : a -> U64 where a implements MHash
|
||||
|
||||
Id := U64 has [MHash {hash}]
|
||||
Id := U64 implements [MHash {hash}]
|
||||
|
||||
hash = \@Id n -> n
|
||||
|
||||
|
@ -97,13 +97,13 @@ fn ability_constrained_in_non_member_usage() {
|
|||
r#"
|
||||
app "test" provides [result] to "./platform"
|
||||
|
||||
MHash has
|
||||
hash : a -> U64 | a has MHash
|
||||
MHash implements
|
||||
hash : a -> U64 where a implements MHash
|
||||
|
||||
mulMHashes : a, a -> U64 | a has MHash
|
||||
mulMHashes : a, a -> U64 where a implements MHash
|
||||
mulMHashes = \x, y -> hash x * hash y
|
||||
|
||||
Id := U64 has [MHash {hash}]
|
||||
Id := U64 implements [MHash {hash}]
|
||||
hash = \@Id n -> n
|
||||
|
||||
result = mulMHashes (@Id 5) (@Id 7)
|
||||
|
@ -122,12 +122,12 @@ fn ability_constrained_in_non_member_usage_inferred() {
|
|||
r#"
|
||||
app "test" provides [result] to "./platform"
|
||||
|
||||
MHash has
|
||||
hash : a -> U64 | a has MHash
|
||||
MHash implements
|
||||
hash : a -> U64 where a implements MHash
|
||||
|
||||
mulMHashes = \x, y -> hash x * hash y
|
||||
|
||||
Id := U64 has [MHash {hash}]
|
||||
Id := U64 implements [MHash {hash}]
|
||||
hash = \@Id n -> n
|
||||
|
||||
result = mulMHashes (@Id 5) (@Id 7)
|
||||
|
@ -146,16 +146,16 @@ fn ability_constrained_in_non_member_multiple_specializations() {
|
|||
r#"
|
||||
app "test" provides [result] to "./platform"
|
||||
|
||||
MHash has
|
||||
hash : a -> U64 | a has MHash
|
||||
MHash implements
|
||||
hash : a -> U64 where a implements MHash
|
||||
|
||||
mulMHashes : a, b -> U64 | a has MHash, b has MHash
|
||||
mulMHashes : a, b -> U64 where a implements MHash, b implements MHash
|
||||
mulMHashes = \x, y -> hash x * hash y
|
||||
|
||||
Id := U64 has [MHash { hash: hashId }]
|
||||
Id := U64 implements [MHash { hash: hashId }]
|
||||
hashId = \@Id n -> n
|
||||
|
||||
Three := {} has [MHash { hash: hashThree }]
|
||||
Three := {} implements [MHash { hash: hashThree }]
|
||||
hashThree = \@Three _ -> 3
|
||||
|
||||
result = mulMHashes (@Id 100) (@Three {})
|
||||
|
@ -174,15 +174,15 @@ fn ability_constrained_in_non_member_multiple_specializations_inferred() {
|
|||
r#"
|
||||
app "test" provides [result] to "./platform"
|
||||
|
||||
MHash has
|
||||
hash : a -> U64 | a has MHash
|
||||
MHash implements
|
||||
hash : a -> U64 where a implements MHash
|
||||
|
||||
mulMHashes = \x, y -> hash x * hash y
|
||||
|
||||
Id := U64 has [MHash { hash: hashId }]
|
||||
Id := U64 implements [MHash { hash: hashId }]
|
||||
hashId = \@Id n -> n
|
||||
|
||||
Three := {} has [MHash { hash: hashThree }]
|
||||
Three := {} implements [MHash { hash: hashThree }]
|
||||
hashThree = \@Three _ -> 3
|
||||
|
||||
result = mulMHashes (@Id 100) (@Three {})
|
||||
|
@ -201,16 +201,16 @@ fn ability_used_as_type_still_compiles() {
|
|||
r#"
|
||||
app "test" provides [result] to "./platform"
|
||||
|
||||
MHash has
|
||||
hash : a -> U64 | a has MHash
|
||||
MHash implements
|
||||
hash : a -> U64 where a implements MHash
|
||||
|
||||
mulMHashes : MHash, MHash -> U64
|
||||
mulMHashes = \x, y -> hash x * hash y
|
||||
|
||||
Id := U64 has [MHash { hash: hashId }]
|
||||
Id := U64 implements [MHash { hash: hashId }]
|
||||
hashId = \@Id n -> n
|
||||
|
||||
Three := {} has [MHash { hash: hashThree }]
|
||||
Three := {} implements [MHash { hash: hashThree }]
|
||||
hashThree = \@Three _ -> 3
|
||||
|
||||
result = mulMHashes (@Id 100) (@Three {})
|
||||
|
@ -229,15 +229,15 @@ fn bounds_to_multiple_abilities() {
|
|||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
Idempot has idempot : a -> a | a has Idempot
|
||||
Consume has consume : a -> Str | a has Consume
|
||||
Idempot implements idempot : a -> a where a implements Idempot
|
||||
Consume implements consume : a -> Str where a implements Consume
|
||||
|
||||
Hello := Str has [Idempot { idempot: idempotHello }, Consume { consume: consumeHello }]
|
||||
Hello := Str implements [Idempot { idempot: idempotHello }, Consume { consume: consumeHello }]
|
||||
|
||||
idempotHello = \@Hello msg -> @Hello msg
|
||||
consumeHello = \@Hello msg -> msg
|
||||
|
||||
lifecycle : a -> Str | a has Idempot & Consume
|
||||
lifecycle : a -> Str where a implements Idempot & Consume
|
||||
lifecycle = \x -> idempot x |> consume
|
||||
|
||||
main = lifecycle (@Hello "hello world")
|
||||
|
@ -256,26 +256,26 @@ fn encode() {
|
|||
r#"
|
||||
app "test" provides [myU8Bytes] to "./platform"
|
||||
|
||||
MEncoder fmt := List U8, fmt -> List U8 | fmt has Format
|
||||
MEncoder fmt := List U8, fmt -> List U8 where fmt implements Format
|
||||
|
||||
MEncoding has
|
||||
toEncoder : val -> MEncoder fmt | val has MEncoding, fmt has Format
|
||||
MEncoding implements
|
||||
toEncoder : val -> MEncoder fmt where val implements MEncoding, fmt implements Format
|
||||
|
||||
Format has
|
||||
u8 : U8 -> MEncoder fmt | fmt has Format
|
||||
Format implements
|
||||
u8 : U8 -> MEncoder fmt where fmt implements Format
|
||||
|
||||
appendWith : List U8, MEncoder fmt, fmt -> List U8 | fmt has Format
|
||||
appendWith : List U8, MEncoder fmt, fmt -> List U8 where fmt implements Format
|
||||
appendWith = \lst, (@MEncoder doFormat), fmt -> doFormat lst fmt
|
||||
|
||||
toBytes : val, fmt -> List U8 | val has MEncoding, fmt has Format
|
||||
toBytes : val, fmt -> List U8 where val implements MEncoding, fmt implements Format
|
||||
toBytes = \val, fmt -> appendWith [] (toEncoder val) fmt
|
||||
|
||||
|
||||
Linear := {} has [Format {u8}]
|
||||
Linear := {} implements [Format {u8}]
|
||||
|
||||
u8 = \n -> @MEncoder (\lst, @Linear {} -> List.append lst n)
|
||||
|
||||
Rgba := { r : U8, g : U8, b : U8, a : U8 } has [MEncoding {toEncoder}]
|
||||
Rgba := { r : U8, g : U8, b : U8, a : U8 } implements [MEncoding {toEncoder}]
|
||||
|
||||
toEncoder = \@Rgba {r, g, b, a} ->
|
||||
@MEncoder \lst, fmt -> lst
|
||||
|
@ -303,19 +303,19 @@ fn decode() {
|
|||
|
||||
MDecodeError : [TooShort, Leftover (List U8)]
|
||||
|
||||
MDecoder val fmt := List U8, fmt -> { result: Result val MDecodeError, rest: List U8 } | fmt has MDecoderFormatting
|
||||
MDecoder val fmt := List U8, fmt -> { result: Result val MDecodeError, rest: List U8 } where fmt implements MDecoderFormatting
|
||||
|
||||
MDecoding has
|
||||
decoder : MDecoder val fmt | val has MDecoding, fmt has MDecoderFormatting
|
||||
MDecoding implements
|
||||
decoder : MDecoder val fmt where val implements MDecoding, fmt implements MDecoderFormatting
|
||||
|
||||
MDecoderFormatting has
|
||||
u8 : MDecoder U8 fmt | fmt has MDecoderFormatting
|
||||
MDecoderFormatting implements
|
||||
u8 : MDecoder U8 fmt where fmt implements MDecoderFormatting
|
||||
|
||||
decodeWith : List U8, MDecoder val fmt, fmt -> { result: Result val MDecodeError, rest: List U8 } | fmt has MDecoderFormatting
|
||||
decodeWith : List U8, MDecoder val fmt, fmt -> { result: Result val MDecodeError, rest: List U8 } where fmt implements MDecoderFormatting
|
||||
decodeWith = \lst, (@MDecoder doDecode), fmt -> doDecode lst fmt
|
||||
|
||||
fromBytes : List U8, fmt -> Result val MDecodeError
|
||||
| fmt has MDecoderFormatting, val has MDecoding
|
||||
where fmt implements MDecoderFormatting, val implements MDecoding
|
||||
fromBytes = \lst, fmt ->
|
||||
when decodeWith lst decoder fmt is
|
||||
{ result, rest } ->
|
||||
|
@ -325,14 +325,14 @@ fn decode() {
|
|||
else Err (Leftover rest)
|
||||
|
||||
|
||||
Linear := {} has [MDecoderFormatting {u8}]
|
||||
Linear := {} implements [MDecoderFormatting {u8}]
|
||||
|
||||
u8 = @MDecoder \lst, @Linear {} ->
|
||||
when List.first lst is
|
||||
Ok n -> { result: Ok n, rest: List.dropFirst lst }
|
||||
Err _ -> { result: Err TooShort, rest: [] }
|
||||
|
||||
MyU8 := U8 has [MDecoding {decoder}]
|
||||
MyU8 := U8 implements [MDecoding {decoder}]
|
||||
|
||||
# impl MDecoding for MyU8
|
||||
decoder = @MDecoder \lst, fmt ->
|
||||
|
@ -360,7 +360,7 @@ fn encode_use_stdlib() {
|
|||
imports [Encode, TotallyNotJson]
|
||||
provides [main] to "./platform"
|
||||
|
||||
HelloWorld := {} has [Encoding {toEncoder}]
|
||||
HelloWorld := {} implements [Encoding {toEncoder}]
|
||||
toEncoder = \@HelloWorld {} ->
|
||||
Encode.custom \bytes, fmt ->
|
||||
bytes
|
||||
|
@ -388,7 +388,7 @@ fn encode_use_stdlib_without_wrapping_custom() {
|
|||
imports [Encode, TotallyNotJson]
|
||||
provides [main] to "./platform"
|
||||
|
||||
HelloWorld := {} has [Encoding {toEncoder}]
|
||||
HelloWorld := {} implements [Encoding {toEncoder}]
|
||||
toEncoder = \@HelloWorld {} -> Encode.string "Hello, World!\n"
|
||||
|
||||
main =
|
||||
|
@ -414,7 +414,7 @@ fn encode_derive_to_encoder_for_opaque() {
|
|||
imports [TotallyNotJson]
|
||||
provides [main] to "./platform"
|
||||
|
||||
HelloWorld := { a: Str } has [Encoding]
|
||||
HelloWorld := { a: Str } implements [Encoding]
|
||||
|
||||
main =
|
||||
result = Str.fromUtf8 (Encode.toBytes (@HelloWorld { a: "Hello, World!" }) TotallyNotJson.json)
|
||||
|
@ -438,7 +438,7 @@ fn to_encoder_encode_custom_has_capture() {
|
|||
imports [Encode, TotallyNotJson]
|
||||
provides [main] to "./platform"
|
||||
|
||||
HelloWorld := Str has [Encoding {toEncoder}]
|
||||
HelloWorld := Str implements [Encoding {toEncoder}]
|
||||
toEncoder = \@HelloWorld s1 ->
|
||||
Encode.custom \bytes, fmt ->
|
||||
bytes
|
||||
|
@ -891,7 +891,7 @@ fn encode_derived_generic_record_with_different_field_types() {
|
|||
imports [Encode, TotallyNotJson]
|
||||
provides [main] to "./platform"
|
||||
|
||||
Q a b := {a: a, b: b} has [Encoding]
|
||||
Q a b := {a: a, b: b} implements [Encoding]
|
||||
|
||||
q = @Q {a: 10u32, b: "fieldb"}
|
||||
|
||||
|
@ -917,7 +917,7 @@ fn encode_derived_generic_tag_with_different_field_types() {
|
|||
imports [Encode, TotallyNotJson]
|
||||
provides [main] to "./platform"
|
||||
|
||||
Q a b := [A a, B b] has [Encoding]
|
||||
Q a b := [A a, B b] implements [Encoding]
|
||||
|
||||
q : Q Str U32
|
||||
q = @Q (B 67)
|
||||
|
@ -969,7 +969,7 @@ fn decode_use_stdlib() {
|
|||
imports [TotallyNotJson]
|
||||
provides [main] to "./platform"
|
||||
|
||||
MyNum := U8 has [Decoding {decoder: myDecoder}]
|
||||
MyNum := U8 implements [Decoding {decoder: myDecoder}]
|
||||
|
||||
myDecoder =
|
||||
Decode.custom \bytes, fmt ->
|
||||
|
@ -1003,7 +1003,7 @@ fn decode_derive_decoder_for_opaque() {
|
|||
imports [TotallyNotJson]
|
||||
provides [main] to "./platform"
|
||||
|
||||
HelloWorld := { a: Str } has [Decoding]
|
||||
HelloWorld := { a: Str } implements [Decoding]
|
||||
|
||||
main =
|
||||
when Str.toUtf8 """{"a":"Hello, World!"}""" |> Decode.fromBytes TotallyNotJson.json is
|
||||
|
@ -1026,7 +1026,7 @@ fn decode_use_stdlib_json_list() {
|
|||
imports [TotallyNotJson]
|
||||
provides [main] to "./platform"
|
||||
|
||||
MyNumList := List U8 has [Decoding {decoder: myDecoder}]
|
||||
MyNumList := List U8 implements [Decoding {decoder: myDecoder}]
|
||||
|
||||
myDecoder =
|
||||
Decode.custom \bytes, fmt ->
|
||||
|
@ -1459,7 +1459,7 @@ mod hash {
|
|||
|
||||
const TEST_HASHER: &str = indoc!(
|
||||
r#"
|
||||
THasher := List U8 has [Hasher {
|
||||
THasher := List U8 implements [Hasher {
|
||||
addBytes: tAddBytes,
|
||||
addU8: tAddU8,
|
||||
addU16: tAddU16,
|
||||
|
@ -2002,7 +2002,7 @@ mod hash {
|
|||
|
||||
{}
|
||||
|
||||
Q := {{ a: U8, b: U8, c: U8 }} has [Hash]
|
||||
Q := {{ a: U8, b: U8, c: U8 }} implements [Hash]
|
||||
|
||||
q = @Q {{ a: 15, b: 27, c: 31 }}
|
||||
|
||||
|
@ -2055,7 +2055,7 @@ mod eq {
|
|||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
LyingEq := U8 has [Eq {isEq}]
|
||||
LyingEq := U8 implements [Eq {isEq}]
|
||||
|
||||
isEq = \@LyingEq m, @LyingEq n -> m != n
|
||||
|
||||
|
@ -2081,7 +2081,7 @@ mod eq {
|
|||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
Q := ({} -> Str) has [Eq {isEq: isEqQ}]
|
||||
Q := ({} -> Str) implements [Eq {isEq: isEqQ}]
|
||||
|
||||
isEqQ = \@Q _, @Q _ -> Bool.true
|
||||
|
||||
|
@ -2101,7 +2101,7 @@ mod eq {
|
|||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
Q := ({} -> Str) has [Eq {isEq: isEqQ}]
|
||||
Q := ({} -> Str) implements [Eq {isEq: isEqQ}]
|
||||
|
||||
isEqQ = \@Q f1, @Q f2 -> (f1 {} == f2 {})
|
||||
|
||||
|
@ -2135,7 +2135,7 @@ mod eq {
|
|||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
Q := U8 has [Eq]
|
||||
Q := U8 implements [Eq]
|
||||
|
||||
main = (@Q 15) == (@Q 15)
|
||||
"#
|
||||
|
|
|
@ -959,7 +959,7 @@ fn list_walk_implements_position() {
|
|||
r#"
|
||||
Option a : [Some a, None]
|
||||
|
||||
find : List a, a -> Option Nat | a has Eq
|
||||
find : List a, a -> Option Nat where a implements Eq
|
||||
find = \list, needle ->
|
||||
findHelp list needle
|
||||
|> .v
|
||||
|
@ -3692,7 +3692,7 @@ fn list_walk_backwards_implements_position() {
|
|||
r#"
|
||||
Option a : [Some a, None]
|
||||
|
||||
find : List a, a -> Option Nat | a has Eq
|
||||
find : List a, a -> Option Nat where a implements Eq
|
||||
find = \list, needle ->
|
||||
findHelp list needle
|
||||
|> .v
|
||||
|
@ -3810,6 +3810,9 @@ fn list_range_length_overflow() {
|
|||
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
mod pattern_match {
|
||||
#[allow(unused_imports)]
|
||||
use crate::helpers::with_larger_debug_stack;
|
||||
|
||||
#[cfg(feature = "gen-llvm")]
|
||||
use crate::helpers::llvm::assert_evals_to;
|
||||
|
||||
|
@ -3819,8 +3822,6 @@ mod pattern_match {
|
|||
#[cfg(feature = "gen-dev")]
|
||||
use crate::helpers::dev::assert_evals_to;
|
||||
|
||||
use crate::helpers::with_larger_debug_stack;
|
||||
|
||||
use super::RocList;
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -891,7 +891,7 @@ fn gen_wrap_int_neq() {
|
|||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
wrappedNotEq : a, a -> Bool | a has Eq
|
||||
wrappedNotEq : a, a -> Bool where a implements Eq
|
||||
wrappedNotEq = \num1, num2 ->
|
||||
num1 != num2
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#[allow(unused_imports)]
|
||||
use crate::helpers::with_larger_debug_stack;
|
||||
|
||||
#[cfg(feature = "gen-llvm")]
|
||||
use crate::helpers::llvm::assert_evals_to;
|
||||
|
||||
|
@ -14,8 +17,6 @@ use roc_mono::layout::{LayoutRepr, STLayoutInterner};
|
|||
#[cfg(test)]
|
||||
use roc_std::{RocList, RocStr, U128};
|
||||
|
||||
use crate::helpers::with_larger_debug_stack;
|
||||
|
||||
#[test]
|
||||
fn width_and_alignment_u8_u8() {
|
||||
use roc_mono::layout::Layout;
|
||||
|
|
|
@ -1349,10 +1349,10 @@ fn specialize_ability_call() {
|
|||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
MHash has
|
||||
hash : a -> U64 | a has MHash
|
||||
MHash implements
|
||||
hash : a -> U64 where a implements MHash
|
||||
|
||||
Id := U64 has [MHash {hash}]
|
||||
Id := U64 implements [MHash {hash}]
|
||||
|
||||
hash : Id -> U64
|
||||
hash = \@Id n -> n
|
||||
|
@ -1385,20 +1385,20 @@ fn encode() {
|
|||
r#"
|
||||
app "test" provides [myU8Bytes] to "./platform"
|
||||
|
||||
MEncoder fmt := List U8, fmt -> List U8 | fmt has Format
|
||||
MEncoder fmt := List U8, fmt -> List U8 where fmt implements Format
|
||||
|
||||
MEncoding has
|
||||
toEncoder : val -> MEncoder fmt | val has MEncoding, fmt has Format
|
||||
MEncoding implements
|
||||
toEncoder : val -> MEncoder fmt where val implements MEncoding, fmt implements Format
|
||||
|
||||
Format has
|
||||
u8 : U8 -> MEncoder fmt | fmt has Format
|
||||
Format implements
|
||||
u8 : U8 -> MEncoder fmt where fmt implements Format
|
||||
|
||||
|
||||
Linear := {} has [Format {u8}]
|
||||
Linear := {} implements [Format {u8}]
|
||||
|
||||
u8 = \n -> @MEncoder (\lst, @Linear {} -> List.append lst n)
|
||||
|
||||
MyU8 := U8 has [MEncoding {toEncoder}]
|
||||
MyU8 := U8 implements [MEncoding {toEncoder}]
|
||||
|
||||
toEncoder = \@MyU8 n -> u8 n
|
||||
|
||||
|
@ -2579,20 +2579,20 @@ fn unspecialized_lambda_set_unification_keeps_all_concrete_types_without_unifica
|
|||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
MEncoder fmt := List U8, fmt -> List U8 | fmt has Format
|
||||
MEncoder fmt := List U8, fmt -> List U8 where fmt implements Format
|
||||
|
||||
MEncoding has
|
||||
toEncoder : val -> MEncoder fmt | val has MEncoding, fmt has Format
|
||||
MEncoding implements
|
||||
toEncoder : val -> MEncoder fmt where val implements MEncoding, fmt implements Format
|
||||
|
||||
Format has
|
||||
u8 : {} -> MEncoder fmt | fmt has Format
|
||||
str : {} -> MEncoder fmt | fmt has Format
|
||||
tag : MEncoder fmt -> MEncoder fmt | fmt has Format
|
||||
Format implements
|
||||
u8 : {} -> MEncoder fmt where fmt implements Format
|
||||
str : {} -> MEncoder fmt where fmt implements Format
|
||||
tag : MEncoder fmt -> MEncoder fmt where fmt implements Format
|
||||
|
||||
Linear := {} has [Format {u8: lU8, str: lStr, tag: lTag}]
|
||||
Linear := {} implements [Format {u8: lU8, str: lStr, tag: lTag}]
|
||||
|
||||
MU8 := U8 has [MEncoding {toEncoder: toEncoderU8}]
|
||||
MStr := Str has [MEncoding {toEncoder: toEncoderStr}]
|
||||
MU8 := U8 implements [MEncoding {toEncoder: toEncoderU8}]
|
||||
MStr := Str implements [MEncoding {toEncoder: toEncoderStr}]
|
||||
|
||||
Q a b := { a: a, b: b }
|
||||
|
||||
|
@ -2642,7 +2642,7 @@ fn unspecialized_lambda_set_unification_keeps_all_concrete_types_without_unifica
|
|||
r#"
|
||||
app "test" imports [TotallyNotJson] provides [main] to "./platform"
|
||||
|
||||
Q a b := { a: a, b: b } has [Encoding {toEncoder: toEncoderQ}]
|
||||
Q a b := { a: a, b: b } implements [Encoding {toEncoder: toEncoderQ}]
|
||||
|
||||
toEncoderQ =
|
||||
\@Q t -> Encode.custom \bytes, fmt ->
|
||||
|
@ -2680,7 +2680,7 @@ fn unspecialized_lambda_set_unification_does_not_duplicate_identical_concrete_ty
|
|||
r#"
|
||||
app "test" imports [TotallyNotJson] provides [main] to "./platform"
|
||||
|
||||
Q a b := { a: a, b: b } has [Encoding {toEncoder: toEncoderQ}]
|
||||
Q a b := { a: a, b: b } implements [Encoding {toEncoder: toEncoderQ}]
|
||||
|
||||
toEncoderQ =
|
||||
\@Q t -> Encode.custom \bytes, fmt ->
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"is"
|
||||
"expect"
|
||||
"dbg"
|
||||
"has"
|
||||
"implements"
|
||||
|
||||
"app"
|
||||
"platform"
|
||||
|
|
|
@ -1 +1 @@
|
|||
Expr(Ability(DemandColon(@15), @7), @0)
|
||||
Expr(Ability(DemandColon(@22), @14), @0)
|
|
@ -1,4 +1,4 @@
|
|||
MEq has
|
||||
eq b c : a, a -> U64 | a has MEq
|
||||
MEq implements
|
||||
eq b c : a, a -> U64 where a implements MEq
|
||||
|
||||
1
|
||||
|
|
|
@ -1 +1 @@
|
|||
Expr(Ability(DemandAlignment(4, @49), @40), @0)
|
||||
Expr(Ability(DemandAlignment(4, @67), @58), @0)
|
|
@ -1,5 +1,5 @@
|
|||
MEq has
|
||||
eq : a, a -> U64 | a has MEq
|
||||
neq : a, a -> U64 | a has MEq
|
||||
MEq implements
|
||||
eq : a, a -> U64 where a implements MEq
|
||||
neq : a, a -> U64 where a implements MEq
|
||||
|
||||
1
|
||||
|
|
|
@ -1 +1 @@
|
|||
Expr(Ability(DemandAlignment(-1, @8), @7), @0)
|
||||
Expr(Ability(DemandAlignment(-1, @15), @14), @0)
|
|
@ -1,4 +1,4 @@
|
|||
MEq has
|
||||
eq : a, a -> U64 | a has MEq
|
||||
MEq implements
|
||||
eq : a, a -> U64 where a implements MEq
|
||||
|
||||
1
|
||||
|
|
|
@ -1 +1 @@
|
|||
Expr(Ability(DemandName(@12), @7), @0)
|
||||
Expr(Ability(DemandName(@19), @14), @0)
|
|
@ -1,4 +1,4 @@
|
|||
MEq has
|
||||
MEq implements
|
||||
123
|
||||
|
||||
1
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Hash has
|
||||
Hash implements
|
||||
hash : a
|
||||
-> U64
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ Defs(
|
|||
Index(0),
|
||||
],
|
||||
regions: [
|
||||
@0-36,
|
||||
@0-43,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
|
@ -19,18 +19,18 @@ Defs(
|
|||
name: @0-4 "Hash",
|
||||
vars: [],
|
||||
},
|
||||
loc_has: @5-8 Has,
|
||||
loc_implements: @5-15 Implements,
|
||||
members: [
|
||||
AbilityMember {
|
||||
name: @11-15 SpaceBefore(
|
||||
name: @18-22 SpaceBefore(
|
||||
"hash",
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
typ: @18-36 Function(
|
||||
typ: @25-43 Function(
|
||||
[
|
||||
@18-19 SpaceAfter(
|
||||
@25-26 SpaceAfter(
|
||||
BoundVariable(
|
||||
"a",
|
||||
),
|
||||
|
@ -39,7 +39,7 @@ Defs(
|
|||
],
|
||||
),
|
||||
],
|
||||
@33-36 Apply(
|
||||
@40-43 Apply(
|
||||
"",
|
||||
"U64",
|
||||
[],
|
||||
|
@ -51,7 +51,7 @@ Defs(
|
|||
],
|
||||
value_defs: [],
|
||||
},
|
||||
@38-39 SpaceBefore(
|
||||
@45-46 SpaceBefore(
|
||||
Num(
|
||||
"1",
|
||||
),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Hash has
|
||||
Hash implements
|
||||
hash : a
|
||||
-> U64
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Hash has
|
||||
Hash implements
|
||||
hash : a -> U64
|
||||
hash2 : a -> U64
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ Defs(
|
|||
Index(0),
|
||||
],
|
||||
regions: [
|
||||
@0-45,
|
||||
@0-52,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
|
@ -19,22 +19,22 @@ Defs(
|
|||
name: @0-4 "Hash",
|
||||
vars: [],
|
||||
},
|
||||
loc_has: @5-8 Has,
|
||||
loc_implements: @5-15 Implements,
|
||||
members: [
|
||||
AbilityMember {
|
||||
name: @11-15 SpaceBefore(
|
||||
name: @18-22 SpaceBefore(
|
||||
"hash",
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
typ: @18-26 Function(
|
||||
typ: @25-33 Function(
|
||||
[
|
||||
@18-19 BoundVariable(
|
||||
@25-26 BoundVariable(
|
||||
"a",
|
||||
),
|
||||
],
|
||||
@23-26 Apply(
|
||||
@30-33 Apply(
|
||||
"",
|
||||
"U64",
|
||||
[],
|
||||
|
@ -42,19 +42,19 @@ Defs(
|
|||
),
|
||||
},
|
||||
AbilityMember {
|
||||
name: @29-34 SpaceBefore(
|
||||
name: @36-41 SpaceBefore(
|
||||
"hash2",
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
typ: @37-45 Function(
|
||||
typ: @44-52 Function(
|
||||
[
|
||||
@37-38 BoundVariable(
|
||||
@44-45 BoundVariable(
|
||||
"a",
|
||||
),
|
||||
],
|
||||
@42-45 Apply(
|
||||
@49-52 Apply(
|
||||
"",
|
||||
"U64",
|
||||
[],
|
||||
|
@ -66,7 +66,7 @@ Defs(
|
|||
],
|
||||
value_defs: [],
|
||||
},
|
||||
@47-48 SpaceBefore(
|
||||
@54-55 SpaceBefore(
|
||||
Num(
|
||||
"1",
|
||||
),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Hash has
|
||||
Hash implements
|
||||
hash : a -> U64
|
||||
hash2 : a -> U64
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ Defs(
|
|||
Index(0),
|
||||
],
|
||||
regions: [
|
||||
@0-37,
|
||||
@0-55,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
|
@ -19,28 +19,28 @@ Defs(
|
|||
name: @0-4 "Hash",
|
||||
vars: [],
|
||||
},
|
||||
loc_has: @5-8 Has,
|
||||
loc_implements: @5-15 Implements,
|
||||
members: [
|
||||
AbilityMember {
|
||||
name: @9-13 "hash",
|
||||
typ: @16-37 Where(
|
||||
@16-24 Function(
|
||||
name: @16-20 "hash",
|
||||
typ: @23-55 Where(
|
||||
@23-31 Function(
|
||||
[
|
||||
@16-17 BoundVariable(
|
||||
@23-24 BoundVariable(
|
||||
"a",
|
||||
),
|
||||
],
|
||||
@21-24 Apply(
|
||||
@28-31 Apply(
|
||||
"",
|
||||
"U64",
|
||||
[],
|
||||
),
|
||||
),
|
||||
[
|
||||
@27-37 HasClause {
|
||||
var: @27-28 "a",
|
||||
@38-55 ImplementsClause {
|
||||
var: @38-39 "a",
|
||||
abilities: [
|
||||
@33-37 Apply(
|
||||
@51-55 Apply(
|
||||
"",
|
||||
"Hash",
|
||||
[],
|
||||
|
@ -55,7 +55,7 @@ Defs(
|
|||
],
|
||||
value_defs: [],
|
||||
},
|
||||
@39-40 SpaceBefore(
|
||||
@57-58 SpaceBefore(
|
||||
Num(
|
||||
"1",
|
||||
),
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
Hash has hash : a -> U64 | a has Hash
|
||||
Hash implements hash : a -> U64 where a implements Hash
|
||||
|
||||
1
|
||||
|
|
|
@ -5,8 +5,8 @@ Defs(
|
|||
Index(1),
|
||||
],
|
||||
regions: [
|
||||
@0-33,
|
||||
@35-68,
|
||||
@0-51,
|
||||
@53-104,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
|
@ -26,27 +26,27 @@ Defs(
|
|||
name: @0-3 "Ab1",
|
||||
vars: [],
|
||||
},
|
||||
loc_has: @4-7 Has,
|
||||
loc_implements: @4-14 Implements,
|
||||
members: [
|
||||
AbilityMember {
|
||||
name: @8-11 "ab1",
|
||||
typ: @14-33 Where(
|
||||
@14-21 Function(
|
||||
name: @15-18 "ab1",
|
||||
typ: @21-51 Where(
|
||||
@21-28 Function(
|
||||
[
|
||||
@14-15 BoundVariable(
|
||||
@21-22 BoundVariable(
|
||||
"a",
|
||||
),
|
||||
],
|
||||
@19-21 Record {
|
||||
@26-28 Record {
|
||||
fields: [],
|
||||
ext: None,
|
||||
},
|
||||
),
|
||||
[
|
||||
@24-33 HasClause {
|
||||
var: @24-25 "a",
|
||||
@35-51 ImplementsClause {
|
||||
var: @35-36 "a",
|
||||
abilities: [
|
||||
@30-33 Apply(
|
||||
@48-51 Apply(
|
||||
"",
|
||||
"Ab1",
|
||||
[],
|
||||
|
@ -60,30 +60,30 @@ Defs(
|
|||
},
|
||||
Ability {
|
||||
header: TypeHeader {
|
||||
name: @35-38 "Ab2",
|
||||
name: @53-56 "Ab2",
|
||||
vars: [],
|
||||
},
|
||||
loc_has: @39-42 Has,
|
||||
loc_implements: @57-67 Implements,
|
||||
members: [
|
||||
AbilityMember {
|
||||
name: @43-46 "ab2",
|
||||
typ: @49-68 Where(
|
||||
@49-56 Function(
|
||||
name: @68-71 "ab2",
|
||||
typ: @74-104 Where(
|
||||
@74-81 Function(
|
||||
[
|
||||
@49-50 BoundVariable(
|
||||
@74-75 BoundVariable(
|
||||
"a",
|
||||
),
|
||||
],
|
||||
@54-56 Record {
|
||||
@79-81 Record {
|
||||
fields: [],
|
||||
ext: None,
|
||||
},
|
||||
),
|
||||
[
|
||||
@59-68 HasClause {
|
||||
var: @59-60 "a",
|
||||
@88-104 ImplementsClause {
|
||||
var: @88-89 "a",
|
||||
abilities: [
|
||||
@65-68 Apply(
|
||||
@101-104 Apply(
|
||||
"",
|
||||
"Ab2",
|
||||
[],
|
||||
|
@ -98,7 +98,7 @@ Defs(
|
|||
],
|
||||
value_defs: [],
|
||||
},
|
||||
@70-71 SpaceBefore(
|
||||
@106-107 SpaceBefore(
|
||||
Num(
|
||||
"1",
|
||||
),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Ab1 has ab1 : a -> {} | a has Ab1
|
||||
Ab1 implements ab1 : a -> {} where a implements Ab1
|
||||
|
||||
Ab2 has ab2 : a -> {} | a has Ab2
|
||||
Ab2 implements ab2 : a -> {} where a implements Ab2
|
||||
|
||||
1
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
app "hello"
|
||||
packages {
|
||||
pf:
|
||||
"https://github.com/roc-lang/basic-cli/releases/download/0.4.0/DI4lqn7LIZs8ZrCDUgLK-tHHpQmxGF1ZrlevRKq5LXk.tar.br",
|
||||
"https://github.com/roc-lang/basic-cli/releases/download/0.5.0/Cufzl36_SnJ4QbOoEmiJ5dIpUxBvdB3NEySvuH82Wio.tar.br",
|
||||
}
|
||||
imports [pf.Stdout]
|
||||
provides [main] to pf
|
||||
|
|
|
@ -24,7 +24,7 @@ Full {
|
|||
Newline,
|
||||
],
|
||||
package_name: @31-145 PackageName(
|
||||
"https://github.com/roc-lang/basic-cli/releases/download/0.4.0/DI4lqn7LIZs8ZrCDUgLK-tHHpQmxGF1ZrlevRKq5LXk.tar.br",
|
||||
"https://github.com/roc-lang/basic-cli/releases/download/0.5.0/Cufzl36_SnJ4QbOoEmiJ5dIpUxBvdB3NEySvuH82Wio.tar.br",
|
||||
),
|
||||
},
|
||||
[
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
app "hello"
|
||||
packages { pf:
|
||||
"https://github.com/roc-lang/basic-cli/releases/download/0.4.0/DI4lqn7LIZs8ZrCDUgLK-tHHpQmxGF1ZrlevRKq5LXk.tar.br"
|
||||
"https://github.com/roc-lang/basic-cli/releases/download/0.5.0/Cufzl36_SnJ4QbOoEmiJ5dIpUxBvdB3NEySvuH82Wio.tar.br"
|
||||
}
|
||||
imports [pf.Stdout]
|
||||
provides [main] to pf
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
A := U8 has [Eq, Hash]
|
||||
A := U8 implements [Eq, Hash]
|
||||
|
||||
A := a | a has Other
|
||||
has [Eq, Hash]
|
||||
A := a where a implements Other
|
||||
implements [Eq, Hash]
|
||||
|
||||
A := a | a has Other
|
||||
has [Eq, Hash]
|
||||
A := a where a implements Other
|
||||
implements [Eq, Hash]
|
||||
|
||||
A := U8 has [Eq { eq }, Hash { hash }]
|
||||
A := U8 implements [Eq { eq }, Hash { hash }]
|
||||
|
||||
A := U8 has [Eq { eq, eq1 }]
|
||||
A := U8 implements [Eq { eq, eq1 }]
|
||||
|
||||
A := U8 has [Eq { eq, eq1 }, Hash]
|
||||
A := U8 implements [Eq { eq, eq1 }, Hash]
|
||||
|
||||
A := U8 has [Hash, Eq { eq, eq1 }]
|
||||
A := U8 implements [Hash, Eq { eq, eq1 }]
|
||||
|
||||
A := U8 has []
|
||||
A := U8 implements []
|
||||
|
||||
A := a | a has Other
|
||||
has [Eq { eq }, Hash { hash }]
|
||||
A := a where a implements Other
|
||||
implements [Eq { eq }, Hash { hash }]
|
||||
|
||||
A := U8 has [Eq {}]
|
||||
A := U8 implements [Eq {}]
|
||||
|
||||
0
|
|
@ -14,15 +14,15 @@ Defs(
|
|||
],
|
||||
regions: [
|
||||
@0-7,
|
||||
@24-44,
|
||||
@61-81,
|
||||
@103-110,
|
||||
@139-146,
|
||||
@167-174,
|
||||
@201-208,
|
||||
@235-242,
|
||||
@251-271,
|
||||
@305-312,
|
||||
@31-62,
|
||||
@86-117,
|
||||
@146-153,
|
||||
@189-196,
|
||||
@224-231,
|
||||
@265-272,
|
||||
@306-313,
|
||||
@329-360,
|
||||
@401-408,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
|
@ -80,18 +80,18 @@ Defs(
|
|||
[],
|
||||
),
|
||||
derived: Some(
|
||||
@12-22 Has(
|
||||
@19-29 Implements(
|
||||
[
|
||||
@13-15 HasAbility {
|
||||
ability: @13-15 Apply(
|
||||
@20-22 ImplementsAbility {
|
||||
ability: @20-22 Apply(
|
||||
"",
|
||||
"Eq",
|
||||
[],
|
||||
),
|
||||
impls: None,
|
||||
},
|
||||
@17-21 HasAbility {
|
||||
ability: @17-21 Apply(
|
||||
@24-28 ImplementsAbility {
|
||||
ability: @24-28 Apply(
|
||||
"",
|
||||
"Hash",
|
||||
[],
|
||||
|
@ -104,18 +104,18 @@ Defs(
|
|||
},
|
||||
Opaque {
|
||||
header: TypeHeader {
|
||||
name: @24-25 "A",
|
||||
name: @31-32 "A",
|
||||
vars: [],
|
||||
},
|
||||
typ: @29-44 Where(
|
||||
@29-30 BoundVariable(
|
||||
typ: @36-62 Where(
|
||||
@36-37 BoundVariable(
|
||||
"a",
|
||||
),
|
||||
[
|
||||
@33-44 HasClause {
|
||||
var: @33-34 "a",
|
||||
@44-62 ImplementsClause {
|
||||
var: @44-45 "a",
|
||||
abilities: [
|
||||
@39-44 Apply(
|
||||
@57-62 Apply(
|
||||
"",
|
||||
"Other",
|
||||
[],
|
||||
|
@ -125,18 +125,18 @@ Defs(
|
|||
],
|
||||
),
|
||||
derived: Some(
|
||||
@49-59 Has(
|
||||
@74-84 Implements(
|
||||
[
|
||||
@50-52 HasAbility {
|
||||
ability: @50-52 Apply(
|
||||
@75-77 ImplementsAbility {
|
||||
ability: @75-77 Apply(
|
||||
"",
|
||||
"Eq",
|
||||
[],
|
||||
),
|
||||
impls: None,
|
||||
},
|
||||
@54-58 HasAbility {
|
||||
ability: @54-58 Apply(
|
||||
@79-83 ImplementsAbility {
|
||||
ability: @79-83 Apply(
|
||||
"",
|
||||
"Hash",
|
||||
[],
|
||||
|
@ -149,18 +149,18 @@ Defs(
|
|||
},
|
||||
Opaque {
|
||||
header: TypeHeader {
|
||||
name: @61-62 "A",
|
||||
name: @86-87 "A",
|
||||
vars: [],
|
||||
},
|
||||
typ: @66-81 Where(
|
||||
@66-67 BoundVariable(
|
||||
typ: @91-117 Where(
|
||||
@91-92 BoundVariable(
|
||||
"a",
|
||||
),
|
||||
[
|
||||
@70-81 HasClause {
|
||||
var: @70-71 "a",
|
||||
@99-117 ImplementsClause {
|
||||
var: @99-100 "a",
|
||||
abilities: [
|
||||
@76-81 Apply(
|
||||
@112-117 Apply(
|
||||
"",
|
||||
"Other",
|
||||
[],
|
||||
|
@ -170,19 +170,19 @@ Defs(
|
|||
],
|
||||
),
|
||||
derived: Some(
|
||||
@91-101 SpaceBefore(
|
||||
Has(
|
||||
@134-144 SpaceBefore(
|
||||
Implements(
|
||||
[
|
||||
@92-94 HasAbility {
|
||||
ability: @92-94 Apply(
|
||||
@135-137 ImplementsAbility {
|
||||
ability: @135-137 Apply(
|
||||
"",
|
||||
"Eq",
|
||||
[],
|
||||
),
|
||||
impls: None,
|
||||
},
|
||||
@96-100 HasAbility {
|
||||
ability: @96-100 Apply(
|
||||
@139-143 ImplementsAbility {
|
||||
ability: @139-143 Apply(
|
||||
"",
|
||||
"Hash",
|
||||
[],
|
||||
|
@ -199,44 +199,44 @@ Defs(
|
|||
},
|
||||
Opaque {
|
||||
header: TypeHeader {
|
||||
name: @103-104 "A",
|
||||
name: @146-147 "A",
|
||||
vars: [],
|
||||
},
|
||||
typ: @108-110 Apply(
|
||||
typ: @151-153 Apply(
|
||||
"",
|
||||
"U8",
|
||||
[],
|
||||
),
|
||||
derived: Some(
|
||||
@115-137 Has(
|
||||
@165-187 Implements(
|
||||
[
|
||||
@116-123 HasAbility {
|
||||
ability: @116-118 Apply(
|
||||
@166-173 ImplementsAbility {
|
||||
ability: @166-168 Apply(
|
||||
"",
|
||||
"Eq",
|
||||
[],
|
||||
),
|
||||
impls: Some(
|
||||
@119-123 HasImpls(
|
||||
@169-173 AbilityImpls(
|
||||
[
|
||||
@120-122 LabelOnly(
|
||||
@120-122 "eq",
|
||||
@170-172 LabelOnly(
|
||||
@170-172 "eq",
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
},
|
||||
@125-136 HasAbility {
|
||||
ability: @125-129 Apply(
|
||||
@175-186 ImplementsAbility {
|
||||
ability: @175-179 Apply(
|
||||
"",
|
||||
"Hash",
|
||||
[],
|
||||
),
|
||||
impls: Some(
|
||||
@130-136 HasImpls(
|
||||
@180-186 AbilityImpls(
|
||||
[
|
||||
@131-135 LabelOnly(
|
||||
@131-135 "hash",
|
||||
@181-185 LabelOnly(
|
||||
@181-185 "hash",
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -248,31 +248,31 @@ Defs(
|
|||
},
|
||||
Opaque {
|
||||
header: TypeHeader {
|
||||
name: @139-140 "A",
|
||||
name: @189-190 "A",
|
||||
vars: [],
|
||||
},
|
||||
typ: @144-146 Apply(
|
||||
typ: @194-196 Apply(
|
||||
"",
|
||||
"U8",
|
||||
[],
|
||||
),
|
||||
derived: Some(
|
||||
@151-165 Has(
|
||||
@208-222 Implements(
|
||||
[
|
||||
@152-164 HasAbility {
|
||||
ability: @152-154 Apply(
|
||||
@209-221 ImplementsAbility {
|
||||
ability: @209-211 Apply(
|
||||
"",
|
||||
"Eq",
|
||||
[],
|
||||
),
|
||||
impls: Some(
|
||||
@155-164 HasImpls(
|
||||
@212-221 AbilityImpls(
|
||||
[
|
||||
@156-158 LabelOnly(
|
||||
@156-158 "eq",
|
||||
@213-215 LabelOnly(
|
||||
@213-215 "eq",
|
||||
),
|
||||
@160-163 LabelOnly(
|
||||
@160-163 "eq1",
|
||||
@217-220 LabelOnly(
|
||||
@217-220 "eq1",
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -284,38 +284,38 @@ Defs(
|
|||
},
|
||||
Opaque {
|
||||
header: TypeHeader {
|
||||
name: @167-168 "A",
|
||||
name: @224-225 "A",
|
||||
vars: [],
|
||||
},
|
||||
typ: @172-174 Apply(
|
||||
typ: @229-231 Apply(
|
||||
"",
|
||||
"U8",
|
||||
[],
|
||||
),
|
||||
derived: Some(
|
||||
@179-199 Has(
|
||||
@243-263 Implements(
|
||||
[
|
||||
@180-192 HasAbility {
|
||||
ability: @180-182 Apply(
|
||||
@244-256 ImplementsAbility {
|
||||
ability: @244-246 Apply(
|
||||
"",
|
||||
"Eq",
|
||||
[],
|
||||
),
|
||||
impls: Some(
|
||||
@183-192 HasImpls(
|
||||
@247-256 AbilityImpls(
|
||||
[
|
||||
@184-186 LabelOnly(
|
||||
@184-186 "eq",
|
||||
@248-250 LabelOnly(
|
||||
@248-250 "eq",
|
||||
),
|
||||
@188-191 LabelOnly(
|
||||
@188-191 "eq1",
|
||||
@252-255 LabelOnly(
|
||||
@252-255 "eq1",
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
},
|
||||
@194-198 HasAbility {
|
||||
ability: @194-198 Apply(
|
||||
@258-262 ImplementsAbility {
|
||||
ability: @258-262 Apply(
|
||||
"",
|
||||
"Hash",
|
||||
[],
|
||||
|
@ -328,39 +328,39 @@ Defs(
|
|||
},
|
||||
Opaque {
|
||||
header: TypeHeader {
|
||||
name: @201-202 "A",
|
||||
name: @265-266 "A",
|
||||
vars: [],
|
||||
},
|
||||
typ: @206-208 Apply(
|
||||
typ: @270-272 Apply(
|
||||
"",
|
||||
"U8",
|
||||
[],
|
||||
),
|
||||
derived: Some(
|
||||
@213-233 Has(
|
||||
@284-304 Implements(
|
||||
[
|
||||
@214-218 HasAbility {
|
||||
ability: @214-218 Apply(
|
||||
@285-289 ImplementsAbility {
|
||||
ability: @285-289 Apply(
|
||||
"",
|
||||
"Hash",
|
||||
[],
|
||||
),
|
||||
impls: None,
|
||||
},
|
||||
@220-232 HasAbility {
|
||||
ability: @220-222 Apply(
|
||||
@291-303 ImplementsAbility {
|
||||
ability: @291-293 Apply(
|
||||
"",
|
||||
"Eq",
|
||||
[],
|
||||
),
|
||||
impls: Some(
|
||||
@223-232 HasImpls(
|
||||
@294-303 AbilityImpls(
|
||||
[
|
||||
@224-226 LabelOnly(
|
||||
@224-226 "eq",
|
||||
@295-297 LabelOnly(
|
||||
@295-297 "eq",
|
||||
),
|
||||
@228-231 LabelOnly(
|
||||
@228-231 "eq1",
|
||||
@299-302 LabelOnly(
|
||||
@299-302 "eq1",
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -372,34 +372,34 @@ Defs(
|
|||
},
|
||||
Opaque {
|
||||
header: TypeHeader {
|
||||
name: @235-236 "A",
|
||||
name: @306-307 "A",
|
||||
vars: [],
|
||||
},
|
||||
typ: @240-242 Apply(
|
||||
typ: @311-313 Apply(
|
||||
"",
|
||||
"U8",
|
||||
[],
|
||||
),
|
||||
derived: Some(
|
||||
@247-249 Has(
|
||||
@325-327 Implements(
|
||||
[],
|
||||
),
|
||||
),
|
||||
},
|
||||
Opaque {
|
||||
header: TypeHeader {
|
||||
name: @251-252 "A",
|
||||
name: @329-330 "A",
|
||||
vars: [],
|
||||
},
|
||||
typ: @256-271 Where(
|
||||
@256-257 BoundVariable(
|
||||
typ: @334-360 Where(
|
||||
@334-335 BoundVariable(
|
||||
"a",
|
||||
),
|
||||
[
|
||||
@260-271 HasClause {
|
||||
var: @260-261 "a",
|
||||
@342-360 ImplementsClause {
|
||||
var: @342-343 "a",
|
||||
abilities: [
|
||||
@266-271 Apply(
|
||||
@355-360 Apply(
|
||||
"",
|
||||
"Other",
|
||||
[],
|
||||
|
@ -409,36 +409,36 @@ Defs(
|
|||
],
|
||||
),
|
||||
derived: Some(
|
||||
@281-303 SpaceBefore(
|
||||
Has(
|
||||
@377-399 SpaceBefore(
|
||||
Implements(
|
||||
[
|
||||
@282-289 HasAbility {
|
||||
ability: @282-284 Apply(
|
||||
@378-385 ImplementsAbility {
|
||||
ability: @378-380 Apply(
|
||||
"",
|
||||
"Eq",
|
||||
[],
|
||||
),
|
||||
impls: Some(
|
||||
@285-289 HasImpls(
|
||||
@381-385 AbilityImpls(
|
||||
[
|
||||
@286-288 LabelOnly(
|
||||
@286-288 "eq",
|
||||
@382-384 LabelOnly(
|
||||
@382-384 "eq",
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
},
|
||||
@291-302 HasAbility {
|
||||
ability: @291-295 Apply(
|
||||
@387-398 ImplementsAbility {
|
||||
ability: @387-391 Apply(
|
||||
"",
|
||||
"Hash",
|
||||
[],
|
||||
),
|
||||
impls: Some(
|
||||
@296-302 HasImpls(
|
||||
@392-398 AbilityImpls(
|
||||
[
|
||||
@297-301 LabelOnly(
|
||||
@297-301 "hash",
|
||||
@393-397 LabelOnly(
|
||||
@393-397 "hash",
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -454,25 +454,25 @@ Defs(
|
|||
},
|
||||
Opaque {
|
||||
header: TypeHeader {
|
||||
name: @305-306 "A",
|
||||
name: @401-402 "A",
|
||||
vars: [],
|
||||
},
|
||||
typ: @310-312 Apply(
|
||||
typ: @406-408 Apply(
|
||||
"",
|
||||
"U8",
|
||||
[],
|
||||
),
|
||||
derived: Some(
|
||||
@317-324 Has(
|
||||
@420-427 Implements(
|
||||
[
|
||||
@318-323 HasAbility {
|
||||
ability: @318-320 Apply(
|
||||
@421-426 ImplementsAbility {
|
||||
ability: @421-423 Apply(
|
||||
"",
|
||||
"Eq",
|
||||
[],
|
||||
),
|
||||
impls: Some(
|
||||
@321-323 HasImpls(
|
||||
@424-426 AbilityImpls(
|
||||
[],
|
||||
),
|
||||
),
|
||||
|
@ -484,7 +484,7 @@ Defs(
|
|||
],
|
||||
value_defs: [],
|
||||
},
|
||||
@326-327 SpaceBefore(
|
||||
@429-430 SpaceBefore(
|
||||
Num(
|
||||
"0",
|
||||
),
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
A := U8 has [Eq, Hash]
|
||||
A := U8 implements [Eq, Hash]
|
||||
|
||||
A := a | a has Other has [Eq, Hash]
|
||||
A := a where a implements Other implements [Eq, Hash]
|
||||
|
||||
A := a | a has Other
|
||||
has [Eq, Hash]
|
||||
A := a where a implements Other
|
||||
implements [Eq, Hash]
|
||||
|
||||
A := U8 has [Eq {eq}, Hash {hash}]
|
||||
A := U8 implements [Eq {eq}, Hash {hash}]
|
||||
|
||||
A := U8 has [Eq {eq, eq1}]
|
||||
A := U8 implements [Eq {eq, eq1}]
|
||||
|
||||
A := U8 has [Eq {eq, eq1}, Hash]
|
||||
A := U8 implements [Eq {eq, eq1}, Hash]
|
||||
|
||||
A := U8 has [Hash, Eq {eq, eq1}]
|
||||
A := U8 implements [Hash, Eq {eq, eq1}]
|
||||
|
||||
A := U8 has []
|
||||
A := U8 implements []
|
||||
|
||||
A := a | a has Other
|
||||
has [Eq {eq}, Hash {hash}]
|
||||
A := a where a implements Other
|
||||
implements [Eq {eq}, Hash {hash}]
|
||||
|
||||
A := U8 has [Eq {}]
|
||||
A := U8 implements [Eq {}]
|
||||
|
||||
0
|
||||
|
|
|
@ -4,7 +4,7 @@ Defs(
|
|||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-27,
|
||||
@0-38,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
|
@ -19,7 +19,7 @@ Defs(
|
|||
@0-1 Identifier(
|
||||
"f",
|
||||
),
|
||||
@4-27 Where(
|
||||
@4-38 Where(
|
||||
@4-16 Function(
|
||||
[
|
||||
@4-5 BoundVariable(
|
||||
|
@ -38,10 +38,10 @@ Defs(
|
|||
),
|
||||
),
|
||||
[
|
||||
@20-27 HasClause {
|
||||
var: @20-21 "a",
|
||||
@24-38 ImplementsClause {
|
||||
var: @24-25 "a",
|
||||
abilities: [
|
||||
@26-27 Apply(
|
||||
@37-38 Apply(
|
||||
"",
|
||||
"A",
|
||||
[],
|
||||
|
@ -53,7 +53,7 @@ Defs(
|
|||
),
|
||||
],
|
||||
},
|
||||
@29-30 SpaceBefore(
|
||||
@40-41 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "f",
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
f : a -> (b -> c) | a has A
|
||||
f : a -> (b -> c) where a implements A
|
||||
|
||||
f
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
f : a -> b | a has Hash & Eq, b has Eq & Hash & Display
|
||||
f : a -> b where a implements Hash & Eq, b implements Eq & Hash & Display
|
||||
|
||||
f : a -> b | a has Hash & Eq, b has Hash & Display & Eq
|
||||
f : a -> b where a implements Hash & Eq, b implements Hash & Display & Eq
|
||||
|
||||
f
|
|
@ -5,8 +5,8 @@ Defs(
|
|||
Index(2147483649),
|
||||
],
|
||||
regions: [
|
||||
@0-55,
|
||||
@57-118,
|
||||
@0-73,
|
||||
@75-154,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
|
@ -26,7 +26,7 @@ Defs(
|
|||
@0-1 Identifier(
|
||||
"f",
|
||||
),
|
||||
@4-55 Where(
|
||||
@4-73 Where(
|
||||
@4-10 Function(
|
||||
[
|
||||
@4-5 BoundVariable(
|
||||
|
@ -38,35 +38,35 @@ Defs(
|
|||
),
|
||||
),
|
||||
[
|
||||
@13-28 HasClause {
|
||||
var: @13-14 "a",
|
||||
@17-39 ImplementsClause {
|
||||
var: @17-18 "a",
|
||||
abilities: [
|
||||
@19-23 Apply(
|
||||
@30-34 Apply(
|
||||
"",
|
||||
"Hash",
|
||||
[],
|
||||
),
|
||||
@26-28 Apply(
|
||||
@37-39 Apply(
|
||||
"",
|
||||
"Eq",
|
||||
[],
|
||||
),
|
||||
],
|
||||
},
|
||||
@30-55 HasClause {
|
||||
var: @30-31 "b",
|
||||
@41-73 ImplementsClause {
|
||||
var: @41-42 "b",
|
||||
abilities: [
|
||||
@36-38 Apply(
|
||||
@54-56 Apply(
|
||||
"",
|
||||
"Eq",
|
||||
[],
|
||||
),
|
||||
@41-45 Apply(
|
||||
@59-63 Apply(
|
||||
"",
|
||||
"Hash",
|
||||
[],
|
||||
),
|
||||
@48-55 Apply(
|
||||
@66-73 Apply(
|
||||
"",
|
||||
"Display",
|
||||
[],
|
||||
|
@ -77,18 +77,18 @@ Defs(
|
|||
),
|
||||
),
|
||||
Annotation(
|
||||
@57-58 Identifier(
|
||||
@75-76 Identifier(
|
||||
"f",
|
||||
),
|
||||
@61-118 Where(
|
||||
@61-67 SpaceAfter(
|
||||
@79-154 Where(
|
||||
@79-85 SpaceAfter(
|
||||
Function(
|
||||
[
|
||||
@61-62 BoundVariable(
|
||||
@79-80 BoundVariable(
|
||||
"a",
|
||||
),
|
||||
],
|
||||
@66-67 BoundVariable(
|
||||
@84-85 BoundVariable(
|
||||
"b",
|
||||
),
|
||||
),
|
||||
|
@ -97,40 +97,40 @@ Defs(
|
|||
],
|
||||
),
|
||||
[
|
||||
@72-87 HasClause {
|
||||
var: @72-73 "a",
|
||||
@94-116 ImplementsClause {
|
||||
var: @94-95 "a",
|
||||
abilities: [
|
||||
@78-82 Apply(
|
||||
@107-111 Apply(
|
||||
"",
|
||||
"Hash",
|
||||
[],
|
||||
),
|
||||
@85-87 Apply(
|
||||
@114-116 Apply(
|
||||
"",
|
||||
"Eq",
|
||||
[],
|
||||
),
|
||||
],
|
||||
},
|
||||
@93-118 HasClause {
|
||||
var: @93-94 SpaceBefore(
|
||||
@122-154 ImplementsClause {
|
||||
var: @122-123 SpaceBefore(
|
||||
"b",
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
abilities: [
|
||||
@99-103 Apply(
|
||||
@135-139 Apply(
|
||||
"",
|
||||
"Hash",
|
||||
[],
|
||||
),
|
||||
@106-113 Apply(
|
||||
@142-149 Apply(
|
||||
"",
|
||||
"Display",
|
||||
[],
|
||||
),
|
||||
@116-118 Apply(
|
||||
@152-154 Apply(
|
||||
"",
|
||||
"Eq",
|
||||
[],
|
||||
|
@ -142,7 +142,7 @@ Defs(
|
|||
),
|
||||
],
|
||||
},
|
||||
@120-121 SpaceBefore(
|
||||
@156-157 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "f",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
f : a -> b | a has Hash & Eq, b has Eq & Hash & Display
|
||||
f : a -> b where a implements Hash & Eq, b implements Eq & Hash & Display
|
||||
|
||||
f : a -> b
|
||||
| a has Hash & Eq,
|
||||
b has Hash & Display & Eq
|
||||
where a implements Hash & Eq,
|
||||
b implements Hash & Display & Eq
|
||||
|
||||
f
|
||||
|
|
|
@ -4,7 +4,7 @@ Defs(
|
|||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-48,
|
||||
@0-73,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
|
@ -19,7 +19,7 @@ Defs(
|
|||
@0-1 Identifier(
|
||||
"f",
|
||||
),
|
||||
@4-48 Where(
|
||||
@4-73 Where(
|
||||
@4-16 Function(
|
||||
[
|
||||
@4-5 BoundVariable(
|
||||
|
@ -38,30 +38,30 @@ Defs(
|
|||
),
|
||||
),
|
||||
[
|
||||
@20-27 HasClause {
|
||||
var: @20-21 "a",
|
||||
@24-38 ImplementsClause {
|
||||
var: @24-25 "a",
|
||||
abilities: [
|
||||
@26-27 Apply(
|
||||
@37-38 Apply(
|
||||
"",
|
||||
"A",
|
||||
[],
|
||||
),
|
||||
],
|
||||
},
|
||||
@29-37 HasClause {
|
||||
var: @29-30 "b",
|
||||
@40-55 ImplementsClause {
|
||||
var: @40-41 "b",
|
||||
abilities: [
|
||||
@35-37 Apply(
|
||||
@53-55 Apply(
|
||||
"",
|
||||
"Eq",
|
||||
[],
|
||||
),
|
||||
],
|
||||
},
|
||||
@39-48 HasClause {
|
||||
var: @39-40 "c",
|
||||
@57-73 ImplementsClause {
|
||||
var: @57-58 "c",
|
||||
abilities: [
|
||||
@45-48 Apply(
|
||||
@70-73 Apply(
|
||||
"",
|
||||
"Ord",
|
||||
[],
|
||||
|
@ -73,7 +73,7 @@ Defs(
|
|||
),
|
||||
],
|
||||
},
|
||||
@50-51 SpaceBefore(
|
||||
@75-76 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "f",
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
f : a -> (b -> c) | a has A, b has Eq, c has Ord
|
||||
f : a -> (b -> c) where a implements A, b implements Eq, c implements Ord
|
||||
|
||||
f
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
f : a -> (b -> c) | a has Hash, b has Eq, c has Ord
|
||||
f : a -> (b -> c) where a implements Hash, b implements Eq, c implements Ord
|
||||
|
||||
f
|
|
@ -4,7 +4,7 @@ Defs(
|
|||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-67,
|
||||
@0-92,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
|
@ -19,7 +19,7 @@ Defs(
|
|||
@0-1 Identifier(
|
||||
"f",
|
||||
),
|
||||
@4-67 Where(
|
||||
@4-92 Where(
|
||||
@4-16 SpaceAfter(
|
||||
Function(
|
||||
[
|
||||
|
@ -43,40 +43,40 @@ Defs(
|
|||
],
|
||||
),
|
||||
[
|
||||
@24-34 HasClause {
|
||||
var: @24-25 "a",
|
||||
@28-45 ImplementsClause {
|
||||
var: @28-29 "a",
|
||||
abilities: [
|
||||
@30-34 Apply(
|
||||
@41-45 Apply(
|
||||
"",
|
||||
"Hash",
|
||||
[],
|
||||
),
|
||||
],
|
||||
},
|
||||
@42-50 HasClause {
|
||||
var: @42-43 SpaceBefore(
|
||||
@53-68 ImplementsClause {
|
||||
var: @53-54 SpaceBefore(
|
||||
"b",
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
abilities: [
|
||||
@48-50 Apply(
|
||||
@66-68 Apply(
|
||||
"",
|
||||
"Eq",
|
||||
[],
|
||||
),
|
||||
],
|
||||
},
|
||||
@58-67 HasClause {
|
||||
var: @58-59 SpaceBefore(
|
||||
@76-92 ImplementsClause {
|
||||
var: @76-77 SpaceBefore(
|
||||
"c",
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
abilities: [
|
||||
@64-67 Apply(
|
||||
@89-92 Apply(
|
||||
"",
|
||||
"Ord",
|
||||
[],
|
||||
|
@ -88,7 +88,7 @@ Defs(
|
|||
),
|
||||
],
|
||||
},
|
||||
@69-70 SpaceBefore(
|
||||
@94-95 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "f",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
f : a -> (b -> c)
|
||||
| a has Hash,
|
||||
b has Eq,
|
||||
c has Ord
|
||||
where a implements Hash,
|
||||
b implements Eq,
|
||||
c implements Ord
|
||||
|
||||
f
|
||||
|
|
|
@ -4,7 +4,7 @@ Defs(
|
|||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-15,
|
||||
@0-26,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
|
@ -19,15 +19,15 @@ Defs(
|
|||
@0-1 Identifier(
|
||||
"f",
|
||||
),
|
||||
@4-15 Where(
|
||||
@4-26 Where(
|
||||
@4-5 BoundVariable(
|
||||
"a",
|
||||
),
|
||||
[
|
||||
@8-15 HasClause {
|
||||
var: @8-9 "a",
|
||||
@12-26 ImplementsClause {
|
||||
var: @12-13 "a",
|
||||
abilities: [
|
||||
@14-15 Apply(
|
||||
@25-26 Apply(
|
||||
"",
|
||||
"A",
|
||||
[],
|
||||
|
@ -39,7 +39,7 @@ Defs(
|
|||
),
|
||||
],
|
||||
},
|
||||
@17-18 SpaceBefore(
|
||||
@28-29 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "f",
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
f : a | a has A
|
||||
f : a where a implements A
|
||||
|
||||
f
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
f : a -> U64 | a has Hash
|
||||
f : a -> U64 where a implements Hash
|
||||
|
||||
f
|
|
@ -4,7 +4,7 @@ Defs(
|
|||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-29,
|
||||
@0-40,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
|
@ -19,7 +19,7 @@ Defs(
|
|||
@0-1 Identifier(
|
||||
"f",
|
||||
),
|
||||
@4-29 Where(
|
||||
@4-40 Where(
|
||||
@4-12 SpaceAfter(
|
||||
Function(
|
||||
[
|
||||
|
@ -38,10 +38,10 @@ Defs(
|
|||
],
|
||||
),
|
||||
[
|
||||
@19-29 HasClause {
|
||||
var: @19-20 "a",
|
||||
@23-40 ImplementsClause {
|
||||
var: @23-24 "a",
|
||||
abilities: [
|
||||
@25-29 Apply(
|
||||
@36-40 Apply(
|
||||
"",
|
||||
"Hash",
|
||||
[],
|
||||
|
@ -53,7 +53,7 @@ Defs(
|
|||
),
|
||||
],
|
||||
},
|
||||
@31-32 SpaceBefore(
|
||||
@42-43 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "f",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
f : a -> U64
|
||||
| a has Hash
|
||||
where a implements Hash
|
||||
|
||||
f
|
||||
|
|
|
@ -5421,10 +5421,10 @@ mod test_fmt {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn opaque_has_clause() {
|
||||
fn opaque_implements_clause() {
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
A := U8 has [Eq, Hash]
|
||||
A := U8 implements [Eq, Hash]
|
||||
|
||||
0
|
||||
"#
|
||||
|
@ -5435,7 +5435,7 @@ mod test_fmt {
|
|||
r#"
|
||||
A :=
|
||||
U8
|
||||
has [Eq, Hash]
|
||||
implements [Eq, Hash]
|
||||
|
||||
0
|
||||
"#
|
||||
|
@ -5443,7 +5443,7 @@ mod test_fmt {
|
|||
indoc!(
|
||||
r#"
|
||||
A := U8
|
||||
has [Eq, Hash]
|
||||
implements [Eq, Hash]
|
||||
|
||||
0
|
||||
"#
|
||||
|
@ -5453,15 +5453,15 @@ mod test_fmt {
|
|||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
A := a | a has Hash has [ Eq, Hash ]
|
||||
A := a where a implements Hash implements [ Eq, Hash ]
|
||||
|
||||
0
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
A := a | a has Hash
|
||||
has [Eq, Hash]
|
||||
A := a where a implements Hash
|
||||
implements [Eq, Hash]
|
||||
|
||||
0
|
||||
"#
|
||||
|
@ -5471,14 +5471,14 @@ mod test_fmt {
|
|||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
A := U8 has []
|
||||
A := U8 implements []
|
||||
|
||||
0
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
A := U8 has []
|
||||
A := U8 implements []
|
||||
|
||||
0
|
||||
"#
|
||||
|
@ -5518,10 +5518,10 @@ mod test_fmt {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn opaque_has_with_impls() {
|
||||
fn opaque_implements_with_impls() {
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
A := U8 has [Eq { eq }, Hash { hash }]
|
||||
A := U8 implements [Eq { eq }, Hash { hash }]
|
||||
|
||||
0
|
||||
"#
|
||||
|
@ -5529,7 +5529,7 @@ mod test_fmt {
|
|||
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
A := U8 has [Eq { eq, eq1 }]
|
||||
A := U8 implements [Eq { eq, eq1 }]
|
||||
|
||||
0
|
||||
"#
|
||||
|
@ -5538,8 +5538,8 @@ mod test_fmt {
|
|||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
A := U8 has [Eq { eq, eq1 }]
|
||||
A := U8 has [Eq {
|
||||
A := U8 implements [Eq { eq, eq1 }]
|
||||
A := U8 implements [Eq {
|
||||
eq,
|
||||
eq1
|
||||
}]
|
||||
|
@ -5549,8 +5549,8 @@ mod test_fmt {
|
|||
),
|
||||
indoc!(
|
||||
r#"
|
||||
A := U8 has [Eq { eq, eq1 }]
|
||||
A := U8 has [
|
||||
A := U8 implements [Eq { eq, eq1 }]
|
||||
A := U8 implements [
|
||||
Eq {
|
||||
eq,
|
||||
eq1,
|
||||
|
@ -5564,8 +5564,8 @@ mod test_fmt {
|
|||
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
A := a | a has Other
|
||||
has [Eq { eq }, Hash { hash }]
|
||||
A := a where a implements Other
|
||||
implements [Eq { eq }, Hash { hash }]
|
||||
|
||||
0
|
||||
"#
|
||||
|
@ -5573,7 +5573,7 @@ mod test_fmt {
|
|||
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
A := U8 has [Eq {}]
|
||||
A := U8 implements [Eq {}]
|
||||
|
||||
0
|
||||
"#
|
||||
|
@ -5621,7 +5621,7 @@ mod test_fmt {
|
|||
dataIndices : List Nat,
|
||||
data : List (T k v),
|
||||
size : Nat,
|
||||
} | k has Hash & Eq
|
||||
} where k implements Hash & Eq
|
||||
|
||||
a
|
||||
"#
|
||||
|
@ -5833,12 +5833,12 @@ mod test_fmt {
|
|||
r#"
|
||||
interface Foo exposes [] imports []
|
||||
|
||||
A has
|
||||
A implements
|
||||
## This is member ab
|
||||
ab : a -> a | a has A
|
||||
ab : a -> a where a implements A
|
||||
|
||||
## This is member de
|
||||
de : a -> a | a has A
|
||||
de : a -> a where a implements A
|
||||
|
||||
f = g
|
||||
"#
|
||||
|
@ -5880,7 +5880,7 @@ mod test_fmt {
|
|||
fn clauses_with_multiple_abilities() {
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
f : {} -> a | a has Eq & Hash & Decode
|
||||
f : {} -> a where a implements Eq & Hash & Decode
|
||||
|
||||
f
|
||||
"#
|
||||
|
@ -5889,8 +5889,8 @@ mod test_fmt {
|
|||
expr_formats_to(
|
||||
indoc!(
|
||||
r#"
|
||||
f : {} -> a | a has Eq & Hash & Decode,
|
||||
b has Eq & Hash
|
||||
f : {} -> a where a implements Eq & Hash & Decode,
|
||||
b implements Eq & Hash
|
||||
|
||||
f
|
||||
"#
|
||||
|
@ -5898,10 +5898,10 @@ mod test_fmt {
|
|||
indoc!(
|
||||
// TODO: ideally, this would look a bit nicer - consider
|
||||
// f : {} -> a
|
||||
// | a has Eq & Hash & Decode,
|
||||
// b has Eq & Hash
|
||||
// where a implements Eq & Hash & Decode,
|
||||
// b implements Eq & Hash
|
||||
r#"
|
||||
f : {} -> a | a has Eq & Hash & Decode, b has Eq & Hash
|
||||
f : {} -> a where a implements Eq & Hash & Decode, b implements Eq & Hash
|
||||
|
||||
f
|
||||
"#
|
||||
|
|
|
@ -14,6 +14,7 @@ roc_error_macros = { path = "../../error_macros" }
|
|||
roc_module = { path = "../module" }
|
||||
roc_region = { path = "../region" }
|
||||
roc_serialize = { path = "../serialize" }
|
||||
roc_parse = { path = "../parse" }
|
||||
|
||||
ven_pretty = { path = "../../vendor/pretty" }
|
||||
|
||||
|
|
|
@ -136,8 +136,8 @@ fn find_names_needed(
|
|||
if !root_appearances.contains_key(&root) {
|
||||
roots.push(root);
|
||||
}
|
||||
// Able vars are always printed at least twice (in the signature, and in the "has"
|
||||
// clause set).
|
||||
// Able vars are always printed at least twice (in the signature, and in the
|
||||
// "implements" clause set).
|
||||
root_appearances.insert(root, Appearances::Multiple);
|
||||
}
|
||||
RecursionVar {
|
||||
|
@ -606,9 +606,16 @@ fn variable_to_string(
|
|||
ctx.able_variables.sort();
|
||||
ctx.able_variables.dedup();
|
||||
for (i, (var, abilities)) in ctx.able_variables.into_iter().enumerate() {
|
||||
buf.push_str(if i == 0 { " | " } else { ", " });
|
||||
if i == 0 {
|
||||
buf.push(' ');
|
||||
buf.push_str(roc_parse::keyword::WHERE)
|
||||
} else {
|
||||
buf.push(',');
|
||||
}
|
||||
buf.push(' ');
|
||||
buf.push_str(var);
|
||||
buf.push_str(" has");
|
||||
buf.push(' ');
|
||||
buf.push_str(roc_parse::keyword::IMPLEMENTS);
|
||||
for (i, ability) in abilities.into_sorted_iter().enumerate() {
|
||||
if i > 0 {
|
||||
buf.push_str(" &");
|
||||
|
|
|
@ -2381,7 +2381,7 @@ pub enum Content {
|
|||
/// This can only happen when unified with a [Self::RigidAbleVar].
|
||||
FlexAbleVar(Option<SubsIndex<Lowercase>>, SubsSlice<Symbol>),
|
||||
/// Like a [Self::RigidVar], but is also bound to 1+ abilities.
|
||||
/// For example, "a has Hash".
|
||||
/// For example, "a implements Hash".
|
||||
RigidAbleVar(SubsIndex<Lowercase>, SubsSlice<Symbol>),
|
||||
/// name given to a recursion variable
|
||||
RecursionVar {
|
||||
|
|
|
@ -1687,7 +1687,7 @@ pub enum Type {
|
|||
}
|
||||
|
||||
/// A lambda set under an arrow in a ability member signature. For example, in
|
||||
/// Default has default : {} -> a | a has Default
|
||||
/// Default has default : {} -> a where a implements Default
|
||||
/// the unspecialized lambda set for the arrow "{} -> a" would be `a:default:1`.
|
||||
///
|
||||
/// Lambda sets in member signatures are never known until those members are specialized at a
|
||||
|
@ -3819,7 +3819,7 @@ fn write_debug_error_type_help(error_type: ErrorType, buf: &mut String, parens:
|
|||
buf.push('(');
|
||||
}
|
||||
buf.push_str(name.as_str());
|
||||
write!(buf, "has {symbol:?}").unwrap();
|
||||
write!(buf, "{} {:?}", roc_parse::keyword::IMPLEMENTS, symbol).unwrap();
|
||||
if write_parens {
|
||||
buf.push(')');
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# +opt infer:print_only_under_alias
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
F a : a | a has Hash
|
||||
F a : a where a implements Hash
|
||||
|
||||
main : F a -> F a
|
||||
#^^^^{-1} a -[[main(0)]]-> a | a has Hash
|
||||
#^^^^{-1} a -[[main(0)]]-> a where a implements Hash
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue