From 65c0d3b7bf57a9dfc452365f07018e1647ba512e Mon Sep 17 00:00:00 2001 From: rvcas Date: Sun, 9 May 2021 21:00:09 -0400 Subject: [PATCH 01/22] tests: add a test for global tags --- editor/tests/solve_expr2.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/editor/tests/solve_expr2.rs b/editor/tests/solve_expr2.rs index 8faa4bcacb..f162f3e577 100644 --- a/editor/tests/solve_expr2.rs +++ b/editor/tests/solve_expr2.rs @@ -238,3 +238,15 @@ fn constrain_list_of_records() { "List { x : Num * }", ) } + +#[test] +fn constrain_global_tag() { + infer_eq( + indoc!( + r#" + Foo + "# + ), + "[ Foo ]*", + ) +} From 8a1702f53590667215e15d91f599f8fa3a5c1ff4 Mon Sep 17 00:00:00 2001 From: rvcas Date: Sun, 9 May 2021 21:00:45 -0400 Subject: [PATCH 02/22] chore: bring TagName into scope --- editor/src/lang/constrain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/src/lang/constrain.rs b/editor/src/lang/constrain.rs index f9ae771a86..3cd3828f92 100644 --- a/editor/src/lang/constrain.rs +++ b/editor/src/lang/constrain.rs @@ -9,7 +9,7 @@ use crate::lang::{ use roc_can::expected::Expected; use roc_collections::all::{BumpMap, BumpMapDefault, Index}; -use roc_module::symbol::Symbol; +use roc_module::{ident::TagName, symbol::Symbol}; use roc_region::all::{Located, Region}; use roc_types::{ subs::Variable, From 3272e9ec9af0001dfc851bf99e59c5acd0eed59c Mon Sep 17 00:00:00 2001 From: rvcas Date: Sun, 9 May 2021 21:01:25 -0400 Subject: [PATCH 03/22] feat(Expr2): implement GlobalTag constraints --- editor/src/lang/constrain.rs | 62 ++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/editor/src/lang/constrain.rs b/editor/src/lang/constrain.rs index 3cd3828f92..14ab80bb69 100644 --- a/editor/src/lang/constrain.rs +++ b/editor/src/lang/constrain.rs @@ -216,6 +216,68 @@ pub fn constrain_expr<'a>( exists(arena, field_vars, And(constraints)) } } + Expr2::GlobalTag { + variant_var, + ext_var, + name, + arguments, + } => { + let mut flex_vars = BumpVec::with_capacity_in(arguments.len(), arena); + let types = PoolVec::with_capacity(arguments.len() as u32, env.pool); + let mut arg_cons = BumpVec::with_capacity_in(arguments.len(), arena); + + for (argument_node_id, type_node_id) in + arguments.iter_node_ids().zip(types.iter_node_ids()) + { + let (var, expr_node_id) = env.pool.get(argument_node_id); + + let argument_expr = env.pool.get(*expr_node_id); + + let arg_con = constrain_expr( + arena, + env, + argument_expr, + Expected::NoExpectation(Type2::Variable(*var)), + region, + ); + + arg_cons.push(arg_con); + flex_vars.push(*var); + + env.pool[type_node_id] = Type2::Variable(*var); + } + + let members = PoolVec::with_capacity(1, env.pool); + + for (member_node_id, member) in members.iter_node_ids().zip(vec![(*name, types)]) { + env.pool[member_node_id] = member; + } + + let union_con = Eq( + Type2::TagUnion(members, env.pool.add(Type2::Variable(*ext_var))), + expected.shallow_clone(), + Category::TagApply { + tag_name: TagName::Global(name.as_str(env.pool).into()), + args_count: arguments.len(), + }, + region, + ); + + let ast_con = Eq( + Type2::Variable(*variant_var), + expected, + Category::Storage(std::file!(), std::line!()), + region, + ); + + flex_vars.push(*variant_var); + flex_vars.push(*ext_var); + + arg_cons.push(union_con); + arg_cons.push(ast_con); + + exists(arena, flex_vars, And(arg_cons)) + } _ => todo!("implement constaints for {:?}", expr), } } From d8431eb6351c1669ba49c66e47948f9047462196 Mon Sep 17 00:00:00 2001 From: rvcas Date: Sun, 9 May 2021 21:02:07 -0400 Subject: [PATCH 04/22] feat(solve): add a different hack for TagName This is interesting because at the moment I don't have the information about whether or not this was a Global or Private Tag. This hack gets the tests passing but we probably want something better here. --- editor/src/lang/solve.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/editor/src/lang/solve.rs b/editor/src/lang/solve.rs index 3d7118e4f4..b50b9d4300 100644 --- a/editor/src/lang/solve.rs +++ b/editor/src/lang/solve.rs @@ -826,7 +826,7 @@ fn type_to_variable<'a>( let mut tag_vars = MutMap::default(); let ext = mempool.get(*ext_id); - for (_tag, tag_argument_types) in tags.iter(mempool) { + for (tag, tag_argument_types) in tags.iter(mempool) { let mut tag_argument_vars = Vec::with_capacity(tag_argument_types.len()); for arg_type in tag_argument_types.iter(mempool) { @@ -836,7 +836,7 @@ fn type_to_variable<'a>( } tag_vars.insert( - roc_module::ident::TagName::Private(Symbol::NUM_NUM), + roc_module::ident::TagName::Global(tag.as_str(mempool).into()), tag_argument_vars, ); } From de0b553431433526c94d609dc5fd998ed45fc385 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Mon, 10 May 2021 10:03:45 +0200 Subject: [PATCH 05/22] editor idea: show Roc cheat sheet on startup It would also be cool for demos. --- editor/editor-ideas.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/editor/editor-ideas.md b/editor/editor-ideas.md index 92a7a796e9..434e798ec2 100644 --- a/editor/editor-ideas.md +++ b/editor/editor-ideas.md @@ -86,6 +86,10 @@ e.g. you have a test `calculate_sum_test` that only uses the function `add`, whe * Mozilla DeepSpeech model runs fast, works pretty well for actions but would need additional training for code input. Possible to reuse [Mozilla common voice](https://github.com/common-voice/common-voice) for creating more "spoken code" data. +### Beginner-focused Features + + * A good screen to show on startup would be a Roc cheat sheet. + ### Productivity features * When refactoring; From d9d08a96e778353c00b400308011cda2ab89fdc3 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Mon, 10 May 2021 16:22:48 +0200 Subject: [PATCH 06/22] test anton-small-vm --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9d2b45afc9..7af13c74fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,14 +8,14 @@ env: jobs: prep-dependency-container: name: fmt, clippy, test --release - runs-on: self-hosted + runs-on: [self-hosted, i5-4690K] timeout-minutes: 60 env: FORCE_COLOR: 1 steps: - uses: actions/checkout@v2 with: - clean: "false" + clean: "true" - name: Earthly version run: earthly --version From 62dcb0f7eb24f5f682db8e101da7096188d8f1ce Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Mon, 10 May 2021 17:25:26 +0200 Subject: [PATCH 07/22] test anton big CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7af13c74fe..cba4a27f50 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ env: jobs: prep-dependency-container: name: fmt, clippy, test --release - runs-on: [self-hosted, i5-4690K] + runs-on: [self-hosted, i7-6700K] timeout-minutes: 60 env: FORCE_COLOR: 1 From dd1226665521265a24006ec317336d2a5b1e2560 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Mon, 10 May 2021 18:07:16 +0200 Subject: [PATCH 08/22] Removed preference to specific CI instance --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cba4a27f50..02ec518c95 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ env: jobs: prep-dependency-container: name: fmt, clippy, test --release - runs-on: [self-hosted, i7-6700K] + runs-on: [self-hosted] timeout-minutes: 60 env: FORCE_COLOR: 1 From b6fe84047ff94c6b203fd73c1c6de814127b9d1f Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 11 May 2021 11:00:24 +0200 Subject: [PATCH 09/22] minimal reproducible example --- editor/editor-ideas.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/editor/editor-ideas.md b/editor/editor-ideas.md index 434e798ec2..af603e1670 100644 --- a/editor/editor-ideas.md +++ b/editor/editor-ideas.md @@ -37,10 +37,11 @@ Nice collection of research on innovative editors, [link](https://futureofcoding * [VS code debug visualization](https://marketplace.visualstudio.com/items?itemName=hediet.debug-visualizer) * [Algorithm visualization for javascript](https://algorithm-visualizer.org) * [godbolt.org Compiler Explorer](https://godbolt.org/) -* Say you have a failing test that used to work, it would be very valuable to see all code that was changed that was used only by that test. -e.g. you have a test `calculate_sum_test` that only uses the function `add`, when the test fails you should be able to see a diff showing only what changed for the function `add`. It would also be great to have a diff of [expression values](https://homepages.cwi.nl/~storm/livelit/images/bret.png) Bret Victor style. An ambitious project would be to suggest or automatically try fixes based on these diffs. * [whitebox debug visualization](https://vimeo.com/483795097) * [Hest](https://ivanish.ca/hest-time-travel/) tool for making highly interactive simulations. +* Say you have a failing test that used to work, it would be very valuable to see all code that was changed that was used only by that test. +e.g. you have a test `calculate_sum_test` that only uses the function `add`, when the test fails you should be able to see a diff showing only what changed for the function `add`. It would also be great to have a diff of [expression values](https://homepages.cwi.nl/~storm/livelit/images/bret.png) Bret Victor style. An ambitious project would be to suggest or automatically try fixes based on these diffs. +* I think it could be possible to create a minimal reproduction of a program / block of code / code used by a single test. So for a failing unit test I would expect it to extract imports, the platform, types and functions that are necessary to run only that unit test and put them in a standalone roc project. This would be useful for sharing bugs with library+application authors and colleagues, for profiling or debugging with all "clutter" removed. ### Structured Editing From 5860fbf46b09e4859e989f141b26bcbd42a83d30 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 11 May 2021 14:47:50 +0200 Subject: [PATCH 10/22] Added Zeljko's editor inspiration. --- editor/editor-ideas.md | 1 + 1 file changed, 1 insertion(+) diff --git a/editor/editor-ideas.md b/editor/editor-ideas.md index af603e1670..6b9cf33db4 100644 --- a/editor/editor-ideas.md +++ b/editor/editor-ideas.md @@ -111,6 +111,7 @@ e.g. you have a test `calculate_sum_test` that only uses the function `add`, whe * Regex-like find and substitution based on plain english description and example (replacement). i.e. replace all `[` between double quotes with `{`. [Inspiration](https://alexmoltzau.medium.com/english-to-regex-thanks-to-gpt-3-13f03b68236e). * Show productivity tips based on behavior. i.e. if the user is scrolling through the error bar and clicking on the next error several times, show a tip with "go to next error" shortcut. * Command to "benchmark this function" or "benchmark this test" with flamegraph and execution time per line. +* Instead of going to definition and having to navigate back and forth between files, show an editable view inside the current file. See [this video](https://www.youtube.com/watch?v=EenznqbW5w8) #### Autocomplete From df2b9c34b65567eb9984eafbef99693723edcff3 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 11 May 2021 17:38:01 +0200 Subject: [PATCH 11/22] Added auto search on error idea --- editor/editor-ideas.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/editor/editor-ideas.md b/editor/editor-ideas.md index 6b9cf33db4..96105e983d 100644 --- a/editor/editor-ideas.md +++ b/editor/editor-ideas.md @@ -112,6 +112,12 @@ e.g. you have a test `calculate_sum_test` that only uses the function `add`, whe * Show productivity tips based on behavior. i.e. if the user is scrolling through the error bar and clicking on the next error several times, show a tip with "go to next error" shortcut. * Command to "benchmark this function" or "benchmark this test" with flamegraph and execution time per line. * Instead of going to definition and having to navigate back and forth between files, show an editable view inside the current file. See [this video](https://www.youtube.com/watch?v=EenznqbW5w8) +* When encountering an unexpected error in the user's program we show a button at the bottom to start an automated search on this error. The search would: + * look for similar errors in github issues of the relevant libraries + * search stackoverflow questions + * search a local history of previously encountered errors and fixes + * search through a database of our zullip questions + * ... #### Autocomplete From 9a8a70d1f9b5551e2417b97a265b3277f8df3f86 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 11 May 2021 18:15:14 +0200 Subject: [PATCH 12/22] More editor ideas --- editor/editor-ideas.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/editor/editor-ideas.md b/editor/editor-ideas.md index 96105e983d..1c62114555 100644 --- a/editor/editor-ideas.md +++ b/editor/editor-ideas.md @@ -89,7 +89,9 @@ e.g. you have a test `calculate_sum_test` that only uses the function `add`, whe ### Beginner-focused Features - * A good screen to show on startup would be a Roc cheat sheet. + * Show Roc cheat sheet on start-up. + * Plugin that translates short pieces of code from another programming language to Roc. [Relevant research](https://www.youtube.com/watch?v=xTzFJIknh7E). Someone who only knows the R language could get started with Roc with less friction if they could quickly define a list R style (`lst <- c(1,2,3)`) and get it translated to Roc. + * Being able to asses or ask the user for the amount of experience they have with Roc would be a valuable feature for recommending plugins, editor tips, recommending tutorials, automated error search (e.g searching common beginner errors first), ... . ### Productivity features From 7a878493bd31e3a6a4be1c9286352b9015c98f47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarjei=20Skj=C3=A6rset?= Date: Wed, 12 May 2021 09:29:04 +0200 Subject: [PATCH 13/22] Remove typo from Elm guide This part confused me when reading through the guide, but now it makes senes. Not sure if the flow of the text makes sense now though, as this same example is repeated twice in a row: ```elm { name : Str, email : Str }* -> Str ``` --- roc-for-elm-programmers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roc-for-elm-programmers.md b/roc-for-elm-programmers.md index d9850d63e4..bad83663cd 100644 --- a/roc-for-elm-programmers.md +++ b/roc-for-elm-programmers.md @@ -209,7 +209,7 @@ In Elm: In Roc: ``` -{ x : name : Str, email : Str }* -> Str +{ name : Str, email : Str }* -> Str ``` Here, the open record's type variable appears immediately after the `}`. From a7fefb70c13e5e72f7ac8196f161cbc9685f4deb Mon Sep 17 00:00:00 2001 From: rvcas Date: Wed, 12 May 2021 20:30:19 -0400 Subject: [PATCH 14/22] chore: use PoolVec::new(nodes, pool) This looks better than using the zip function and a raw for loop. --- editor/src/lang/constrain.rs | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/editor/src/lang/constrain.rs b/editor/src/lang/constrain.rs index 14ab80bb69..733bc09941 100644 --- a/editor/src/lang/constrain.rs +++ b/editor/src/lang/constrain.rs @@ -247,14 +247,11 @@ pub fn constrain_expr<'a>( env.pool[type_node_id] = Type2::Variable(*var); } - let members = PoolVec::with_capacity(1, env.pool); - - for (member_node_id, member) in members.iter_node_ids().zip(vec![(*name, types)]) { - env.pool[member_node_id] = member; - } - let union_con = Eq( - Type2::TagUnion(members, env.pool.add(Type2::Variable(*ext_var))), + Type2::TagUnion( + PoolVec::new(vec![(*name, types)].into_iter(), env.pool), + env.pool.add(Type2::Variable(*ext_var)), + ), expected.shallow_clone(), Category::TagApply { tag_name: TagName::Global(name.as_str(env.pool).into()), @@ -330,13 +327,7 @@ fn empty_list_type(pool: &mut Pool, var: Variable) -> Type2 { #[inline(always)] fn list_type(pool: &mut Pool, typ: Type2) -> Type2 { - let args = PoolVec::with_capacity(1, pool); - - for (arg_node_id, arg) in args.iter_node_ids().zip(vec![typ]) { - pool[arg_node_id] = arg; - } - - builtin_type(Symbol::LIST_LIST, args) + builtin_type(Symbol::LIST_LIST, PoolVec::new(vec![typ].into_iter(), pool)) } #[inline(always)] From 9d9c395d49237bd7c77950159d7bbc35d5b11532 Mon Sep 17 00:00:00 2001 From: rvcas Date: Thu, 13 May 2021 14:46:02 -0400 Subject: [PATCH 15/22] feat: reintroduce the Lookup constraint --- editor/src/lang/constrain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/src/lang/constrain.rs b/editor/src/lang/constrain.rs index 733bc09941..1c770cf15d 100644 --- a/editor/src/lang/constrain.rs +++ b/editor/src/lang/constrain.rs @@ -21,7 +21,7 @@ use roc_types::{ pub enum Constraint<'a> { Eq(Type2, Expected, Category, Region), // Store(Type, Variable, &'static str, u32), - // Lookup(Symbol, Expected, Region), + Lookup(Symbol, Expected, Region), // Pattern(Region, PatternCategory, Type, PExpected), And(BumpVec<'a, Constraint<'a>>), Let(&'a LetConstraint<'a>), From 11beb10e4956627c3a73a105fc3b21b00139691c Mon Sep 17 00:00:00 2001 From: rvcas Date: Thu, 13 May 2021 14:47:16 -0400 Subject: [PATCH 16/22] feat: port over the match arm for Lookup in solve --- editor/src/lang/solve.rs | 144 ++++++++++++++++++++------------------- 1 file changed, 74 insertions(+), 70 deletions(-) diff --git a/editor/src/lang/solve.rs b/editor/src/lang/solve.rs index b50b9d4300..fa5e0473a7 100644 --- a/editor/src/lang/solve.rs +++ b/editor/src/lang/solve.rs @@ -1,7 +1,7 @@ #![allow(clippy::all)] #![allow(dead_code)] use crate::lang::constrain::Constraint::{self, *}; -use crate::lang::pool::Pool; +use crate::lang::pool::{Pool, ShallowClone}; use crate::lang::types::Type2; use bumpalo::Bump; use roc_can::expected::{Expected, PExpected}; @@ -270,75 +270,79 @@ fn solve<'a>( // } // } // } - // Lookup(symbol, expectation, region) => { - // match env.vars_by_symbol.get(&symbol) { - // Some(var) => { - // // Deep copy the vars associated with this symbol before unifying them. - // // Otherwise, suppose we have this: - // // - // // identity = \a -> a - // // - // // x = identity 5 - // // - // // When we call (identity 5), it's important that we not unify - // // on identity's original vars. If we do, the type of `identity` will be - // // mutated to be `Int -> Int` instead of `a -> `, which would be incorrect; - // // the type of `identity` is more general than that! - // // - // // Instead, we want to unify on a *copy* of its vars. If the copy unifies - // // successfully (in this case, to `Int -> Int`), we can use that to - // // infer the type of this lookup (in this case, `Int`) without ever - // // having mutated the original. - // // - // // If this Lookup is targeting a value in another module, - // // then we copy from that module's Subs into our own. If the value - // // is being looked up in this module, then we use our Subs as both - // // the source and destination. - // let actual = deep_copy_var(subs, rank, pools, *var); - // let expected = type_to_var( - // subs, - // rank, - // pools, - // cached_aliases, - // expectation.get_type_ref(), - // ); - // match unify(subs, actual, expected) { - // Success(vars) => { - // introduce(subs, rank, pools, &vars); - // - // state - // } - // - // Failure(vars, actual_type, expected_type) => { - // introduce(subs, rank, pools, &vars); - // - // let problem = TypeError::BadExpr( - // *region, - // Category::Lookup(*symbol), - // actual_type, - // expectation.clone().replace(expected_type), - // ); - // - // problems.push(problem); - // - // state - // } - // BadType(vars, problem) => { - // introduce(subs, rank, pools, &vars); - // - // problems.push(TypeError::BadType(problem)); - // - // state - // } - // } - // } - // None => { - // problems.push(TypeError::UnexposedLookup(*symbol)); - // - // state - // } - // } - // } + Lookup(symbol, expectation, region) => { + match env.vars_by_symbol.get(&symbol) { + Some(var) => { + // Deep copy the vars associated with this symbol before unifying them. + // Otherwise, suppose we have this: + // + // identity = \a -> a + // + // x = identity 5 + // + // When we call (identity 5), it's important that we not unify + // on identity's original vars. If we do, the type of `identity` will be + // mutated to be `Int -> Int` instead of `a -> `, which would be incorrect; + // the type of `identity` is more general than that! + // + // Instead, we want to unify on a *copy* of its vars. If the copy unifies + // successfully (in this case, to `Int -> Int`), we can use that to + // infer the type of this lookup (in this case, `Int`) without ever + // having mutated the original. + // + // If this Lookup is targeting a value in another module, + // then we copy from that module's Subs into our own. If the value + // is being looked up in this module, then we use our Subs as both + // the source and destination. + let actual = deep_copy_var(subs, rank, pools, *var); + + let expected = type_to_var( + arena, + mempool, + subs, + rank, + pools, + cached_aliases, + expectation.get_type_ref(), + ); + + match unify(subs, actual, expected) { + Success(vars) => { + introduce(subs, rank, pools, &vars); + + state + } + + Failure(vars, actual_type, expected_type) => { + introduce(subs, rank, pools, &vars); + + let problem = TypeError::BadExpr( + *region, + Category::Lookup(*symbol), + actual_type, + expectation.shallow_clone().replace(expected_type), + ); + + problems.push(problem); + + state + } + BadType(vars, problem) => { + introduce(subs, rank, pools, &vars); + + problems.push(TypeError::BadType(problem)); + + state + } + } + } + None => { + problems.push(TypeError::UnexposedLookup(*symbol)); + + state + } + } + } And(sub_constraints) => { let mut state = state; From fea2757554f0d5856167c27db147da91a7f4980d Mon Sep 17 00:00:00 2001 From: rvcas Date: Thu, 13 May 2021 14:47:48 -0400 Subject: [PATCH 17/22] feat(Expr2): implement Var(symbol) --- editor/src/lang/constrain.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/editor/src/lang/constrain.rs b/editor/src/lang/constrain.rs index 1c770cf15d..5eeb6ba2a1 100644 --- a/editor/src/lang/constrain.rs +++ b/editor/src/lang/constrain.rs @@ -52,6 +52,7 @@ pub fn constrain_expr<'a>( Expr2::SmallStr(_) => Eq(str_type(env.pool), expected, Category::Str, region), Expr2::Blank => True, Expr2::EmptyRecord => constrain_empty_record(expected, region), + Expr2::Var(symbol) => Lookup(*symbol, expected, region), Expr2::SmallInt { var, .. } => { let mut flex_vars = BumpVec::with_capacity_in(1, arena); From 89b509005343c9ad24ddd44c0a5cb32c01883237 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Fri, 14 May 2021 00:01:00 -0400 Subject: [PATCH 18/22] Use std::iter::once over vec![] and into_iter --- editor/src/lang/constrain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/src/lang/constrain.rs b/editor/src/lang/constrain.rs index 733bc09941..4745d6970f 100644 --- a/editor/src/lang/constrain.rs +++ b/editor/src/lang/constrain.rs @@ -249,7 +249,7 @@ pub fn constrain_expr<'a>( let union_con = Eq( Type2::TagUnion( - PoolVec::new(vec![(*name, types)].into_iter(), env.pool), + PoolVec::new(std::iter::once((*name, types)), env.pool), env.pool.add(Type2::Variable(*ext_var)), ), expected.shallow_clone(), From dc20612bbb8e528cb9d3a2107f4f176df247a93f Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Fri, 14 May 2021 09:26:39 +0200 Subject: [PATCH 19/22] Added Richard's Inquisitive code editor inspiration. --- editor/editor-ideas.md | 1 + 1 file changed, 1 insertion(+) diff --git a/editor/editor-ideas.md b/editor/editor-ideas.md index 1c62114555..c40bfd8140 100644 --- a/editor/editor-ideas.md +++ b/editor/editor-ideas.md @@ -138,6 +138,7 @@ e.g. you have a test `calculate_sum_test` that only uses the function `add`, whe * [Codota](https://www.codota.com) AI autocomplete and example searching. * [Aroma](https://ai.facebook.com/blog/aroma-ml-for-code-recommendation) showing examples similar to current code. * [MISM](https://arxiv.org/abs/2006.05265) neural network based code similarity scoring. +* [Inquisitive code editor](https://web.eecs.utk.edu/~azh/blog/inquisitivecodeeditor.html) Interactive bug detection with doc+test generation. ### Non-Code Related Inspiration From 087ee18f098b904da2515e6d81fe70f5e81241be Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 14 May 2021 12:42:25 +0200 Subject: [PATCH 20/22] use macros in preparation for lambda set inference --- compiler/builtins/src/std.rs | 1089 +++++++++++++++------------------- 1 file changed, 486 insertions(+), 603 deletions(-) diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index e7f40f2b7d..60f15bcd8d 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -68,28 +68,53 @@ const TOP_LEVEL_CLOSURE_VAR: VarId = VarId::from_u32(5); pub fn types() -> MutMap { let mut types = HashMap::with_capacity_and_hasher(NUM_BUILTIN_IMPORTS, default_hasher()); - let mut add_type = |symbol, typ| { - debug_assert!( - !types.contains_key(&symbol), - "Duplicate type definition for {:?}", - symbol - ); + macro_rules! add_type { + ($symbol:expr, $typ:expr $(,)?) => {{ + debug_assert!( + !types.contains_key(&$symbol), + "Duplicate type definition for {:?}", + $symbol + ); - // TODO instead of using Region::zero for all of these, - // instead use the Region where they were defined in their - // source .roc files! This can give nicer error messages. - types.insert(symbol, (typ, Region::zero())); - }; + // TODO instead of using Region::zero for all of these, + // instead use the Region where they were defined in their + // source .roc files! This can give nicer error messages. + types.insert($symbol, ($typ, Region::zero())); + }}; + } + + macro_rules! add_top_level_function_type { + ($symbol:expr, $arguments:expr, $result:expr $(,)?) => {{ + debug_assert!( + !types.contains_key(&$symbol), + "Duplicate type definition for {:?}", + $symbol + ); + + let ext = Box::new(SolvedType::Flex(TOP_LEVEL_CLOSURE_VAR)); + // in the future, we will enable the line below + // let closure_var = Box::new(SolvedType::TagUnion( + // vec![(TagName::Closure($symbol), vec![])], + // ext, + // )); + let closure_var = ext; + + let typ = SolvedType::Func($arguments, closure_var, $result); + + // TODO instead of using Region::zero for all of these, + // instead use the Region where they were defined in their + // source .roc files! This can give nicer error messages. + types.insert($symbol, (typ, Region::zero())); + }}; + } // Num module // add or (+) : Num a, Num a -> Num a - add_type( + add_top_level_function_type!( Symbol::NUM_ADD, - top_level_function( - vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], - Box::new(num_type(flex(TVAR1))), - ), + vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], + Box::new(num_type(flex(TVAR1))), ); fn overflow() -> SolvedType { @@ -100,190 +125,171 @@ pub fn types() -> MutMap { } // addChecked : Num a, Num a -> Result (Num a) [ Overflow ]* - add_type( + add_top_level_function_type!( Symbol::NUM_ADD_CHECKED, - top_level_function( - vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], - Box::new(result_type(num_type(flex(TVAR1)), overflow())), - ), + vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], + Box::new(result_type(num_type(flex(TVAR1)), overflow())), ); // addWrap : Int range, Int range -> Int range - add_type( + add_top_level_function_type!( Symbol::NUM_ADD_WRAP, - top_level_function( - vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], - Box::new(int_type(flex(TVAR1))), - ), + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR1))), ); // sub or (-) : Num a, Num a -> Num a - add_type( + add_top_level_function_type!( Symbol::NUM_SUB, - top_level_function( - vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], - Box::new(num_type(flex(TVAR1))), - ), + vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], + Box::new(num_type(flex(TVAR1))), ); // subWrap : Int range, Int range -> Int range - add_type( + add_top_level_function_type!( Symbol::NUM_SUB_WRAP, - top_level_function( - vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], - Box::new(int_type(flex(TVAR1))), - ), + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR1))), ); // subChecked : Num a, Num a -> Result (Num a) [ Overflow ]* - add_type( + add_top_level_function_type!( Symbol::NUM_SUB_CHECKED, - top_level_function( - vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], - Box::new(result_type(num_type(flex(TVAR1)), overflow())), - ), + vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], + Box::new(result_type(num_type(flex(TVAR1)), overflow())), ); // mul or (*) : Num a, Num a -> Num a - add_type( + add_top_level_function_type!( Symbol::NUM_MUL, - top_level_function( - vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], - Box::new(num_type(flex(TVAR1))), - ), + vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], + Box::new(num_type(flex(TVAR1))), ); // mulWrap : Int range, Int range -> Int range - add_type( + add_top_level_function_type!( Symbol::NUM_MUL_WRAP, - top_level_function( - vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], - Box::new(int_type(flex(TVAR1))), - ), + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR1))), ); // mulChecked : Num a, Num a -> Result (Num a) [ Overflow ]* - add_type( + add_top_level_function_type!( Symbol::NUM_MUL_CHECKED, - top_level_function( - vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], - Box::new(result_type(num_type(flex(TVAR1)), overflow())), - ), + vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], + Box::new(result_type(num_type(flex(TVAR1)), overflow())), ); // abs : Num a -> Num a - add_type( + add_top_level_function_type!( Symbol::NUM_ABS, - top_level_function(vec![num_type(flex(TVAR1))], Box::new(num_type(flex(TVAR1)))), + vec![num_type(flex(TVAR1))], + Box::new(num_type(flex(TVAR1))) ); // neg : Num a -> Num a - add_type( + add_top_level_function_type!( Symbol::NUM_NEG, - top_level_function(vec![num_type(flex(TVAR1))], Box::new(num_type(flex(TVAR1)))), + vec![num_type(flex(TVAR1))], + Box::new(num_type(flex(TVAR1))) ); // isEq or (==) : a, a -> Bool - add_type( + add_top_level_function_type!( Symbol::BOOL_EQ, - top_level_function(vec![flex(TVAR1), flex(TVAR1)], Box::new(bool_type())), + vec![flex(TVAR1), flex(TVAR1)], + Box::new(bool_type()) ); // isNeq or (!=) : a, a -> Bool - add_type( + add_top_level_function_type!( Symbol::BOOL_NEQ, - top_level_function(vec![flex(TVAR1), flex(TVAR1)], Box::new(bool_type())), + vec![flex(TVAR1), flex(TVAR1)], + Box::new(bool_type()) ); // isLt or (<) : Num a, Num a -> Bool - add_type( + add_top_level_function_type!( Symbol::NUM_LT, - top_level_function( - vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], - Box::new(bool_type()), - ), + vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], + Box::new(bool_type()), ); // isLte or (<=) : Num a, Num a -> Bool - add_type( + add_top_level_function_type!( Symbol::NUM_LTE, - top_level_function( - vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], - Box::new(bool_type()), - ), + vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], + Box::new(bool_type()), ); // isGt or (>) : Num a, Num a -> Bool - add_type( + add_top_level_function_type!( Symbol::NUM_GT, - top_level_function( - vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], - Box::new(bool_type()), - ), + vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], + Box::new(bool_type()), ); // isGte or (>=) : Num a, Num a -> Bool - add_type( + add_top_level_function_type!( Symbol::NUM_GTE, - top_level_function( - vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], - Box::new(bool_type()), - ), + vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], + Box::new(bool_type()), ); // compare : Num a, Num a -> [ LT, EQ, GT ] - add_type( + add_top_level_function_type!( Symbol::NUM_COMPARE, - top_level_function( - vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], - Box::new(ordering_type()), - ), + vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))], + Box::new(ordering_type()), ); // toFloat : Num * -> Float * - add_type( + add_top_level_function_type!( Symbol::NUM_TO_FLOAT, - top_level_function( - vec![num_type(flex(TVAR1))], - Box::new(float_type(flex(TVAR2))), - ), + vec![num_type(flex(TVAR1))], + Box::new(float_type(flex(TVAR2))), ); // isNegative : Num a -> Bool - add_type( + add_top_level_function_type!( Symbol::NUM_IS_NEGATIVE, - top_level_function(vec![num_type(flex(TVAR1))], Box::new(bool_type())), + vec![num_type(flex(TVAR1))], + Box::new(bool_type()) ); // isPositive : Num a -> Bool - add_type( + add_top_level_function_type!( Symbol::NUM_IS_POSITIVE, - top_level_function(vec![num_type(flex(TVAR1))], Box::new(bool_type())), + vec![num_type(flex(TVAR1))], + Box::new(bool_type()) ); // isZero : Num a -> Bool - add_type( + add_top_level_function_type!( Symbol::NUM_IS_ZERO, - top_level_function(vec![num_type(flex(TVAR1))], Box::new(bool_type())), + vec![num_type(flex(TVAR1))], + Box::new(bool_type()) ); // isEven : Num a -> Bool - add_type( + add_top_level_function_type!( Symbol::NUM_IS_EVEN, - top_level_function(vec![num_type(flex(TVAR1))], Box::new(bool_type())), + vec![num_type(flex(TVAR1))], + Box::new(bool_type()) ); // isOdd : Num a -> Bool - add_type( + add_top_level_function_type!( Symbol::NUM_IS_ODD, - top_level_function(vec![num_type(flex(TVAR1))], Box::new(bool_type())), + vec![num_type(flex(TVAR1))], + Box::new(bool_type()) ); // maxInt : Int range - add_type(Symbol::NUM_MAX_INT, int_type(flex(TVAR1))); + add_type!(Symbol::NUM_MAX_INT, int_type(flex(TVAR1))); // minInt : Int range - add_type(Symbol::NUM_MIN_INT, int_type(flex(TVAR1))); + add_type!(Symbol::NUM_MIN_INT, int_type(flex(TVAR1))); // div : Int, Int -> Result Int [ DivByZero ]* let div_by_zero = SolvedType::TagUnion( @@ -291,122 +297,99 @@ pub fn types() -> MutMap { Box::new(SolvedType::Wildcard), ); - add_type( + add_top_level_function_type!( Symbol::NUM_DIV_INT, - top_level_function( - vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], - Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())), - ), + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())), ); // bitwiseAnd : Int a, Int a -> Int a - add_type( + add_top_level_function_type!( Symbol::NUM_BITWISE_AND, - top_level_function( - vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], - Box::new(int_type(flex(TVAR1))), - ), + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR1))), ); // bitwiseXor : Int a, Int a -> Int a - add_type( + add_top_level_function_type!( Symbol::NUM_BITWISE_XOR, - top_level_function( - vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], - Box::new(int_type(flex(TVAR1))), - ), + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR1))), ); // bitwiseOr : Int a, Int a -> Int a - add_type( + add_top_level_function_type!( Symbol::NUM_BITWISE_OR, - top_level_function( - vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], - Box::new(int_type(flex(TVAR1))), - ), + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR1))), ); // shiftLeftBy : Int a, Int a -> Int a - add_type( + add_top_level_function_type!( Symbol::NUM_SHIFT_LEFT, - top_level_function( - vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], - Box::new(int_type(flex(TVAR1))), - ), + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR1))), ); // shiftRightBy : Int a, Int a -> Int a - add_type( + add_top_level_function_type!( Symbol::NUM_SHIFT_RIGHT, - top_level_function( - vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], - Box::new(int_type(flex(TVAR1))), - ), + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR1))), ); // shiftRightZfBy : Int a, Int a -> Int a - add_type( + add_top_level_function_type!( Symbol::NUM_SHIFT_RIGHT_ZERO_FILL, - top_level_function( - vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], - Box::new(int_type(flex(TVAR1))), - ), + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR1))), ); // intCast : Int a -> Int b - add_type( + add_top_level_function_type!( Symbol::NUM_INT_CAST, - top_level_function(vec![int_type(flex(TVAR1))], Box::new(int_type(flex(TVAR2)))), + vec![int_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR2))) ); // rem : Int a, Int a -> Result (Int a) [ DivByZero ]* - add_type( + add_top_level_function_type!( Symbol::NUM_REM, - top_level_function( - vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], - Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())), - ), + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())), ); // mod : Int a, Int a -> Result (Int a) [ DivByZero ]* - add_type( + add_top_level_function_type!( Symbol::NUM_MOD_INT, - top_level_function( - vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], - Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())), - ), + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())), ); // isMultipleOf : Int a, Int a -> Bool - add_type( + add_top_level_function_type!( Symbol::NUM_IS_MULTIPLE_OF, - top_level_function( - vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], - Box::new(bool_type()), - ), + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(bool_type()), ); // maxI128 : I128 - add_type(Symbol::NUM_MAX_I128, i128_type()); + add_type!(Symbol::NUM_MAX_I128, i128_type()); // Float module // div : Float a, Float a -> Float a - add_type( + add_top_level_function_type!( Symbol::NUM_DIV_FLOAT, - top_level_function( - vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))], - Box::new(result_type(float_type(flex(TVAR1)), div_by_zero.clone())), - ), + vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))], + Box::new(result_type(float_type(flex(TVAR1)), div_by_zero.clone())), ); // mod : Float a, Float a -> Result (Float a) [ DivByZero ]* - add_type( + add_top_level_function_type!( Symbol::NUM_MOD_FLOAT, - top_level_function( - vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))], - Box::new(result_type(float_type(flex(TVAR1)), div_by_zero)), - ), + vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))], + Box::new(result_type(float_type(flex(TVAR1)), div_by_zero)), ); // sqrt : Float a -> Float a @@ -415,12 +398,10 @@ pub fn types() -> MutMap { Box::new(SolvedType::Wildcard), ); - add_type( + add_top_level_function_type!( Symbol::NUM_SQRT, - top_level_function( - vec![float_type(flex(TVAR1))], - Box::new(result_type(float_type(flex(TVAR1)), sqrt_of_negative)), - ), + vec![float_type(flex(TVAR1))], + Box::new(result_type(float_type(flex(TVAR1)), sqrt_of_negative)), ); // log : Float a -> Float a @@ -429,205 +410,184 @@ pub fn types() -> MutMap { Box::new(SolvedType::Wildcard), ); - add_type( + add_top_level_function_type!( Symbol::NUM_LOG, - top_level_function( - vec![float_type(flex(TVAR1))], - Box::new(result_type(float_type(flex(TVAR1)), log_needs_positive)), - ), + vec![float_type(flex(TVAR1))], + Box::new(result_type(float_type(flex(TVAR1)), log_needs_positive)), ); // round : Float a -> Int b - add_type( + add_top_level_function_type!( Symbol::NUM_ROUND, - top_level_function( - vec![float_type(flex(TVAR1))], - Box::new(int_type(flex(TVAR2))), - ), + vec![float_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR2))), ); // sin : Float a -> Float a - add_type( + add_top_level_function_type!( Symbol::NUM_SIN, - top_level_function( - vec![float_type(flex(TVAR1))], - Box::new(float_type(flex(TVAR1))), - ), + vec![float_type(flex(TVAR1))], + Box::new(float_type(flex(TVAR1))), ); // cos : Float a -> Float a - add_type( + add_top_level_function_type!( Symbol::NUM_COS, - top_level_function( - vec![float_type(flex(TVAR1))], - Box::new(float_type(flex(TVAR1))), - ), + vec![float_type(flex(TVAR1))], + Box::new(float_type(flex(TVAR1))), ); // tan : Float a -> Float a - add_type( + add_top_level_function_type!( Symbol::NUM_TAN, - top_level_function( - vec![float_type(flex(TVAR1))], - Box::new(float_type(flex(TVAR1))), - ), + vec![float_type(flex(TVAR1))], + Box::new(float_type(flex(TVAR1))), ); // maxFloat : Float a - add_type(Symbol::NUM_MAX_FLOAT, float_type(flex(TVAR1))); + add_type!(Symbol::NUM_MAX_FLOAT, float_type(flex(TVAR1))); // minFloat : Float a - add_type(Symbol::NUM_MIN_FLOAT, float_type(flex(TVAR1))); + add_type!(Symbol::NUM_MIN_FLOAT, float_type(flex(TVAR1))); // pow : Float a, Float a -> Float a - add_type( + add_top_level_function_type!( Symbol::NUM_POW, - top_level_function( - vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))], - Box::new(float_type(flex(TVAR1))), - ), + vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))], + Box::new(float_type(flex(TVAR1))), ); // ceiling : Float a -> Int b - add_type( + add_top_level_function_type!( Symbol::NUM_CEILING, - top_level_function( - vec![float_type(flex(TVAR1))], - Box::new(int_type(flex(TVAR2))), - ), + vec![float_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR2))), ); // powInt : Int a, Int a -> Int a - add_type( + add_top_level_function_type!( Symbol::NUM_POW_INT, - top_level_function( - vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], - Box::new(int_type(flex(TVAR1))), - ), + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR1))), ); // floor : Float a -> Int b - add_type( + add_top_level_function_type!( Symbol::NUM_FLOOR, - top_level_function( - vec![float_type(flex(TVAR1))], - Box::new(int_type(flex(TVAR2))), - ), + vec![float_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR2))), ); // atan : Float a -> Float a - add_type( + add_top_level_function_type!( Symbol::NUM_ATAN, - top_level_function( - vec![float_type(flex(TVAR1))], - Box::new(float_type(flex(TVAR1))), - ), + vec![float_type(flex(TVAR1))], + Box::new(float_type(flex(TVAR1))), ); // acos : Float a -> Float a - add_type( + add_top_level_function_type!( Symbol::NUM_ACOS, - top_level_function( - vec![float_type(flex(TVAR1))], - Box::new(float_type(flex(TVAR1))), - ), + vec![float_type(flex(TVAR1))], + Box::new(float_type(flex(TVAR1))), ); // asin : Float a -> Float a - add_type( + add_top_level_function_type!( Symbol::NUM_ASIN, - top_level_function( - vec![float_type(flex(TVAR1))], - Box::new(float_type(flex(TVAR1))), - ), + vec![float_type(flex(TVAR1))], + Box::new(float_type(flex(TVAR1))), ); // Bool module // and : Bool, Bool -> Bool - add_type( + add_top_level_function_type!( Symbol::BOOL_AND, - top_level_function(vec![bool_type(), bool_type()], Box::new(bool_type())), + vec![bool_type(), bool_type()], + Box::new(bool_type()) ); // or : Bool, Bool -> Bool - add_type( + add_top_level_function_type!( Symbol::BOOL_OR, - top_level_function(vec![bool_type(), bool_type()], Box::new(bool_type())), + vec![bool_type(), bool_type()], + Box::new(bool_type()) ); // xor : Bool, Bool -> Bool - add_type( + add_top_level_function_type!( Symbol::BOOL_XOR, - top_level_function(vec![bool_type(), bool_type()], Box::new(bool_type())), + vec![bool_type(), bool_type()], + Box::new(bool_type()) ); // not : Bool -> Bool - add_type( - Symbol::BOOL_NOT, - top_level_function(vec![bool_type()], Box::new(bool_type())), - ); + add_top_level_function_type!(Symbol::BOOL_NOT, vec![bool_type()], Box::new(bool_type())); // Str module // Str.split : Str, Str -> List Str - add_type( + add_top_level_function_type!( Symbol::STR_SPLIT, - top_level_function( - vec![str_type(), str_type()], - Box::new(list_type(str_type())), - ), + vec![str_type(), str_type()], + Box::new(list_type(str_type())), ); // Str.concat : Str, Str -> Str - add_type( + add_top_level_function_type!( Symbol::STR_CONCAT, - top_level_function(vec![str_type(), str_type()], Box::new(str_type())), + vec![str_type(), str_type()], + Box::new(str_type()), ); // Str.joinWith : List Str, Str -> Str - add_type( + add_top_level_function_type!( Symbol::STR_JOIN_WITH, - top_level_function( - vec![list_type(str_type()), str_type()], - Box::new(str_type()), - ), + vec![list_type(str_type()), str_type()], + Box::new(str_type()), ); // isEmpty : Str -> Bool - add_type( + add_top_level_function_type!( Symbol::STR_IS_EMPTY, - top_level_function(vec![str_type()], Box::new(bool_type())), + vec![str_type()], + Box::new(bool_type()) ); // startsWith : Str, Str -> Bool - add_type( + add_top_level_function_type!( Symbol::STR_STARTS_WITH, - top_level_function(vec![str_type(), str_type()], Box::new(bool_type())), + vec![str_type(), str_type()], + Box::new(bool_type()) ); // startsWithCodePoint : Str, U32 -> Bool - add_type( + add_top_level_function_type!( Symbol::STR_STARTS_WITH_CODE_POINT, - top_level_function(vec![str_type(), u32_type()], Box::new(bool_type())), + vec![str_type(), u32_type()], + Box::new(bool_type()) ); // endsWith : Str, Str -> Bool - add_type( + add_top_level_function_type!( Symbol::STR_ENDS_WITH, - top_level_function(vec![str_type(), str_type()], Box::new(bool_type())), + vec![str_type(), str_type()], + Box::new(bool_type()) ); // countGraphemes : Str -> Nat - add_type( + add_top_level_function_type!( Symbol::STR_COUNT_GRAPHEMES, - top_level_function(vec![str_type()], Box::new(nat_type())), + vec![str_type()], + Box::new(nat_type()) ); // fromInt : Int a -> Str - add_type( + add_top_level_function_type!( Symbol::STR_FROM_INT, - top_level_function(vec![int_type(flex(TVAR1))], Box::new(str_type())), + vec![int_type(flex(TVAR1))], + Box::new(str_type()) ); // fromUtf8 : List U8 -> Result Str [ BadUtf8 Utf8Problem ]* @@ -640,24 +600,24 @@ pub fn types() -> MutMap { Box::new(SolvedType::Wildcard), ); - add_type( + add_top_level_function_type!( Symbol::STR_FROM_UTF8, - top_level_function( - vec![list_type(u8_type())], - Box::new(result_type(str_type(), bad_utf8)), - ), + vec![list_type(u8_type())], + Box::new(result_type(str_type(), bad_utf8)), ); // toBytes : Str -> List U8 - add_type( + add_top_level_function_type!( Symbol::STR_TO_BYTES, - top_level_function(vec![str_type()], Box::new(list_type(u8_type()))), + vec![str_type()], + Box::new(list_type(u8_type())) ); // fromFloat : Float a -> Str - add_type( + add_top_level_function_type!( Symbol::STR_FROM_FLOAT, - top_level_function(vec![float_type(flex(TVAR1))], Box::new(str_type())), + vec![float_type(flex(TVAR1))], + Box::new(str_type()) ); // List module @@ -668,12 +628,10 @@ pub fn types() -> MutMap { Box::new(SolvedType::Wildcard), ); - add_type( + add_top_level_function_type!( Symbol::LIST_GET, - top_level_function( - vec![list_type(flex(TVAR1)), nat_type()], - Box::new(result_type(flex(TVAR1), index_out_of_bounds)), - ), + vec![list_type(flex(TVAR1)), nat_type()], + Box::new(result_type(flex(TVAR1), index_out_of_bounds)), ); // first : List elem -> Result elem [ ListWasEmpty ]* @@ -682,92 +640,74 @@ pub fn types() -> MutMap { Box::new(SolvedType::Wildcard), ); - add_type( + add_top_level_function_type!( Symbol::LIST_FIRST, - top_level_function( - vec![list_type(flex(TVAR1))], - Box::new(result_type(flex(TVAR1), list_was_empty.clone())), - ), + vec![list_type(flex(TVAR1))], + Box::new(result_type(flex(TVAR1), list_was_empty.clone())), ); // last : List elem -> Result elem [ ListWasEmpty ]* - add_type( + add_top_level_function_type!( Symbol::LIST_LAST, - top_level_function( - vec![list_type(flex(TVAR1))], - Box::new(result_type(flex(TVAR1), list_was_empty)), - ), + vec![list_type(flex(TVAR1))], + Box::new(result_type(flex(TVAR1), list_was_empty)), ); // set : List elem, Nat, elem -> List elem - add_type( + add_top_level_function_type!( Symbol::LIST_SET, - top_level_function( - vec![list_type(flex(TVAR1)), nat_type(), flex(TVAR1)], - Box::new(list_type(flex(TVAR1))), - ), + vec![list_type(flex(TVAR1)), nat_type(), flex(TVAR1)], + Box::new(list_type(flex(TVAR1))), ); // concat : List elem, List elem -> List elem - add_type( + add_top_level_function_type!( Symbol::LIST_CONCAT, - top_level_function( - vec![list_type(flex(TVAR1)), list_type(flex(TVAR1))], - Box::new(list_type(flex(TVAR1))), - ), + vec![list_type(flex(TVAR1)), list_type(flex(TVAR1))], + Box::new(list_type(flex(TVAR1))), ); // contains : List elem, elem -> Bool - add_type( + add_top_level_function_type!( Symbol::LIST_CONTAINS, - top_level_function( - vec![list_type(flex(TVAR1)), flex(TVAR1)], - Box::new(bool_type()), - ), + vec![list_type(flex(TVAR1)), flex(TVAR1)], + Box::new(bool_type()), ); // sum : List (Num a) -> Num a - add_type( + add_top_level_function_type!( Symbol::LIST_SUM, - top_level_function( - vec![list_type(num_type(flex(TVAR1)))], - Box::new(num_type(flex(TVAR1))), - ), + vec![list_type(num_type(flex(TVAR1)))], + Box::new(num_type(flex(TVAR1))), ); // product : List (Num a) -> Num a - add_type( + add_top_level_function_type!( Symbol::LIST_PRODUCT, - top_level_function( - vec![list_type(num_type(flex(TVAR1)))], - Box::new(num_type(flex(TVAR1))), - ), + vec![list_type(num_type(flex(TVAR1)))], + Box::new(num_type(flex(TVAR1))), ); // walk : List elem, (elem -> accum -> accum), accum -> accum - add_type( + add_top_level_function_type!( Symbol::LIST_WALK, - top_level_function( - vec![ - list_type(flex(TVAR1)), - closure(vec![flex(TVAR1), flex(TVAR2)], TVAR3, Box::new(flex(TVAR2))), - flex(TVAR2), - ], - Box::new(flex(TVAR2)), - ), + vec![ + list_type(flex(TVAR1)), + closure(vec![flex(TVAR1), flex(TVAR2)], TVAR3, Box::new(flex(TVAR2))), + flex(TVAR2), + ], + Box::new(flex(TVAR2)), ); // walkBackwards : List elem, (elem -> accum -> accum), accum -> accum - add_type( + add_top_level_function_type!( Symbol::LIST_WALK_BACKWARDS, - top_level_function( - vec![ - list_type(flex(TVAR1)), - closure(vec![flex(TVAR1), flex(TVAR2)], TVAR3, Box::new(flex(TVAR2))), - flex(TVAR2), - ], - Box::new(flex(TVAR2)), - ), + vec![ + list_type(flex(TVAR1)), + closure(vec![flex(TVAR1), flex(TVAR2)], TVAR3, Box::new(flex(TVAR2))), + flex(TVAR2), + ], + Box::new(flex(TVAR2)), ); fn until_type(content: SolvedType) -> SolvedType { @@ -782,38 +722,35 @@ pub fn types() -> MutMap { } // walkUntil : List elem, (elem -> accum -> [ Continue accum, Stop accum ]), accum -> accum - add_type( + add_top_level_function_type!( Symbol::LIST_WALK_UNTIL, - top_level_function( - vec![ - list_type(flex(TVAR1)), - closure( - vec![flex(TVAR1), flex(TVAR2)], - TVAR3, - Box::new(until_type(flex(TVAR2))), - ), - flex(TVAR2), - ], - Box::new(flex(TVAR2)), - ), + vec![ + list_type(flex(TVAR1)), + closure( + vec![flex(TVAR1), flex(TVAR2)], + TVAR3, + Box::new(until_type(flex(TVAR2))), + ), + flex(TVAR2), + ], + Box::new(flex(TVAR2)), ); // keepIf : List elem, (elem -> Bool) -> List elem - add_type( + add_top_level_function_type!( Symbol::LIST_KEEP_IF, - top_level_function( - vec![ - list_type(flex(TVAR1)), - closure(vec![flex(TVAR1)], TVAR2, Box::new(bool_type())), - ], - Box::new(list_type(flex(TVAR1))), - ), + vec![ + list_type(flex(TVAR1)), + closure(vec![flex(TVAR1)], TVAR2, Box::new(bool_type())), + ], + Box::new(list_type(flex(TVAR1))), ); // keepOks : List before, (before -> Result after *) -> List after - add_type(Symbol::LIST_KEEP_OKS, { + { let_tvars! { star, cvar, before, after}; - top_level_function( + add_top_level_function_type!( + Symbol::LIST_KEEP_OKS, vec![ list_type(flex(before)), closure( @@ -824,12 +761,14 @@ pub fn types() -> MutMap { ], Box::new(list_type(flex(after))), ) - }); + }; // keepErrs: List before, (before -> Result * after) -> List after - add_type(Symbol::LIST_KEEP_ERRS, { + { let_tvars! { star, cvar, before, after}; - top_level_function( + + add_top_level_function_type!( + Symbol::LIST_KEEP_ERRS, vec![ list_type(flex(before)), closure( @@ -840,44 +779,43 @@ pub fn types() -> MutMap { ], Box::new(list_type(flex(after))), ) - }); + }; // range : Int a, Int a -> List (Int a) - add_type(Symbol::LIST_RANGE, { - top_level_function( - vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], - Box::new(list_type(int_type(flex(TVAR1)))), - ) - }); + add_top_level_function_type!( + Symbol::LIST_RANGE, + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(list_type(int_type(flex(TVAR1)))), + ); // map : List before, (before -> after) -> List after - add_type( + add_top_level_function_type!( Symbol::LIST_MAP, - top_level_function( - vec![ - list_type(flex(TVAR1)), - closure(vec![flex(TVAR1)], TVAR3, Box::new(flex(TVAR2))), - ], - Box::new(list_type(flex(TVAR2))), - ), + vec![ + list_type(flex(TVAR1)), + closure(vec![flex(TVAR1)], TVAR3, Box::new(flex(TVAR2))), + ], + Box::new(list_type(flex(TVAR2))), ); // mapWithIndex : List before, (Nat, before -> after) -> List after - add_type(Symbol::LIST_MAP_WITH_INDEX, { + { let_tvars! { cvar, before, after}; - top_level_function( + add_top_level_function_type!( + Symbol::LIST_MAP_WITH_INDEX, vec![ list_type(flex(before)), closure(vec![nat_type(), flex(before)], cvar, Box::new(flex(after))), ], Box::new(list_type(flex(after))), ) - }); + }; // map2 : List a, List b, (a, b -> c) -> List c - add_type(Symbol::LIST_MAP2, { + { let_tvars! {a, b, c, cvar}; - top_level_function( + add_top_level_function_type!( + Symbol::LIST_MAP2, vec![ list_type(flex(a)), list_type(flex(b)), @@ -885,13 +823,14 @@ pub fn types() -> MutMap { ], Box::new(list_type(flex(c))), ) - }); + }; - // map3 : List a, List b, List c, (a, b, c -> d) -> List d - add_type(Symbol::LIST_MAP3, { + { let_tvars! {a, b, c, d, cvar}; - top_level_function( + // map3 : List a, List b, List c, (a, b, c -> d) -> List d + add_top_level_function_type!( + Symbol::LIST_MAP3, vec![ list_type(flex(a)), list_type(flex(b)), @@ -900,114 +839,102 @@ pub fn types() -> MutMap { ], Box::new(list_type(flex(d))), ) - }); + }; // append : List elem, elem -> List elem - add_type( + add_top_level_function_type!( Symbol::LIST_APPEND, - top_level_function( - vec![list_type(flex(TVAR1)), flex(TVAR1)], - Box::new(list_type(flex(TVAR1))), - ), + vec![list_type(flex(TVAR1)), flex(TVAR1)], + Box::new(list_type(flex(TVAR1))), ); // prepend : List elem, elem -> List elem - add_type( + add_top_level_function_type!( Symbol::LIST_PREPEND, - top_level_function( - vec![list_type(flex(TVAR1)), flex(TVAR1)], - Box::new(list_type(flex(TVAR1))), - ), + vec![list_type(flex(TVAR1)), flex(TVAR1)], + Box::new(list_type(flex(TVAR1))), ); // join : List (List elem) -> List elem - add_type( + add_top_level_function_type!( Symbol::LIST_JOIN, - top_level_function( - vec![list_type(list_type(flex(TVAR1)))], - Box::new(list_type(flex(TVAR1))), - ), + vec![list_type(list_type(flex(TVAR1)))], + Box::new(list_type(flex(TVAR1))), ); // single : a -> List a - add_type( + add_top_level_function_type!( Symbol::LIST_SINGLE, - top_level_function(vec![flex(TVAR1)], Box::new(list_type(flex(TVAR1)))), + vec![flex(TVAR1)], + Box::new(list_type(flex(TVAR1))) ); // repeat : Nat, elem -> List elem - add_type( + add_top_level_function_type!( Symbol::LIST_REPEAT, - top_level_function( - vec![nat_type(), flex(TVAR1)], - Box::new(list_type(flex(TVAR1))), - ), + vec![nat_type(), flex(TVAR1)], + Box::new(list_type(flex(TVAR1))), ); // reverse : List elem -> List elem - add_type( + add_top_level_function_type!( Symbol::LIST_REVERSE, - top_level_function( - vec![list_type(flex(TVAR1))], - Box::new(list_type(flex(TVAR1))), - ), + vec![list_type(flex(TVAR1))], + Box::new(list_type(flex(TVAR1))), ); // len : List * -> Nat - add_type( + add_top_level_function_type!( Symbol::LIST_LEN, - top_level_function(vec![list_type(flex(TVAR1))], Box::new(nat_type())), + vec![list_type(flex(TVAR1))], + Box::new(nat_type()) ); // isEmpty : List * -> Bool - add_type( + add_top_level_function_type!( Symbol::LIST_IS_EMPTY, - top_level_function(vec![list_type(flex(TVAR1))], Box::new(bool_type())), + vec![list_type(flex(TVAR1))], + Box::new(bool_type()) ); // sortWith : List a, (a, a -> Ordering) -> List a - add_type( + add_top_level_function_type!( Symbol::LIST_SORT_WITH, - top_level_function( - vec![ - list_type(flex(TVAR1)), - closure( - vec![flex(TVAR1), flex(TVAR1)], - TVAR2, - Box::new(ordering_type()), - ), - ], - Box::new(list_type(flex(TVAR1))), - ), + vec![ + list_type(flex(TVAR1)), + closure( + vec![flex(TVAR1), flex(TVAR1)], + TVAR2, + Box::new(ordering_type()), + ), + ], + Box::new(list_type(flex(TVAR1))), ); // Dict module // Dict.hashTestOnly : Nat, v -> Nat - add_type( + add_top_level_function_type!( Symbol::DICT_TEST_HASH, - top_level_function(vec![u64_type(), flex(TVAR2)], Box::new(nat_type())), + vec![u64_type(), flex(TVAR2)], + Box::new(nat_type()) ); // len : Dict * * -> Nat - add_type( + add_top_level_function_type!( Symbol::DICT_LEN, - top_level_function( - vec![dict_type(flex(TVAR1), flex(TVAR2))], - Box::new(nat_type()), - ), + vec![dict_type(flex(TVAR1), flex(TVAR2))], + Box::new(nat_type()), ); // empty : Dict * * - add_type(Symbol::DICT_EMPTY, dict_type(flex(TVAR1), flex(TVAR2))); + add_type!(Symbol::DICT_EMPTY, dict_type(flex(TVAR1), flex(TVAR2))); // single : k, v -> Dict k v - add_type( + add_top_level_function_type!( Symbol::DICT_SINGLE, - top_level_function( - vec![flex(TVAR1), flex(TVAR2)], - Box::new(dict_type(flex(TVAR1), flex(TVAR2))), - ), + vec![flex(TVAR1), flex(TVAR2)], + Box::new(dict_type(flex(TVAR1), flex(TVAR2))), ); // get : Dict k v, k -> Result v [ KeyNotFound ]* @@ -1016,264 +943,220 @@ pub fn types() -> MutMap { Box::new(SolvedType::Wildcard), ); - add_type( + add_top_level_function_type!( Symbol::DICT_GET, - top_level_function( - vec![dict_type(flex(TVAR1), flex(TVAR2)), flex(TVAR1)], - Box::new(result_type(flex(TVAR2), key_not_found)), - ), + vec![dict_type(flex(TVAR1), flex(TVAR2)), flex(TVAR1)], + Box::new(result_type(flex(TVAR2), key_not_found)), ); // Dict.insert : Dict k v, k, v -> Dict k v - add_type( + add_top_level_function_type!( Symbol::DICT_INSERT, - top_level_function( - vec![ - dict_type(flex(TVAR1), flex(TVAR2)), - flex(TVAR1), - flex(TVAR2), - ], - Box::new(dict_type(flex(TVAR1), flex(TVAR2))), - ), + vec![ + dict_type(flex(TVAR1), flex(TVAR2)), + flex(TVAR1), + flex(TVAR2), + ], + Box::new(dict_type(flex(TVAR1), flex(TVAR2))), ); // Dict.remove : Dict k v, k -> Dict k v - add_type( + add_top_level_function_type!( Symbol::DICT_REMOVE, - top_level_function( - vec![dict_type(flex(TVAR1), flex(TVAR2)), flex(TVAR1)], - Box::new(dict_type(flex(TVAR1), flex(TVAR2))), - ), + vec![dict_type(flex(TVAR1), flex(TVAR2)), flex(TVAR1)], + Box::new(dict_type(flex(TVAR1), flex(TVAR2))), ); // Dict.contains : Dict k v, k -> Bool - add_type( + add_top_level_function_type!( Symbol::DICT_CONTAINS, - top_level_function( - vec![dict_type(flex(TVAR1), flex(TVAR2)), flex(TVAR1)], - Box::new(bool_type()), - ), + vec![dict_type(flex(TVAR1), flex(TVAR2)), flex(TVAR1)], + Box::new(bool_type()), ); // Dict.keys : Dict k v -> List k - add_type( + add_top_level_function_type!( Symbol::DICT_KEYS, - top_level_function( - vec![dict_type(flex(TVAR1), flex(TVAR2))], - Box::new(list_type(flex(TVAR1))), - ), + vec![dict_type(flex(TVAR1), flex(TVAR2))], + Box::new(list_type(flex(TVAR1))), ); // Dict.values : Dict k v -> List v - add_type( + add_top_level_function_type!( Symbol::DICT_VALUES, - top_level_function( - vec![dict_type(flex(TVAR1), flex(TVAR2))], - Box::new(list_type(flex(TVAR2))), - ), + vec![dict_type(flex(TVAR1), flex(TVAR2))], + Box::new(list_type(flex(TVAR2))), ); // Dict.union : Dict k v, Dict k v -> Dict k v - add_type( + add_top_level_function_type!( Symbol::DICT_UNION, - top_level_function( - vec![ - dict_type(flex(TVAR1), flex(TVAR2)), - dict_type(flex(TVAR1), flex(TVAR2)), - ], - Box::new(dict_type(flex(TVAR1), flex(TVAR2))), - ), + vec![ + dict_type(flex(TVAR1), flex(TVAR2)), + dict_type(flex(TVAR1), flex(TVAR2)), + ], + Box::new(dict_type(flex(TVAR1), flex(TVAR2))), ); // Dict.intersection : Dict k v, Dict k v -> Dict k v - add_type( + add_top_level_function_type!( Symbol::DICT_INTERSECTION, - top_level_function( - vec![ - dict_type(flex(TVAR1), flex(TVAR2)), - dict_type(flex(TVAR1), flex(TVAR2)), - ], - Box::new(dict_type(flex(TVAR1), flex(TVAR2))), - ), + vec![ + dict_type(flex(TVAR1), flex(TVAR2)), + dict_type(flex(TVAR1), flex(TVAR2)), + ], + Box::new(dict_type(flex(TVAR1), flex(TVAR2))), ); // Dict.difference : Dict k v, Dict k v -> Dict k v - add_type( + add_top_level_function_type!( Symbol::DICT_DIFFERENCE, - top_level_function( - vec![ - dict_type(flex(TVAR1), flex(TVAR2)), - dict_type(flex(TVAR1), flex(TVAR2)), - ], - Box::new(dict_type(flex(TVAR1), flex(TVAR2))), - ), + vec![ + dict_type(flex(TVAR1), flex(TVAR2)), + dict_type(flex(TVAR1), flex(TVAR2)), + ], + Box::new(dict_type(flex(TVAR1), flex(TVAR2))), ); // Dict.walk : Dict k v, (k, v, accum -> accum), accum -> accum - add_type( + add_top_level_function_type!( Symbol::DICT_WALK, - top_level_function( - vec![ - dict_type(flex(TVAR1), flex(TVAR2)), - closure( - vec![flex(TVAR1), flex(TVAR2), flex(TVAR3)], - TVAR4, - Box::new(flex(TVAR3)), - ), - flex(TVAR3), - ], - Box::new(flex(TVAR3)), - ), + vec![ + dict_type(flex(TVAR1), flex(TVAR2)), + closure( + vec![flex(TVAR1), flex(TVAR2), flex(TVAR3)], + TVAR4, + Box::new(flex(TVAR3)), + ), + flex(TVAR3), + ], + Box::new(flex(TVAR3)), ); // Set module // empty : Set a - add_type(Symbol::SET_EMPTY, set_type(flex(TVAR1))); + add_type!(Symbol::SET_EMPTY, set_type(flex(TVAR1))); // single : a -> Set a - add_type( + add_top_level_function_type!( Symbol::SET_SINGLE, - top_level_function(vec![flex(TVAR1)], Box::new(set_type(flex(TVAR1)))), + vec![flex(TVAR1)], + Box::new(set_type(flex(TVAR1))) ); // len : Set * -> Nat - add_type( + add_top_level_function_type!( Symbol::SET_LEN, - top_level_function(vec![set_type(flex(TVAR1))], Box::new(nat_type())), + vec![set_type(flex(TVAR1))], + Box::new(nat_type()) ); // toList : Set a -> List a - add_type( + add_top_level_function_type!( Symbol::SET_TO_LIST, - top_level_function( - vec![set_type(flex(TVAR1))], - Box::new(list_type(flex(TVAR1))), - ), + vec![set_type(flex(TVAR1))], + Box::new(list_type(flex(TVAR1))), ); - // fromList : Set a -> List a - add_type( + // fromList : List a -> Set a + add_top_level_function_type!( Symbol::SET_FROM_LIST, - top_level_function( - vec![list_type(flex(TVAR1))], - Box::new(set_type(flex(TVAR1))), - ), + vec![list_type(flex(TVAR1))], + Box::new(set_type(flex(TVAR1))), ); // union : Set a, Set a -> Set a - add_type( + add_top_level_function_type!( Symbol::SET_UNION, - top_level_function( - vec![set_type(flex(TVAR1)), set_type(flex(TVAR1))], - Box::new(set_type(flex(TVAR1))), - ), + vec![set_type(flex(TVAR1)), set_type(flex(TVAR1))], + Box::new(set_type(flex(TVAR1))), ); // difference : Set a, Set a -> Set a - add_type( + add_top_level_function_type!( Symbol::SET_DIFFERENCE, - top_level_function( - vec![set_type(flex(TVAR1)), set_type(flex(TVAR1))], - Box::new(set_type(flex(TVAR1))), - ), + vec![set_type(flex(TVAR1)), set_type(flex(TVAR1))], + Box::new(set_type(flex(TVAR1))), ); // intersection : Set a, Set a -> Set a - add_type( + add_top_level_function_type!( Symbol::SET_INTERSECTION, - top_level_function( - vec![set_type(flex(TVAR1)), set_type(flex(TVAR1))], - Box::new(set_type(flex(TVAR1))), - ), + vec![set_type(flex(TVAR1)), set_type(flex(TVAR1))], + Box::new(set_type(flex(TVAR1))), ); // Set.walk : Set a, (a, b -> b), b -> b - add_type( + add_top_level_function_type!( Symbol::SET_WALK, - top_level_function( - vec![ - set_type(flex(TVAR1)), - closure(vec![flex(TVAR1), flex(TVAR2)], TVAR3, Box::new(flex(TVAR2))), - flex(TVAR2), - ], - Box::new(flex(TVAR2)), - ), + vec![ + set_type(flex(TVAR1)), + closure(vec![flex(TVAR1), flex(TVAR2)], TVAR3, Box::new(flex(TVAR2))), + flex(TVAR2), + ], + Box::new(flex(TVAR2)), ); - add_type( + add_top_level_function_type!( Symbol::SET_INSERT, - top_level_function( - vec![set_type(flex(TVAR1)), flex(TVAR1)], - Box::new(set_type(flex(TVAR1))), - ), + vec![set_type(flex(TVAR1)), flex(TVAR1)], + Box::new(set_type(flex(TVAR1))), ); - add_type( + add_top_level_function_type!( Symbol::SET_REMOVE, - top_level_function( - vec![set_type(flex(TVAR1)), flex(TVAR1)], - Box::new(set_type(flex(TVAR1))), - ), + vec![set_type(flex(TVAR1)), flex(TVAR1)], + Box::new(set_type(flex(TVAR1))), ); - add_type( + add_top_level_function_type!( Symbol::SET_CONTAINS, - top_level_function( - vec![set_type(flex(TVAR1)), flex(TVAR1)], - Box::new(bool_type()), - ), + vec![set_type(flex(TVAR1)), flex(TVAR1)], + Box::new(bool_type()), ); // Result module // map : Result a err, (a -> b) -> Result b err - add_type( + add_top_level_function_type!( Symbol::RESULT_MAP, - top_level_function( - vec![ - result_type(flex(TVAR1), flex(TVAR3)), - closure(vec![flex(TVAR1)], TVAR4, Box::new(flex(TVAR2))), - ], - Box::new(result_type(flex(TVAR2), flex(TVAR3))), - ), + vec![ + result_type(flex(TVAR1), flex(TVAR3)), + closure(vec![flex(TVAR1)], TVAR4, Box::new(flex(TVAR2))), + ], + Box::new(result_type(flex(TVAR2), flex(TVAR3))), ); // mapErr : Result a x, (x -> y) -> Result a x - add_type( + add_top_level_function_type!( Symbol::RESULT_MAP_ERR, - top_level_function( - vec![ - result_type(flex(TVAR1), flex(TVAR3)), - closure(vec![flex(TVAR3)], TVAR4, Box::new(flex(TVAR2))), - ], - Box::new(result_type(flex(TVAR1), flex(TVAR2))), - ), + vec![ + result_type(flex(TVAR1), flex(TVAR3)), + closure(vec![flex(TVAR3)], TVAR4, Box::new(flex(TVAR2))), + ], + Box::new(result_type(flex(TVAR1), flex(TVAR2))), ); // after : Result a err, (a -> Result b err) -> Result b err - add_type( + add_top_level_function_type!( Symbol::RESULT_AFTER, - top_level_function( - vec![ - result_type(flex(TVAR1), flex(TVAR3)), - closure( - vec![flex(TVAR1)], - TVAR4, - Box::new(result_type(flex(TVAR2), flex(TVAR3))), - ), - ], - Box::new(result_type(flex(TVAR2), flex(TVAR3))), - ), + vec![ + result_type(flex(TVAR1), flex(TVAR3)), + closure( + vec![flex(TVAR1)], + TVAR4, + Box::new(result_type(flex(TVAR2), flex(TVAR3))), + ), + ], + Box::new(result_type(flex(TVAR2), flex(TVAR3))), ); // withDefault : Result a x, a -> a - add_type( + add_top_level_function_type!( Symbol::RESULT_WITH_DEFAULT, - top_level_function( - vec![result_type(flex(TVAR1), flex(TVAR3)), flex(TVAR1)], - Box::new(flex(TVAR1)), - ), + vec![result_type(flex(TVAR1), flex(TVAR3)), flex(TVAR1)], + Box::new(flex(TVAR1)), ); types From fd422ab1d234c1fdf829a7b77c2c7e8a851775bf Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 14 May 2021 12:49:15 +0200 Subject: [PATCH 21/22] remove dead code --- compiler/builtins/src/std.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index 60f15bcd8d..c0d8f9b39e 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -1167,15 +1167,6 @@ fn flex(tvar: VarId) -> SolvedType { SolvedType::Flex(tvar) } -#[inline(always)] -fn top_level_function(arguments: Vec, ret: Box) -> SolvedType { - SolvedType::Func( - arguments, - Box::new(SolvedType::Flex(TOP_LEVEL_CLOSURE_VAR)), - ret, - ) -} - #[inline(always)] fn closure(arguments: Vec, closure_var: VarId, ret: Box) -> SolvedType { SolvedType::Func(arguments, Box::new(SolvedType::Flex(closure_var)), ret) From e17d15f4f2186aa1db9b3ef78014d741ebd1d2f3 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Fri, 14 May 2021 16:16:55 +0200 Subject: [PATCH 22/22] Added nextjournal editor inspiration --- editor/editor-ideas.md | 1 + 1 file changed, 1 insertion(+) diff --git a/editor/editor-ideas.md b/editor/editor-ideas.md index c40bfd8140..41ff4dbfff 100644 --- a/editor/editor-ideas.md +++ b/editor/editor-ideas.md @@ -139,6 +139,7 @@ e.g. you have a test `calculate_sum_test` that only uses the function `add`, whe * [Aroma](https://ai.facebook.com/blog/aroma-ml-for-code-recommendation) showing examples similar to current code. * [MISM](https://arxiv.org/abs/2006.05265) neural network based code similarity scoring. * [Inquisitive code editor](https://web.eecs.utk.edu/~azh/blog/inquisitivecodeeditor.html) Interactive bug detection with doc+test generation. +* [NextJournal](https://nextjournal.com/joe-loco/command-bar?token=DpU6ewNQnLhYtVkwhs9GeX) Discoverable commands and shortcuts. ### Non-Code Related Inspiration