From 1f6b3fb39f8532d109323d2df085375df835bb8d Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Sat, 25 Nov 2023 19:22:14 +0100 Subject: [PATCH 001/105] smarter ci manager prototype --- .github/workflows/benchmarks.yml | 2 +- .github/workflows/ci_manager.yml | 50 +++++++++++++++++++ .../workflows/devtools_test_linux_x86_64.yml | 2 +- .../devtools_test_macos_apple_silicon.yml | 2 +- .github/workflows/macos_x86_64.yml | 2 +- .github/workflows/markdown_link_check.yml | 2 +- .github/workflows/nix_linux_arm64_cargo.yml | 2 +- .github/workflows/nix_linux_arm64_default.yml | 2 +- .github/workflows/nix_linux_x86_64.yml | 2 +- .github/workflows/nix_macos_apple_silicon.yml | 2 +- .github/workflows/nix_macos_x86_64.yml | 2 +- .github/workflows/ubuntu_x86_64.yml | 2 +- .github/workflows/windows_release_build.yml | 2 +- .github/workflows/windows_tests.yml | 2 +- 14 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/ci_manager.yml diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 4d016a3e3c..063b0a6a13 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -1,5 +1,5 @@ on: - pull_request: + workflow_call: name: Benchmarks diff --git a/.github/workflows/ci_manager.yml b/.github/workflows/ci_manager.yml new file mode 100644 index 0000000000..74ca105cc2 --- /dev/null +++ b/.github/workflows/ci_manager.yml @@ -0,0 +1,50 @@ +on: + pull_request: + +name: CI manager + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + check-changes: + runs-on: ubuntu-22.04 + outputs: + full_tests: ${{ steps.filter.outputs.full_tests }} + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Check for only .md changes + id: filter + run: | + if git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | grep -qvE '(\.md$)'; then + echo "::set-output name=full_tests::true" + else + echo "::set-output name=full_tests::false" + fi + + start-nix-linux-x86-64-tests: + needs: check-changes + if: needs.check-changes.full_tests == 'true' + uses: ./.github/workflows/nix_linux_x86_64.yml + + start-nix-macos-apple-silicon-tests: + needs: check-changes + if: needs.check-changes.full_tests == 'true' + uses: ./.github/workflows/nix_macos_apple_silicon.yml + + finish-full: + runs-on: ubuntu-22.04 + needs: [start-nix-linux-x86-64-tests, start-nix-macos-apple-silicon-tests] + steps: + - run: echo "all jobs succeeded!" + + finish-basic: + runs-on: ubuntu-22.04 + needs: [check-changes] + if: needs.check-changes.full_tests == 'false' + steps: + - run: echo "all jobs succeeded!" + \ No newline at end of file diff --git a/.github/workflows/devtools_test_linux_x86_64.yml b/.github/workflows/devtools_test_linux_x86_64.yml index bc4eb36b60..705af508e7 100644 --- a/.github/workflows/devtools_test_linux_x86_64.yml +++ b/.github/workflows/devtools_test_linux_x86_64.yml @@ -1,5 +1,5 @@ on: - pull_request: + workflow_call: name: devtools nix files test - linux diff --git a/.github/workflows/devtools_test_macos_apple_silicon.yml b/.github/workflows/devtools_test_macos_apple_silicon.yml index 874e2c026f..736bd57880 100644 --- a/.github/workflows/devtools_test_macos_apple_silicon.yml +++ b/.github/workflows/devtools_test_macos_apple_silicon.yml @@ -1,5 +1,5 @@ on: - pull_request: + workflow_call: name: devtools nix files test - macos diff --git a/.github/workflows/macos_x86_64.yml b/.github/workflows/macos_x86_64.yml index 809d7a02cf..a659ab8e89 100644 --- a/.github/workflows/macos_x86_64.yml +++ b/.github/workflows/macos_x86_64.yml @@ -1,5 +1,5 @@ on: - pull_request: + workflow_call: name: Macos x86-64 rust tests diff --git a/.github/workflows/markdown_link_check.yml b/.github/workflows/markdown_link_check.yml index 1b60da4f8c..70aca73ad7 100644 --- a/.github/workflows/markdown_link_check.yml +++ b/.github/workflows/markdown_link_check.yml @@ -1,5 +1,5 @@ on: - pull_request: + workflow_call: schedule: - cron: '0 9 * * *' # 9=9am utc+0 diff --git a/.github/workflows/nix_linux_arm64_cargo.yml b/.github/workflows/nix_linux_arm64_cargo.yml index 52dfde0a2e..54d5b2c155 100644 --- a/.github/workflows/nix_linux_arm64_cargo.yml +++ b/.github/workflows/nix_linux_arm64_cargo.yml @@ -1,5 +1,5 @@ on: - pull_request: + workflow_call: name: test cargo build on linux arm64 inside nix diff --git a/.github/workflows/nix_linux_arm64_default.yml b/.github/workflows/nix_linux_arm64_default.yml index be06485367..05e3854468 100644 --- a/.github/workflows/nix_linux_arm64_default.yml +++ b/.github/workflows/nix_linux_arm64_default.yml @@ -1,5 +1,5 @@ on: - pull_request: + workflow_call: name: test default.nix on linux arm64 diff --git a/.github/workflows/nix_linux_x86_64.yml b/.github/workflows/nix_linux_x86_64.yml index 417674e926..a4c2a159d8 100644 --- a/.github/workflows/nix_linux_x86_64.yml +++ b/.github/workflows/nix_linux_x86_64.yml @@ -1,5 +1,5 @@ on: - pull_request: + workflow_call: name: Nix linux x86_64 cargo test diff --git a/.github/workflows/nix_macos_apple_silicon.yml b/.github/workflows/nix_macos_apple_silicon.yml index f885c4ca7b..08c3b6877d 100644 --- a/.github/workflows/nix_macos_apple_silicon.yml +++ b/.github/workflows/nix_macos_apple_silicon.yml @@ -1,5 +1,5 @@ on: - pull_request: + workflow_call: name: Nix apple silicon cargo test diff --git a/.github/workflows/nix_macos_x86_64.yml b/.github/workflows/nix_macos_x86_64.yml index bad8246bb6..9635ea1648 100644 --- a/.github/workflows/nix_macos_x86_64.yml +++ b/.github/workflows/nix_macos_x86_64.yml @@ -1,5 +1,5 @@ on: - pull_request: + workflow_call: name: Nix macOS x86_64 cargo test diff --git a/.github/workflows/ubuntu_x86_64.yml b/.github/workflows/ubuntu_x86_64.yml index 462b297778..3bad79af0a 100644 --- a/.github/workflows/ubuntu_x86_64.yml +++ b/.github/workflows/ubuntu_x86_64.yml @@ -1,5 +1,5 @@ on: - pull_request: + workflow_call: name: CI diff --git a/.github/workflows/windows_release_build.yml b/.github/workflows/windows_release_build.yml index 3fbff61d00..3803555133 100644 --- a/.github/workflows/windows_release_build.yml +++ b/.github/workflows/windows_release_build.yml @@ -1,5 +1,5 @@ on: - pull_request: + workflow_call: name: windows - release build diff --git a/.github/workflows/windows_tests.yml b/.github/workflows/windows_tests.yml index 78f574be64..4f0ea34ba2 100644 --- a/.github/workflows/windows_tests.yml +++ b/.github/workflows/windows_tests.yml @@ -1,5 +1,5 @@ on: - pull_request: + workflow_call: name: windows - subset of tests From e5623a6a55242448a3c4a1e87a7330553b5d25b3 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Sat, 25 Nov 2023 19:47:16 +0100 Subject: [PATCH 002/105] fix deprecation --- .github/workflows/ci_manager.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci_manager.yml b/.github/workflows/ci_manager.yml index 74ca105cc2..c79fbfb8d0 100644 --- a/.github/workflows/ci_manager.yml +++ b/.github/workflows/ci_manager.yml @@ -20,19 +20,19 @@ jobs: id: filter run: | if git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | grep -qvE '(\.md$)'; then - echo "::set-output name=full_tests::true" + echo "run_tests=full" >> $GITHUB_STATE else - echo "::set-output name=full_tests::false" + echo "run_tests=basic" >> $GITHUB_STATE fi start-nix-linux-x86-64-tests: needs: check-changes - if: needs.check-changes.full_tests == 'true' + if: needs.check-changes.run_tests == 'full' uses: ./.github/workflows/nix_linux_x86_64.yml start-nix-macos-apple-silicon-tests: needs: check-changes - if: needs.check-changes.full_tests == 'true' + if: needs.check-changes.run_tests == 'full' uses: ./.github/workflows/nix_macos_apple_silicon.yml finish-full: @@ -44,7 +44,7 @@ jobs: finish-basic: runs-on: ubuntu-22.04 needs: [check-changes] - if: needs.check-changes.full_tests == 'false' + if: needs.check-changes.run_tests == 'basic' steps: - run: echo "all jobs succeeded!" \ No newline at end of file From b606e497d7d163883d7f92be903a52f8dcc50de9 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Sat, 25 Nov 2023 19:48:59 +0100 Subject: [PATCH 003/105] fix git diff --- .github/workflows/ci_manager.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_manager.yml b/.github/workflows/ci_manager.yml index c79fbfb8d0..6d75e561d4 100644 --- a/.github/workflows/ci_manager.yml +++ b/.github/workflows/ci_manager.yml @@ -19,7 +19,7 @@ jobs: - name: Check for only .md changes id: filter run: | - if git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | grep -qvE '(\.md$)'; then + if git diff --name-only origin/${{ github.base_ref }} HEAD | grep -qvE '(\.md$)'; then echo "run_tests=full" >> $GITHUB_STATE else echo "run_tests=basic" >> $GITHUB_STATE From fd395f5cbb199805a9a1b99db97a4202af5dd37d Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Sat, 25 Nov 2023 19:50:05 +0100 Subject: [PATCH 004/105] need fetch first --- .github/workflows/ci_manager.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci_manager.yml b/.github/workflows/ci_manager.yml index 6d75e561d4..e9424f1286 100644 --- a/.github/workflows/ci_manager.yml +++ b/.github/workflows/ci_manager.yml @@ -19,6 +19,7 @@ jobs: - name: Check for only .md changes id: filter run: | + git fetch origin ${{ github.base_ref }} if git diff --name-only origin/${{ github.base_ref }} HEAD | grep -qvE '(\.md$)'; then echo "run_tests=full" >> $GITHUB_STATE else From 94f9953a1e1bffa00bf3361cce8cdaa202cc544b Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Sat, 25 Nov 2023 19:52:09 +0100 Subject: [PATCH 005/105] forgot outputs --- .github/workflows/ci_manager.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci_manager.yml b/.github/workflows/ci_manager.yml index e9424f1286..d465936ff8 100644 --- a/.github/workflows/ci_manager.yml +++ b/.github/workflows/ci_manager.yml @@ -28,12 +28,12 @@ jobs: start-nix-linux-x86-64-tests: needs: check-changes - if: needs.check-changes.run_tests == 'full' + if: needs.check-changes.outputs.run_tests == 'full' uses: ./.github/workflows/nix_linux_x86_64.yml start-nix-macos-apple-silicon-tests: needs: check-changes - if: needs.check-changes.run_tests == 'full' + if: needs.check-changes.outputs.run_tests == 'full' uses: ./.github/workflows/nix_macos_apple_silicon.yml finish-full: @@ -45,7 +45,7 @@ jobs: finish-basic: runs-on: ubuntu-22.04 needs: [check-changes] - if: needs.check-changes.run_tests == 'basic' + if: needs.check-changes.outputs.run_tests == 'basic' steps: - run: echo "all jobs succeeded!" \ No newline at end of file From 85afcdd011ee16d4933d6184468f12be0b7a551a Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 25 Nov 2023 19:54:51 +0100 Subject: [PATCH 006/105] add clarifying comment to callee_saved --- crates/compiler/gen_dev/src/generic64/aarch64.rs | 1 + crates/compiler/gen_dev/src/generic64/x86_64.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/crates/compiler/gen_dev/src/generic64/aarch64.rs b/crates/compiler/gen_dev/src/generic64/aarch64.rs index 6f0a2d580c..cdb7a35d31 100644 --- a/crates/compiler/gen_dev/src/generic64/aarch64.rs +++ b/crates/compiler/gen_dev/src/generic64/aarch64.rs @@ -365,6 +365,7 @@ impl CallConv for AArch64C /// 213568: f90033fd str x29, [sp, #96] const SHADOW_SPACE_SIZE: u8 = 16; + // These are registers that a called function must save and restore if it wants to use them. #[inline(always)] fn general_callee_saved(reg: &AArch64GeneralReg) -> bool { matches!( diff --git a/crates/compiler/gen_dev/src/generic64/x86_64.rs b/crates/compiler/gen_dev/src/generic64/x86_64.rs index a79817127a..e44eab3ace 100644 --- a/crates/compiler/gen_dev/src/generic64/x86_64.rs +++ b/crates/compiler/gen_dev/src/generic64/x86_64.rs @@ -199,6 +199,7 @@ impl CallConv for X86_64Syste ]; const SHADOW_SPACE_SIZE: u8 = 0; + // These are registers that a called function must save and restore if it wants to use them. #[inline(always)] fn general_callee_saved(reg: &X86_64GeneralReg) -> bool { matches!( @@ -1409,6 +1410,8 @@ impl CallConv for X86_64Windo ]; const SHADOW_SPACE_SIZE: u8 = 32; + // These are registers that a called function must save and restore if it wants to use them. + // // Refer https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#callercallee-saved-registers // > The x64 ABI considers registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15, and XMM6-XMM15 nonvolatile. // > They must be saved and restored by a function that uses them. From c55c785833b05fed57278c0441d074282becb870 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Sat, 25 Nov 2023 20:03:14 +0100 Subject: [PATCH 007/105] fix job outputs --- .github/workflows/ci_manager.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci_manager.yml b/.github/workflows/ci_manager.yml index d465936ff8..c3b2a81e16 100644 --- a/.github/workflows/ci_manager.yml +++ b/.github/workflows/ci_manager.yml @@ -11,13 +11,13 @@ jobs: check-changes: runs-on: ubuntu-22.04 outputs: - full_tests: ${{ steps.filter.outputs.full_tests }} + run_tests: ${{ steps.filecheck.outputs.run_tests }} steps: - name: Checkout uses: actions/checkout@v3 - name: Check for only .md changes - id: filter + id: filecheck run: | git fetch origin ${{ github.base_ref }} if git diff --name-only origin/${{ github.base_ref }} HEAD | grep -qvE '(\.md$)'; then From f6fd3e4e1f87afccf4b7e1bc4e4e8cb47f2bcf51 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Sat, 25 Nov 2023 20:07:06 +0100 Subject: [PATCH 008/105] debugging skip reason --- .github/workflows/ci_manager.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci_manager.yml b/.github/workflows/ci_manager.yml index c3b2a81e16..5da36b5604 100644 --- a/.github/workflows/ci_manager.yml +++ b/.github/workflows/ci_manager.yml @@ -48,4 +48,14 @@ jobs: if: needs.check-changes.outputs.run_tests == 'basic' steps: - run: echo "all jobs succeeded!" + + + print-test-output: + runs-on: ubuntu-22.04 + needs: check-changes + steps: + - name: Print run_tests output + run: | + echo "run_tests output: ${{ needs.check-changes.outputs.run_tests }}" + \ No newline at end of file From b639afdb86f5ccf6929eb2aa7abc8b76c9e174c2 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Sat, 25 Nov 2023 20:09:51 +0100 Subject: [PATCH 009/105] more debugging --- .github/workflows/ci_manager.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci_manager.yml b/.github/workflows/ci_manager.yml index 5da36b5604..f7212161fd 100644 --- a/.github/workflows/ci_manager.yml +++ b/.github/workflows/ci_manager.yml @@ -21,11 +21,13 @@ jobs: run: | git fetch origin ${{ github.base_ref }} if git diff --name-only origin/${{ github.base_ref }} HEAD | grep -qvE '(\.md$)'; then - echo "run_tests=full" >> $GITHUB_STATE + echo "run_tests=full" >> $GITHUB_OUTPUT else - echo "run_tests=basic" >> $GITHUB_STATE + echo "run_tests=basic" >> $GITHUB_OUTPUT fi + - run: echo "debug output ${{ steps.filecheck.outputs.run_tests }}" + start-nix-linux-x86-64-tests: needs: check-changes if: needs.check-changes.outputs.run_tests == 'full' From 00d04644c57f1a5399d4a16af7ccefaeb6a60837 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Sat, 25 Nov 2023 20:14:14 +0100 Subject: [PATCH 010/105] try to fix cancel --- .github/workflows/nix_linux_x86_64.yml | 4 ---- .github/workflows/nix_macos_apple_silicon.yml | 3 --- 2 files changed, 7 deletions(-) diff --git a/.github/workflows/nix_linux_x86_64.yml b/.github/workflows/nix_linux_x86_64.yml index a4c2a159d8..f3f957f70d 100644 --- a/.github/workflows/nix_linux_x86_64.yml +++ b/.github/workflows/nix_linux_x86_64.yml @@ -3,10 +3,6 @@ on: name: Nix linux x86_64 cargo test -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - env: RUST_BACKTRACE: 1 diff --git a/.github/workflows/nix_macos_apple_silicon.yml b/.github/workflows/nix_macos_apple_silicon.yml index 08c3b6877d..0af9c73636 100644 --- a/.github/workflows/nix_macos_apple_silicon.yml +++ b/.github/workflows/nix_macos_apple_silicon.yml @@ -3,9 +3,6 @@ on: name: Nix apple silicon cargo test -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true env: RUST_BACKTRACE: 1 From 104c44a75477849635fa2d6a258a1fc66bb1e75d Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 25 Nov 2023 20:18:37 +0100 Subject: [PATCH 011/105] ensure that when a switch case uses a callee-saved register, that register gets stored/restored properly --- crates/compiler/gen_dev/src/generic64/mod.rs | 17 +++- .../compiler/gen_dev/src/generic64/storage.rs | 77 +++++++++++++------ 2 files changed, 67 insertions(+), 27 deletions(-) diff --git a/crates/compiler/gen_dev/src/generic64/mod.rs b/crates/compiler/gen_dev/src/generic64/mod.rs index 58d458aa4b..73a1146e2c 100644 --- a/crates/compiler/gen_dev/src/generic64/mod.rs +++ b/crates/compiler/gen_dev/src/generic64/mod.rs @@ -82,8 +82,8 @@ pub trait CallConv, - general_saved_regs: &[GeneralReg], - float_saved_regs: &[FloatReg], + saved_general_regs: &[GeneralReg], + saved_float_regs: &[FloatReg], requested_stack_size: i32, fn_call_stack_size: i32, ) -> i32; @@ -900,8 +900,11 @@ impl< let mut out = bumpalo::vec![in self.env.arena]; // Setup stack. - let used_general_regs = self.storage_manager.general_used_callee_saved_regs(); - let used_float_regs = self.storage_manager.float_used_callee_saved_regs(); + let (used_general_regs, used_float_regs) = self + .storage_manager + .used_callee_saved_regs + .as_vecs(self.env.arena); + let aligned_stack_size = CC::setup_stack( &mut out, &used_general_regs, @@ -1199,6 +1202,12 @@ impl< max_branch_stack_size = std::cmp::max(max_branch_stack_size, self.storage_manager.stack_size()); base_storage.update_fn_call_stack_size(self.storage_manager.fn_call_stack_size()); + + // make sure that used callee-saved registers get saved/restored even if used in only + // one of the branches of the switch + base_storage + .used_callee_saved_regs + .extend(&self.storage_manager.used_callee_saved_regs); } self.storage_manager = base_storage; self.literal_map = base_literal_map; diff --git a/crates/compiler/gen_dev/src/generic64/storage.rs b/crates/compiler/gen_dev/src/generic64/storage.rs index b9e260a80e..1c6b48e054 100644 --- a/crates/compiler/gen_dev/src/generic64/storage.rs +++ b/crates/compiler/gen_dev/src/generic64/storage.rs @@ -3,7 +3,7 @@ use crate::{ pointer_layouts, sign_extended_int_builtins, single_register_floats, single_register_int_builtins, single_register_integers, single_register_layouts, Env, }; -use bumpalo::collections::Vec; +use bumpalo::collections::{CollectIn, Vec}; use roc_builtins::bitcode::{FloatWidth, IntWidth}; use roc_collections::all::{MutMap, MutSet}; use roc_error_macros::{internal_error, todo_lambda_erasure}; @@ -118,10 +118,7 @@ pub struct StorageManager< general_used_regs: Vec<'a, (GeneralReg, Symbol)>, float_used_regs: Vec<'a, (FloatReg, Symbol)>, - // TODO: it probably would be faster to make these a list that linearly scans rather than hashing. - // used callee saved regs must be tracked for pushing and popping at the beginning/end of the function. - general_used_callee_saved_regs: MutSet, - float_used_callee_saved_regs: MutSet, + pub(crate) used_callee_saved_regs: UsedCalleeRegisters, free_stack_chunks: Vec<'a, (i32, u32)>, stack_size: u32, @@ -152,16 +149,62 @@ pub fn new_storage_manager< join_param_map: MutMap::default(), general_free_regs: bumpalo::vec![in env.arena], general_used_regs: bumpalo::vec![in env.arena], - general_used_callee_saved_regs: MutSet::default(), + // must be saved on entering a function, and restored before returning + used_callee_saved_regs: UsedCalleeRegisters::default(), float_free_regs: bumpalo::vec![in env.arena], float_used_regs: bumpalo::vec![in env.arena], - float_used_callee_saved_regs: MutSet::default(), free_stack_chunks: bumpalo::vec![in env.arena], stack_size: 0, fn_call_stack_size: 0, } } +// optimization idea: use a bitset +#[derive(Debug, Clone)] +pub(crate) struct UsedCalleeRegisters { + general: MutSet, + float: MutSet, +} + +impl UsedCalleeRegisters { + fn clear(&mut self) { + self.general.clear(); + self.float.clear(); + } + + fn insert_general(&mut self, reg: GeneralReg) -> bool { + self.general.insert(reg) + } + + fn insert_float(&mut self, reg: FloatReg) -> bool { + self.float.insert(reg) + } + + pub(crate) fn extend(&mut self, other: &Self) { + self.general.extend(other.general.iter().copied()); + self.float.extend(other.float.iter().copied()); + } + + pub(crate) fn as_vecs<'a>( + &self, + arena: &'a bumpalo::Bump, + ) -> (Vec<'a, GeneralReg>, Vec<'a, FloatReg>) { + ( + self.general.iter().copied().collect_in(arena), + self.float.iter().copied().collect_in(arena), + ) + } +} + +impl Default for UsedCalleeRegisters { + fn default() -> Self { + Self { + general: Default::default(), + float: Default::default(), + } + } +} + impl< 'a, 'r, @@ -175,16 +218,16 @@ impl< self.symbol_storage_map.clear(); self.allocation_map.clear(); self.join_param_map.clear(); - self.general_used_callee_saved_regs.clear(); + self.used_callee_saved_regs.clear(); self.general_free_regs.clear(); self.general_used_regs.clear(); self.general_free_regs .extend_from_slice(CC::GENERAL_DEFAULT_FREE_REGS); - self.float_used_callee_saved_regs.clear(); self.float_free_regs.clear(); self.float_used_regs.clear(); self.float_free_regs .extend_from_slice(CC::FLOAT_DEFAULT_FREE_REGS); + self.used_callee_saved_regs.clear(); self.free_stack_chunks.clear(); self.stack_size = 0; self.fn_call_stack_size = 0; @@ -198,18 +241,6 @@ impl< self.fn_call_stack_size } - pub fn general_used_callee_saved_regs(&self) -> Vec<'a, GeneralReg> { - let mut used_regs = bumpalo::vec![in self.env.arena]; - used_regs.extend(&self.general_used_callee_saved_regs); - used_regs - } - - pub fn float_used_callee_saved_regs(&self) -> Vec<'a, FloatReg> { - let mut used_regs = bumpalo::vec![in self.env.arena]; - used_regs.extend(&self.float_used_callee_saved_regs); - used_regs - } - /// Returns true if the symbol is storing a primitive value. pub fn is_stored_primitive(&self, sym: &Symbol) -> bool { matches!( @@ -223,7 +254,7 @@ impl< fn get_general_reg(&mut self, buf: &mut Vec<'a, u8>) -> GeneralReg { if let Some(reg) = self.general_free_regs.pop() { if CC::general_callee_saved(®) { - self.general_used_callee_saved_regs.insert(reg); + self.used_callee_saved_regs.insert_general(reg); } reg } else if !self.general_used_regs.is_empty() { @@ -240,7 +271,7 @@ impl< fn get_float_reg(&mut self, buf: &mut Vec<'a, u8>) -> FloatReg { if let Some(reg) = self.float_free_regs.pop() { if CC::float_callee_saved(®) { - self.float_used_callee_saved_regs.insert(reg); + self.used_callee_saved_regs.insert_float(reg); } reg } else if !self.float_used_regs.is_empty() { From 714404b0811f27e17181c5da81f595448af178ff Mon Sep 17 00:00:00 2001 From: Becker A Date: Sun, 26 Nov 2023 01:14:46 -0700 Subject: [PATCH 012/105] Fixed `roc format --stdin --stdout` to format output fixes #6088 Signed-off-by: Becker A. --- crates/cli/src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 8cb445379d..9d6fc8af81 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -333,7 +333,10 @@ fn main() -> io::Result<()> { } } FormatMode::WriteToStdout => { - std::io::stdout().lock().write_all(src.as_bytes()).unwrap(); + std::io::stdout() + .lock() + .write_all(formatted_src.as_bytes()) + .unwrap(); 0 } From 0a48962abe644678c222ed45a1567cd5966bd23d Mon Sep 17 00:00:00 2001 From: Elias Mulhall Date: Sun, 26 Nov 2023 08:28:47 -0500 Subject: [PATCH 013/105] replace unreachable! with internal_error! in expr canonicalization See https://github.com/roc-lang/roc/issues/2046 --- crates/compiler/can/src/expr.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/compiler/can/src/expr.rs b/crates/compiler/can/src/expr.rs index 7f173ff8fe..d33d353d60 100644 --- a/crates/compiler/can/src/expr.rs +++ b/crates/compiler/can/src/expr.rs @@ -1062,10 +1062,10 @@ pub fn canonicalize_expr<'a>( }) } ast::Expr::RecordBuilder(_) => { - unreachable!("RecordBuilder should have been desugared by now") + internal_error!("RecordBuilder should have been desugared by now") } ast::Expr::Backpassing(_, _, _) => { - unreachable!("Backpassing should have been desugared by now") + internal_error!("Backpassing should have been desugared by now") } ast::Expr::Closure(loc_arg_patterns, loc_body_expr) => { let (closure_data, output) = @@ -2338,10 +2338,10 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr { loc_answer.value } Some(_) => { - unreachable!("Tried to inline a non-function"); + internal_error!("Tried to inline a non-function"); } None => { - unreachable!( + internal_error!( "Tried to inline a builtin that wasn't registered: {:?}", symbol ); From 439ce1143c802488717b8971fd80a4055b742e43 Mon Sep 17 00:00:00 2001 From: Elias Mulhall Date: Sun, 26 Nov 2023 08:49:31 -0500 Subject: [PATCH 014/105] desugar patterns during canonicalization Traverse pattern ASTs and desugar two cases - Desugar optional record field default value expr. This expr might contain nodes that need to be desugared, such as binary operations. Failing to desugar this expr can cause an internal panic later in canonicalization. - Discard SpaceBefore and SpaceAfter nodes so that patterns can be destructured over multiple lines. Keeping these nodes can cause an internal panic later in canonicalization. Fixes [1]. [1]: https://github.com/roc-lang/roc/issues/5653. --- crates/compiler/can/src/operator.rs | 109 +++++++++++++++++++++++--- crates/compiler/can/tests/test_can.rs | 48 ++++++++++++ 2 files changed, 145 insertions(+), 12 deletions(-) diff --git a/crates/compiler/can/src/operator.rs b/crates/compiler/can/src/operator.rs index 0e45e69567..27a7feb040 100644 --- a/crates/compiler/can/src/operator.rs +++ b/crates/compiler/can/src/operator.rs @@ -8,7 +8,8 @@ use roc_module::called_via::{BinOp, CalledVia}; use roc_module::ident::ModuleName; use roc_parse::ast::Expr::{self, *}; use roc_parse::ast::{ - AssignedField, Collection, RecordBuilderField, StrLiteral, StrSegment, ValueDef, WhenBranch, + AssignedField, Collection, Pattern, RecordBuilderField, StrLiteral, StrSegment, ValueDef, + WhenBranch, }; use roc_region::all::{Loc, Region}; @@ -70,7 +71,10 @@ fn desugar_value_def<'a>(arena: &'a Bump, def: &'a ValueDef<'a>) -> ValueDef<'a> use ValueDef::*; match def { - Body(loc_pattern, loc_expr) => Body(loc_pattern, desugar_expr(arena, loc_expr)), + Body(loc_pattern, loc_expr) => Body( + desugar_loc_pattern(arena, loc_pattern), + desugar_expr(arena, loc_expr), + ), ann @ Annotation(_, _) => *ann, AnnotatedBody { ann_pattern, @@ -238,7 +242,10 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Loc>) -> &'a Loc } Closure(loc_patterns, loc_ret) => arena.alloc(Loc { region: loc_expr.region, - value: Closure(loc_patterns, desugar_expr(arena, loc_ret)), + value: Closure( + desugar_loc_patterns(arena, loc_patterns), + desugar_expr(arena, loc_ret), + ), }), Backpassing(loc_patterns, loc_body, loc_ret) => { // loc_patterns <- loc_body @@ -249,7 +256,8 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Loc>) -> &'a Loc let desugared_body = desugar_expr(arena, loc_body); let desugared_ret = desugar_expr(arena, loc_ret); - let closure = Expr::Closure(loc_patterns, desugared_ret); + let desugared_loc_patterns = desugar_loc_patterns(arena, loc_patterns); + let closure = Expr::Closure(desugared_loc_patterns, desugared_ret); let loc_closure = Loc::at(loc_expr.region, closure); match &desugared_body.value { @@ -352,10 +360,8 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Loc>) -> &'a Loc let mut desugared_branches = Vec::with_capacity_in(branches.len(), arena); for branch in branches.iter() { - let desugared = desugar_expr(arena, &branch.value); - - let mut alternatives = Vec::with_capacity_in(branch.patterns.len(), arena); - alternatives.extend(branch.patterns.iter().copied()); + let desugared_expr = desugar_expr(arena, &branch.value); + let desugared_patterns = desugar_loc_patterns(arena, branch.patterns); let desugared_guard = if let Some(guard) = &branch.guard { Some(*desugar_expr(arena, guard)) @@ -363,11 +369,9 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Loc>) -> &'a Loc None }; - let alternatives = alternatives.into_bump_slice(); - desugared_branches.push(&*arena.alloc(WhenBranch { - patterns: alternatives, - value: *desugared, + patterns: desugared_patterns, + value: *desugared_expr, guard: desugared_guard, })); } @@ -544,6 +548,87 @@ fn desugar_field<'a>( } } +fn desugar_loc_patterns<'a>( + arena: &'a Bump, + loc_patterns: &'a [Loc>], +) -> &'a [Loc>] { + Vec::from_iter_in( + loc_patterns.iter().map(|loc_pattern| Loc { + region: loc_pattern.region, + value: desugar_pattern(arena, loc_pattern.value), + }), + arena, + ) + .into_bump_slice() +} + +fn desugar_loc_pattern<'a>( + arena: &'a Bump, + loc_pattern: &'a Loc>, +) -> &'a Loc> { + arena.alloc(Loc { + region: loc_pattern.region, + value: desugar_pattern(arena, loc_pattern.value), + }) +} + +// Find `OptionalField`s and desugar the default value exprs. Also discard `SpaceBefore` and +// `SpaceAfter` nodes so that patterns can be destructured over multiple lines. +fn desugar_pattern<'a>(arena: &'a Bump, pattern: Pattern<'a>) -> Pattern<'a> { + use roc_parse::ast::Pattern::*; + + match pattern { + Identifier(_) + | Tag(_) + | OpaqueRef(_) + | NumLiteral(_) + | NonBase10Literal { .. } + | FloatLiteral(_) + | StrLiteral(_) + | Underscore(_) + | SingleQuote(_) + | ListRest(_) + | Malformed(_) + | MalformedIdent(_, _) + | QualifiedIdentifier { .. } => pattern, + + Apply(tag, arg_patterns) => { + // Skip desugaring the tag, it should either be a Tag or OpaqueRef + let desugared_arg_patterns = Vec::from_iter_in( + arg_patterns.iter().map(|arg_pattern| Loc { + region: arg_pattern.region, + value: desugar_pattern(arena, arg_pattern.value), + }), + arena, + ) + .into_bump_slice(); + + Apply(tag, desugared_arg_patterns) + } + RecordDestructure(field_patterns) => { + RecordDestructure(field_patterns.map_items(arena, |field_pattern| Loc { + region: field_pattern.region, + value: desugar_pattern(arena, field_pattern.value), + })) + } + RequiredField(name, field_pattern) => { + RequiredField(name, desugar_loc_pattern(arena, field_pattern)) + } + OptionalField(name, expr) => OptionalField(name, desugar_expr(arena, expr)), + Tuple(patterns) => Tuple(patterns.map_items(arena, |elem_pattern| Loc { + region: elem_pattern.region, + value: desugar_pattern(arena, elem_pattern.value), + })), + List(patterns) => List(patterns.map_items(arena, |elem_pattern| Loc { + region: elem_pattern.region, + value: desugar_pattern(arena, elem_pattern.value), + })), + As(sub_pattern, symbol) => As(desugar_loc_pattern(arena, sub_pattern), symbol), + SpaceBefore(sub_pattern, _spaces) => desugar_pattern(arena, *sub_pattern), + SpaceAfter(sub_pattern, _spaces) => desugar_pattern(arena, *sub_pattern), + } +} + struct RecordBuilderArg<'a> { closure: &'a Loc>, apply_exprs: Vec<'a, &'a Loc>>, diff --git a/crates/compiler/can/tests/test_can.rs b/crates/compiler/can/tests/test_can.rs index 2afe3eff29..4945c0ccf3 100644 --- a/crates/compiler/can/tests/test_can.rs +++ b/crates/compiler/can/tests/test_can.rs @@ -1231,6 +1231,54 @@ mod test_can { assert_eq!(problems, Vec::new()); } + #[test] + fn optional_field_with_binary_op() { + let src = indoc!( + r#" + { bar ? 1 + 1 } = {} + bar + "# + ); + let arena = Bump::new(); + let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); + + assert_eq!(problems, Vec::new()); + } + + #[test] + fn nested_optional_field_with_binary_op() { + let src = indoc!( + r#" + when { x: ([{}], "foo") } is + { x: ([{ bar ? 1 + 1 }], _) } -> bar + "# + ); + let arena = Bump::new(); + let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); + + assert_eq!(problems, Vec::new()); + } + + #[test] + fn multiline_record_pattern() { + let src = indoc!( + r#" + x = { a: 1, b: 2, c: 3 } + { + a, + b, + c, + } = x + + a + b + c + "# + ); + let arena = Bump::new(); + let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); + + assert_eq!(problems, Vec::new()); + } + #[test] fn issue_2534() { let src = indoc!( From d924125e6dd1bc3bd1eb99af00eda259e4cd06ba Mon Sep 17 00:00:00 2001 From: Elias Mulhall Date: Sun, 26 Nov 2023 20:12:44 -0500 Subject: [PATCH 015/105] remove unnecessary comment --- crates/compiler/can/src/operator.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/compiler/can/src/operator.rs b/crates/compiler/can/src/operator.rs index 27a7feb040..5692aa2eb6 100644 --- a/crates/compiler/can/src/operator.rs +++ b/crates/compiler/can/src/operator.rs @@ -572,8 +572,6 @@ fn desugar_loc_pattern<'a>( }) } -// Find `OptionalField`s and desugar the default value exprs. Also discard `SpaceBefore` and -// `SpaceAfter` nodes so that patterns can be destructured over multiple lines. fn desugar_pattern<'a>(arena: &'a Bump, pattern: Pattern<'a>) -> Pattern<'a> { use roc_parse::ast::Pattern::*; From 0ccc71389a0127e5e1a8e44e5f699e7d4165fe36 Mon Sep 17 00:00:00 2001 From: Elias Mulhall Date: Sun, 26 Nov 2023 20:14:32 -0500 Subject: [PATCH 016/105] move pattern desugar tests to test_mono --- crates/compiler/can/tests/test_can.rs | 48 ------------------- .../generated/multiline_record_pattern.txt | 15 ++++++ .../nested_optional_field_with_binary_op.txt | 23 +++++++++ .../optional_field_with_binary_op.txt | 10 ++++ crates/compiler/test_mono/src/tests.rs | 31 ++++++++++++ 5 files changed, 79 insertions(+), 48 deletions(-) create mode 100644 crates/compiler/test_mono/generated/multiline_record_pattern.txt create mode 100644 crates/compiler/test_mono/generated/nested_optional_field_with_binary_op.txt create mode 100644 crates/compiler/test_mono/generated/optional_field_with_binary_op.txt diff --git a/crates/compiler/can/tests/test_can.rs b/crates/compiler/can/tests/test_can.rs index 4945c0ccf3..2afe3eff29 100644 --- a/crates/compiler/can/tests/test_can.rs +++ b/crates/compiler/can/tests/test_can.rs @@ -1231,54 +1231,6 @@ mod test_can { assert_eq!(problems, Vec::new()); } - #[test] - fn optional_field_with_binary_op() { - let src = indoc!( - r#" - { bar ? 1 + 1 } = {} - bar - "# - ); - let arena = Bump::new(); - let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); - - assert_eq!(problems, Vec::new()); - } - - #[test] - fn nested_optional_field_with_binary_op() { - let src = indoc!( - r#" - when { x: ([{}], "foo") } is - { x: ([{ bar ? 1 + 1 }], _) } -> bar - "# - ); - let arena = Bump::new(); - let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); - - assert_eq!(problems, Vec::new()); - } - - #[test] - fn multiline_record_pattern() { - let src = indoc!( - r#" - x = { a: 1, b: 2, c: 3 } - { - a, - b, - c, - } = x - - a + b + c - "# - ); - let arena = Bump::new(); - let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); - - assert_eq!(problems, Vec::new()); - } - #[test] fn issue_2534() { let src = indoc!( diff --git a/crates/compiler/test_mono/generated/multiline_record_pattern.txt b/crates/compiler/test_mono/generated/multiline_record_pattern.txt new file mode 100644 index 0000000000..2e73bc5486 --- /dev/null +++ b/crates/compiler/test_mono/generated/multiline_record_pattern.txt @@ -0,0 +1,15 @@ +procedure Num.19 (#Attr.2, #Attr.3): + let Num.292 : I64 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Num.292; + +procedure Test.0 (): + let Test.7 : I64 = 1i64; + let Test.8 : I64 = 2i64; + let Test.9 : I64 = 3i64; + let Test.1 : {I64, I64, I64} = Struct {Test.7, Test.8, Test.9}; + let Test.2 : I64 = StructAtIndex 0 Test.1; + let Test.3 : I64 = StructAtIndex 1 Test.1; + let Test.4 : I64 = StructAtIndex 2 Test.1; + let Test.6 : I64 = CallByName Num.19 Test.2 Test.3; + let Test.5 : I64 = CallByName Num.19 Test.6 Test.4; + ret Test.5; diff --git a/crates/compiler/test_mono/generated/nested_optional_field_with_binary_op.txt b/crates/compiler/test_mono/generated/nested_optional_field_with_binary_op.txt new file mode 100644 index 0000000000..404f08f3d8 --- /dev/null +++ b/crates/compiler/test_mono/generated/nested_optional_field_with_binary_op.txt @@ -0,0 +1,23 @@ +procedure Num.19 (#Attr.2, #Attr.3): + let Num.291 : I64 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Num.291; + +procedure Test.0 (): + let Test.17 : {} = Struct {}; + let Test.15 : List {} = Array [Test.17]; + let Test.16 : Str = "foo"; + let Test.14 : {List {}, Str} = Struct {Test.15, Test.16}; + let Test.10 : List {} = StructAtIndex 0 Test.14; + dec Test.16; + let Test.11 : U64 = lowlevel ListLen Test.10; + dec Test.10; + let Test.12 : U64 = 1i64; + let Test.13 : Int1 = lowlevel Eq Test.11 Test.12; + if Test.13 then + let Test.5 : I64 = 1i64; + let Test.6 : I64 = 1i64; + let Test.2 : I64 = CallByName Num.19 Test.5 Test.6; + ret Test.2; + else + let Test.7 : I64 = 0i64; + ret Test.7; diff --git a/crates/compiler/test_mono/generated/optional_field_with_binary_op.txt b/crates/compiler/test_mono/generated/optional_field_with_binary_op.txt new file mode 100644 index 0000000000..d0bfce4f16 --- /dev/null +++ b/crates/compiler/test_mono/generated/optional_field_with_binary_op.txt @@ -0,0 +1,10 @@ +procedure Num.19 (#Attr.2, #Attr.3): + let Num.291 : I64 = lowlevel NumAdd #Attr.2 #Attr.3; + ret Num.291; + +procedure Test.0 (): + let Test.5 : {} = Struct {}; + let Test.3 : I64 = 1i64; + let Test.4 : I64 = 1i64; + let Test.1 : I64 = CallByName Num.19 Test.3 Test.4; + ret Test.1; diff --git a/crates/compiler/test_mono/src/tests.rs b/crates/compiler/test_mono/src/tests.rs index ae2a28ec5b..0f56a1f237 100644 --- a/crates/compiler/test_mono/src/tests.rs +++ b/crates/compiler/test_mono/src/tests.rs @@ -893,6 +893,37 @@ fn optional_when() { "# } +#[mono_test] +fn optional_field_with_binary_op() { + r#" + { bar ? 1 + 1 } = {} + bar + "# +} + +#[mono_test] +fn nested_optional_field_with_binary_op() { + r#" + when { x: ([{}], "foo") } is + { x: ([{ bar ? 1 + 1 }], _) } -> bar + _ -> 0 + "# +} + +#[mono_test] +fn multiline_record_pattern() { + r#" + x = { a: 1, b: 2, c: 3 } + { + a, + b, + c, + } = x + + a + b + c + "# +} + #[mono_test] fn nested_pattern_match() { r#" From 176ea22965651c1013cfa5c0e3e9e6f431b1af20 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Mon, 27 Nov 2023 11:43:00 +0100 Subject: [PATCH 017/105] fix sccache install https://github.com/mozilla/sccache/issues/1988 Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com> --- Earthfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Earthfile b/Earthfile index 50ddf63938..ae0df6e89c 100644 --- a/Earthfile +++ b/Earthfile @@ -34,7 +34,7 @@ install-zig-llvm: RUN apt -y install libssl-dev RUN OPENSSL_NO_VENDOR=1 cargo install wasm-pack # sccache - RUN cargo install sccache + RUN cargo install sccache --locked RUN sccache -V ENV RUSTC_WRAPPER=/usr/local/cargo/bin/sccache ENV SCCACHE_DIR=/earthbuild/sccache_dir From 32221a2e99af7f1d371578ad22b0ff0934713878 Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 27 Nov 2023 21:51:31 +0100 Subject: [PATCH 018/105] fix dropping the wrong argument for List.map when it captures --- crates/compiler/mono/src/code_gen_help/mod.rs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/crates/compiler/mono/src/code_gen_help/mod.rs b/crates/compiler/mono/src/code_gen_help/mod.rs index 7374cbb2cd..f8f76584bc 100644 --- a/crates/compiler/mono/src/code_gen_help/mod.rs +++ b/crates/compiler/mono/src/code_gen_help/mod.rs @@ -673,7 +673,25 @@ impl<'a> CallerProc<'a> { let argument_layouts = match capture_layout { None => passed_function.argument_layouts, - Some(_) => &passed_function.argument_layouts[1..], + Some(_capture_layout) => { + let capture_layout_index = passed_function.argument_layouts.len() - 1; + + #[cfg(debug_assertions)] + { + let passed_capture_layout = + passed_function.argument_layouts[capture_layout_index]; + let repr = layout_interner.get_repr(passed_capture_layout); + + if let LayoutRepr::LambdaSet(lambda_set) = repr { + assert!(layout_interner + .equiv(_capture_layout, lambda_set.runtime_representation())); + } else { + panic!("unexpected layout for capture argument"); + } + } + + &passed_function.argument_layouts[..capture_layout_index] + } }; let capture_symbol = ARG_SYMBOLS[0]; From d141237a17296cdd9ead3c1e73d1225a542f2f53 Mon Sep 17 00:00:00 2001 From: caryoscelus Date: Mon, 27 Nov 2023 19:10:24 +0000 Subject: [PATCH 019/105] Report lacking `to` while parsing app header --- crates/reporting/src/error/parse.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/crates/reporting/src/error/parse.rs b/crates/reporting/src/error/parse.rs index 2631bdf1f5..c4b03f8623 100644 --- a/crates/reporting/src/error/parse.rs +++ b/crates/reporting/src/error/parse.rs @@ -3515,6 +3515,31 @@ fn to_provides_report<'a>( EProvides::Space(error, pos) => to_space_report(alloc, lines, filename, &error, pos), + EProvides::IndentTo(pos) => { + let surroundings = Region::new(start, pos); + let region = LineColumnRegion::from_pos(lines.convert_pos(pos)); + + let doc = alloc.stack([ + alloc.reflow(r"I am partway through parsing a header, but I got stuck here:"), + alloc.region_with_subregion(lines.convert_region(surroundings), region), + alloc.concat([ + alloc.reflow("I am expecting the "), + alloc.keyword("to"), + alloc.reflow(" keyword next, like"), + ]), + alloc + .parser_suggestion("to pf") + .indent(4), + ]); + + Report { + filename, + doc, + title: "WEIRD PROVIDES".to_string(), + severity: Severity::RuntimeError, + } + } + _ => todo!("unhandled parse error {:?}", parse_problem), } } From 3332503f1d04faa57239fbe487bc16c0c09ed165 Mon Sep 17 00:00:00 2001 From: caryoscelus Date: Tue, 28 Nov 2023 02:18:50 +0000 Subject: [PATCH 020/105] Test reporting lack of `to` in app header --- crates/compiler/load/tests/test_reporting.rs | 27 ++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/crates/compiler/load/tests/test_reporting.rs b/crates/compiler/load/tests/test_reporting.rs index 4ff9230642..d9adf18f3d 100644 --- a/crates/compiler/load/tests/test_reporting.rs +++ b/crates/compiler/load/tests/test_reporting.rs @@ -5982,6 +5982,33 @@ In roc, functions are always written as a lambda, like{} ) } + #[test] + fn provides_missing_to_in_app_header() { + report_header_problem_as( + indoc!( + r#" + app "broken" + provides [main] + "# + ), + indoc!( + r#" + ── WEIRD PROVIDES ──────────────────────────────────────── /code/proj/Main.roc ─ + + I am partway through parsing a header, but I got stuck here: + + 1│ app "broken" + 2│ provides [main] + ^ + + I am expecting the `to` keyword next, like + + to pf + "# + ), + ) + } + #[test] fn platform_requires_rigids() { report_header_problem_as( From 2fc8e88ccada86564b603beeec4b11379e2f8eff Mon Sep 17 00:00:00 2001 From: caryoscelus Date: Tue, 28 Nov 2023 05:52:43 +0000 Subject: [PATCH 021/105] Report lacking platform name in app header --- crates/compiler/load/tests/test_reporting.rs | 27 ++++++++++++++++++++ crates/reporting/src/error/parse.rs | 21 +++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/crates/compiler/load/tests/test_reporting.rs b/crates/compiler/load/tests/test_reporting.rs index d9adf18f3d..cd763522ac 100644 --- a/crates/compiler/load/tests/test_reporting.rs +++ b/crates/compiler/load/tests/test_reporting.rs @@ -6009,6 +6009,33 @@ In roc, functions are always written as a lambda, like{} ) } + #[test] + fn provides_to_missing_platform_in_app_header() { + report_header_problem_as( + indoc!( + r#" + app "broken" + provides [main] to + "# + ), + indoc!( + r#" + ── WEIRD PROVIDES ──────────────────────────────────────── /code/proj/Main.roc ─ + + I am partway through parsing a header, but I got stuck here: + + 1│ app "broken" + 2│ provides [main] to + ^ + + I am expecting platform name, like + + to pf + "# + ), + ) + } + #[test] fn platform_requires_rigids() { report_header_problem_as( diff --git a/crates/reporting/src/error/parse.rs b/crates/reporting/src/error/parse.rs index c4b03f8623..4882dab163 100644 --- a/crates/reporting/src/error/parse.rs +++ b/crates/reporting/src/error/parse.rs @@ -3540,6 +3540,27 @@ fn to_provides_report<'a>( } } + EProvides::IndentListStart(pos) => { + let surroundings = Region::new(start, pos); + let region = LineColumnRegion::from_pos(lines.convert_pos(pos)); + + let doc = alloc.stack([ + alloc.reflow(r"I am partway through parsing a header, but I got stuck here:"), + alloc.region_with_subregion(lines.convert_region(surroundings), region), + alloc.reflow("I am expecting platform name, like"), + alloc + .parser_suggestion("to pf") + .indent(4), + ]); + + Report { + filename, + doc, + title: "WEIRD PROVIDES".to_string(), + severity: Severity::RuntimeError, + } + } + _ => todo!("unhandled parse error {:?}", parse_problem), } } From 73597778b9754238bb3d666a57888cd49c8103a7 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:41:54 +0100 Subject: [PATCH 022/105] minor wording change Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com> --- crates/compiler/load/tests/test_reporting.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/compiler/load/tests/test_reporting.rs b/crates/compiler/load/tests/test_reporting.rs index cd763522ac..9cf2f4bccc 100644 --- a/crates/compiler/load/tests/test_reporting.rs +++ b/crates/compiler/load/tests/test_reporting.rs @@ -6001,7 +6001,7 @@ In roc, functions are always written as a lambda, like{} 2│ provides [main] ^ - I am expecting the `to` keyword next, like + I am expecting the `to` keyword next, like: to pf "# @@ -6028,7 +6028,7 @@ In roc, functions are always written as a lambda, like{} 2│ provides [main] to ^ - I am expecting platform name, like + I am expecting the platform name next, like: to pf "# From ba1a1e9243265e92d1ec005af1b6aa374ad97a18 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:42:52 +0100 Subject: [PATCH 023/105] minor wording change Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com> --- crates/reporting/src/error/parse.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/reporting/src/error/parse.rs b/crates/reporting/src/error/parse.rs index 4882dab163..839da6c2f4 100644 --- a/crates/reporting/src/error/parse.rs +++ b/crates/reporting/src/error/parse.rs @@ -3525,7 +3525,7 @@ fn to_provides_report<'a>( alloc.concat([ alloc.reflow("I am expecting the "), alloc.keyword("to"), - alloc.reflow(" keyword next, like"), + alloc.reflow(" keyword next, like:"), ]), alloc .parser_suggestion("to pf") @@ -3547,7 +3547,7 @@ fn to_provides_report<'a>( let doc = alloc.stack([ alloc.reflow(r"I am partway through parsing a header, but I got stuck here:"), alloc.region_with_subregion(lines.convert_region(surroundings), region), - alloc.reflow("I am expecting platform name, like"), + alloc.reflow("I am expecting the platform name next, like:"), alloc .parser_suggestion("to pf") .indent(4), From 0bdda5d49ed94f9c9920b26b97f93bb5752d8257 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 28 Nov 2023 16:26:13 +0100 Subject: [PATCH 024/105] misc changes --- .github/workflows/ci_manager.yml | 24 ++++--------------- .github/workflows/markdown_link_check.yml | 2 +- .github/workflows/nix_linux_x86_64.yml | 4 ++++ .github/workflows/nix_macos_apple_silicon.yml | 3 +++ 4 files changed, 13 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci_manager.yml b/.github/workflows/ci_manager.yml index f7212161fd..abbb0057b4 100644 --- a/.github/workflows/ci_manager.yml +++ b/.github/workflows/ci_manager.yml @@ -3,10 +3,6 @@ on: name: CI manager -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - jobs: check-changes: runs-on: ubuntu-22.04 @@ -23,7 +19,7 @@ jobs: if git diff --name-only origin/${{ github.base_ref }} HEAD | grep -qvE '(\.md$)'; then echo "run_tests=full" >> $GITHUB_OUTPUT else - echo "run_tests=basic" >> $GITHUB_OUTPUT + echo "run_tests=none" >> $GITHUB_OUTPUT fi - run: echo "debug output ${{ steps.filecheck.outputs.run_tests }}" @@ -42,22 +38,12 @@ jobs: runs-on: ubuntu-22.04 needs: [start-nix-linux-x86-64-tests, start-nix-macos-apple-silicon-tests] steps: - - run: echo "all jobs succeeded!" + - run: echo "all workflows succeeded!" - finish-basic: + finish-none: runs-on: ubuntu-22.04 needs: [check-changes] - if: needs.check-changes.outputs.run_tests == 'basic' + if: needs.check-changes.outputs.run_tests == 'none' steps: - - run: echo "all jobs succeeded!" - - - print-test-output: - runs-on: ubuntu-22.04 - needs: check-changes - steps: - - name: Print run_tests output - run: | - echo "run_tests output: ${{ needs.check-changes.outputs.run_tests }}" - + - run: echo "Only non-code files changed. CI manager did not run any workflows." \ No newline at end of file diff --git a/.github/workflows/markdown_link_check.yml b/.github/workflows/markdown_link_check.yml index 70aca73ad7..1b60da4f8c 100644 --- a/.github/workflows/markdown_link_check.yml +++ b/.github/workflows/markdown_link_check.yml @@ -1,5 +1,5 @@ on: - workflow_call: + pull_request: schedule: - cron: '0 9 * * *' # 9=9am utc+0 diff --git a/.github/workflows/nix_linux_x86_64.yml b/.github/workflows/nix_linux_x86_64.yml index f3f957f70d..a4c2a159d8 100644 --- a/.github/workflows/nix_linux_x86_64.yml +++ b/.github/workflows/nix_linux_x86_64.yml @@ -3,6 +3,10 @@ on: name: Nix linux x86_64 cargo test +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: RUST_BACKTRACE: 1 diff --git a/.github/workflows/nix_macos_apple_silicon.yml b/.github/workflows/nix_macos_apple_silicon.yml index 0af9c73636..08c3b6877d 100644 --- a/.github/workflows/nix_macos_apple_silicon.yml +++ b/.github/workflows/nix_macos_apple_silicon.yml @@ -3,6 +3,9 @@ on: name: Nix apple silicon cargo test +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true env: RUST_BACKTRACE: 1 From abf4d1bf819822b145f6b576a379175de27b1f96 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 28 Nov 2023 16:48:52 +0100 Subject: [PATCH 025/105] set up all workflows --- .github/workflows/benchmarks.yml | 4 -- .github/workflows/ci_manager.yml | 56 ++++++++++++++++++- .../workflows/devtools_test_linux_x86_64.yml | 6 +- .../devtools_test_macos_apple_silicon.yml | 6 +- .github/workflows/macos_x86_64.yml | 4 -- .github/workflows/nix_linux_arm64_cargo.yml | 4 -- .github/workflows/nix_linux_arm64_default.yml | 4 -- .github/workflows/nix_linux_x86_64.yml | 4 -- .github/workflows/nix_macos_apple_silicon.yml | 4 -- .github/workflows/nix_macos_x86_64.yml | 4 -- .github/workflows/ubuntu_x86_64.yml | 4 -- .github/workflows/windows_release_build.yml | 4 -- .github/workflows/windows_tests.yml | 4 -- 13 files changed, 59 insertions(+), 49 deletions(-) diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 063b0a6a13..381477e925 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -3,10 +3,6 @@ on: name: Benchmarks -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - env: RUST_BACKTRACE: 1 ROC_NUM_WORKERS: 1 diff --git a/.github/workflows/ci_manager.yml b/.github/workflows/ci_manager.yml index abbb0057b4..6ac4d57843 100644 --- a/.github/workflows/ci_manager.yml +++ b/.github/workflows/ci_manager.yml @@ -3,6 +3,11 @@ on: name: CI manager +# cancel current runs when a new commit is pushed +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: check-changes: runs-on: ubuntu-22.04 @@ -12,11 +17,11 @@ jobs: - name: Checkout uses: actions/checkout@v3 - - name: Check for only .md changes + - name: Check if only css, html or md files changed id: filecheck run: | git fetch origin ${{ github.base_ref }} - if git diff --name-only origin/${{ github.base_ref }} HEAD | grep -qvE '(\.md$)'; then + if git diff --name-only origin/${{ github.base_ref }} HEAD | grep -qvE '(\.md$|\.css$|\.html$)'; then echo "run_tests=full" >> $GITHUB_OUTPUT else echo "run_tests=none" >> $GITHUB_OUTPUT @@ -29,14 +34,59 @@ jobs: if: needs.check-changes.outputs.run_tests == 'full' uses: ./.github/workflows/nix_linux_x86_64.yml + start-nix-linux-aarch64-build-default-test: + needs: check-changes + if: needs.check-changes.outputs.run_tests == 'full' + uses: ./.github/workflows/nix_linux_arm64_default.yml + + start-nix-linux-aarch64-cargo-build-test: + needs: check-changes + if: needs.check-changes.outputs.run_tests == 'full' + uses: ./.github/workflows/nix_linux_arm64_cargo.yml + start-nix-macos-apple-silicon-tests: needs: check-changes if: needs.check-changes.outputs.run_tests == 'full' uses: ./.github/workflows/nix_macos_apple_silicon.yml + start-macos-x86-64-tests: + needs: check-changes + if: needs.check-changes.outputs.run_tests == 'full' + uses: ./.github/workflows/ubuntu_x86_64.yml + + start-ubuntu-x86-64-tests: + needs: check-changes + if: needs.check-changes.outputs.run_tests == 'full' + uses: ./.github/workflows/ubuntu_x86_64.yml + + start-windows-release-build-test: + needs: check-changes + if: needs.check-changes.outputs.run_tests == 'full' + uses: ./.github/workflows/windows_release_build.yml + + start-windows-tests: + needs: check-changes + if: needs.check-changes.outputs.run_tests == 'full' + uses: ./.github/workflows/windows_tests.yml + + start-roc-benchmarks: + needs: check-changes + if: needs.check-changes.outputs.run_tests == 'full' + uses: ./.github/workflows/benchmarks.yml + finish-full: runs-on: ubuntu-22.04 - needs: [start-nix-linux-x86-64-tests, start-nix-macos-apple-silicon-tests] + needs: [ + start-nix-linux-x86-64-tests, + start-nix-linux-aarch64-build-default-test, + start-nix-linux-aarch64-cargo-build-test, + start-nix-macos-apple-silicon-tests, + start-macos-x86-64-tests, + start-ubuntu-x86-64-tests, + start-windows-release-build-test, + start-windows-tests, + start-roc-benchmarks + ] steps: - run: echo "all workflows succeeded!" diff --git a/.github/workflows/devtools_test_linux_x86_64.yml b/.github/workflows/devtools_test_linux_x86_64.yml index 705af508e7..7aa613b8e8 100644 --- a/.github/workflows/devtools_test_linux_x86_64.yml +++ b/.github/workflows/devtools_test_linux_x86_64.yml @@ -1,11 +1,11 @@ on: - workflow_call: + pull_request: name: devtools nix files test - linux concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: devtools-test-linux: diff --git a/.github/workflows/devtools_test_macos_apple_silicon.yml b/.github/workflows/devtools_test_macos_apple_silicon.yml index 736bd57880..2abed8eac4 100644 --- a/.github/workflows/devtools_test_macos_apple_silicon.yml +++ b/.github/workflows/devtools_test_macos_apple_silicon.yml @@ -1,11 +1,11 @@ on: - workflow_call: + pull_request: name: devtools nix files test - macos concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: devtools-test-macos: diff --git a/.github/workflows/macos_x86_64.yml b/.github/workflows/macos_x86_64.yml index a659ab8e89..a8b88390b4 100644 --- a/.github/workflows/macos_x86_64.yml +++ b/.github/workflows/macos_x86_64.yml @@ -3,10 +3,6 @@ on: name: Macos x86-64 rust tests -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - env: RUST_BACKTRACE: 1 diff --git a/.github/workflows/nix_linux_arm64_cargo.yml b/.github/workflows/nix_linux_arm64_cargo.yml index 54d5b2c155..488d6af721 100644 --- a/.github/workflows/nix_linux_arm64_cargo.yml +++ b/.github/workflows/nix_linux_arm64_cargo.yml @@ -3,10 +3,6 @@ on: name: test cargo build on linux arm64 inside nix -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - env: RUST_BACKTRACE: 1 diff --git a/.github/workflows/nix_linux_arm64_default.yml b/.github/workflows/nix_linux_arm64_default.yml index 05e3854468..0352fc3fd8 100644 --- a/.github/workflows/nix_linux_arm64_default.yml +++ b/.github/workflows/nix_linux_arm64_default.yml @@ -3,10 +3,6 @@ on: name: test default.nix on linux arm64 -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - env: RUST_BACKTRACE: 1 diff --git a/.github/workflows/nix_linux_x86_64.yml b/.github/workflows/nix_linux_x86_64.yml index a4c2a159d8..f3f957f70d 100644 --- a/.github/workflows/nix_linux_x86_64.yml +++ b/.github/workflows/nix_linux_x86_64.yml @@ -3,10 +3,6 @@ on: name: Nix linux x86_64 cargo test -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - env: RUST_BACKTRACE: 1 diff --git a/.github/workflows/nix_macos_apple_silicon.yml b/.github/workflows/nix_macos_apple_silicon.yml index 08c3b6877d..baac08bc4f 100644 --- a/.github/workflows/nix_macos_apple_silicon.yml +++ b/.github/workflows/nix_macos_apple_silicon.yml @@ -3,10 +3,6 @@ on: name: Nix apple silicon cargo test -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - env: RUST_BACKTRACE: 1 diff --git a/.github/workflows/nix_macos_x86_64.yml b/.github/workflows/nix_macos_x86_64.yml index 9635ea1648..8fde16b746 100644 --- a/.github/workflows/nix_macos_x86_64.yml +++ b/.github/workflows/nix_macos_x86_64.yml @@ -3,10 +3,6 @@ on: name: Nix macOS x86_64 cargo test -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - env: RUST_BACKTRACE: 1 diff --git a/.github/workflows/ubuntu_x86_64.yml b/.github/workflows/ubuntu_x86_64.yml index 3bad79af0a..d5c6338e0c 100644 --- a/.github/workflows/ubuntu_x86_64.yml +++ b/.github/workflows/ubuntu_x86_64.yml @@ -3,10 +3,6 @@ on: name: CI -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - env: RUST_BACKTRACE: 1 diff --git a/.github/workflows/windows_release_build.yml b/.github/workflows/windows_release_build.yml index 3803555133..ef67101b4f 100644 --- a/.github/workflows/windows_release_build.yml +++ b/.github/workflows/windows_release_build.yml @@ -3,10 +3,6 @@ on: name: windows - release build -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - env: RUST_BACKTRACE: 1 diff --git a/.github/workflows/windows_tests.yml b/.github/workflows/windows_tests.yml index 4f0ea34ba2..8271303b62 100644 --- a/.github/workflows/windows_tests.yml +++ b/.github/workflows/windows_tests.yml @@ -3,10 +3,6 @@ on: name: windows - subset of tests -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - env: RUST_BACKTRACE: 1 From 89ac46af9a8d2aa02630a6ff75969cbbd803abda Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 28 Nov 2023 17:51:34 +0100 Subject: [PATCH 026/105] test css change --- www/public/site.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/public/site.css b/www/public/site.css index 25ae78a5c7..f055665dcd 100644 --- a/www/public/site.css +++ b/www/public/site.css @@ -55,7 +55,7 @@ body { width: 100%; height: 100%; box-sizing: border-box; - overflow-x: hidden; /* This shouldn't be necessary, but without it, mobile has a right gutter. */ + overflow-x: hidden; /* This shouldn't be necessary, but without it mobile has a right gutter. */ } p { From 771e573aa0b599ed13c6aa6f794bd39e408c85c1 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 28 Nov 2023 17:56:01 +0100 Subject: [PATCH 027/105] test hello world breaking change --- examples/helloWorld.roc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/helloWorld.roc b/examples/helloWorld.roc index 50e600dd4e..a44ea172e3 100644 --- a/examples/helloWorld.roc +++ b/examples/helloWorld.roc @@ -1,5 +1,5 @@ app "helloWorld" - packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } + packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/OQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } imports [pf.Stdout] provides [main] to pf From 29f3ff002a74d969c32d0834e67168d46e0a9e59 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 28 Nov 2023 18:07:15 +0100 Subject: [PATCH 028/105] back to normal --- examples/helloWorld.roc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/helloWorld.roc b/examples/helloWorld.roc index a44ea172e3..50e600dd4e 100644 --- a/examples/helloWorld.roc +++ b/examples/helloWorld.roc @@ -1,5 +1,5 @@ app "helloWorld" - packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/OQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } + packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } imports [pf.Stdout] provides [main] to pf From 66d41af6a9d103e181e3fa9c9cc55a7f4bb19007 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Tue, 28 Nov 2023 13:25:00 -0500 Subject: [PATCH 029/105] Update sponsors --- README.md | 2 ++ www/content/index.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/README.md b/README.md index 619b596bf4..f1f6c83852 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ If you would like your company to become a corporate sponsor of Roc's developmen We'd also like to express our gratitude to our generous [individual sponsors](https://github.com/sponsors/roc-lang/)! A special thanks to those sponsoring $25/month or more: +* [Alex Binaei](https://github.com/mrmizz) +* [Jono Mallanyk](https://github.com/jonomallanyk) * [Chris Packett](https://github.com/chris-packett) * [James Birtles](https://github.com/jamesbirtles) * [Ivo Balbaert](https://github.com/Ivo-Balbaert) diff --git a/www/content/index.md b/www/content/index.md index fb0c5ba903..9e9a781c84 100644 --- a/www/content/index.md +++ b/www/content/index.md @@ -144,6 +144,8 @@ If you would like your organization to become an official sponsor of Roc's devel We'd also like to express our gratitude to our generous [individual sponsors](https://github.com/sponsors/roc-lang/)! A special thanks to those sponsoring $25/month or more:
    +
  • Alex Binaei +
  • Jono Mallanyk
  • Chris Packett
  • James Birtles
  • Ivo Balbaert
  • From 440a7d932d58b6813e84275ebd30ec45c49a34a6 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 29 Nov 2023 08:15:56 +1100 Subject: [PATCH 030/105] add pattern matching example fix heading --- www/content/tutorial.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/content/tutorial.md b/www/content/tutorial.md index f4e7f97b2f..0531dd7e0c 100644 --- a/www/content/tutorial.md +++ b/www/content/tutorial.md @@ -510,7 +510,7 @@ outside a record field. Optionality is a concept that exists only in record fields, and it's intended for the use case of config records like this. The ergonomics of destructuring mean this wouldn't be a good fit for data modeling, consider using a `Result` type instead. -## [Tags](#tags) {#tags} +## [Tags & Pattern Matching](#tags) {#tags} Sometimes we want to represent that something can have one of several values. For example: @@ -661,6 +661,8 @@ This can be both more concise and more efficient (at runtime) than calling [`Lis > **Note:** Each list pattern can only have one `..`, which is known as the "rest pattern" because it's where the _rest_ of the list goes. +See the [Pattern Matching example](https://www.roc-lang.org/examples/PatternMatching/README.html) which shows different ways to do pattern matching in Roc using tags, strings, and numbers. + ## [Booleans](#booleans) {#booleans} In many programming languages, `true` and `false` are special language keywords that refer to the two [boolean](https://en.wikipedia.org/wiki/Boolean_data_type) values. In Roc, booleans do not get special keywords; instead, they are exposed as the ordinary values `Bool.true` and `Bool.false`. From e5326bdd17e238259e7c4002ac6a19cf6b754323 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 29 Nov 2023 08:18:11 +1100 Subject: [PATCH 031/105] add Task and Error Handling example --- www/content/tutorial.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/www/content/tutorial.md b/www/content/tutorial.md index 0531dd7e0c..1082744127 100644 --- a/www/content/tutorial.md +++ b/www/content/tutorial.md @@ -1687,6 +1687,8 @@ Some important things to note about backpassing and `await`: - Backpassing syntax does not need to be used with `await` in particular. It can be used with any function. - Roc's compiler treats functions defined with backpassing exactly the same way as functions defined the other way. The only difference between `\text ->` and `text <-` is how they look, so feel free to use whichever looks nicer to you! +See the [Task & Error Handling example](https://www.roc-lang.org/examples/Tasks/README.html) for a more detailed explanation of how to use tasks to help with error handling in a larger program. + ## [Abilities](#abilities) {#abilities} \[This part of the tutorial has not been written yet. Coming soon!\] From becdfe71806007523f518c696858670eb80ca77e Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 29 Nov 2023 08:25:50 +1100 Subject: [PATCH 032/105] add reference to Examples --- www/content/tutorial.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/www/content/tutorial.md b/www/content/tutorial.md index 1082744127..923fde7ff2 100644 --- a/www/content/tutorial.md +++ b/www/content/tutorial.md @@ -1693,6 +1693,14 @@ See the [Task & Error Handling example](https://www.roc-lang.org/examples/Tasks/ \[This part of the tutorial has not been written yet. Coming soon!\] +## Examples + +Well done on making it this far! + +We've covered all of the basic syntax and features of Roc in this Tutorial. You should now have a good foundation and be ready to start writing your own applications. + +You can continue reading through more advanced topics below, or perhaps checkout some of the [Examples](/example) for more a detailed exploration of ways to do various things. + ## [Appendix: Advanced Concepts](#appendix-advanced-concepts) {#appendix-advanced-concepts} Here are some concepts you likely won't need as a beginner, but may want to know about eventually. This is listed as an appendix rather than the main tutorial, to emphasize that it's totally fine to stop reading here and go build things! From 23bf068b2c2820d95f092b881278c2f575192ead Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 29 Nov 2023 08:30:44 +1100 Subject: [PATCH 033/105] add Importing Files Example --- www/content/tutorial.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/www/content/tutorial.md b/www/content/tutorial.md index 923fde7ff2..f2cb9c1f11 100644 --- a/www/content/tutorial.md +++ b/www/content/tutorial.md @@ -1493,6 +1493,19 @@ See [Html Interface](https://github.com/roc-lang/roc/blob/main/examples/virtual- See [Platform Switching Rust](https://github.com/roc-lang/roc/blob/main/examples/platform-switching/rust-platform/main.roc) for an example. +### [Importing Files](#importing-files) {#importing-files} + +You can import files directly into your module as a `Str` or a `List U8` at compile time. This is can be useful for when working with data you would like to keep in a separate file, e.g. JSON or YAML configuration. + +```roc +imports [ + "some-file" as someStr : Str, + "some-file" as someBytes : List U8, +] +``` + +See the [Ingest Files Example](https://www.roc-lang.org/examples/IngestFiles/README.html) for a demonstration on using this feature. + ## [Tasks](#tasks) {#tasks} Tasks are technically not part of the Roc language, but they're very common in platforms. Let's continue using the [basic-cli](https://github.com/roc-lang/basic-cli) platform we've been using up to this point as an example! From b84e242d0ed38c28e403d8c294ca5bdea506b69d Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 29 Nov 2023 08:41:58 +1100 Subject: [PATCH 034/105] add Record Builder section and Example --- www/content/tutorial.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/www/content/tutorial.md b/www/content/tutorial.md index f2cb9c1f11..fab2afd925 100644 --- a/www/content/tutorial.md +++ b/www/content/tutorial.md @@ -2021,6 +2021,36 @@ For this reason, any time you see a function that only runs a `when` on its only \[This part of the tutorial has not been written yet. Coming soon!\] +### [Record Builder](#record-builder) {#record-builder} + +The record builder syntax sugar is a useful feature which leverages the functional programming concept of [applicative functors](https://lucamug.medium.com/functors-applicatives-and-monads-in-pictures-784c2b5786f7), to provide a flexible method for constructing complex types. + +The record builder syntax sugar helps to build up a record by applying a series of functions to it. + +For example, let's say we write a record-builder as follows: + +```roc +{ aliceID, bobID, trudyID } = + initIDCount { + aliceID: <- incID, + bobID: <- incID, + trudyID: <- incID, + } |> extractState +``` + +The above desguars to the following. + +```roc +{ aliceID, bobID, trudyID } = + initIDCount (\aID -> \bID -> \cID -> { aliceID: aID, bobID: bID, trudyID: cID }) + |> incID + |> incID + |> incID + |> extractState +``` + +See the [Record Builder Example](https://www.roc-lang.org/examples/RecordBuilder/README.html) for an explanation of how to use this feature. + ### [Reserved Keywords](#reserved-keywords) {#reserved-keywords} These are all the reserved keywords in Roc. You can't choose any of these as names, except as record field names. From e7a9b8aa157252c0317670de28e681ca5349c504 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 29 Nov 2023 09:12:40 +1100 Subject: [PATCH 035/105] remove Phantom Types section --- www/content/tutorial.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/www/content/tutorial.md b/www/content/tutorial.md index fab2afd925..3c9a0f8e36 100644 --- a/www/content/tutorial.md +++ b/www/content/tutorial.md @@ -2017,10 +2017,6 @@ For this reason, any time you see a function that only runs a `when` on its only > > Also just like with records, you can use this to compose tag union type aliases. For example, you can write `NetworkError : [Timeout, Disconnected]` and then `Problem : [InvalidInput, UnknownFormat]NetworkError` -### [Phantom Types](#phantom-types) {#phantom-types} - -\[This part of the tutorial has not been written yet. Coming soon!\] - ### [Record Builder](#record-builder) {#record-builder} The record builder syntax sugar is a useful feature which leverages the functional programming concept of [applicative functors](https://lucamug.medium.com/functors-applicatives-and-monads-in-pictures-784c2b5786f7), to provide a flexible method for constructing complex types. From 4fafc669b8a019a4d55fecaf26998536e9b1a87f Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 28 Nov 2023 23:47:53 +0100 Subject: [PATCH 036/105] in record fields give a forced imported thunk a unique symbol --- crates/compiler/mono/src/ir.rs | 13 +++++--- .../compiler/test_gen/src/gen_primitives.rs | 33 +++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/crates/compiler/mono/src/ir.rs b/crates/compiler/mono/src/ir.rs index 88a01c496b..c3360e7f64 100644 --- a/crates/compiler/mono/src/ir.rs +++ b/crates/compiler/mono/src/ir.rs @@ -6020,7 +6020,12 @@ fn compile_struct_like<'a, L, UnusedLayout>( match take_elem_expr(index) { Some((var, loc_expr)) => { match can_reuse_symbol(env, layout_cache, procs, &loc_expr.value, var) { - Imported(symbol) | LocalFunction(symbol) | UnspecializedExpr(symbol) => { + Imported(symbol) => { + // we cannot re-use the symbol in this case; it is used as a value, but defined as a thunk + elem_symbols.push(env.unique_symbol()); + can_elems.push(Field::FunctionOrUnspecialized(symbol, variable)); + } + LocalFunction(symbol) | UnspecializedExpr(symbol) => { elem_symbols.push(symbol); can_elems.push(Field::FunctionOrUnspecialized(symbol, variable)); } @@ -6068,15 +6073,15 @@ fn compile_struct_like<'a, L, UnusedLayout>( Field::ValueSymbol => { // this symbol is already defined; nothing to do } - Field::FunctionOrUnspecialized(symbol, variable) => { + Field::FunctionOrUnspecialized(can_symbol, variable) => { stmt = specialize_symbol( env, procs, layout_cache, Some(variable), - symbol, + *symbol, env.arena.alloc(stmt), - symbol, + can_symbol, ); } Field::Field(var, loc_expr) => { diff --git a/crates/compiler/test_gen/src/gen_primitives.rs b/crates/compiler/test_gen/src/gen_primitives.rs index c283d9aa5d..4509a2a60c 100644 --- a/crates/compiler/test_gen/src/gen_primitives.rs +++ b/crates/compiler/test_gen/src/gen_primitives.rs @@ -4630,3 +4630,36 @@ fn many_arguments() { i64 ); } + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] +fn multiple_uses_of_bool_true_record() { + assert_evals_to!( + indoc!( + r#" + (Bool.true, Bool.true).0 + "# + ), + true, + bool + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] +fn multiple_uses_of_bool_true_tag_union() { + assert_evals_to!( + indoc!( + r#" + x : [ One Bool Bool, Empty ] + x = One Bool.true Bool.true + + when x is + One a _ -> a + Empty -> Bool.false + "# + ), + true, + bool + ); +} From 5a872a1bddc87b08ed5d576614b1332431938875 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Mon, 28 Aug 2023 21:45:01 -0400 Subject: [PATCH 037/105] Add Nat to Inspect ability --- crates/compiler/builtins/roc/Inspect.roc | 2 ++ crates/compiler/module/src/symbol.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index f4009f38fa..79103f4c2c 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -26,6 +26,7 @@ interface Inspect i64, u128, i128, + nat, f32, f64, dec, @@ -73,6 +74,7 @@ InspectFormatter implements i64 : I64 -> Inspector f where f implements InspectFormatter u128 : U128 -> Inspector f where f implements InspectFormatter i128 : I128 -> Inspector f where f implements InspectFormatter + nat : Nat -> 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 diff --git a/crates/compiler/module/src/symbol.rs b/crates/compiler/module/src/symbol.rs index e4266a158c..8db42669aa 100644 --- a/crates/compiler/module/src/symbol.rs +++ b/crates/compiler/module/src/symbol.rs @@ -1625,6 +1625,7 @@ define_builtins! { 29 INSPECT_CUSTOM: "custom" 30 INSPECT_APPLY: "apply" 31 INSPECT_TO_INSPECTOR: "toInspector" + 32 INSPECT_NAT: "nat" } 15 JSON: "TotallyNotJson" => { 0 JSON_JSON: "TotallyNotJson" From fb9e0fc777990fa4a31992abe238d57b92efd3f0 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Mon, 28 Aug 2023 21:46:08 -0400 Subject: [PATCH 038/105] Add Inspect to obligation checker --- crates/compiler/solve/src/ability.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index 83272ccd0f..5521e8e332 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -373,7 +373,11 @@ impl ObligationCache { let ImplKey { opaque, ability } = impl_key; - let has_declared_impl = abilities_store.has_declared_implementation(opaque, ability); + // Every type has the Inspect ability automatically, even opaques with no `implements` declaration. + // (Those opaques get a default implementation that returns something along the lines of "") + let is_inspect = ability == Symbol::INSPECT_INSPECT_ABILITY; + let has_known_impl = + is_inspect || abilities_store.has_declared_implementation(opaque, ability); // Some builtins, like Float32 and Bool, would have a cyclic dependency on Encode/Decode/etc. // if their Roc implementations explicitly defined some abilities they support. @@ -385,15 +389,13 @@ impl ObligationCache { _ => false, }; - let has_declared_impl = has_declared_impl || builtin_opaque_impl_ok(); - - let obligation_result = if !has_declared_impl { + let obligation_result = if has_known_impl || builtin_opaque_impl_ok() { + Ok(()) + } else { Err(Unfulfilled::OpaqueDoesNotImplement { typ: opaque, ability, }) - } else { - Ok(()) }; self.impl_cache.insert(impl_key, obligation_result); From d0841fb0189e106fe82236259288250a5eda629c Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Mon, 28 Aug 2023 21:46:17 -0400 Subject: [PATCH 039/105] Add derive key for Inspect --- crates/compiler/can/src/derive.rs | 40 +++++ crates/compiler/derive/src/lib.rs | 5 +- crates/compiler/derive_key/src/inspect.rs | 194 ++++++++++++++++++++++ crates/compiler/derive_key/src/lib.rs | 16 ++ crates/compiler/derive_key/src/util.rs | 4 + crates/compiler/module/src/symbol.rs | 1 + 6 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 crates/compiler/derive_key/src/inspect.rs diff --git a/crates/compiler/can/src/derive.rs b/crates/compiler/can/src/derive.rs index fd85aaa514..09623703e7 100644 --- a/crates/compiler/can/src/derive.rs +++ b/crates/compiler/can/src/derive.rs @@ -213,6 +213,42 @@ fn is_eq<'a>(env: &mut Env<'a>, at_opaque: &'a str) -> ast::Expr<'a> { ) } +fn to_inspector<'a>(env: &mut Env<'a>, at_opaque: &'a str) -> ast::Expr<'a> { + let alloc_pat = |it| env.arena.alloc(Loc::at(DERIVED_REGION, it)); + let alloc_expr = |it| env.arena.alloc(Loc::at(DERIVED_REGION, it)); + + let payload = "#payload"; + + // \@Opaq payload + let opaque_ref = alloc_pat(ast::Pattern::OpaqueRef(at_opaque)); + let opaque_apply_pattern = ast::Pattern::Apply( + opaque_ref, + &*env + .arena + .alloc([Loc::at(DERIVED_REGION, ast::Pattern::Identifier(payload))]), + ); + + // Inspect.toInspector payload + let call_member = alloc_expr(ast::Expr::Apply( + alloc_expr(ast::Expr::Var { + module_name: "Inspect", + ident: "toInspector", + }), + &*env.arena.alloc([&*alloc_expr(ast::Expr::Var { + module_name: "", + ident: payload, + })]), + roc_module::called_via::CalledVia::Space, + )); + + // \@Opaq payload -> Inspect.toInspector payload + ast::Expr::Closure( + env.arena + .alloc([Loc::at(DERIVED_REGION, opaque_apply_pattern)]), + call_member, + ) +} + pub const DERIVED_REGION: Region = Region::zero(); pub(crate) fn synthesize_member_impl<'a>( @@ -232,6 +268,10 @@ pub(crate) fn synthesize_member_impl<'a>( Symbol::DECODE_DECODER => (format!("#{opaque_name}_decoder"), decoder(env, at_opaque)), Symbol::HASH_HASH => (format!("#{opaque_name}_hash"), hash(env, at_opaque)), Symbol::BOOL_IS_EQ => (format!("#{opaque_name}_isEq"), is_eq(env, at_opaque)), + Symbol::INSPECT_TO_INSPECTOR => ( + format!("#{opaque_name}_toInspector"), + to_inspector(env, at_opaque), + ), other => internal_error!("{:?} is not a derivable ability member!", other), }; diff --git a/crates/compiler/derive/src/lib.rs b/crates/compiler/derive/src/lib.rs index 43d547ddb5..a1cdb81cc3 100644 --- a/crates/compiler/derive/src/lib.rs +++ b/crates/compiler/derive/src/lib.rs @@ -8,7 +8,7 @@ use roc_can::expr::Expr; use roc_can::pattern::Pattern; use roc_can::{def::Def, module::ExposedByModule}; use roc_collections::{MutMap, VecMap}; -use roc_derive_key::DeriveKey; +use roc_derive_key::{inspect, DeriveKey}; use roc_module::symbol::{IdentIds, ModuleId, Symbol}; use roc_region::all::Loc; use roc_types::subs::{ @@ -79,6 +79,9 @@ fn build_derived_body( decoding::derive_decoder(&mut env, decoder_key, derived_symbol) } DeriveKey::Hash(hash_key) => hash::derive_hash(&mut env, hash_key, derived_symbol), + DeriveKey::ToInspector(to_inspector_key) => { + inspect::derive_to_inspector(&mut env, to_inspector_key, derived_symbol) + } }; let def = Def { diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs new file mode 100644 index 0000000000..55045b9551 --- /dev/null +++ b/crates/compiler/derive_key/src/inspect.rs @@ -0,0 +1,194 @@ +use roc_module::{ + ident::{Lowercase, TagName}, + symbol::Symbol, +}; +use roc_types::subs::{Content, FlatType, GetSubsSlice, Subs, Variable}; + +use crate::{ + util::{ + check_derivable_ext_var, debug_name_fn, debug_name_record, debug_name_tag, debug_name_tuple, + }, + DeriveError, +}; + +#[derive(Hash)] +pub enum FlatInspectable { + Immediate(Symbol), + Key(FlatInspectableKey), +} + +#[derive(Hash, PartialEq, Eq, Debug, Clone)] +pub enum FlatInspectableKey { + List(/* takes one variable */), + Set(/* takes one variable */), + Dict(/* takes two variables */), + // Unfortunate that we must allocate here, c'est la vie + Record(Vec), + Tuple(u32), + TagUnion(Vec<(TagName, u16)>), + Function(u32 /* arity; +1 for return type */), + Error, + TypeVar(String), +} + +impl FlatInspectableKey { + pub(crate) fn debug_name(&self) -> String { + match self { + FlatInspectableKey::List() => "list".to_string(), + FlatInspectableKey::Set() => "set".to_string(), + FlatInspectableKey::Dict() => "dict".to_string(), + FlatInspectableKey::Record(fields) => debug_name_record(fields), + FlatInspectableKey::Tuple(arity) => debug_name_tuple(*arity), + FlatInspectableKey::TagUnion(tags) => debug_name_tag(tags), + FlatInspectableKey::Function(arity) => debug_name_fn(*arity), + FlatInspectableKey::Error => "error".to_string(), + FlatInspectableKey::TypeVar(name) => format!("typeVariable({name})"), + } + } +} + +impl FlatInspectable { + pub(crate) fn from_var(subs: &Subs, var: Variable) -> FlatInspectable { + use DeriveError::*; + use FlatInspectable::*; + match *subs.get_content_without_compacting(var) { + Content::Structure(flat_type) => match flat_type { + FlatType::Apply(sym, _) => match sym { + Symbol::LIST_LIST => Key(FlatInspectableKey::List()), + Symbol::SET_SET => Key(FlatInspectableKey::Set()), + Symbol::DICT_DICT => Key(FlatInspectableKey::Dict()), + Symbol::STR_STR => Immediate(Symbol::INSPECT_STR), + Symbol::NUM_NUM => { + todo!(); + // TODO need to match again to see what type of Num it was, then + // use Symbol::INSPECT_WHATEVERNUMBERTYPE + } + _ => Immediate(Symbol::INSPECT_OPAQUE), + }, + FlatType::Record(fields, ext) => { + let (fields_iter, ext) = fields.unsorted_iterator_and_ext(subs, ext); + + check_derivable_ext_var(subs, ext, |ext| { + todo!(); // TODO open records can still derive Inspect, but we need to decide how/if to render the ext var. + + // matches!(ext, Content::Structure(FlatType::EmptyRecord)) + }); + + let mut field_names = Vec::with_capacity(fields.len()); + for (field_name, _) in fields_iter { + field_names.push(field_name.clone()); + } + + field_names.sort(); + + Key(FlatInspectableKey::Record(field_names)) + } + FlatType::Tuple(elems, ext) => { + let (elems_iter, ext) = elems.sorted_iterator_and_ext(subs, ext); + + check_derivable_ext_var(subs, ext, |ext| { + todo!(); // TODO open tuples can still derive Inspect, but we need to decide how/if to render the ext var. + + // matches!(ext, Content::Structure(FlatType::EmptyTuple)) + }); + + Key(FlatInspectableKey::Tuple(elems_iter.count() as _)) + } + FlatType::TagUnion(tags, ext) | FlatType::RecursiveTagUnion(_, tags, ext) => { + // The recursion var doesn't matter, because the derived implementation will only + // look on the surface of the tag union type, and more over the payloads of the + // arguments will be left generic for the monomorphizer to fill in with the + // appropriate type. That is, + // [ A t1, B t1 t2 ] + // and + // [ A t1, B t1 t2 ] as R + // look the same on the surface, because `R` is only somewhere inside of the + // `t`-prefixed payload types. + let (tags_iter, ext) = tags.unsorted_tags_and_ext(subs, ext); + + check_derivable_ext_var(subs, ext.var(), |ext| { + todo!(); // TODO open tag unions can still derive Inspect, but we need to decide how/if to render the ext var. + + // matches!(ext, Content::Structure(FlatType::EmptyTagUnion)) + }); + + let mut tag_names_and_payload_sizes: Vec<_> = tags_iter + .tags + .into_iter() + .map(|(name, payload_slice)| { + let payload_size = payload_slice.len(); + (name.clone(), payload_size as _) + }) + .collect(); + + tag_names_and_payload_sizes.sort_by(|(t1, _), (t2, _)| t1.cmp(t2)); + + Key(FlatInspectableKey::TagUnion(tag_names_and_payload_sizes)) + } + FlatType::FunctionOrTagUnion(names_index, _, _) => { + Key(FlatInspectableKey::TagUnion( + subs.get_subs_slice(names_index) + .iter() + .map(|t| (t.clone(), 0)) + .collect(), + )) + } + FlatType::EmptyRecord => Key(FlatInspectableKey::Record(Vec::new())), + FlatType::EmptyTuple => todo!(), + FlatType::EmptyTagUnion => Key(FlatInspectableKey::TagUnion(Vec::new())), + // + FlatType::Func(slice, ..) => { + let arity = subs.get_subs_slice(slice).len(); + + Key(FlatInspectableKey::Function(arity as u32)) + } + }, + Content::Alias(sym, _, real_var, _) => match Self::from_builtin_alias(sym) { + Some(lambda) => lambda, + // TODO: I believe it is okay to unwrap opaques here because derivers are only used + // by the backend, and the backend treats opaques like structural aliases. + _ => Self::from_var(subs, real_var), + }, + Content::RangedNumber(range) => { + Self::from_var(subs, range.default_compilation_variable()) + } + Content::RecursionVar { structure, .. } => Self::from_var(subs, structure), + Content::Error => Key(FlatInspectableKey::Error), + Content::FlexVar(_) + | Content::RigidVar(_) + | Content::FlexAbleVar(_, _) + | Content::RigidAbleVar(_, _) => { + let var_name: String = todo!(); + + Key(FlatInspectableKey::TypeVar(var_name)) + } + Content::LambdaSet(_) | Content::ErasedLambda => { + unreachable!(); + } + } + } + + pub(crate) const fn from_builtin_alias(symbol: Symbol) -> Option { + use FlatInspectable::*; + + match symbol { + Symbol::BOOL_BOOL => Some(Immediate(Symbol::ENCODE_BOOL)), + Symbol::NUM_U8 | Symbol::NUM_UNSIGNED8 => Some(Immediate(Symbol::INSPECT_U8)), + Symbol::NUM_U16 | Symbol::NUM_UNSIGNED16 => Some(Immediate(Symbol::INSPECT_U16)), + Symbol::NUM_U32 | Symbol::NUM_UNSIGNED32 => Some(Immediate(Symbol::INSPECT_U32)), + Symbol::NUM_U64 | Symbol::NUM_UNSIGNED64 => Some(Immediate(Symbol::INSPECT_U64)), + Symbol::NUM_U128 | Symbol::NUM_UNSIGNED128 => Some(Immediate(Symbol::INSPECT_U128)), + Symbol::NUM_I8 | Symbol::NUM_SIGNED8 => Some(Immediate(Symbol::INSPECT_I8)), + Symbol::NUM_I16 | Symbol::NUM_SIGNED16 => Some(Immediate(Symbol::INSPECT_I16)), + Symbol::NUM_I32 | Symbol::NUM_SIGNED32 => Some(Immediate(Symbol::INSPECT_I32)), + Symbol::NUM_I64 | Symbol::NUM_SIGNED64 => Some(Immediate(Symbol::INSPECT_I64)), + Symbol::NUM_I128 | Symbol::NUM_SIGNED128 => Some(Immediate(Symbol::INSPECT_I128)), + Symbol::NUM_DEC | Symbol::NUM_DECIMAL => Some(Immediate(Symbol::INSPECT_DEC)), + Symbol::NUM_F32 | Symbol::NUM_BINARY32 => Some(Immediate(Symbol::INSPECT_F32)), + Symbol::NUM_F64 | Symbol::NUM_BINARY64 => Some(Immediate(Symbol::INSPECT_F64)), + Symbol::NUM_NAT | Symbol::NUM_NATURAL => Some(Immediate(Symbol::INSPECT_NAT)), + // TODO List, Dict, Set, etc. + _ => None, + } + } +} diff --git a/crates/compiler/derive_key/src/lib.rs b/crates/compiler/derive_key/src/lib.rs index 8d122c2661..53db35816e 100644 --- a/crates/compiler/derive_key/src/lib.rs +++ b/crates/compiler/derive_key/src/lib.rs @@ -16,12 +16,14 @@ pub mod decoding; pub mod encoding; pub mod hash; +pub mod inspect; mod util; use decoding::{FlatDecodable, FlatDecodableKey}; use encoding::{FlatEncodable, FlatEncodableKey}; use hash::{FlatHash, FlatHashKey}; +use inspect::{FlatInspectable, FlatInspectableKey}; use roc_module::symbol::Symbol; use roc_types::subs::{Subs, Variable}; @@ -40,6 +42,7 @@ pub enum DeriveKey { ToEncoder(FlatEncodableKey), Decoder(FlatDecodableKey), Hash(FlatHashKey), + ToInspector(FlatInspectableKey), } impl DeriveKey { @@ -48,6 +51,7 @@ impl DeriveKey { DeriveKey::ToEncoder(key) => format!("toEncoder_{}", key.debug_name()), DeriveKey::Decoder(key) => format!("decoder_{}", key.debug_name()), DeriveKey::Hash(key) => format!("hash_{}", key.debug_name()), + DeriveKey::ToInspector(key) => format!("toInspector_{}", key.debug_name()), } } } @@ -77,6 +81,7 @@ pub enum DeriveBuiltin { Decoder, Hash, IsEq, + ToInspector, } impl TryFrom for DeriveBuiltin { @@ -88,6 +93,7 @@ impl TryFrom for DeriveBuiltin { Symbol::DECODE_DECODER => Ok(DeriveBuiltin::Decoder), Symbol::HASH_HASH => Ok(DeriveBuiltin::Hash), Symbol::BOOL_IS_EQ => Ok(DeriveBuiltin::IsEq), + Symbol::INSPECT_TO_INSPECTOR => Ok(DeriveBuiltin::ToInspector), _ => Err(value), } } @@ -121,6 +127,10 @@ impl Derived { Symbol::BOOL_STRUCTURAL_EQ, )) } + DeriveBuiltin::ToInspector => match FlatInspectable::from_var(subs, var) { + FlatInspectable::Immediate(imm) => Ok(Derived::Immediate(imm)), + FlatInspectable::Key(repr) => Ok(Derived::Key(DeriveKey::ToInspector(repr))), + }, } } @@ -151,6 +161,12 @@ impl Derived { Symbol::BOOL_STRUCTURAL_EQ, )) } + DeriveBuiltin::ToInspector => { + match inspect::FlatInspectable::from_builtin_alias(symbol).unwrap() { + FlatInspectable::Immediate(imm) => Ok(Derived::Immediate(imm)), + FlatInspectable::Key(repr) => Ok(Derived::Key(DeriveKey::ToInspector(repr))), + } + } } } } diff --git a/crates/compiler/derive_key/src/util.rs b/crates/compiler/derive_key/src/util.rs index 8fbab82957..a6229c3e25 100644 --- a/crates/compiler/derive_key/src/util.rs +++ b/crates/compiler/derive_key/src/util.rs @@ -60,3 +60,7 @@ pub(crate) fn debug_name_tag(tags: &[(TagName, u16)]) -> String { str.push(']'); str } + +pub(crate) fn debug_name_fn(arity: u32) -> String { + format!("(arity:{arity} -> _)") +} diff --git a/crates/compiler/module/src/symbol.rs b/crates/compiler/module/src/symbol.rs index 8db42669aa..2ba48416ad 100644 --- a/crates/compiler/module/src/symbol.rs +++ b/crates/compiler/module/src/symbol.rs @@ -53,6 +53,7 @@ pub const DERIVABLE_ABILITIES: &[(Symbol, &[Symbol])] = &[ (Symbol::DECODE_DECODING, &[Symbol::DECODE_DECODER]), (Symbol::HASH_HASH_ABILITY, &[Symbol::HASH_HASH]), (Symbol::BOOL_EQ, &[Symbol::BOOL_IS_EQ]), + (Symbol::INSPECT_INSPECT, &[Symbol::INSPECT_TO_INSPECTOR]), ]; /// In Debug builds only, Symbol has a name() method that lets From 00c27b087b88a2f63dbf431b576475cc57327143 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Fri, 1 Sep 2023 22:29:22 -0400 Subject: [PATCH 040/105] Add Inspect to builtin_module_with_unlisted_ability_impl --- crates/compiler/solve/src/ability.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index 5521e8e332..a29b98e6ef 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -1394,11 +1394,14 @@ impl AbilityResolver for AbilitiesStore { } } -/// Whether this a module whose types' ability implementations should be checked via derive_key, +/// Whether this is a module whose types' ability implementations should be checked via derive_key, /// because they do not explicitly list ability implementations due to circular dependencies. #[inline] pub(crate) fn builtin_module_with_unlisted_ability_impl(module_id: ModuleId) -> bool { - matches!(module_id, ModuleId::NUM | ModuleId::BOOL) + matches!( + module_id, + ModuleId::NUM | ModuleId::BOOL | ModuleId::INSPECT + ) } #[derive(Debug)] From 34148645ae72dfabfcf918e518c6e0b58527d320 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 6 Sep 2023 21:24:52 -0400 Subject: [PATCH 041/105] wip --- crates/compiler/builtins/roc/Inspect.roc | 22 +- crates/compiler/derive/src/inspect.rs | 1096 ++++++++++++++++++++ crates/compiler/derive/src/lib.rs | 4 +- crates/compiler/derive_key/src/encoding.rs | 8 +- crates/compiler/derive_key/src/inspect.rs | 53 +- crates/compiler/module/src/symbol.rs | 2 + 6 files changed, 1139 insertions(+), 46 deletions(-) create mode 100644 crates/compiler/derive/src/inspect.rs diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 79103f4c2c..987a0eebce 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -33,6 +33,9 @@ interface Inspect custom, apply, toInspector, + # TODO don't expose these - there's some way to do this! + inspectFn, + inspectOpaque, ] imports [ Bool.{ Bool }, @@ -57,12 +60,11 @@ InspectFormatter implements 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 ``, ``, etc - opaque : Str -> Inspector f where f implements InspectFormatter + # In text, this would render as `` + opaque : Inspector f where f implements InspectFormatter + + # In text, this would render as `` + function : Inspector f where f implements InspectFormatter u8 : U8 -> Inspector f where f implements InspectFormatter i8 : I8 -> Inspector f where f implements InspectFormatter @@ -94,3 +96,11 @@ inspect : val -> f where val implements Inspect, f implements InspectFormatter inspect = \val -> (@Inspector valFn) = toInspector val valFn (init {}) + +## Should not be exposed, only used in auto-deriving +inspectFn : * -> Inspector f where f implements InspectFormatter +inspectFn = \_ -> function + +## Should not be exposed, only used in auto-deriving +inspectOpaque : * -> Inspector f where f implements InspectFormatter +inspectOpaque = \_ -> opaque diff --git a/crates/compiler/derive/src/inspect.rs b/crates/compiler/derive/src/inspect.rs new file mode 100644 index 0000000000..c8413fbad6 --- /dev/null +++ b/crates/compiler/derive/src/inspect.rs @@ -0,0 +1,1096 @@ +//! Derivers for the `Inspect` ability. + +use std::iter::once; + +use roc_can::expr::{ + AnnotatedMark, ClosureData, Expr, Field, Recursive, WhenBranch, WhenBranchPattern, +}; +use roc_can::pattern::Pattern; +use roc_collections::SendMap; +use roc_derive_key::inspect::FlatInspectableKey; +use roc_module::called_via::CalledVia; +use roc_module::ident::Lowercase; +use roc_module::symbol::Symbol; +use roc_region::all::{Loc, Region}; +use roc_types::subs::{ + Content, ExhaustiveMark, FlatType, GetSubsSlice, LambdaSet, OptVariable, RecordFields, + RedundantMark, SubsSlice, TagExt, TupleElems, UnionLambdas, UnionTags, Variable, + VariableSubsSlice, +}; +use roc_types::types::RecordField; + +use crate::util::Env; +use crate::{synth_var, DerivedBody}; + +pub(crate) fn derive_to_inspector( + env: &mut Env<'_>, + key: FlatInspectableKey, + def_symbol: Symbol, +) -> DerivedBody { + let (body, body_type) = match key { + FlatInspectableKey::List() => to_inspector_list(env, def_symbol), + FlatInspectableKey::Set() => todo!(), + FlatInspectableKey::Dict() => todo!(), + FlatInspectableKey::Record(fields) => { + // Generalized record var so we can reuse this impl between many records: + // if fields = { a, b }, this is { a: t1, b: t2 } for fresh t1, t2. + let flex_fields = fields + .into_iter() + .map(|name| { + ( + name, + RecordField::Required(env.subs.fresh_unnamed_flex_var()), + ) + }) + .collect::>(); + let fields = RecordFields::insert_into_subs(env.subs, flex_fields); + let record_var = synth_var( + env.subs, + Content::Structure(FlatType::Record(fields, Variable::EMPTY_RECORD)), + ); + + to_encoder_record(env, record_var, fields, def_symbol) + } + FlatInspectableKey::Tuple(arity) => { + // Generalized tuple var so we can reuse this impl between many tuples: + // if arity = n, this is (t1, ..., tn) for fresh t1, ..., tn. + let flex_elems = (0..arity) + .map(|idx| (idx as usize, env.subs.fresh_unnamed_flex_var())) + .collect::>(); + let elems = TupleElems::insert_into_subs(env.subs, flex_elems); + let tuple_var = synth_var( + env.subs, + Content::Structure(FlatType::Tuple(elems, Variable::EMPTY_TUPLE)), + ); + + to_encoder_tuple(env, tuple_var, elems, def_symbol) + } + FlatInspectableKey::TagUnion(tags) => { + // Generalized tag union var so we can reuse this impl between many unions: + // if tags = [ A arity=2, B arity=1 ], this is [ A t1 t2, B t3 ] for fresh t1, t2, t3 + let flex_tag_labels = tags + .into_iter() + .map(|(label, arity)| { + let variables_slice = + VariableSubsSlice::reserve_into_subs(env.subs, arity.into()); + for var_index in variables_slice { + env.subs[var_index] = env.subs.fresh_unnamed_flex_var(); + } + (label, variables_slice) + }) + .collect::>(); + let union_tags = UnionTags::insert_slices_into_subs(env.subs, flex_tag_labels); + let tag_union_var = synth_var( + env.subs, + Content::Structure(FlatType::TagUnion( + union_tags, + TagExt::Any(Variable::EMPTY_TAG_UNION), + )), + ); + + to_encoder_tag_union(env, tag_union_var, union_tags, def_symbol) + } + FlatInspectableKey::Function(_arity) => { + // Desired output: \x, y, z -> ... ===> "" + + todo!(); + } + FlatInspectableKey::Opaque => todo!(), + FlatInspectableKey::Error => todo!(), + }; + + let specialization_lambda_sets = + env.get_specialization_lambda_sets(body_type, Symbol::ENCODE_TO_ENCODER); + + DerivedBody { + body, + body_type, + specialization_lambda_sets, + } +} + +fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { + // Build \lst -> Encode.list lst (\elem -> Encode.toEncoder elem) + // + // TODO eta reduce this baby ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + use Expr::*; + + let lst_sym = env.new_symbol("lst"); + let elem_sym = env.new_symbol("elem"); + + // List elem + let elem_var = env.subs.fresh_unnamed_flex_var(); + let elem_var_slice = SubsSlice::insert_into_subs(env.subs, [elem_var]); + let list_var = synth_var( + env.subs, + Content::Structure(FlatType::Apply(Symbol::LIST_LIST, elem_var_slice)), + ); + + // build `toEncoder elem` type + // 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 + let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let elem_encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 + let elem_to_encoder_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + elem_var_slice, + to_encoder_clos_var, + elem_encoder_var, + )), + ); + + // 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 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, + Loc::at_zero(to_encoder_var), + to_encoder_clos_var, + elem_encoder_var, + )); + + // toEncoder elem + let to_encoder_call = Call( + to_encoder_fn, + vec![(elem_var, Loc::at_zero(Var(elem_sym, elem_var)))], + CalledVia::Space, + ); + + // elem -[to_elem_encoder]-> toEncoder elem + let to_elem_encoder_sym = env.new_symbol("to_elem_encoder"); + + // Create fn_var for ambient capture; we fix it up below. + let to_elem_encoder_fn_var = synth_var(env.subs, Content::Error); + + // -[to_elem_encoder]-> + let to_elem_encoder_labels = + UnionLambdas::insert_into_subs(env.subs, once((to_elem_encoder_sym, vec![]))); + let to_elem_encoder_lset = synth_var( + env.subs, + Content::LambdaSet(LambdaSet { + solved: to_elem_encoder_labels, + recursion_var: OptVariable::NONE, + unspecialized: SubsSlice::default(), + ambient_function: to_elem_encoder_fn_var, + }), + ); + // elem -[to_elem_encoder]-> toEncoder elem + env.subs.set_content( + to_elem_encoder_fn_var, + Content::Structure(FlatType::Func( + elem_var_slice, + to_elem_encoder_lset, + elem_encoder_var, + )), + ); + + // \elem -> toEncoder elem + let to_elem_encoder = Closure(ClosureData { + function_type: to_elem_encoder_fn_var, + closure_type: to_elem_encoder_lset, + return_type: elem_encoder_var, + name: to_elem_encoder_sym, + captured_symbols: vec![], + recursive: Recursive::NotRecursive, + arguments: vec![( + elem_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(elem_sym)), + )], + loc_body: Box::new(Loc::at_zero(to_encoder_call)), + }); + + // build `Encode.list lst (\elem -> Encode.toEncoder elem)` type + // 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 + let this_encode_list_args_slice = + VariableSubsSlice::insert_into_subs(env.subs, [list_var, to_elem_encoder_fn_var]); + let this_encode_list_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let this_list_encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_encode_list_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + this_encode_list_args_slice, + this_encode_list_clos_var, + this_list_encoder_var, + )), + ); + + // 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 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, + Loc::at_zero(encode_list), + this_encode_list_clos_var, + this_list_encoder_var, + )); + + // Encode.list lst to_elem_encoder + let encode_list_call = Call( + encode_list_fn, + vec![ + (list_var, Loc::at_zero(Var(lst_sym, list_var))), + (to_elem_encoder_fn_var, Loc::at_zero(to_elem_encoder)), + ], + CalledVia::Space, + ); + + // Encode.custom \bytes, fmt -> Encode.appendWith bytes (Encode.list ..) fmt + let (body, this_encoder_var) = wrap_in_encode_custom( + env, + encode_list_call, + this_list_encoder_var, + lst_sym, + list_var, + ); + + // \lst -> Encode.list lst (\elem -> Encode.toEncoder elem) + // Create fn_var for ambient capture; we fix it up below. + let fn_var = synth_var(env.subs, Content::Error); + + // -[fn_name]-> + let fn_name_labels = UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![]))); + let fn_clos_var = synth_var( + env.subs, + Content::LambdaSet(LambdaSet { + solved: fn_name_labels, + recursion_var: OptVariable::NONE, + unspecialized: SubsSlice::default(), + ambient_function: fn_var, + }), + ); + // List elem -[fn_name]-> Encoder fmt + let list_var_slice = SubsSlice::insert_into_subs(env.subs, once(list_var)); + env.subs.set_content( + fn_var, + Content::Structure(FlatType::Func( + list_var_slice, + fn_clos_var, + this_encoder_var, + )), + ); + + // \lst -[fn_name]-> Encode.list lst (\elem -> Encode.toEncoder elem) + let clos = Closure(ClosureData { + function_type: fn_var, + closure_type: fn_clos_var, + return_type: this_encoder_var, + name: fn_name, + captured_symbols: vec![], + recursive: Recursive::NotRecursive, + arguments: vec![( + list_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(lst_sym)), + )], + loc_body: Box::new(Loc::at_zero(body)), + }); + + (clos, fn_var) +} + +fn to_encoder_record( + env: &mut Env<'_>, + record_var: Variable, + fields: RecordFields, + fn_name: Symbol, +) -> (Expr, Variable) { + // Suppose rcd = { a: t1, b: t2 }. Build + // + // \rcd -> Encode.record [ + // { key: "a", value: Encode.toEncoder rcd.a }, + // { key: "b", value: Encode.toEncoder rcd.b }, + // ] + + let rcd_sym = env.new_symbol("rcd"); + let whole_rcd_var = env.subs.fresh_unnamed_flex_var(); // type of the { key, value } records in the list + + use Expr::*; + + let fields_list = fields + .iter_all() + .map(|(field_name_index, field_var_index, _)| { + let field_name = env.subs[field_name_index].clone(); + let field_var = env.subs[field_var_index]; + let field_var_slice = VariableSubsSlice::new(field_var_index.index, 1); + + // key: "a" + let key_field = Field { + var: Variable::STR, + region: Region::zero(), + loc_expr: Box::new(Loc::at_zero(Str(field_name.as_str().into()))), + }; + + // rcd.a + let field_access = RecordAccess { + record_var, + ext_var: env.subs.fresh_unnamed_flex_var(), + field_var, + loc_expr: Box::new(Loc::at_zero(Var( + rcd_sym, + env.subs.fresh_unnamed_flex_var(), + ))), + field: field_name, + }; + + // build `toEncoder rcd.a` type + // 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 + let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_to_encoder_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + field_var_slice, + to_encoder_clos_var, + encoder_var, + )), + ); + + // 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 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, + Loc::at_zero(to_encoder_var), + to_encoder_clos_var, + encoder_var, + )); + + // toEncoder rcd.a + let to_encoder_call = Call( + to_encoder_fn, + vec![(field_var, Loc::at_zero(field_access))], + CalledVia::Space, + ); + + // value: toEncoder rcd.a + let value_field = Field { + var: encoder_var, + region: Region::zero(), + loc_expr: Box::new(Loc::at_zero(to_encoder_call)), + }; + + // { key: "a", value: toEncoder rcd.a } + let mut kv = SendMap::default(); + kv.insert("key".into(), key_field); + kv.insert("value".into(), value_field); + + let this_record_fields = RecordFields::insert_into_subs( + env.subs, + (once(("key".into(), RecordField::Required(Variable::STR)))) + .chain(once(("value".into(), RecordField::Required(encoder_var)))), + ); + let this_record_var = synth_var( + env.subs, + Content::Structure(FlatType::Record(this_record_fields, Variable::EMPTY_RECORD)), + ); + // NOTE: must be done to unify the lambda sets under `encoder_var` + env.unify(this_record_var, whole_rcd_var); + + Loc::at_zero(Record { + record_var: whole_rcd_var, + fields: kv, + }) + }) + .collect::>(); + + // typeof [ { key: .., value: .. }, { key: .., value: .. } ] + let fields_rcd_var_slice = VariableSubsSlice::insert_into_subs(env.subs, once(whole_rcd_var)); + let fields_list_var = synth_var( + env.subs, + Content::Structure(FlatType::Apply(Symbol::LIST_LIST, fields_rcd_var_slice)), + ); + + // [ { key: .., value: ..}, .. ] + let fields_list = List { + elem_var: whole_rcd_var, + loc_elems: fields_list, + }; + + // build `Encode.record [ { key: .., value: ..}, .. ]` type + // 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 + let fields_list_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, once(fields_list_var)); + let encode_record_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_encode_record_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + fields_list_var_slice, + encode_record_clos_var, + encoder_var, + )), + ); + + // 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 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, + Loc::at_zero(encode_record_var), + encode_record_clos_var, + encoder_var, + )); + + // Encode.record [ { key: .., value: .. }, .. ] + let encode_record_call = Call( + encode_record_fn, + vec![(fields_list_var, Loc::at_zero(fields_list))], + CalledVia::Space, + ); + + // Encode.custom \bytes, fmt -> Encode.appendWith bytes (Encode.record ..) fmt + let (body, this_encoder_var) = + wrap_in_encode_custom(env, encode_record_call, encoder_var, rcd_sym, record_var); + + // Create fn_var for ambient capture; we fix it up below. + let fn_var = synth_var(env.subs, Content::Error); + + // -[fn_name]-> + let fn_name_labels = UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![]))); + let fn_clos_var = synth_var( + env.subs, + Content::LambdaSet(LambdaSet { + solved: fn_name_labels, + recursion_var: OptVariable::NONE, + unspecialized: SubsSlice::default(), + ambient_function: fn_var, + }), + ); + // typeof rcd -[fn_name]-> (typeof Encode.record [ .. ] = Encoder fmt) + let record_var_slice = SubsSlice::insert_into_subs(env.subs, once(record_var)); + env.subs.set_content( + fn_var, + Content::Structure(FlatType::Func( + record_var_slice, + fn_clos_var, + this_encoder_var, + )), + ); + + // \rcd -[fn_name]-> Encode.record [ { key: .., value: .. }, .. ] + let clos = Closure(ClosureData { + function_type: fn_var, + closure_type: fn_clos_var, + return_type: this_encoder_var, + name: fn_name, + captured_symbols: vec![], + recursive: Recursive::NotRecursive, + arguments: vec![( + record_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(rcd_sym)), + )], + loc_body: Box::new(Loc::at_zero(body)), + }); + + (clos, fn_var) +} + +fn to_encoder_tuple( + env: &mut Env<'_>, + tuple_var: Variable, + elems: TupleElems, + fn_name: Symbol, +) -> (Expr, Variable) { + // Suppose tup = (t1, t2). Build + // + // \tup -> Encode.tuple [ + // Encode.toEncoder tup.0, + // Encode.toEncoder tup.1, + // ] + + let tup_sym = env.new_symbol("tup"); + let whole_encoder_in_list_var = env.subs.fresh_unnamed_flex_var(); // type of the encoder in the list + + use Expr::*; + + let elem_encoders_list = elems + .iter_all() + .map(|(elem_index, elem_var_index)| { + let index = env.subs[elem_index]; + let elem_var = env.subs[elem_var_index]; + let elem_var_slice = VariableSubsSlice::new(elem_var_index.index, 1); + + // tup.0 + let tuple_access = TupleAccess { + tuple_var, + ext_var: env.subs.fresh_unnamed_flex_var(), + elem_var, + loc_expr: Box::new(Loc::at_zero(Var( + tup_sym, + env.subs.fresh_unnamed_flex_var(), + ))), + index, + }; + + // build `toEncoder tup.0` type + // 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 + let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_to_encoder_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + elem_var_slice, + to_encoder_clos_var, + encoder_var, + )), + ); + + // 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 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, + Loc::at_zero(to_encoder_var), + to_encoder_clos_var, + encoder_var, + )); + + // toEncoder tup.0 + let to_encoder_call = Call( + to_encoder_fn, + vec![(elem_var, Loc::at_zero(tuple_access))], + CalledVia::Space, + ); + + // NOTE: must be done to unify the lambda sets under `encoder_var` + env.unify(encoder_var, whole_encoder_in_list_var); + + Loc::at_zero(to_encoder_call) + }) + .collect::>(); + + // typeof [ toEncoder tup.0, toEncoder tup.1 ] + let whole_encoder_in_list_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, once(whole_encoder_in_list_var)); + let elem_encoders_list_var = synth_var( + env.subs, + Content::Structure(FlatType::Apply( + Symbol::LIST_LIST, + whole_encoder_in_list_var_slice, + )), + ); + + // [ toEncoder tup.0, toEncoder tup.1 ] + let elem_encoders_list = List { + elem_var: whole_encoder_in_list_var, + loc_elems: elem_encoders_list, + }; + + // build `Encode.tuple [ toEncoder tup.0, toEncoder tup.1 ]` type + // 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 + let elem_encoders_list_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, once(elem_encoders_list_var)); + let encode_tuple_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_encode_tuple_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + elem_encoders_list_var_slice, + encode_tuple_clos_var, + encoder_var, + )), + ); + + // 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 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, + Loc::at_zero(encode_tuple_var), + encode_tuple_clos_var, + encoder_var, + )); + + // Encode.tuple [ { key: .., value: .. }, .. ] + let encode_tuple_call = Call( + encode_tuple_fn, + vec![(elem_encoders_list_var, Loc::at_zero(elem_encoders_list))], + CalledVia::Space, + ); + + // Encode.custom \bytes, fmt -> Encode.appendWith bytes (Encode.tuple_var ..) fmt + let (body, this_encoder_var) = + wrap_in_encode_custom(env, encode_tuple_call, encoder_var, tup_sym, tuple_var); + + // Create fn_var for ambient capture; we fix it up below. + let fn_var = synth_var(env.subs, Content::Error); + + // -[fn_name]-> + let fn_name_labels = UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![]))); + let fn_clos_var = synth_var( + env.subs, + Content::LambdaSet(LambdaSet { + solved: fn_name_labels, + recursion_var: OptVariable::NONE, + unspecialized: SubsSlice::default(), + ambient_function: fn_var, + }), + ); + // typeof tup -[fn_name]-> (typeof Encode.tuple [ .. ] = Encoder fmt) + let tuple_var_slice = SubsSlice::insert_into_subs(env.subs, once(tuple_var)); + env.subs.set_content( + fn_var, + Content::Structure(FlatType::Func( + tuple_var_slice, + fn_clos_var, + this_encoder_var, + )), + ); + + // \tup -[fn_name]-> Encode.tuple [ { key: .., value: .. }, .. ] + let clos = Closure(ClosureData { + function_type: fn_var, + closure_type: fn_clos_var, + return_type: this_encoder_var, + name: fn_name, + captured_symbols: vec![], + recursive: Recursive::NotRecursive, + arguments: vec![( + tuple_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(tup_sym)), + )], + loc_body: Box::new(Loc::at_zero(body)), + }); + + (clos, fn_var) +} + +fn to_encoder_tag_union( + env: &mut Env<'_>, + tag_union_var: Variable, + tags: UnionTags, + fn_name: Symbol, +) -> (Expr, Variable) { + // Suppose tag = [ A t1 t2, B t3 ]. Build + // + // \tag -> when tag is + // A v1 v2 -> Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] + // B v3 -> Encode.tag "B" [ Encode.toEncoder v3 ] + + let tag_sym = env.new_symbol("tag"); + let whole_tag_encoders_var = env.subs.fresh_unnamed_flex_var(); // type of the Encode.tag ... calls in the branch bodies + + use Expr::*; + + let branches = tags + .iter_all() + .map(|(tag_name_index, tag_vars_slice_index)| { + // A + let tag_name = &env.subs[tag_name_index].clone(); + let vars_slice = env.subs[tag_vars_slice_index]; + // t1 t2 + let payload_vars = env.subs.get_subs_slice(vars_slice).to_vec(); + // v1 v2 + let payload_syms: Vec<_> = std::iter::repeat_with(|| env.unique_symbol()) + .take(payload_vars.len()) + .collect(); + + // `A v1 v2` pattern + let pattern = Pattern::AppliedTag { + whole_var: tag_union_var, + tag_name: tag_name.clone(), + ext_var: Variable::EMPTY_TAG_UNION, + // (t1, v1) (t2, v2) + arguments: (payload_vars.iter()) + .zip(payload_syms.iter()) + .map(|(var, sym)| (*var, Loc::at_zero(Pattern::Identifier(*sym)))) + .collect(), + }; + let branch_pattern = WhenBranchPattern { + pattern: Loc::at_zero(pattern), + degenerate: false, + }; + + // whole type of the elements in [ Encode.toEncoder v1, Encode.toEncoder v2 ] + let whole_payload_encoders_var = env.subs.fresh_unnamed_flex_var(); + // [ Encode.toEncoder v1, Encode.toEncoder v2 ] + let payload_to_encoders = (payload_syms.iter()) + .zip(payload_vars.iter()) + .map(|(&sym, &sym_var)| { + // build `toEncoder v1` type + // expected: val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + let to_encoder_fn_var = + env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER); + + // wanted: t1 -[clos]-> t' + let var_slice_of_sym_var = + VariableSubsSlice::insert_into_subs(env.subs, [sym_var]); // [ t1 ] + let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let encoder_var = env.subs.fresh_unnamed_flex_var(); // t' + let this_to_encoder_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + var_slice_of_sym_var, + to_encoder_clos_var, + encoder_var, + )), + ); + + // 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 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(( + this_to_encoder_fn_var, + Loc::at_zero(to_encoder_var), + to_encoder_clos_var, + encoder_var, + )); + + // toEncoder rcd.a + let to_encoder_call = Call( + to_encoder_fn, + vec![(sym_var, Loc::at_zero(Var(sym, sym_var)))], + CalledVia::Space, + ); + + // NOTE: must be done to unify the lambda sets under `encoder_var` + env.unify(encoder_var, whole_payload_encoders_var); + + Loc::at_zero(to_encoder_call) + }) + .collect(); + + // typeof [ Encode.toEncoder v1, Encode.toEncoder v2 ] + let whole_encoders_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, [whole_payload_encoders_var]); + let payload_encoders_list_var = synth_var( + env.subs, + Content::Structure(FlatType::Apply(Symbol::LIST_LIST, whole_encoders_var_slice)), + ); + + // [ Encode.toEncoder v1, Encode.toEncoder v2 ] + let payload_encoders_list = List { + elem_var: whole_payload_encoders_var, + loc_elems: payload_to_encoders, + }; + + // build `Encode.tag "A" [ ... ]` type + // 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' + let this_encode_tag_args_var_slice = VariableSubsSlice::insert_into_subs( + env.subs, + [Variable::STR, payload_encoders_list_var], + ); + let this_encode_tag_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> + let this_encoder_var = env.subs.fresh_unnamed_flex_var(); // t' + let this_encode_tag_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + this_encode_tag_args_var_slice, + this_encode_tag_clos_var, + this_encoder_var, + )), + ); + + // 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 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, + Loc::at_zero(encode_tag_var), + this_encode_tag_clos_var, + this_encoder_var, + )); + + // Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] + let encode_tag_call = Call( + encode_tag_fn, + vec![ + // (Str, "A") + (Variable::STR, Loc::at_zero(Str(tag_name.0.as_str().into()))), + // (List (Encoder fmt), [ Encode.toEncoder v1, Encode.toEncoder v2 ]) + ( + payload_encoders_list_var, + Loc::at_zero(payload_encoders_list), + ), + ], + CalledVia::Space, + ); + + // NOTE: must be done to unify the lambda sets under `encoder_var` + // Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] ~ whole_encoders + env.unify(this_encoder_var, whole_tag_encoders_var); + + WhenBranch { + patterns: vec![branch_pattern], + value: Loc::at_zero(encode_tag_call), + guard: None, + redundant: RedundantMark::known_non_redundant(), + } + }) + .collect::>(); + + // when tag is + // A v1 v2 -> Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] + // B v3 -> Encode.tag "B" [ Encode.toEncoder v3 ] + let when_branches = When { + loc_cond: Box::new(Loc::at_zero(Var(tag_sym, tag_union_var))), + cond_var: tag_union_var, + expr_var: whole_tag_encoders_var, + region: Region::zero(), + branches, + branches_cond_var: tag_union_var, + exhaustive: ExhaustiveMark::known_exhaustive(), + }; + + // Encode.custom \bytes, fmt -> Encode.appendWith bytes (when ..) fmt + let (body, this_encoder_var) = wrap_in_encode_custom( + env, + when_branches, + whole_tag_encoders_var, + tag_sym, + tag_union_var, + ); + + // Create fn_var for ambient capture; we fix it up below. + let fn_var = synth_var(env.subs, Content::Error); + + // -[fn_name]-> + let fn_name_labels = UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![]))); + let fn_clos_var = synth_var( + env.subs, + Content::LambdaSet(LambdaSet { + solved: fn_name_labels, + recursion_var: OptVariable::NONE, + unspecialized: SubsSlice::default(), + ambient_function: fn_var, + }), + ); + // tag_union_var -[fn_name]-> whole_tag_encoders_var + let tag_union_var_slice = SubsSlice::insert_into_subs(env.subs, once(tag_union_var)); + env.subs.set_content( + fn_var, + Content::Structure(FlatType::Func( + tag_union_var_slice, + fn_clos_var, + this_encoder_var, + )), + ); + + // \tag -> + // Encode.custom \bytes, fmt -> Encode.appendWith bytes ( + // when tag is + // A v1 v2 -> Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] + // B v3 -> Encode.tag "B" [ Encode.toEncoder v3 ]) + // fmt + let clos = Closure(ClosureData { + function_type: fn_var, + closure_type: fn_clos_var, + return_type: this_encoder_var, + name: fn_name, + captured_symbols: vec![], + recursive: Recursive::NotRecursive, + arguments: vec![( + tag_union_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(tag_sym)), + )], + loc_body: Box::new(Loc::at_zero(body)), + }); + + (clos, fn_var) +} + +/// Lift `encoder` to `Encode.custom \bytes, fmt -> Encode.appendWith bytes encoder fmt` +/// +/// TODO: currently it appears that just `encoder` is not isomorphic to the lift, on the +/// monomorphization level, even though we would think it is. In particular, unspecialized lambda +/// sets fail to resolve when we use the non-lifted version. +/// More investigation is needed to figure out why. +fn wrap_in_encode_custom( + env: &mut Env, + encoder: Expr, + encoder_var: Variable, + captured_symbol: Symbol, + captured_var: Variable, +) -> (Expr, Variable) { + use Expr::*; + + let fn_name = env.new_symbol("custom"); + + // bytes: List U8 + let bytes_sym = env.new_symbol("bytes"); + let bytes_var = Variable::LIST_U8; + + // 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 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 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]-> + let this_append_with_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + this_append_with_args_var_slice, + this_append_with_clos_var, + Variable::LIST_U8, + )), + ); + + // 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 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)), + this_append_with_clos_var, + Variable::LIST_U8, + )); + + // Encode.appendWith bytes encoder fmt + let append_with_call = Call( + append_with_fn, + vec![ + // (bytes_var, bytes) + (bytes_var, Loc::at_zero(Var(bytes_sym, bytes_var))), + // (encoder_var, encoder) + (encoder_var, Loc::at_zero(encoder)), + // (fmt, fmt_var) + (fmt_var, Loc::at_zero(Var(fmt_sym, fmt_var))), + ], + CalledVia::Space, + ); + + // Create fn_var for ambient capture; we fix it up below. + let fn_var = synth_var(env.subs, Content::Error); + + // -[[FN_name captured_var]]-> + let fn_name_labels = + UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![captured_var]))); + let fn_clos_var = synth_var( + env.subs, + Content::LambdaSet(LambdaSet { + solved: fn_name_labels, + recursion_var: OptVariable::NONE, + unspecialized: SubsSlice::default(), + ambient_function: fn_var, + }), + ); + + // bytes, fmt -[[FN_name captured_var]]-> Encode.appendWith bytes encoder fmt + let args_slice = SubsSlice::insert_into_subs(env.subs, vec![bytes_var, fmt_var]); + env.subs.set_content( + fn_var, + Content::Structure(FlatType::Func(args_slice, fn_clos_var, Variable::LIST_U8)), + ); + + // \bytes, fmt -[[fn_name captured_var]]-> Encode.appendWith bytes encoder fmt + let clos = Closure(ClosureData { + function_type: fn_var, + closure_type: fn_clos_var, + return_type: Variable::LIST_U8, + name: fn_name, + captured_symbols: vec![(captured_symbol, captured_var)], + recursive: Recursive::NotRecursive, + arguments: vec![ + ( + bytes_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(bytes_sym)), + ), + ( + fmt_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(fmt_sym)), + ), + ], + loc_body: Box::new(Loc::at_zero(append_with_call)), + }); + + // Build + // Encode.custom \bytes, fmt -> Encode.appendWith bytes encoder fmt + // + // 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' + let this_custom_args_var_slice = VariableSubsSlice::insert_into_subs(env.subs, [fn_var]); + let this_custom_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> + let this_custom_encoder_var = env.subs.fresh_unnamed_flex_var(); // t' + let this_custom_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + this_custom_args_var_slice, + this_custom_clos_var, + this_custom_encoder_var, + )), + ); + + // (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 where fmt implements EncoderFormatting + let custom_fn = Box::new(( + this_custom_fn_var, + Loc::at_zero(Var(Symbol::ENCODE_CUSTOM, this_custom_fn_var)), + this_custom_clos_var, // -[clos]-> + this_custom_encoder_var, // t' ~ Encoder fmt + )); + + // Encode.custom \bytes, fmt -> Encode.appendWith bytes encoder fmt + let custom_call = Call( + custom_fn, + vec![(fn_var, Loc::at_zero(clos))], + CalledVia::Space, + ); + + (custom_call, this_custom_encoder_var) +} diff --git a/crates/compiler/derive/src/lib.rs b/crates/compiler/derive/src/lib.rs index a1cdb81cc3..fdb4679d6e 100644 --- a/crates/compiler/derive/src/lib.rs +++ b/crates/compiler/derive/src/lib.rs @@ -8,7 +8,7 @@ use roc_can::expr::Expr; use roc_can::pattern::Pattern; use roc_can::{def::Def, module::ExposedByModule}; use roc_collections::{MutMap, VecMap}; -use roc_derive_key::{inspect, DeriveKey}; +use roc_derive_key::DeriveKey; use roc_module::symbol::{IdentIds, ModuleId, Symbol}; use roc_region::all::Loc; use roc_types::subs::{ @@ -19,7 +19,7 @@ use util::Env; mod decoding; mod encoding; mod hash; - +mod inspect; mod util; pub(crate) const DERIVED_SYNTH: ModuleId = ModuleId::DERIVED_SYNTH; diff --git a/crates/compiler/derive_key/src/encoding.rs b/crates/compiler/derive_key/src/encoding.rs index 10211ea5b3..423941bc7d 100644 --- a/crates/compiler/derive_key/src/encoding.rs +++ b/crates/compiler/derive_key/src/encoding.rs @@ -55,6 +55,7 @@ impl FlatEncodable { FlatType::Record(fields, ext) => { let (fields_iter, ext) = fields.unsorted_iterator_and_ext(subs, ext); + // TODO someday we can put #[cfg(debug_assertions)] around this, but for now let's always do it. check_derivable_ext_var(subs, ext, |ext| { matches!(ext, Content::Structure(FlatType::EmptyRecord)) })?; @@ -71,6 +72,7 @@ impl FlatEncodable { FlatType::Tuple(elems, ext) => { let (elems_iter, ext) = elems.sorted_iterator_and_ext(subs, ext); + // TODO someday we can put #[cfg(debug_assertions)] around this, but for now let's always do it. check_derivable_ext_var(subs, ext, |ext| { matches!(ext, Content::Structure(FlatType::EmptyTuple)) })?; @@ -89,6 +91,7 @@ impl FlatEncodable { // `t`-prefixed payload types. let (tags_iter, ext) = tags.unsorted_tags_and_ext(subs, ext); + // TODO someday we can put #[cfg(debug_assertions)] around this, but for now let's always do it. check_derivable_ext_var(subs, ext.var(), |ext| { matches!(ext, Content::Structure(FlatType::EmptyTagUnion)) })?; @@ -115,10 +118,9 @@ impl FlatEncodable { ))) } FlatType::EmptyRecord => Ok(Key(FlatEncodableKey::Record(vec![]))), - FlatType::EmptyTuple => todo!(), FlatType::EmptyTagUnion => Ok(Key(FlatEncodableKey::TagUnion(vec![]))), - // FlatType::Func(..) => Err(Underivable), + FlatType::EmptyTuple => unreachable!("Somehow Encoding derivation got an expression that's an empty tuple, which shouldn't be possible!"), }, Content::Alias(sym, _, real_var, _) => match from_builtin_symbol(sym) { Some(lambda) => lambda, @@ -129,9 +131,7 @@ impl FlatEncodable { Content::RangedNumber(range) => { Self::from_var(subs, range.default_compilation_variable()) } - // Content::RecursionVar { structure, .. } => Self::from_var(subs, structure), - // Content::Error => Err(Underivable), Content::FlexVar(_) | Content::RigidVar(_) diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs index 55045b9551..439033aee7 100644 --- a/crates/compiler/derive_key/src/inspect.rs +++ b/crates/compiler/derive_key/src/inspect.rs @@ -4,11 +4,8 @@ use roc_module::{ }; use roc_types::subs::{Content, FlatType, GetSubsSlice, Subs, Variable}; -use crate::{ - util::{ - check_derivable_ext_var, debug_name_fn, debug_name_record, debug_name_tag, debug_name_tuple, - }, - DeriveError, +use crate::util::{ + check_derivable_ext_var, debug_name_fn, debug_name_record, debug_name_tag, debug_name_tuple, }; #[derive(Hash)] @@ -27,8 +24,9 @@ pub enum FlatInspectableKey { Tuple(u32), TagUnion(Vec<(TagName, u16)>), Function(u32 /* arity; +1 for return type */), + /// This means specifically an opaque type where the author hasn't requested that it derive Inspect (or implemented it) + Opaque, Error, - TypeVar(String), } impl FlatInspectableKey { @@ -42,15 +40,15 @@ impl FlatInspectableKey { FlatInspectableKey::TagUnion(tags) => debug_name_tag(tags), FlatInspectableKey::Function(arity) => debug_name_fn(*arity), FlatInspectableKey::Error => "error".to_string(), - FlatInspectableKey::TypeVar(name) => format!("typeVariable({name})"), + FlatInspectableKey::Opaque => "opaque".to_string(), } } } impl FlatInspectable { pub(crate) fn from_var(subs: &Subs, var: Variable) -> FlatInspectable { - use DeriveError::*; use FlatInspectable::*; + match *subs.get_content_without_compacting(var) { Content::Structure(flat_type) => match flat_type { FlatType::Apply(sym, _) => match sym { @@ -58,21 +56,15 @@ impl FlatInspectable { Symbol::SET_SET => Key(FlatInspectableKey::Set()), Symbol::DICT_DICT => Key(FlatInspectableKey::Dict()), Symbol::STR_STR => Immediate(Symbol::INSPECT_STR), - Symbol::NUM_NUM => { - todo!(); - // TODO need to match again to see what type of Num it was, then - // use Symbol::INSPECT_WHATEVERNUMBERTYPE - } _ => Immediate(Symbol::INSPECT_OPAQUE), }, FlatType::Record(fields, ext) => { let (fields_iter, ext) = fields.unsorted_iterator_and_ext(subs, ext); + // TODO someday we can put #[cfg(debug_assertions)] around this, but for now let's always do it. check_derivable_ext_var(subs, ext, |ext| { - todo!(); // TODO open records can still derive Inspect, but we need to decide how/if to render the ext var. - - // matches!(ext, Content::Structure(FlatType::EmptyRecord)) - }); + matches!(ext, Content::Structure(FlatType::EmptyRecord)) + }).expect("Compiler error: unexpected nonempty ext var when deriving Inspect for record"); let mut field_names = Vec::with_capacity(fields.len()); for (field_name, _) in fields_iter { @@ -86,11 +78,10 @@ impl FlatInspectable { FlatType::Tuple(elems, ext) => { let (elems_iter, ext) = elems.sorted_iterator_and_ext(subs, ext); + // TODO someday we can put #[cfg(debug_assertions)] around this, but for now let's always do it. check_derivable_ext_var(subs, ext, |ext| { - todo!(); // TODO open tuples can still derive Inspect, but we need to decide how/if to render the ext var. - - // matches!(ext, Content::Structure(FlatType::EmptyTuple)) - }); + matches!(ext, Content::Structure(FlatType::EmptyTuple)) + }).expect("Compiler error: unexpected nonempty ext var when deriving Inspect for tuple"); Key(FlatInspectableKey::Tuple(elems_iter.count() as _)) } @@ -106,11 +97,10 @@ impl FlatInspectable { // `t`-prefixed payload types. let (tags_iter, ext) = tags.unsorted_tags_and_ext(subs, ext); + // TODO someday we can put #[cfg(debug_assertions)] around this, but for now let's always do it. check_derivable_ext_var(subs, ext.var(), |ext| { - todo!(); // TODO open tag unions can still derive Inspect, but we need to decide how/if to render the ext var. - - // matches!(ext, Content::Structure(FlatType::EmptyTagUnion)) - }); + matches!(ext, Content::Structure(FlatType::EmptyTagUnion)) + }).expect("Compiler error: unexpected nonempty ext var when deriving Inspect for tag union"); let mut tag_names_and_payload_sizes: Vec<_> = tags_iter .tags @@ -134,14 +124,13 @@ impl FlatInspectable { )) } FlatType::EmptyRecord => Key(FlatInspectableKey::Record(Vec::new())), - FlatType::EmptyTuple => todo!(), FlatType::EmptyTagUnion => Key(FlatInspectableKey::TagUnion(Vec::new())), - // FlatType::Func(slice, ..) => { let arity = subs.get_subs_slice(slice).len(); Key(FlatInspectableKey::Function(arity as u32)) } + FlatType::EmptyTuple => unreachable!("Somehow Inspect derivation got an expression that's an empty tuple, which shouldn't be possible!"), }, Content::Alias(sym, _, real_var, _) => match Self::from_builtin_alias(sym) { Some(lambda) => lambda, @@ -157,13 +146,9 @@ impl FlatInspectable { Content::FlexVar(_) | Content::RigidVar(_) | Content::FlexAbleVar(_, _) - | Content::RigidAbleVar(_, _) => { - let var_name: String = todo!(); - - Key(FlatInspectableKey::TypeVar(var_name)) - } - Content::LambdaSet(_) | Content::ErasedLambda => { - unreachable!(); + | Content::RigidAbleVar(_, _) + | Content::LambdaSet(_) | Content::ErasedLambda => { + unreachable!("There must have been a bug in the solver, because we're trying to derive Inspect on a non-concrete type."); } } } diff --git a/crates/compiler/module/src/symbol.rs b/crates/compiler/module/src/symbol.rs index 2ba48416ad..6465511b25 100644 --- a/crates/compiler/module/src/symbol.rs +++ b/crates/compiler/module/src/symbol.rs @@ -1627,6 +1627,8 @@ define_builtins! { 30 INSPECT_APPLY: "apply" 31 INSPECT_TO_INSPECTOR: "toInspector" 32 INSPECT_NAT: "nat" + 33 INSPECT_INSPECT_FN: "inspectFn" + 34 INSPECT_INSPECT_OPAQUE: "inspectOpaque" } 15 JSON: "TotallyNotJson" => { 0 JSON_JSON: "TotallyNotJson" From c87e3e7413d82a6b380c2a654af255db1efa41e1 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Tue, 12 Sep 2023 11:49:26 -0500 Subject: [PATCH 042/105] TODO --- crates/compiler/can/src/derive.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/compiler/can/src/derive.rs b/crates/compiler/can/src/derive.rs index 09623703e7..fd51376919 100644 --- a/crates/compiler/can/src/derive.rs +++ b/crates/compiler/can/src/derive.rs @@ -241,6 +241,12 @@ fn to_inspector<'a>(env: &mut Env<'a>, at_opaque: &'a str) -> ast::Expr<'a> { roc_module::called_via::CalledVia::Space, )); + // TODO: change the derived implementation to be something that includes the opaque symbol in + // the derivation, e.g. something like + // + // \@Opaq payload -> + // Inspect.opaqueWrapper "toString symbol" payload + // \@Opaq payload -> Inspect.toInspector payload ast::Expr::Closure( env.arena From 5c805ce80f163e1d8639f44f447d54c69b42e543 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Tue, 12 Sep 2023 12:11:36 -0500 Subject: [PATCH 043/105] Get first inspect for non-Inspect-implementing opaques specialized --- crates/compiler/builtins/roc/Inspect.roc | 18 ++------ crates/compiler/can/src/def.rs | 1 + crates/compiler/derive_key/src/inspect.rs | 44 +++++++++++++++---- crates/compiler/module/src/symbol.rs | 37 ++++++++-------- crates/compiler/solve/src/specialize.rs | 13 +++++- .../inspect/non_implementing_opaque.txt | 6 +++ 6 files changed, 75 insertions(+), 44 deletions(-) create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 987a0eebce..615a5863aa 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -15,6 +15,7 @@ interface Inspect record, bool, str, + function, opaque, u8, i8, @@ -33,13 +34,10 @@ interface Inspect custom, apply, toInspector, - # TODO don't expose these - there's some way to do this! - inspectFn, - inspectOpaque, ] imports [ Bool.{ Bool }, - Num.{ U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, F32, F64, Dec }, + Num.{ U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, F32, F64, Dec, Nat }, List, Str, ] @@ -61,10 +59,10 @@ InspectFormatter implements dict : dict, KeyValWalker state dict key value, (key -> Inspector f), (value -> Inspector f) -> Inspector f where f implements InspectFormatter # In text, this would render as `` - opaque : Inspector f where f implements InspectFormatter + opaque : * -> Inspector f where f implements InspectFormatter # In text, this would render as `` - function : Inspector f where f implements InspectFormatter + function : * -> Inspector f where f implements InspectFormatter u8 : U8 -> Inspector f where f implements InspectFormatter i8 : I8 -> Inspector f where f implements InspectFormatter @@ -96,11 +94,3 @@ inspect : val -> f where val implements Inspect, f implements InspectFormatter inspect = \val -> (@Inspector valFn) = toInspector val valFn (init {}) - -## Should not be exposed, only used in auto-deriving -inspectFn : * -> Inspector f where f implements InspectFormatter -inspectFn = \_ -> function - -## Should not be exposed, only used in auto-deriving -inspectOpaque : * -> Inspector f where f implements InspectFormatter -inspectOpaque = \_ -> opaque diff --git a/crates/compiler/can/src/def.rs b/crates/compiler/can/src/def.rs index 2496689eb8..804665e3a9 100644 --- a/crates/compiler/can/src/def.rs +++ b/crates/compiler/can/src/def.rs @@ -718,6 +718,7 @@ fn canonicalize_opaque<'a>( let ability_region = ability.region; + // Op := {} has [Eq] let (ability, members) = match ability.value { ast::TypeAnnotation::Apply(module_name, ident, []) => { match make_apply_symbol(env, region, scope, module_name, ident) { diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs index 439033aee7..0f71c854a9 100644 --- a/crates/compiler/derive_key/src/inspect.rs +++ b/crates/compiler/derive_key/src/inspect.rs @@ -2,7 +2,10 @@ use roc_module::{ ident::{Lowercase, TagName}, symbol::Symbol, }; -use roc_types::subs::{Content, FlatType, GetSubsSlice, Subs, Variable}; +use roc_types::{ + subs::{Content, FlatType, GetSubsSlice, Subs, Variable}, + types::AliasKind, +}; use crate::util::{ check_derivable_ext_var, debug_name_fn, debug_name_record, debug_name_tag, debug_name_tuple, @@ -125,18 +128,41 @@ impl FlatInspectable { } FlatType::EmptyRecord => Key(FlatInspectableKey::Record(Vec::new())), FlatType::EmptyTagUnion => Key(FlatInspectableKey::TagUnion(Vec::new())), - FlatType::Func(slice, ..) => { - let arity = subs.get_subs_slice(slice).len(); - - Key(FlatInspectableKey::Function(arity as u32)) + FlatType::Func(..) => { + Immediate(Symbol::INSPECT_FUNCTION) } FlatType::EmptyTuple => unreachable!("Somehow Inspect derivation got an expression that's an empty tuple, which shouldn't be possible!"), }, - Content::Alias(sym, _, real_var, _) => match Self::from_builtin_alias(sym) { + Content::Alias(sym, _, real_var, kind) => match Self::from_builtin_alias(sym) { Some(lambda) => lambda, - // TODO: I believe it is okay to unwrap opaques here because derivers are only used - // by the backend, and the backend treats opaques like structural aliases. - _ => Self::from_var(subs, real_var), + + _ => { + match kind { + AliasKind::Structural => { + Self::from_var(subs, real_var) + } + AliasKind::Opaque => { + // There are two cases in which `Inspect` can be derived for an opaque + // type. + // 1. An opaque type claims to implement `Inspect` and asks us to + // auto-derive it. E.g. + // + // ```text + // Op := {} implements [Inspect] + // ``` + // + // In this case, we generate a synthetic implementation during + // canonicalization that defers to `inspect`ing the inner type. As + // such, this case is never reached in this branch. + // + // 2. An opaque type does not explicitly claim to implement + // `Inspect`. In this case, we print a default opaque string for + // the opaque type. + Immediate(Symbol::INSPECT_OPAQUE) + } + } + } + }, Content::RangedNumber(range) => { Self::from_var(subs, range.default_compilation_variable()) diff --git a/crates/compiler/module/src/symbol.rs b/crates/compiler/module/src/symbol.rs index 6465511b25..d86c117a32 100644 --- a/crates/compiler/module/src/symbol.rs +++ b/crates/compiler/module/src/symbol.rs @@ -1610,25 +1610,24 @@ define_builtins! { 13 INSPECT_BOOL: "bool" 14 INSPECT_STR: "str" 15 INSPECT_OPAQUE: "opaque" - 16 INSPECT_U8: "u8" - 17 INSPECT_I8: "i8" - 18 INSPECT_U16: "u16" - 19 INSPECT_I16: "i16" - 20 INSPECT_U32: "u32" - 21 INSPECT_I32: "i32" - 22 INSPECT_U64: "u64" - 23 INSPECT_I64: "i64" - 24 INSPECT_U128: "u128" - 25 INSPECT_I128: "i128" - 26 INSPECT_F32: "f32" - 27 INSPECT_F64: "f64" - 28 INSPECT_DEC: "dec" - 29 INSPECT_CUSTOM: "custom" - 30 INSPECT_APPLY: "apply" - 31 INSPECT_TO_INSPECTOR: "toInspector" - 32 INSPECT_NAT: "nat" - 33 INSPECT_INSPECT_FN: "inspectFn" - 34 INSPECT_INSPECT_OPAQUE: "inspectOpaque" + 16 INSPECT_FUNCTION: "function" + 17 INSPECT_U8: "u8" + 18 INSPECT_I8: "i8" + 19 INSPECT_U16: "u16" + 20 INSPECT_I16: "i16" + 21 INSPECT_U32: "u32" + 22 INSPECT_I32: "i32" + 23 INSPECT_U64: "u64" + 24 INSPECT_I64: "i64" + 25 INSPECT_U128: "u128" + 26 INSPECT_I128: "i128" + 27 INSPECT_F32: "f32" + 28 INSPECT_F64: "f64" + 29 INSPECT_DEC: "dec" + 30 INSPECT_CUSTOM: "custom" + 31 INSPECT_APPLY: "apply" + 32 INSPECT_TO_INSPECTOR: "toInspector" + 33 INSPECT_NAT: "nat" } 15 JSON: "TotallyNotJson" => { 0 JSON_JSON: "TotallyNotJson" diff --git a/crates/compiler/solve/src/specialize.rs b/crates/compiler/solve/src/specialize.rs index 2ccee11d50..7673eb5bd4 100644 --- a/crates/compiler/solve/src/specialize.rs +++ b/crates/compiler/solve/src/specialize.rs @@ -634,8 +634,17 @@ fn make_specialization_decision( }; match abilities_store.get_implementation(impl_key) { None => { - // Doesn't specialize; an error will already be reported for this. - SpecializeDecision::Drop + match ability_member { + // Inspect is special - if there is no implementation for the + // opaque type, we always emit a default implementation. + Symbol::INSPECT_TO_INSPECTOR => SpecializeDecision::Specialize( + Immediate(Symbol::INSPECT_OPAQUE), + ), + _ => { + // Doesn't specialize; an error will already be reported for this. + SpecializeDecision::Drop + } + } } Some(MemberImpl::Error) => { // TODO: probably not right, we may want to choose a derive decision! diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt new file mode 100644 index 0000000000..c0b907ae38 --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt @@ -0,0 +1,6 @@ +app "test" provides [main] to "./platform" + +Op := {} + +main = Inspect.toInspector (@Op {}) +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Op -[[] + f:Inspect.opaque(15):1]-> Inspector f where f implements InspectFormatter From d36eba98fcb9ffe21496fa3b68995517664007ad Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Tue, 12 Sep 2023 12:17:34 -0500 Subject: [PATCH 044/105] Add a few more opaque tests `specialize/inspect/opaque_derived` does not yet pass. --- .../ability/specialize/inspect/opaque_custom_impl.txt | 9 +++++++++ .../tests/ability/specialize/inspect/opaque_derived.txt | 6 ++++++ 2 files changed, 15 insertions(+) create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt new file mode 100644 index 0000000000..2b5a4b1cfa --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt @@ -0,0 +1,9 @@ +app "test" provides [main] to "./platform" + +Op := U8 implements [Inspect { toInspector: myToInspector }] + +myToInspector : Op -> Inspector f where f implements InspectFormatter +myToInspector = \@Op num -> Inspect.u8 num + +main = Inspect.toInspector (@Op 1u8) +# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(2): Op -[[myToInspector(2)]]-> Inspector f where f implements InspectFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt new file mode 100644 index 0000000000..cfe872a6bd --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt @@ -0,0 +1,6 @@ +app "test" provides [main] to "./platform" + +Op := U8 implements [Inspect] + +main = Inspect.toInspector (@Op 1u8) +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Op -[[] + f:Inspect.opaque(15):1]-> Inspector f where f implements InspectFormatter From 443f6593c51fcf09670c3087d462fa4fea57c464 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 18 Oct 2023 08:04:58 -0400 Subject: [PATCH 045/105] Add Inspect.Inspect to subs and auto-derive --- crates/compiler/solve/src/ability.rs | 106 +++++++++++++++++++++++++++ crates/compiler/types/src/subs.rs | 3 + 2 files changed, 109 insertions(+) diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index a29b98e6ef..6ffa242ba1 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -386,6 +386,7 @@ impl ObligationCache { DeriveDecoding::ABILITY => DeriveDecoding::is_derivable_builtin_opaque(opaque), DeriveEq::ABILITY => DeriveEq::is_derivable_builtin_opaque(opaque), DeriveHash::ABILITY => DeriveHash::is_derivable_builtin_opaque(opaque), + DeriveInspect::ABILITY => DeriveInspect::is_derivable_builtin_opaque(opaque), _ => false, }; @@ -851,6 +852,111 @@ trait DerivableVisitor { } } +struct DeriveInspect; +impl DerivableVisitor for DeriveInspect { + const ABILITY: Symbol = Symbol::INSPECT_INSPECT; + const ABILITY_SLICE: SubsSlice = Subs::AB_INSPECT; + + #[inline(always)] + fn is_derivable_builtin_opaque(symbol: Symbol) -> bool { + (is_builtin_number_alias(symbol) && !is_builtin_nat_alias(symbol)) + || is_builtin_bool_alias(symbol) + } + + #[inline(always)] + fn visit_recursion(_var: Variable) -> Result { + Ok(Descend(true)) + } + + #[inline(always)] + fn visit_apply(var: Variable, symbol: Symbol) -> Result { + if matches!( + symbol, + Symbol::LIST_LIST | Symbol::SET_SET | Symbol::DICT_DICT | Symbol::STR_STR, + ) { + Ok(Descend(true)) + } else { + Err(NotDerivable { + var, + context: NotDerivableContext::NoContext, + }) + } + } + + #[inline(always)] + fn visit_record( + _subs: &Subs, + _var: Variable, + _fields: RecordFields, + ) -> Result { + Ok(Descend(true)) + } + + #[inline(always)] + fn visit_tuple( + _subs: &Subs, + _var: Variable, + _elems: TupleElems, + ) -> Result { + Ok(Descend(true)) + } + + #[inline(always)] + fn visit_tag_union(_var: Variable) -> Result { + Ok(Descend(true)) + } + + #[inline(always)] + fn visit_recursive_tag_union(_var: Variable) -> Result { + Ok(Descend(true)) + } + + #[inline(always)] + fn visit_function_or_tag_union(_var: Variable) -> Result { + Ok(Descend(true)) + } + + #[inline(always)] + fn visit_empty_record(_var: Variable) -> Result<(), NotDerivable> { + Ok(()) + } + + #[inline(always)] + fn visit_empty_tag_union(_var: Variable) -> Result<(), NotDerivable> { + Ok(()) + } + + #[inline(always)] + fn visit_alias(var: Variable, symbol: Symbol) -> Result { + if is_builtin_number_alias(symbol) { + if is_builtin_nat_alias(symbol) { + Err(NotDerivable { + var, + context: NotDerivableContext::Encode(NotDerivableEncode::Nat), + }) + } else { + Ok(Descend(false)) + } + } else { + Ok(Descend(true)) + } + } + + #[inline(always)] + fn visit_ranged_number(_var: Variable, _range: NumericRange) -> Result<(), NotDerivable> { + Ok(()) + } + + #[inline(always)] + fn visit_floating_point_content( + _var: Variable, + _subs: &mut Subs, + _content_var: Variable, + ) -> Result { + Ok(Descend(false)) + } +} + struct DeriveEncoding; impl DerivableVisitor for DeriveEncoding { const ABILITY: Symbol = Symbol::ENCODE_ENCODING; diff --git a/crates/compiler/types/src/subs.rs b/crates/compiler/types/src/subs.rs index 8a62e63650..07dda6b003 100644 --- a/crates/compiler/types/src/subs.rs +++ b/crates/compiler/types/src/subs.rs @@ -1726,6 +1726,8 @@ impl Subs { pub const AB_HASH: SubsSlice = SubsSlice::new(3, 1); #[rustfmt::skip] pub const AB_EQ: SubsSlice = SubsSlice::new(4, 1); + #[rustfmt::skip] + pub const AB_INSPECT: SubsSlice = SubsSlice::new(5, 1); // END INIT-SymbolSubsSlice pub fn new() -> Self { @@ -1754,6 +1756,7 @@ impl Subs { symbol_names.push(Symbol::HASH_HASHER); symbol_names.push(Symbol::HASH_HASH_ABILITY); symbol_names.push(Symbol::BOOL_EQ); + symbol_names.push(Symbol::INSPECT_INSPECT); // END INIT-SymbolNames // IFTTT INIT-VariableSubsSlice From 768b55b8c58af6accf279b019089d2ffaf681b9e Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 18 Oct 2023 16:01:27 -0400 Subject: [PATCH 046/105] Add some Inspect.inspect tests, fix a bug --- crates/compiler/derive_key/src/inspect.rs | 2 +- crates/compiler/test_gen/src/gen_abilities.rs | 109 +++++++++++++++++- 2 files changed, 104 insertions(+), 7 deletions(-) diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs index 0f71c854a9..3bc5793c46 100644 --- a/crates/compiler/derive_key/src/inspect.rs +++ b/crates/compiler/derive_key/src/inspect.rs @@ -183,7 +183,7 @@ impl FlatInspectable { use FlatInspectable::*; match symbol { - Symbol::BOOL_BOOL => Some(Immediate(Symbol::ENCODE_BOOL)), + Symbol::BOOL_BOOL => Some(Immediate(Symbol::INSPECT_BOOL)), Symbol::NUM_U8 | Symbol::NUM_UNSIGNED8 => Some(Immediate(Symbol::INSPECT_U8)), Symbol::NUM_U16 | Symbol::NUM_UNSIGNED16 => Some(Immediate(Symbol::INSPECT_U16)), Symbol::NUM_U32 | Symbol::NUM_UNSIGNED32 => Some(Immediate(Symbol::INSPECT_U32)), diff --git a/crates/compiler/test_gen/src/gen_abilities.rs b/crates/compiler/test_gen/src/gen_abilities.rs index 218e8f6f79..4f45e5510c 100644 --- a/crates/compiler/test_gen/src/gen_abilities.rs +++ b/crates/compiler/test_gen/src/gen_abilities.rs @@ -2159,19 +2159,19 @@ fn issue_4772_weakened_monomorphic_destructure() { getNumber = { result, rest } = Decode.fromBytesPartial (Str.toUtf8 "\"1234\"") TotallyNotJson.json - - when result is - Ok val -> - when Str.toI64 val is + + when result is + Ok val -> + when Str.toI64 val is Ok number -> Ok {val : number, input : rest} Err InvalidNumStr -> Err (ParsingFailure "not a number") - Err _ -> + Err _ -> Err (ParsingFailure "not a number") - main = + main = getNumber |> Result.map .val |> Result.withDefault 0 "### ), @@ -2180,3 +2180,100 @@ fn issue_4772_weakened_monomorphic_destructure() { ) }) } + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn inspect_bool() { + assert_evals_to!( + indoc!( + r#" + app "test" provides [main] to "./platform" + + main = [ + Inspect.inspect Bool.true, + Inspect.inspect Bool.false, + ] |> Str.joinWith ", " + "# + ), + RocStr::from("Bool.true, Bool.false"), + RocStr + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn inspect_num() { + assert_evals_to!( + indoc!( + r#" + app "test" provides [main] to "./platform" + + main = [ + Inspect.inspect 42, # Num * + Inspect.inspect 0x5, # Int * + Inspect.inspect (0.1 + 0.2), # Frac * + Inspect.inspect 1u8, # U8 + Inspect.inspect 2i8, # I8 + Inspect.inspect 3u16, # U16 + Inspect.inspect 4i16, # I16 + Inspect.inspect 5u32, # U32 + Inspect.inspect 6i32, # I32 + Inspect.inspect 7u64, # U64 + Inspect.inspect 8i64, # I64 + Inspect.inspect 9u128, # U128 + Inspect.inspect 10i128, # I128 + Inspect.inspect 1.1f32, # F32 + Inspect.inspect 2.2f64, # F64 + Inspect.inspect (1.1dec + 2.2), # Dec + ] |> Str.joinWith ", " + "# + ), + RocStr::from("42, 5, 0.3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1.1, 2.2, 3.3"), + RocStr + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn inspect_list() { + assert_evals_to!( + indoc!( + r#" + app "test" provides [main] to "./platform" + + main = [ + Inspect.inspect [], # List * + Inspect.inspect [0, 1, 2], # List (Num *) + Inspect.inspect [1, 0x2, 3], # List (Int *) + Inspect.inspect [0.1 + 0.2, 0.4], # List (Frac *) + Inspect.inspect [1u8, 2u8], # List U8 + Inspect.inspect ["foo"], # List Str + ] |> Str.joinWith ", " + "# + ), + RocStr::from("[], [0, 1, 2], [1, 2, 3], [0.3, 0.4], [1, 2], [\"foo\"]"), + RocStr + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn inspect_str() { + assert_evals_to!( + indoc!( + r#" + app "test" provides [main] to "./platform" + + main = [ + Inspect.inspect "", + Inspect.inspect "a small string", + Inspect.inspect "an extraordinarily long string - so long it's on the heap!", + ] |> Str.joinWith ", " + "# + ), + RocStr::from( + r#""", "a small string", "an extraordinarily long string - so long it's on the heap!""# + ), + RocStr + ); +} From b8e644a1e399161e27cd1fae39861ebab593d143 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 27 Nov 2023 17:13:11 -0800 Subject: [PATCH 047/105] add DbgFormatter to inspect --- crates/compiler/builtins/roc/Inspect.roc | 258 +++++++++++++++++- crates/compiler/module/src/symbol.rs | 2 + crates/compiler/test_gen/src/gen_abilities.rs | 8 +- 3 files changed, 262 insertions(+), 6 deletions(-) diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 615a5863aa..611fa04e00 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -34,6 +34,8 @@ interface Inspect custom, apply, toInspector, + DbgFormatter, + toDbgStr, ] imports [ Bool.{ Bool }, @@ -59,10 +61,12 @@ InspectFormatter implements dict : dict, KeyValWalker state dict key value, (key -> Inspector f), (value -> Inspector f) -> Inspector f where f implements InspectFormatter # In text, this would render as `` - opaque : * -> Inspector f where f implements InspectFormatter + # TODO: Pass the type name to opaque so that it can be displayed. + opaque : Inspector f where f implements InspectFormatter # In text, this would render as `` - function : * -> Inspector f where f implements InspectFormatter + # TODO: Maybe pass the the function name or signiture to function so that it can be displayed. + function : Inspector f where f implements InspectFormatter u8 : U8 -> Inspector f where f implements InspectFormatter i8 : I8 -> Inspector f where f implements InspectFormatter @@ -94,3 +98,253 @@ inspect : val -> f where val implements Inspect, f implements InspectFormatter inspect = \val -> (@Inspector valFn) = toInspector val valFn (init {}) + + +# The current default formatter for inspect. +# This just returns a simple string for debugging. +# More powerful formatters will likely be wanted in the future. +DbgFormatter := { data : Str } + implements [ + InspectFormatter { + init: dbgInit, + list: dbgList, + set: dbgSet, + dict: dbgDict, + tag: dbgTag, + tuple: dbgTuple, + record: dbgRecord, + bool: dbgBool, + str: dbgStr, + opaque: dbgOpaque, + function: dbgFunction, + u8: dbgU8, + i8: dbgI8, + u16: dbgU16, + i16: dbgI16, + u32: dbgU32, + i32: dbgI32, + u64: dbgU64, + i64: dbgI64, + u128: dbgU128, + i128: dbgI128, + nat: dbgNat, + f32: dbgF32, + f64: dbgF64, + dec: dbgDec, + }, + ] + +dbgInit : {} -> DbgFormatter +dbgInit = \{} -> @DbgFormatter { data: "" } + +dbgList : list, ElemWalker (DbgFormatter, Bool) list elem, (elem -> Inspector DbgFormatter) -> Inspector DbgFormatter +dbgList = \content, walkFn, toDbgInspector -> + f0 <- custom + dbgWrite f0 "[" + |> \f1 -> + (f2, prependSep), elem <- walkFn content (f1, Bool.false) + f3 = + if prependSep then + dbgWrite f2 ", " + else + f2 + + elem + |> toDbgInspector + |> apply f3 + |> \f4 -> (f4, Bool.true) + |> .0 + |> dbgWrite "]" + +dbgSet : set, ElemWalker (DbgFormatter, Bool) set elem, (elem -> Inspector DbgFormatter) -> Inspector DbgFormatter +dbgSet = \content, walkFn, toDbgInspector -> + f0 <- custom + dbgWrite f0 "{" + |> \f1 -> + (f2, prependSep), elem <- walkFn content (f1, Bool.false) + f3 = + if prependSep then + dbgWrite f2 ", " + else + f2 + + elem + |> toDbgInspector + |> apply f3 + |> \f4 -> (f4, Bool.true) + |> .0 + |> dbgWrite "}" + +dbgDict : dict, KeyValWalker (DbgFormatter, Bool) dict key value, (key -> Inspector DbgFormatter), (value -> Inspector DbgFormatter) -> Inspector DbgFormatter +dbgDict = \d, walkFn, keyToInspector, valueToInspector -> + f0 <- custom + dbgWrite f0 "{" + |> \f1 -> + (f2, prependSep), key, value <- walkFn d (f1, Bool.false) + f3 = + if prependSep then + dbgWrite f2 ", " + else + f2 + + apply (keyToInspector key) f3 + |> dbgWrite ": " + |> \x -> apply (valueToInspector value) x + |> \f4 -> (f4, Bool.true) + |> .0 + |> dbgWrite "}" + +dbgTag : Str, List (Inspector DbgFormatter) -> Inspector DbgFormatter +dbgTag = \name, fields -> + if List.isEmpty fields then + f0 <- custom + dbgWrite f0 name + else + f0 <- custom + dbgWrite f0 "(" + |> dbgWrite name + |> \f1 -> + f2, inspector <- List.walk fields f1 + dbgWrite f2 " " + |> \x -> apply inspector x + |> dbgWrite ")" + +dbgTuple : List (Inspector DbgFormatter) -> Inspector DbgFormatter +dbgTuple = \fields -> + f0 <- custom + dbgWrite f0 "(" + |> \f1 -> + (f2, prependSep), inspector <- List.walk fields (f1, Bool.false) + f3 = + if prependSep then + dbgWrite f2 ", " + else + f2 + + apply inspector f3 + |> \f4 -> (f4, Bool.true) + |> .0 + |> dbgWrite ")" + +dbgRecord : List { key : Str, value : Inspector DbgFormatter } -> Inspector DbgFormatter +dbgRecord = \fields -> + f0 <- custom + dbgWrite f0 "{" + |> \f1 -> + (f2, prependSep), { key, value } <- List.walk fields (f1, Bool.false) + f3 = + if prependSep then + dbgWrite f2 ", " + else + f2 + + dbgWrite f3 key + |> dbgWrite ": " + |> \x -> apply value x + |> \f4 -> (f4, Bool.true) + |> .0 + |> dbgWrite "}" + +dbgBool : Bool -> Inspector DbgFormatter +dbgBool = \b -> + if b then + f0 <- custom + dbgWrite f0 "true" + else + f0 <- custom + dbgWrite f0 "false" + +dbgStr : Str -> Inspector DbgFormatter +dbgStr = \s -> + f0 <- custom + f0 + |> dbgWrite "\"" + |> dbgWrite s + |> dbgWrite "\"" + +dbgOpaque : Inspector DbgFormatter +dbgOpaque = + f0 <- custom + dbgWrite f0 "" + +dbgFunction : Inspector DbgFormatter +dbgFunction = + f0 <- custom + dbgWrite f0 "" + +dbgU8 : U8 -> Inspector DbgFormatter +dbgU8 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgI8 : I8 -> Inspector DbgFormatter +dbgI8 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgU16 : U16 -> Inspector DbgFormatter +dbgU16 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgI16 : I16 -> Inspector DbgFormatter +dbgI16 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgU32 : U32 -> Inspector DbgFormatter +dbgU32 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgI32 : I32 -> Inspector DbgFormatter +dbgI32 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgU64 : U64 -> Inspector DbgFormatter +dbgU64 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgI64 : I64 -> Inspector DbgFormatter +dbgI64 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgU128 : U128 -> Inspector DbgFormatter +dbgU128 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgI128 : I128 -> Inspector DbgFormatter +dbgI128 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgNat : Nat -> Inspector DbgFormatter +dbgNat = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgF32 : F32 -> Inspector DbgFormatter +dbgF32 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgF64 : F64 -> Inspector DbgFormatter +dbgF64 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgDec : Dec -> Inspector DbgFormatter +dbgDec = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgWrite : DbgFormatter, Str -> DbgFormatter +dbgWrite = \@DbgFormatter { data }, added -> + @DbgFormatter { data: Str.concat data added } + +toDbgStr : DbgFormatter -> Str +toDbgStr = \@DbgFormatter { data } -> data diff --git a/crates/compiler/module/src/symbol.rs b/crates/compiler/module/src/symbol.rs index d86c117a32..bbd130d326 100644 --- a/crates/compiler/module/src/symbol.rs +++ b/crates/compiler/module/src/symbol.rs @@ -1628,6 +1628,8 @@ define_builtins! { 31 INSPECT_APPLY: "apply" 32 INSPECT_TO_INSPECTOR: "toInspector" 33 INSPECT_NAT: "nat" + 34 INSPECT_DBG_FORMATTER: "DbgFormatter" exposed_type=true + 35 INSPECT_TO_DBG_STR: "toDbgStr" } 15 JSON: "TotallyNotJson" => { 0 JSON_JSON: "TotallyNotJson" diff --git a/crates/compiler/test_gen/src/gen_abilities.rs b/crates/compiler/test_gen/src/gen_abilities.rs index 4f45e5510c..44c5e4b5f5 100644 --- a/crates/compiler/test_gen/src/gen_abilities.rs +++ b/crates/compiler/test_gen/src/gen_abilities.rs @@ -2192,7 +2192,7 @@ fn inspect_bool() { main = [ Inspect.inspect Bool.true, Inspect.inspect Bool.false, - ] |> Str.joinWith ", " + ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# ), RocStr::from("Bool.true, Bool.false"), @@ -2225,7 +2225,7 @@ fn inspect_num() { Inspect.inspect 1.1f32, # F32 Inspect.inspect 2.2f64, # F64 Inspect.inspect (1.1dec + 2.2), # Dec - ] |> Str.joinWith ", " + ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# ), RocStr::from("42, 5, 0.3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1.1, 2.2, 3.3"), @@ -2248,7 +2248,7 @@ fn inspect_list() { Inspect.inspect [0.1 + 0.2, 0.4], # List (Frac *) Inspect.inspect [1u8, 2u8], # List U8 Inspect.inspect ["foo"], # List Str - ] |> Str.joinWith ", " + ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# ), RocStr::from("[], [0, 1, 2], [1, 2, 3], [0.3, 0.4], [1, 2], [\"foo\"]"), @@ -2268,7 +2268,7 @@ fn inspect_str() { Inspect.inspect "", Inspect.inspect "a small string", Inspect.inspect "an extraordinarily long string - so long it's on the heap!", - ] |> Str.joinWith ", " + ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# ), RocStr::from( From 96b3cc300f353fea776cda3f49c91859915fd2c8 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 27 Nov 2023 17:29:44 -0800 Subject: [PATCH 048/105] encode/encoder to inspect/inspector --- crates/compiler/derive/src/inspect.rs | 873 +++++++++++++------------- 1 file changed, 440 insertions(+), 433 deletions(-) diff --git a/crates/compiler/derive/src/inspect.rs b/crates/compiler/derive/src/inspect.rs index c8413fbad6..1fd048c997 100644 --- a/crates/compiler/derive/src/inspect.rs +++ b/crates/compiler/derive/src/inspect.rs @@ -49,7 +49,7 @@ pub(crate) fn derive_to_inspector( Content::Structure(FlatType::Record(fields, Variable::EMPTY_RECORD)), ); - to_encoder_record(env, record_var, fields, def_symbol) + to_inspector_record(env, record_var, fields, def_symbol) } FlatInspectableKey::Tuple(arity) => { // Generalized tuple var so we can reuse this impl between many tuples: @@ -63,7 +63,7 @@ pub(crate) fn derive_to_inspector( Content::Structure(FlatType::Tuple(elems, Variable::EMPTY_TUPLE)), ); - to_encoder_tuple(env, tuple_var, elems, def_symbol) + to_inspector_tuple(env, tuple_var, elems, def_symbol) } FlatInspectableKey::TagUnion(tags) => { // Generalized tag union var so we can reuse this impl between many unions: @@ -88,7 +88,7 @@ pub(crate) fn derive_to_inspector( )), ); - to_encoder_tag_union(env, tag_union_var, union_tags, def_symbol) + to_inspector_tag_union(env, tag_union_var, union_tags, def_symbol) } FlatInspectableKey::Function(_arity) => { // Desired output: \x, y, z -> ... ===> "" @@ -100,7 +100,7 @@ pub(crate) fn derive_to_inspector( }; let specialization_lambda_sets = - env.get_specialization_lambda_sets(body_type, Symbol::ENCODE_TO_ENCODER); + env.get_specialization_lambda_sets(body_type, Symbol::INSPECT_TO_INSPECTOR); DerivedBody { body, @@ -110,7 +110,7 @@ pub(crate) fn derive_to_inspector( } fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { - // Build \lst -> Encode.list lst (\elem -> Encode.toEncoder elem) + // Build \lst -> Inspect.list lst (\elem -> Inspect.toInspector elem) // // TODO eta reduce this baby ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,76 +127,77 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { Content::Structure(FlatType::Apply(Symbol::LIST_LIST, elem_var_slice)), ); - // build `toEncoder elem` type - // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting - let to_encoder_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER); + // build `toInspector elem` type + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); // elem -[clos]-> t1 - let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos - let elem_encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 - let elem_to_encoder_fn_var = synth_var( + let to_inspector_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let elem_inspector_var = env.subs.fresh_unnamed_flex_var(); // t1 + let elem_to_inspector_fn_var = synth_var( env.subs, Content::Structure(FlatType::Func( elem_var_slice, - to_encoder_clos_var, - elem_encoder_var, + to_inspector_clos_var, + elem_inspector_var, )), ); - // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting // ~ elem -[clos]-> t1 - env.unify(to_encoder_fn_var, elem_to_encoder_fn_var); + env.unify(to_inspector_fn_var, elem_to_inspector_fn_var); - // 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, - Loc::at_zero(to_encoder_var), - to_encoder_clos_var, - elem_encoder_var, + // toInspector : (typeof rcd.a) -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_var = + AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, elem_to_inspector_fn_var); + let to_inspector_fn = Box::new(( + to_inspector_fn_var, + Loc::at_zero(to_inspector_var), + to_inspector_clos_var, + elem_inspector_var, )); - // toEncoder elem - let to_encoder_call = Call( - to_encoder_fn, + // toInspector elem + let to_inspector_call = Call( + to_inspector_fn, vec![(elem_var, Loc::at_zero(Var(elem_sym, elem_var)))], CalledVia::Space, ); - // elem -[to_elem_encoder]-> toEncoder elem - let to_elem_encoder_sym = env.new_symbol("to_elem_encoder"); + // elem -[to_elem_inspector]-> toInspector elem + let to_elem_inspector_sym = env.new_symbol("to_elem_inspector"); // Create fn_var for ambient capture; we fix it up below. - let to_elem_encoder_fn_var = synth_var(env.subs, Content::Error); + let to_elem_inspector_fn_var = synth_var(env.subs, Content::Error); - // -[to_elem_encoder]-> - let to_elem_encoder_labels = - UnionLambdas::insert_into_subs(env.subs, once((to_elem_encoder_sym, vec![]))); - let to_elem_encoder_lset = synth_var( + // -[to_elem_inspector]-> + let to_elem_inspector_labels = + UnionLambdas::insert_into_subs(env.subs, once((to_elem_inspector_sym, vec![]))); + let to_elem_inspector_lset = synth_var( env.subs, Content::LambdaSet(LambdaSet { - solved: to_elem_encoder_labels, + solved: to_elem_inspector_labels, recursion_var: OptVariable::NONE, unspecialized: SubsSlice::default(), - ambient_function: to_elem_encoder_fn_var, + ambient_function: to_elem_inspector_fn_var, }), ); - // elem -[to_elem_encoder]-> toEncoder elem + // elem -[to_elem_inspector]-> toInspector elem env.subs.set_content( - to_elem_encoder_fn_var, + to_elem_inspector_fn_var, Content::Structure(FlatType::Func( elem_var_slice, - to_elem_encoder_lset, - elem_encoder_var, + to_elem_inspector_lset, + elem_inspector_var, )), ); - // \elem -> toEncoder elem - let to_elem_encoder = Closure(ClosureData { - function_type: to_elem_encoder_fn_var, - closure_type: to_elem_encoder_lset, - return_type: elem_encoder_var, - name: to_elem_encoder_sym, + // \elem -> toInspector elem + let to_elem_inspector = Closure(ClosureData { + function_type: to_elem_inspector_fn_var, + closure_type: to_elem_inspector_lset, + return_type: elem_inspector_var, + name: to_elem_inspector_sym, captured_symbols: vec![], recursive: Recursive::NotRecursive, arguments: vec![( @@ -204,60 +205,60 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { AnnotatedMark::known_exhaustive(), Loc::at_zero(Pattern::Identifier(elem_sym)), )], - loc_body: Box::new(Loc::at_zero(to_encoder_call)), + loc_body: Box::new(Loc::at_zero(to_inspector_call)), }); - // build `Encode.list lst (\elem -> Encode.toEncoder elem)` type - // 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); + // build `Inspect.list lst (\elem -> Inspect.toInspector elem)` type + // List e, (e -> Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_list_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_LIST); - // List elem, to_elem_encoder_fn_var -[clos]-> t1 - let this_encode_list_args_slice = - VariableSubsSlice::insert_into_subs(env.subs, [list_var, to_elem_encoder_fn_var]); - let this_encode_list_clos_var = env.subs.fresh_unnamed_flex_var(); // clos - let this_list_encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 - let this_encode_list_fn_var = synth_var( + // List elem, to_elem_inspector_fn_var -[clos]-> t1 + let this_inspect_list_args_slice = + VariableSubsSlice::insert_into_subs(env.subs, [list_var, to_elem_inspector_fn_var]); + let this_inspect_list_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let this_list_inspector_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_inspect_list_fn_var = synth_var( env.subs, Content::Structure(FlatType::Func( - this_encode_list_args_slice, - this_encode_list_clos_var, - this_list_encoder_var, + this_inspect_list_args_slice, + this_inspect_list_clos_var, + this_list_inspector_var, )), ); - // 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); + // List e, (e -> Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // ~ List elem, to_elem_inspector_fn_var -[clos]-> t1 + env.unify(inspect_list_fn_var, this_inspect_list_fn_var); - // 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, - Loc::at_zero(encode_list), - this_encode_list_clos_var, - this_list_encoder_var, + // Inspect.list : List elem, to_elem_inspector_fn_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_list = AbilityMember(Symbol::INSPECT_LIST, None, this_inspect_list_fn_var); + let inspect_list_fn = Box::new(( + this_inspect_list_fn_var, + Loc::at_zero(inspect_list), + this_inspect_list_clos_var, + this_list_inspector_var, )); - // Encode.list lst to_elem_encoder - let encode_list_call = Call( - encode_list_fn, + // Inspect.list lst to_elem_inspector + let inspect_list_call = Call( + inspect_list_fn, vec![ (list_var, Loc::at_zero(Var(lst_sym, list_var))), - (to_elem_encoder_fn_var, Loc::at_zero(to_elem_encoder)), + (to_elem_inspector_fn_var, Loc::at_zero(to_elem_inspector)), ], CalledVia::Space, ); - // Encode.custom \bytes, fmt -> Encode.appendWith bytes (Encode.list ..) fmt - let (body, this_encoder_var) = wrap_in_encode_custom( + // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (Inspect.list ..) fmt + let (body, this_inspector_var) = wrap_in_inspect_custom( env, - encode_list_call, - this_list_encoder_var, + inspect_list_call, + this_list_inspector_var, lst_sym, list_var, ); - // \lst -> Encode.list lst (\elem -> Encode.toEncoder elem) + // \lst -> Inspect.list lst (\elem -> Inspect.toInspector elem) // Create fn_var for ambient capture; we fix it up below. let fn_var = synth_var(env.subs, Content::Error); @@ -272,22 +273,22 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { ambient_function: fn_var, }), ); - // List elem -[fn_name]-> Encoder fmt + // List elem -[fn_name]-> Inspector fmt let list_var_slice = SubsSlice::insert_into_subs(env.subs, once(list_var)); env.subs.set_content( fn_var, Content::Structure(FlatType::Func( list_var_slice, fn_clos_var, - this_encoder_var, + this_inspector_var, )), ); - // \lst -[fn_name]-> Encode.list lst (\elem -> Encode.toEncoder elem) + // \lst -[fn_name]-> Inspect.list lst (\elem -> Inspect.toInspector elem) let clos = Closure(ClosureData { function_type: fn_var, closure_type: fn_clos_var, - return_type: this_encoder_var, + return_type: this_inspector_var, name: fn_name, captured_symbols: vec![], recursive: Recursive::NotRecursive, @@ -302,7 +303,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { (clos, fn_var) } -fn to_encoder_record( +fn to_inspector_record( env: &mut Env<'_>, record_var: Variable, fields: RecordFields, @@ -310,9 +311,9 @@ fn to_encoder_record( ) -> (Expr, Variable) { // Suppose rcd = { a: t1, b: t2 }. Build // - // \rcd -> Encode.record [ - // { key: "a", value: Encode.toEncoder rcd.a }, - // { key: "b", value: Encode.toEncoder rcd.b }, + // \rcd -> Inspect.record [ + // { key: "a", value: Inspect.toInspector rcd.a }, + // { key: "b", value: Inspect.toInspector rcd.b }, // ] let rcd_sym = env.new_symbol("rcd"); @@ -346,50 +347,51 @@ fn to_encoder_record( field: field_name, }; - // build `toEncoder rcd.a` type - // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting - let to_encoder_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER); + // build `toInspector rcd.a` type + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); // (typeof rcd.a) -[clos]-> t1 - let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos - let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 - let this_to_encoder_fn_var = synth_var( + let to_inspector_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let inspector_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_to_inspector_fn_var = synth_var( env.subs, Content::Structure(FlatType::Func( field_var_slice, - to_encoder_clos_var, - encoder_var, + to_inspector_clos_var, + inspector_var, )), ); - // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting // ~ (typeof rcd.a) -[clos]-> t1 - env.unify(to_encoder_fn_var, this_to_encoder_fn_var); + env.unify(to_inspector_fn_var, this_to_inspector_fn_var); - // 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, - Loc::at_zero(to_encoder_var), - to_encoder_clos_var, - encoder_var, + // toInspector : (typeof rcd.a) -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_var = + AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, to_inspector_fn_var); + let to_inspector_fn = Box::new(( + to_inspector_fn_var, + Loc::at_zero(to_inspector_var), + to_inspector_clos_var, + inspector_var, )); - // toEncoder rcd.a - let to_encoder_call = Call( - to_encoder_fn, + // toInspector rcd.a + let to_inspector_call = Call( + to_inspector_fn, vec![(field_var, Loc::at_zero(field_access))], CalledVia::Space, ); - // value: toEncoder rcd.a + // value: toInspector rcd.a let value_field = Field { - var: encoder_var, + var: inspector_var, region: Region::zero(), - loc_expr: Box::new(Loc::at_zero(to_encoder_call)), + loc_expr: Box::new(Loc::at_zero(to_inspector_call)), }; - // { key: "a", value: toEncoder rcd.a } + // { key: "a", value: toInspector rcd.a } let mut kv = SendMap::default(); kv.insert("key".into(), key_field); kv.insert("value".into(), value_field); @@ -397,13 +399,13 @@ fn to_encoder_record( let this_record_fields = RecordFields::insert_into_subs( env.subs, (once(("key".into(), RecordField::Required(Variable::STR)))) - .chain(once(("value".into(), RecordField::Required(encoder_var)))), + .chain(once(("value".into(), RecordField::Required(inspector_var)))), ); let this_record_var = synth_var( env.subs, Content::Structure(FlatType::Record(this_record_fields, Variable::EMPTY_RECORD)), ); - // NOTE: must be done to unify the lambda sets under `encoder_var` + // NOTE: must be done to unify the lambda sets under `inspector_var` env.unify(this_record_var, whole_rcd_var); Loc::at_zero(Record { @@ -426,47 +428,47 @@ fn to_encoder_record( loc_elems: fields_list, }; - // build `Encode.record [ { key: .., value: ..}, .. ]` type - // 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); + // build `Inspect.record [ { key: .., value: ..}, .. ]` type + // List { key : Str, value : Inspector fmt } -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_record_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_RECORD); // fields_list_var -[clos]-> t1 let fields_list_var_slice = VariableSubsSlice::insert_into_subs(env.subs, once(fields_list_var)); - let encode_record_clos_var = env.subs.fresh_unnamed_flex_var(); // clos - let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 - let this_encode_record_fn_var = synth_var( + let inspect_record_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let inspector_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_inspect_record_fn_var = synth_var( env.subs, Content::Structure(FlatType::Func( fields_list_var_slice, - encode_record_clos_var, - encoder_var, + inspect_record_clos_var, + inspector_var, )), ); - // List { key : Str, value : Encoder fmt } -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // List { key : Str, value : Inspector fmt } -[uls]-> Inspector fmt where fmt implements InspectorFormatting // ~ fields_list_var -[clos]-> t1 - env.unify(encode_record_fn_var, this_encode_record_fn_var); + env.unify(inspect_record_fn_var, this_inspect_record_fn_var); - // 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, - Loc::at_zero(encode_record_var), - encode_record_clos_var, - encoder_var, + // Inspect.record : fields_list_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_record_var = AbilityMember(Symbol::INSPECT_RECORD, None, inspect_record_fn_var); + let inspect_record_fn = Box::new(( + inspect_record_fn_var, + Loc::at_zero(inspect_record_var), + inspect_record_clos_var, + inspector_var, )); - // Encode.record [ { key: .., value: .. }, .. ] - let encode_record_call = Call( - encode_record_fn, + // Inspect.record [ { key: .., value: .. }, .. ] + let inspect_record_call = Call( + inspect_record_fn, vec![(fields_list_var, Loc::at_zero(fields_list))], CalledVia::Space, ); - // Encode.custom \bytes, fmt -> Encode.appendWith bytes (Encode.record ..) fmt - let (body, this_encoder_var) = - wrap_in_encode_custom(env, encode_record_call, encoder_var, rcd_sym, record_var); + // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (Inspect.record ..) fmt + let (body, this_inspector_var) = + wrap_in_inspect_custom(env, inspect_record_call, inspector_var, rcd_sym, record_var); // Create fn_var for ambient capture; we fix it up below. let fn_var = synth_var(env.subs, Content::Error); @@ -482,22 +484,22 @@ fn to_encoder_record( ambient_function: fn_var, }), ); - // typeof rcd -[fn_name]-> (typeof Encode.record [ .. ] = Encoder fmt) + // typeof rcd -[fn_name]-> (typeof Inspect.record [ .. ] = Inspector fmt) let record_var_slice = SubsSlice::insert_into_subs(env.subs, once(record_var)); env.subs.set_content( fn_var, Content::Structure(FlatType::Func( record_var_slice, fn_clos_var, - this_encoder_var, + this_inspector_var, )), ); - // \rcd -[fn_name]-> Encode.record [ { key: .., value: .. }, .. ] + // \rcd -[fn_name]-> Inspect.record [ { key: .., value: .. }, .. ] let clos = Closure(ClosureData { function_type: fn_var, closure_type: fn_clos_var, - return_type: this_encoder_var, + return_type: this_inspector_var, name: fn_name, captured_symbols: vec![], recursive: Recursive::NotRecursive, @@ -512,7 +514,7 @@ fn to_encoder_record( (clos, fn_var) } -fn to_encoder_tuple( +fn to_inspector_tuple( env: &mut Env<'_>, tuple_var: Variable, elems: TupleElems, @@ -520,17 +522,17 @@ fn to_encoder_tuple( ) -> (Expr, Variable) { // Suppose tup = (t1, t2). Build // - // \tup -> Encode.tuple [ - // Encode.toEncoder tup.0, - // Encode.toEncoder tup.1, + // \tup -> Inspect.tuple [ + // Inspect.toInspector tup.0, + // Inspect.toInspector tup.1, // ] let tup_sym = env.new_symbol("tup"); - let whole_encoder_in_list_var = env.subs.fresh_unnamed_flex_var(); // type of the encoder in the list + let whole_inspector_in_list_var = env.subs.fresh_unnamed_flex_var(); // type of the inspector in the list use Expr::*; - let elem_encoders_list = elems + let elem_inspectors_list = elems .iter_all() .map(|(elem_index, elem_var_index)| { let index = env.subs[elem_index]; @@ -549,107 +551,108 @@ fn to_encoder_tuple( index, }; - // build `toEncoder tup.0` type - // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting - let to_encoder_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER); + // build `toInspector tup.0` type + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); // (typeof tup.0) -[clos]-> t1 - let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos - let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 - let this_to_encoder_fn_var = synth_var( + let to_inspector_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let inspector_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_to_inspector_fn_var = synth_var( env.subs, Content::Structure(FlatType::Func( elem_var_slice, - to_encoder_clos_var, - encoder_var, + to_inspector_clos_var, + inspector_var, )), ); - // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting // ~ (typeof tup.0) -[clos]-> t1 - env.unify(to_encoder_fn_var, this_to_encoder_fn_var); + env.unify(to_inspector_fn_var, this_to_inspector_fn_var); - // 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, - Loc::at_zero(to_encoder_var), - to_encoder_clos_var, - encoder_var, + // toInspector : (typeof tup.0) -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_var = + AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, to_inspector_fn_var); + let to_inspector_fn = Box::new(( + to_inspector_fn_var, + Loc::at_zero(to_inspector_var), + to_inspector_clos_var, + inspector_var, )); - // toEncoder tup.0 - let to_encoder_call = Call( - to_encoder_fn, + // toInspector tup.0 + let to_inspector_call = Call( + to_inspector_fn, vec![(elem_var, Loc::at_zero(tuple_access))], CalledVia::Space, ); - // NOTE: must be done to unify the lambda sets under `encoder_var` - env.unify(encoder_var, whole_encoder_in_list_var); + // NOTE: must be done to unify the lambda sets under `inspector_var` + env.unify(inspector_var, whole_inspector_in_list_var); - Loc::at_zero(to_encoder_call) + Loc::at_zero(to_inspector_call) }) .collect::>(); - // typeof [ toEncoder tup.0, toEncoder tup.1 ] - let whole_encoder_in_list_var_slice = - VariableSubsSlice::insert_into_subs(env.subs, once(whole_encoder_in_list_var)); - let elem_encoders_list_var = synth_var( + // typeof [ toInspector tup.0, toInspector tup.1 ] + let whole_inspector_in_list_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, once(whole_inspector_in_list_var)); + let elem_inspectors_list_var = synth_var( env.subs, Content::Structure(FlatType::Apply( Symbol::LIST_LIST, - whole_encoder_in_list_var_slice, + whole_inspector_in_list_var_slice, )), ); - // [ toEncoder tup.0, toEncoder tup.1 ] - let elem_encoders_list = List { - elem_var: whole_encoder_in_list_var, - loc_elems: elem_encoders_list, + // [ toInspector tup.0, toInspector tup.1 ] + let elem_inspectors_list = List { + elem_var: whole_inspector_in_list_var, + loc_elems: elem_inspectors_list, }; - // build `Encode.tuple [ toEncoder tup.0, toEncoder tup.1 ]` type - // List (Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting - let encode_tuple_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TUPLE); + // build `Inspect.tuple [ toInspector tup.0, toInspector tup.1 ]` type + // List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_tuple_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TUPLE); - // elem_encoders_list_var -[clos]-> t1 - let elem_encoders_list_var_slice = - VariableSubsSlice::insert_into_subs(env.subs, once(elem_encoders_list_var)); - let encode_tuple_clos_var = env.subs.fresh_unnamed_flex_var(); // clos - let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 - let this_encode_tuple_fn_var = synth_var( + // elem_inspectors_list_var -[clos]-> t1 + let elem_inspectors_list_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, once(elem_inspectors_list_var)); + let inspect_tuple_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let inspector_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_inspect_tuple_fn_var = synth_var( env.subs, Content::Structure(FlatType::Func( - elem_encoders_list_var_slice, - encode_tuple_clos_var, - encoder_var, + elem_inspectors_list_var_slice, + inspect_tuple_clos_var, + inspector_var, )), ); - // 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); + // List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // ~ elem_inspectors_list_var -[clos]-> t1 + env.unify(inspect_tuple_fn_var, this_inspect_tuple_fn_var); - // 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, - Loc::at_zero(encode_tuple_var), - encode_tuple_clos_var, - encoder_var, + // Inspect.tuple : elem_inspectors_list_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_tuple_var = AbilityMember(Symbol::INSPECT_TUPLE, None, inspect_tuple_fn_var); + let inspect_tuple_fn = Box::new(( + inspect_tuple_fn_var, + Loc::at_zero(inspect_tuple_var), + inspect_tuple_clos_var, + inspector_var, )); - // Encode.tuple [ { key: .., value: .. }, .. ] - let encode_tuple_call = Call( - encode_tuple_fn, - vec![(elem_encoders_list_var, Loc::at_zero(elem_encoders_list))], + // Inspect.tuple [ { key: .., value: .. }, .. ] + let inspect_tuple_call = Call( + inspect_tuple_fn, + vec![(elem_inspectors_list_var, Loc::at_zero(elem_inspectors_list))], CalledVia::Space, ); - // Encode.custom \bytes, fmt -> Encode.appendWith bytes (Encode.tuple_var ..) fmt - let (body, this_encoder_var) = - wrap_in_encode_custom(env, encode_tuple_call, encoder_var, tup_sym, tuple_var); + // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (Inspect.tuple_var ..) fmt + let (body, this_inspector_var) = + wrap_in_inspect_custom(env, inspect_tuple_call, inspector_var, tup_sym, tuple_var); // Create fn_var for ambient capture; we fix it up below. let fn_var = synth_var(env.subs, Content::Error); @@ -665,22 +668,22 @@ fn to_encoder_tuple( ambient_function: fn_var, }), ); - // typeof tup -[fn_name]-> (typeof Encode.tuple [ .. ] = Encoder fmt) + // typeof tup -[fn_name]-> (typeof Inspect.tuple [ .. ] = Inspector fmt) let tuple_var_slice = SubsSlice::insert_into_subs(env.subs, once(tuple_var)); env.subs.set_content( fn_var, Content::Structure(FlatType::Func( tuple_var_slice, fn_clos_var, - this_encoder_var, + this_inspector_var, )), ); - // \tup -[fn_name]-> Encode.tuple [ { key: .., value: .. }, .. ] + // \tup -[fn_name]-> Inspect.tuple [ { key: .., value: .. }, .. ] let clos = Closure(ClosureData { function_type: fn_var, closure_type: fn_clos_var, - return_type: this_encoder_var, + return_type: this_inspector_var, name: fn_name, captured_symbols: vec![], recursive: Recursive::NotRecursive, @@ -695,7 +698,7 @@ fn to_encoder_tuple( (clos, fn_var) } -fn to_encoder_tag_union( +fn to_inspector_tag_union( env: &mut Env<'_>, tag_union_var: Variable, tags: UnionTags, @@ -704,11 +707,11 @@ fn to_encoder_tag_union( // Suppose tag = [ A t1 t2, B t3 ]. Build // // \tag -> when tag is - // A v1 v2 -> Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] - // B v3 -> Encode.tag "B" [ Encode.toEncoder v3 ] + // A v1 v2 -> Inspect.tag "A" [ Inspect.toInspector v1, Inspect.toInspector v2 ] + // B v3 -> Inspect.tag "B" [ Inspect.toInspector v3 ] let tag_sym = env.new_symbol("tag"); - let whole_tag_encoders_var = env.subs.fresh_unnamed_flex_var(); // type of the Encode.tag ... calls in the branch bodies + let whole_tag_inspectors_var = env.subs.fresh_unnamed_flex_var(); // type of the Inspect.tag ... calls in the branch bodies use Expr::*; @@ -741,128 +744,131 @@ fn to_encoder_tag_union( degenerate: false, }; - // whole type of the elements in [ Encode.toEncoder v1, Encode.toEncoder v2 ] - let whole_payload_encoders_var = env.subs.fresh_unnamed_flex_var(); - // [ Encode.toEncoder v1, Encode.toEncoder v2 ] - let payload_to_encoders = (payload_syms.iter()) + // whole type of the elements in [ Inspect.toInspector v1, Inspect.toInspector v2 ] + let whole_payload_inspectors_var = env.subs.fresh_unnamed_flex_var(); + // [ Inspect.toInspector v1, Inspect.toInspector v2 ] + let payload_to_inspectors = (payload_syms.iter()) .zip(payload_vars.iter()) .map(|(&sym, &sym_var)| { - // build `toEncoder v1` type - // expected: val -[uls]-> Encoder fmt where fmt implements EncoderFormatting - let to_encoder_fn_var = - env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER); + // build `toInspector v1` type + // expected: val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_fn_var = + env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); // wanted: t1 -[clos]-> t' let var_slice_of_sym_var = VariableSubsSlice::insert_into_subs(env.subs, [sym_var]); // [ t1 ] - let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos - let encoder_var = env.subs.fresh_unnamed_flex_var(); // t' - let this_to_encoder_fn_var = synth_var( + let to_inspector_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let inspector_var = env.subs.fresh_unnamed_flex_var(); // t' + let this_to_inspector_fn_var = synth_var( env.subs, Content::Structure(FlatType::Func( var_slice_of_sym_var, - to_encoder_clos_var, - encoder_var, + to_inspector_clos_var, + inspector_var, )), ); - // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting // ~ t1 -[clos]-> t' - env.unify(to_encoder_fn_var, this_to_encoder_fn_var); + env.unify(to_inspector_fn_var, this_to_inspector_fn_var); - // 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(( - this_to_encoder_fn_var, - Loc::at_zero(to_encoder_var), - to_encoder_clos_var, - encoder_var, + // toInspector : t1 -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_var = + AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, this_to_inspector_fn_var); + let to_inspector_fn = Box::new(( + this_to_inspector_fn_var, + Loc::at_zero(to_inspector_var), + to_inspector_clos_var, + inspector_var, )); - // toEncoder rcd.a - let to_encoder_call = Call( - to_encoder_fn, + // toInspector rcd.a + let to_inspector_call = Call( + to_inspector_fn, vec![(sym_var, Loc::at_zero(Var(sym, sym_var)))], CalledVia::Space, ); - // NOTE: must be done to unify the lambda sets under `encoder_var` - env.unify(encoder_var, whole_payload_encoders_var); + // NOTE: must be done to unify the lambda sets under `inspector_var` + env.unify(inspector_var, whole_payload_inspectors_var); - Loc::at_zero(to_encoder_call) + Loc::at_zero(to_inspector_call) }) .collect(); - // typeof [ Encode.toEncoder v1, Encode.toEncoder v2 ] - let whole_encoders_var_slice = - VariableSubsSlice::insert_into_subs(env.subs, [whole_payload_encoders_var]); - let payload_encoders_list_var = synth_var( + // typeof [ Inspect.toInspector v1, Inspect.toInspector v2 ] + let whole_inspectors_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, [whole_payload_inspectors_var]); + let payload_inspectors_list_var = synth_var( env.subs, - Content::Structure(FlatType::Apply(Symbol::LIST_LIST, whole_encoders_var_slice)), - ); - - // [ Encode.toEncoder v1, Encode.toEncoder v2 ] - let payload_encoders_list = List { - elem_var: whole_payload_encoders_var, - loc_elems: payload_to_encoders, - }; - - // build `Encode.tag "A" [ ... ]` type - // 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' - let this_encode_tag_args_var_slice = VariableSubsSlice::insert_into_subs( - env.subs, - [Variable::STR, payload_encoders_list_var], - ); - let this_encode_tag_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> - let this_encoder_var = env.subs.fresh_unnamed_flex_var(); // t' - let this_encode_tag_fn_var = synth_var( - env.subs, - Content::Structure(FlatType::Func( - this_encode_tag_args_var_slice, - this_encode_tag_clos_var, - this_encoder_var, + Content::Structure(FlatType::Apply( + Symbol::LIST_LIST, + whole_inspectors_var_slice, )), ); - // 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); + // [ Inspect.toInspector v1, Inspect.toInspector v2 ] + let payload_inspectors_list = List { + elem_var: whole_payload_inspectors_var, + loc_elems: payload_to_inspectors, + }; - // 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, - Loc::at_zero(encode_tag_var), - this_encode_tag_clos_var, - this_encoder_var, + // build `Inspect.tag "A" [ ... ]` type + // expected: Str, List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_tag_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TAG); + + // wanted: Str, List whole_inspectors_var -[clos]-> t' + let this_inspect_tag_args_var_slice = VariableSubsSlice::insert_into_subs( + env.subs, + [Variable::STR, payload_inspectors_list_var], + ); + let this_inspect_tag_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> + let this_inspector_var = env.subs.fresh_unnamed_flex_var(); // t' + let this_inspect_tag_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + this_inspect_tag_args_var_slice, + this_inspect_tag_clos_var, + this_inspector_var, + )), + ); + + // Str, List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // ~ Str, List whole_inspectors_var -[clos]-> t' + env.unify(inspect_tag_fn_var, this_inspect_tag_fn_var); + + // Inspect.tag : Str, List whole_inspectors_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_tag_var = AbilityMember(Symbol::INSPECT_TAG, None, this_inspect_tag_fn_var); + let inspect_tag_fn = Box::new(( + this_inspect_tag_fn_var, + Loc::at_zero(inspect_tag_var), + this_inspect_tag_clos_var, + this_inspector_var, )); - // Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] - let encode_tag_call = Call( - encode_tag_fn, + // Inspect.tag "A" [ Inspect.toInspector v1, Inspect.toInspector v2 ] + let inspect_tag_call = Call( + inspect_tag_fn, vec![ // (Str, "A") (Variable::STR, Loc::at_zero(Str(tag_name.0.as_str().into()))), - // (List (Encoder fmt), [ Encode.toEncoder v1, Encode.toEncoder v2 ]) + // (List (Inspector fmt), [ Inspect.toInspector v1, Inspect.toInspector v2 ]) ( - payload_encoders_list_var, - Loc::at_zero(payload_encoders_list), + payload_inspectors_list_var, + Loc::at_zero(payload_inspectors_list), ), ], CalledVia::Space, ); - // NOTE: must be done to unify the lambda sets under `encoder_var` - // Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] ~ whole_encoders - env.unify(this_encoder_var, whole_tag_encoders_var); + // NOTE: must be done to unify the lambda sets under `inspector_var` + // Inspect.tag "A" [ Inspect.toInspector v1, Inspect.toInspector v2 ] ~ whole_inspectors + env.unify(this_inspector_var, whole_tag_inspectors_var); WhenBranch { patterns: vec![branch_pattern], - value: Loc::at_zero(encode_tag_call), + value: Loc::at_zero(inspect_tag_call), guard: None, redundant: RedundantMark::known_non_redundant(), } @@ -870,23 +876,23 @@ fn to_encoder_tag_union( .collect::>(); // when tag is - // A v1 v2 -> Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] - // B v3 -> Encode.tag "B" [ Encode.toEncoder v3 ] + // A v1 v2 -> Inspect.tag "A" [ Inspect.toInspector v1, Inspect.toInspector v2 ] + // B v3 -> Inspect.tag "B" [ Inspect.toInspector v3 ] let when_branches = When { loc_cond: Box::new(Loc::at_zero(Var(tag_sym, tag_union_var))), cond_var: tag_union_var, - expr_var: whole_tag_encoders_var, + expr_var: whole_tag_inspectors_var, region: Region::zero(), branches, branches_cond_var: tag_union_var, exhaustive: ExhaustiveMark::known_exhaustive(), }; - // Encode.custom \bytes, fmt -> Encode.appendWith bytes (when ..) fmt - let (body, this_encoder_var) = wrap_in_encode_custom( + // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (when ..) fmt + let (body, this_inspector_var) = wrap_in_inspect_custom( env, when_branches, - whole_tag_encoders_var, + whole_tag_inspectors_var, tag_sym, tag_union_var, ); @@ -905,27 +911,27 @@ fn to_encoder_tag_union( ambient_function: fn_var, }), ); - // tag_union_var -[fn_name]-> whole_tag_encoders_var + // tag_union_var -[fn_name]-> whole_tag_inspectors_var let tag_union_var_slice = SubsSlice::insert_into_subs(env.subs, once(tag_union_var)); env.subs.set_content( fn_var, Content::Structure(FlatType::Func( tag_union_var_slice, fn_clos_var, - this_encoder_var, + this_inspector_var, )), ); // \tag -> - // Encode.custom \bytes, fmt -> Encode.appendWith bytes ( + // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes ( // when tag is - // A v1 v2 -> Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] - // B v3 -> Encode.tag "B" [ Encode.toEncoder v3 ]) + // A v1 v2 -> Inspect.tag "A" [ Inspect.toInspector v1, Inspect.toInspector v2 ] + // B v3 -> Inspect.tag "B" [ Inspect.toInspector v3 ]) // fmt let clos = Closure(ClosureData { function_type: fn_var, closure_type: fn_clos_var, - return_type: this_encoder_var, + return_type: this_inspector_var, name: fn_name, captured_symbols: vec![], recursive: Recursive::NotRecursive, @@ -940,157 +946,158 @@ fn to_encoder_tag_union( (clos, fn_var) } -/// Lift `encoder` to `Encode.custom \bytes, fmt -> Encode.appendWith bytes encoder fmt` +/// Lift `inspector` to `Inspect.custom \bytes, fmt -> Inspect.appendWith bytes inspector fmt` /// -/// TODO: currently it appears that just `encoder` is not isomorphic to the lift, on the +/// TODO: currently it appears that just `inspector` is not isomorphic to the lift, on the /// monomorphization level, even though we would think it is. In particular, unspecialized lambda /// sets fail to resolve when we use the non-lifted version. /// More investigation is needed to figure out why. -fn wrap_in_encode_custom( - env: &mut Env, - encoder: Expr, - encoder_var: Variable, - captured_symbol: Symbol, - captured_var: Variable, +fn wrap_in_inspect_custom( + _env: &mut Env, + _inspector: Expr, + _inspector_var: Variable, + _captured_symbol: Symbol, + _captured_var: Variable, ) -> (Expr, Variable) { - use Expr::*; + unimplemented!(); + // use Expr::*; - let fn_name = env.new_symbol("custom"); + // let fn_name = env.new_symbol("custom"); - // bytes: List U8 - let bytes_sym = env.new_symbol("bytes"); - let bytes_var = Variable::LIST_U8; + // // bytes: List U8 + // let bytes_sym = env.new_symbol("bytes"); + // let bytes_var = Variable::LIST_U8; - // fmt: fmt where fmt implements EncoderFormatting - let fmt_sym = env.new_symbol("fmt"); - let fmt_var = env.subs.fresh_unnamed_flex_var(); + // // fmt: fmt where fmt implements InspectorFormatting + // 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 where fmt implements EncoderFormatting - let append_with_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_APPEND_WITH); + // // build `Inspect.appendWith bytes inspector fmt` type + // // expected: Inspect.appendWith : List U8, Inspector fmt, fmt -[appendWith]-> List U8 where fmt implements InspectorFormatting + // let append_with_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_APPEND_WITH); - // 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]-> - let this_append_with_fn_var = synth_var( - env.subs, - Content::Structure(FlatType::Func( - this_append_with_args_var_slice, - this_append_with_clos_var, - Variable::LIST_U8, - )), - ); + // // wanted: Inspect.appendWith : List U8, inspector_var, fmt -[clos]-> List U8 where fmt implements InspectorFormatting + // let this_append_with_args_var_slice = + // VariableSubsSlice::insert_into_subs(env.subs, [Variable::LIST_U8, inspector_var, fmt_var]); + // let this_append_with_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> + // let this_append_with_fn_var = synth_var( + // env.subs, + // Content::Structure(FlatType::Func( + // this_append_with_args_var_slice, + // this_append_with_clos_var, + // Variable::LIST_U8, + // )), + // ); - // 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); + // // List U8, Inspector fmt, fmt -[appendWith]-> List U8 where fmt implements InspectorFormatting + // // ~ List U8, inspector_var, fmt -[clos]-> List U8 where fmt implements InspectorFormatting + // env.unify(append_with_fn_var, this_append_with_fn_var); - // 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)), - this_append_with_clos_var, - Variable::LIST_U8, - )); + // // Inspect.appendWith : List U8, inspector_var, fmt -[appendWith]-> List U8 where fmt implements InspectorFormatting + // let append_with_fn = Box::new(( + // this_append_with_fn_var, + // Loc::at_zero(Var(Symbol::INSPECT_APPEND_WITH, this_append_with_fn_var)), + // this_append_with_clos_var, + // Variable::LIST_U8, + // )); - // Encode.appendWith bytes encoder fmt - let append_with_call = Call( - append_with_fn, - vec![ - // (bytes_var, bytes) - (bytes_var, Loc::at_zero(Var(bytes_sym, bytes_var))), - // (encoder_var, encoder) - (encoder_var, Loc::at_zero(encoder)), - // (fmt, fmt_var) - (fmt_var, Loc::at_zero(Var(fmt_sym, fmt_var))), - ], - CalledVia::Space, - ); + // // Inspect.appendWith bytes inspector fmt + // let append_with_call = Call( + // append_with_fn, + // vec![ + // // (bytes_var, bytes) + // (bytes_var, Loc::at_zero(Var(bytes_sym, bytes_var))), + // // (inspector_var, inspector) + // (inspector_var, Loc::at_zero(inspector)), + // // (fmt, fmt_var) + // (fmt_var, Loc::at_zero(Var(fmt_sym, fmt_var))), + // ], + // CalledVia::Space, + // ); - // Create fn_var for ambient capture; we fix it up below. - let fn_var = synth_var(env.subs, Content::Error); + // // Create fn_var for ambient capture; we fix it up below. + // let fn_var = synth_var(env.subs, Content::Error); - // -[[FN_name captured_var]]-> - let fn_name_labels = - UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![captured_var]))); - let fn_clos_var = synth_var( - env.subs, - Content::LambdaSet(LambdaSet { - solved: fn_name_labels, - recursion_var: OptVariable::NONE, - unspecialized: SubsSlice::default(), - ambient_function: fn_var, - }), - ); + // // -[[FN_name captured_var]]-> + // let fn_name_labels = + // UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![captured_var]))); + // let fn_clos_var = synth_var( + // env.subs, + // Content::LambdaSet(LambdaSet { + // solved: fn_name_labels, + // recursion_var: OptVariable::NONE, + // unspecialized: SubsSlice::default(), + // ambient_function: fn_var, + // }), + // ); - // bytes, fmt -[[FN_name captured_var]]-> Encode.appendWith bytes encoder fmt - let args_slice = SubsSlice::insert_into_subs(env.subs, vec![bytes_var, fmt_var]); - env.subs.set_content( - fn_var, - Content::Structure(FlatType::Func(args_slice, fn_clos_var, Variable::LIST_U8)), - ); + // // bytes, fmt -[[FN_name captured_var]]-> Inspect.appendWith bytes inspector fmt + // let args_slice = SubsSlice::insert_into_subs(env.subs, vec![bytes_var, fmt_var]); + // env.subs.set_content( + // fn_var, + // Content::Structure(FlatType::Func(args_slice, fn_clos_var, Variable::LIST_U8)), + // ); - // \bytes, fmt -[[fn_name captured_var]]-> Encode.appendWith bytes encoder fmt - let clos = Closure(ClosureData { - function_type: fn_var, - closure_type: fn_clos_var, - return_type: Variable::LIST_U8, - name: fn_name, - captured_symbols: vec![(captured_symbol, captured_var)], - recursive: Recursive::NotRecursive, - arguments: vec![ - ( - bytes_var, - AnnotatedMark::known_exhaustive(), - Loc::at_zero(Pattern::Identifier(bytes_sym)), - ), - ( - fmt_var, - AnnotatedMark::known_exhaustive(), - Loc::at_zero(Pattern::Identifier(fmt_sym)), - ), - ], - loc_body: Box::new(Loc::at_zero(append_with_call)), - }); + // // \bytes, fmt -[[fn_name captured_var]]-> Inspect.appendWith bytes inspector fmt + // let clos = Closure(ClosureData { + // function_type: fn_var, + // closure_type: fn_clos_var, + // return_type: Variable::LIST_U8, + // name: fn_name, + // captured_symbols: vec![(captured_symbol, captured_var)], + // recursive: Recursive::NotRecursive, + // arguments: vec![ + // ( + // bytes_var, + // AnnotatedMark::known_exhaustive(), + // Loc::at_zero(Pattern::Identifier(bytes_sym)), + // ), + // ( + // fmt_var, + // AnnotatedMark::known_exhaustive(), + // Loc::at_zero(Pattern::Identifier(fmt_sym)), + // ), + // ], + // loc_body: Box::new(Loc::at_zero(append_with_call)), + // }); - // Build - // Encode.custom \bytes, fmt -> Encode.appendWith bytes encoder fmt - // - // 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); + // // Build + // // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes inspector fmt + // // + // // expected: Inspect.custom : (List U8, fmt -> List U8) -> Inspector fmt where fmt implements InspectorFormatting + // let custom_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_CUSTOM); - // wanted: Encode.custom : fn_var -[clos]-> t' - let this_custom_args_var_slice = VariableSubsSlice::insert_into_subs(env.subs, [fn_var]); - let this_custom_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> - let this_custom_encoder_var = env.subs.fresh_unnamed_flex_var(); // t' - let this_custom_fn_var = synth_var( - env.subs, - Content::Structure(FlatType::Func( - this_custom_args_var_slice, - this_custom_clos_var, - this_custom_encoder_var, - )), - ); + // // wanted: Inspect.custom : fn_var -[clos]-> t' + // let this_custom_args_var_slice = VariableSubsSlice::insert_into_subs(env.subs, [fn_var]); + // let this_custom_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> + // let this_custom_inspector_var = env.subs.fresh_unnamed_flex_var(); // t' + // let this_custom_fn_var = synth_var( + // env.subs, + // Content::Structure(FlatType::Func( + // this_custom_args_var_slice, + // this_custom_clos_var, + // this_custom_inspector_var, + // )), + // ); - // (List U8, fmt -> List U8) -[..]-> Encoder fmt where fmt implements EncoderFormatting - // ~ fn_var -[clos]-> t' - env.unify(custom_fn_var, this_custom_fn_var); + // // (List U8, fmt -> List U8) -[..]-> Inspector fmt where fmt implements InspectorFormatting + // // ~ fn_var -[clos]-> t' + // env.unify(custom_fn_var, this_custom_fn_var); - // 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)), - this_custom_clos_var, // -[clos]-> - this_custom_encoder_var, // t' ~ Encoder fmt - )); + // // Inspect.custom : (List U8, fmt -> List U8) -> Inspector fmt where fmt implements InspectorFormatting + // let custom_fn = Box::new(( + // this_custom_fn_var, + // Loc::at_zero(Var(Symbol::INSPECT_CUSTOM, this_custom_fn_var)), + // this_custom_clos_var, // -[clos]-> + // this_custom_inspector_var, // t' ~ Inspector fmt + // )); - // Encode.custom \bytes, fmt -> Encode.appendWith bytes encoder fmt - let custom_call = Call( - custom_fn, - vec![(fn_var, Loc::at_zero(clos))], - CalledVia::Space, - ); + // // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes inspector fmt + // let custom_call = Call( + // custom_fn, + // vec![(fn_var, Loc::at_zero(clos))], + // CalledVia::Space, + // ); - (custom_call, this_custom_encoder_var) + // (custom_call, this_custom_inspector_var) } From c57bc4db11a5b14372ce06569b35e18ec90cfba9 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 27 Nov 2023 17:46:27 -0800 Subject: [PATCH 049/105] add uitest to view bool inspect derive --- .../compiler/uitest/tests/ability/specialize/inspect/bool.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt new file mode 100644 index 0000000000..7b11b76012 --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt @@ -0,0 +1,4 @@ +app "test" provides [main] to "./platform" + +main = Inspect.toInspector Bool.true +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[] + f:Inspect.bool(13):1]-> Inspector f where f implements InspectFormatter From f0dee1f6e923543d35b0cc4973dab9f4b76ed99d Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 27 Nov 2023 17:59:41 -0800 Subject: [PATCH 050/105] add missing ToInspector case --- crates/compiler/test_derive/src/util.rs | 5 +++++ .../specialize/inspect/{bool.txt => bool_to_inspector.txt} | 0 2 files changed, 5 insertions(+) rename crates/compiler/uitest/tests/ability/specialize/inspect/{bool.txt => bool_to_inspector.txt} (100%) diff --git a/crates/compiler/test_derive/src/util.rs b/crates/compiler/test_derive/src/util.rs index bb5d7bb6dc..0f5cacd2e7 100644 --- a/crates/compiler/test_derive/src/util.rs +++ b/crates/compiler/test_derive/src/util.rs @@ -68,6 +68,11 @@ fn module_source_and_path(builtin: DeriveBuiltin) -> (ModuleId, &'static str, Pa module_source(ModuleId::BOOL), builtins_path.join("Bool.roc"), ), + DeriveBuiltin::ToInspector => ( + ModuleId::INSPECT, + module_source(ModuleId::INSPECT), + builtins_path.join("Inspect.roc"), + ), } } diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt similarity index 100% rename from crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt rename to crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt From 3434d3154aec8e5d4da391f22e2116998fda2e11 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 27 Nov 2023 22:15:09 -0800 Subject: [PATCH 051/105] Ayaz's fix and first passing inspect test --- crates/compiler/builtins/roc/Inspect.roc | 4 ++-- crates/compiler/solve/src/ability.rs | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 611fa04e00..03e46e1b48 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -249,10 +249,10 @@ dbgBool : Bool -> Inspector DbgFormatter dbgBool = \b -> if b then f0 <- custom - dbgWrite f0 "true" + dbgWrite f0 "Bool.true" else f0 <- custom - dbgWrite f0 "false" + dbgWrite f0 "Bool.false" dbgStr : Str -> Inspector DbgFormatter dbgStr = \s -> diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index 6ffa242ba1..cce612453c 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -1504,10 +1504,7 @@ impl AbilityResolver for AbilitiesStore { /// because they do not explicitly list ability implementations due to circular dependencies. #[inline] pub(crate) fn builtin_module_with_unlisted_ability_impl(module_id: ModuleId) -> bool { - matches!( - module_id, - ModuleId::NUM | ModuleId::BOOL | ModuleId::INSPECT - ) + matches!(module_id, ModuleId::NUM | ModuleId::BOOL) } #[derive(Debug)] From 2e486953be6e64fa80974a8c6852131c898a0882 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 27 Nov 2023 22:21:10 -0800 Subject: [PATCH 052/105] put inspect tests in their own module --- crates/compiler/test_gen/src/gen_abilities.rs | 107 ++++++++++-------- 1 file changed, 59 insertions(+), 48 deletions(-) diff --git a/crates/compiler/test_gen/src/gen_abilities.rs b/crates/compiler/test_gen/src/gen_abilities.rs index 44c5e4b5f5..50fbbeb243 100644 --- a/crates/compiler/test_gen/src/gen_abilities.rs +++ b/crates/compiler/test_gen/src/gen_abilities.rs @@ -2181,12 +2181,25 @@ fn issue_4772_weakened_monomorphic_destructure() { }) } -#[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] -fn inspect_bool() { - assert_evals_to!( - indoc!( - r#" +mod inspect { + #[cfg(feature = "gen-llvm")] + use crate::helpers::llvm::assert_evals_to; + + #[cfg(feature = "gen-wasm")] + use crate::helpers::wasm::assert_evals_to; + + #[cfg(all(test, any(feature = "gen-llvm", feature = "gen-wasm")))] + use indoc::indoc; + + #[cfg(all(test, any(feature = "gen-llvm", feature = "gen-wasm")))] + use roc_std::RocStr; + + #[test] + #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] + fn bool() { + assert_evals_to!( + indoc!( + r#" app "test" provides [main] to "./platform" main = [ @@ -2194,24 +2207,21 @@ fn inspect_bool() { Inspect.inspect Bool.false, ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# - ), - RocStr::from("Bool.true, Bool.false"), - RocStr - ); -} + ), + RocStr::from("Bool.true, Bool.false"), + RocStr + ); + } -#[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] -fn inspect_num() { - assert_evals_to!( - indoc!( - r#" + #[test] + #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] + fn num() { + assert_evals_to!( + indoc!( + r#" app "test" provides [main] to "./platform" main = [ - Inspect.inspect 42, # Num * - Inspect.inspect 0x5, # Int * - Inspect.inspect (0.1 + 0.2), # Frac * Inspect.inspect 1u8, # U8 Inspect.inspect 2i8, # I8 Inspect.inspect 3u16, # U16 @@ -2227,18 +2237,18 @@ fn inspect_num() { Inspect.inspect (1.1dec + 2.2), # Dec ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# - ), - RocStr::from("42, 5, 0.3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1.1, 2.2, 3.3"), - RocStr - ); -} + ), + RocStr::from("42, 5, 0.3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1.1, 2.2, 3.3"), + RocStr + ); + } -#[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] -fn inspect_list() { - assert_evals_to!( - indoc!( - r#" + #[test] + #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] + fn list() { + assert_evals_to!( + indoc!( + r#" app "test" provides [main] to "./platform" main = [ @@ -2250,18 +2260,18 @@ fn inspect_list() { Inspect.inspect ["foo"], # List Str ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# - ), - RocStr::from("[], [0, 1, 2], [1, 2, 3], [0.3, 0.4], [1, 2], [\"foo\"]"), - RocStr - ); -} + ), + RocStr::from("[], [0, 1, 2], [1, 2, 3], [0.3, 0.4], [1, 2], [\"foo\"]"), + RocStr + ); + } -#[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] -fn inspect_str() { - assert_evals_to!( - indoc!( - r#" + #[test] + #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] + fn str() { + assert_evals_to!( + indoc!( + r#" app "test" provides [main] to "./platform" main = [ @@ -2270,10 +2280,11 @@ fn inspect_str() { Inspect.inspect "an extraordinarily long string - so long it's on the heap!", ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# - ), - RocStr::from( - r#""", "a small string", "an extraordinarily long string - so long it's on the heap!""# - ), - RocStr - ); + ), + RocStr::from( + r#""", "a small string", "an extraordinarily long string - so long it's on the heap!""# + ), + RocStr + ); + } } From a1a563074dc859956e7b66209ec05797f9d77892 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 27 Nov 2023 22:25:51 -0800 Subject: [PATCH 053/105] expand ui tests to numbers --- .../specialize/inspect/bool_to_inspector.txt | 4 ++-- .../specialize/inspect/num_a_to_inspector.txt | 4 ++++ .../ability/specialize/inspect/u8_to_inspector.txt | 4 ++++ .../generalization_among_large_recursive_group.txt | 14 +++++++------- 4 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt index 7b11b76012..50661600b3 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt @@ -1,4 +1,4 @@ app "test" provides [main] to "./platform" -main = Inspect.toInspector Bool.true -# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[] + f:Inspect.bool(13):1]-> Inspector f where f implements InspectFormatter +main = Inspect.toInspector Bool.true |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[Inspect.dbgBool(43)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt new file mode 100644 index 0000000000..7d6958d913 --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt @@ -0,0 +1,4 @@ +app "test" provides [main] to "./platform" + +main = Inspect.toInspector 7 |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[Inspect.dbgBool(43)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt new file mode 100644 index 0000000000..346c608138 --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt @@ -0,0 +1,4 @@ +app "test" provides [main] to "./platform" + +main = Inspect.toInspector 7u8 |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[Inspect.dbgBool(43)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt b/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt index 6238bd9ad1..5b89442a58 100644 --- a/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt +++ b/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt @@ -3,22 +3,22 @@ app "test" provides [main] to "./platform" f = \{} -> -#^{-1} <1874><117>{} -<120>[[f(1)]]-> <116>[Ok <1882>{}]<80>* +#^{-1} <2722><117>{} -<120>[[f(1)]]-> <116>[Ok <2730>{}]<80>* when g {} is -# ^ <1864><1882>{} -<1872>[[g(2)]]-> <72>[Ok <1882>{}]<102>* +# ^ <2712><2730>{} -<2720>[[g(2)]]-> <72>[Ok <2730>{}]<102>* _ -> Ok {} g = \{} -> -#^{-1} <1864><1882>{} -<1872>[[g(2)]]-> <72>[Ok <1882>{}]<102>* +#^{-1} <2712><2730>{} -<2720>[[g(2)]]-> <72>[Ok <2730>{}]<102>* when h {} is -# ^ <1869><1882>{} -<1877>[[h(3)]]-> <94>[Ok <1882>{}]<124>* +# ^ <2717><2730>{} -<2725>[[h(3)]]-> <94>[Ok <2730>{}]<124>* _ -> Ok {} h = \{} -> -#^{-1} <1869><1882>{} -<1877>[[h(3)]]-> <94>[Ok <1882>{}]<124>* +#^{-1} <2717><2730>{} -<2725>[[h(3)]]-> <94>[Ok <2730>{}]<124>* when f {} is -# ^ <1874><117>{} -<120>[[f(1)]]-> <116>[Ok <1882>{}]<80>* +# ^ <2722><117>{} -<120>[[f(1)]]-> <116>[Ok <2730>{}]<80>* _ -> Ok {} main = f {} -# ^ <1884><133>{} -<136>[[f(1)]]-> <138>[Ok <1882>{}]<1883>w_a +# ^ <2732><133>{} -<136>[[f(1)]]-> <138>[Ok <2730>{}]<2731>w_a From 35078a22952ddb4a2d05a0926c472f8e0ab3ce49 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 09:20:33 -0800 Subject: [PATCH 054/105] allow nat in DeriveInspect --- crates/compiler/solve/src/ability.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index cce612453c..36eac7736a 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -859,8 +859,8 @@ impl DerivableVisitor for DeriveInspect { #[inline(always)] fn is_derivable_builtin_opaque(symbol: Symbol) -> bool { - (is_builtin_number_alias(symbol) && !is_builtin_nat_alias(symbol)) - || is_builtin_bool_alias(symbol) + // TODO: Should this just be true? All values are always inspectable. + is_builtin_number_alias(symbol) || is_builtin_bool_alias(symbol) } #[inline(always)] @@ -927,16 +927,9 @@ impl DerivableVisitor for DeriveInspect { } #[inline(always)] - fn visit_alias(var: Variable, symbol: Symbol) -> Result { + fn visit_alias(_var: Variable, symbol: Symbol) -> Result { if is_builtin_number_alias(symbol) { - if is_builtin_nat_alias(symbol) { - Err(NotDerivable { - var, - context: NotDerivableContext::Encode(NotDerivableEncode::Nat), - }) - } else { - Ok(Descend(false)) - } + Ok(Descend(false)) } else { Ok(Descend(true)) } From f2ab6b54f3468e2601e0a3a8fcf0e43786f8e57d Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 09:33:11 -0800 Subject: [PATCH 055/105] correct Inspect.opaque and Inspect.function to be function calls --- crates/compiler/builtins/roc/Inspect.roc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 03e46e1b48..64a5f8fcb3 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -62,11 +62,11 @@ InspectFormatter implements # In text, this would render as `` # TODO: Pass the type name to opaque so that it can be displayed. - opaque : Inspector f where f implements InspectFormatter + opaque : * -> Inspector f where f implements InspectFormatter # In text, this would render as `` # TODO: Maybe pass the the function name or signiture to function so that it can be displayed. - function : Inspector f where f implements InspectFormatter + function : * -> Inspector f where f implements InspectFormatter u8 : U8 -> Inspector f where f implements InspectFormatter i8 : I8 -> Inspector f where f implements InspectFormatter @@ -262,13 +262,13 @@ dbgStr = \s -> |> dbgWrite s |> dbgWrite "\"" -dbgOpaque : Inspector DbgFormatter -dbgOpaque = +dbgOpaque : * -> Inspector DbgFormatter +dbgOpaque = \_ -> f0 <- custom dbgWrite f0 "" -dbgFunction : Inspector DbgFormatter -dbgFunction = +dbgFunction : * -> Inspector DbgFormatter +dbgFunction = \_ -> f0 <- custom dbgWrite f0 "" From 796c2b1ded3df666d844118bddb0ffed8893c600 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 09:54:02 -0800 Subject: [PATCH 056/105] unwrap builtin opaques like NUM_NUM --- crates/compiler/derive_key/src/inspect.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs index 3bc5793c46..18f67dec8e 100644 --- a/crates/compiler/derive_key/src/inspect.rs +++ b/crates/compiler/derive_key/src/inspect.rs @@ -141,6 +141,10 @@ impl FlatInspectable { AliasKind::Structural => { Self::from_var(subs, real_var) } + AliasKind::Opaque if sym.is_builtin() => { + // TODO: Is this correct for all builtins? It is at least required for the Num wrapper types. + Self::from_var(subs, real_var) + } AliasKind::Opaque => { // There are two cases in which `Inspect` can be derived for an opaque // type. From 6eedd08e5a77edc7ed0a3ad850a3112583d7f5cf Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 09:55:35 -0800 Subject: [PATCH 057/105] add Debug to FlatInspectable --- crates/compiler/derive_key/src/inspect.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs index 18f67dec8e..1fa026863d 100644 --- a/crates/compiler/derive_key/src/inspect.rs +++ b/crates/compiler/derive_key/src/inspect.rs @@ -11,7 +11,7 @@ use crate::util::{ check_derivable_ext_var, debug_name_fn, debug_name_record, debug_name_tag, debug_name_tuple, }; -#[derive(Hash)] +#[derive(Hash, Debug)] pub enum FlatInspectable { Immediate(Symbol), Key(FlatInspectableKey), From 82cda1965c0e6e8a3141815bfd79648ac94c708c Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 10:05:25 -0800 Subject: [PATCH 058/105] use INSPECT_INSPECT_ABILITY instead of INSPECT_INSPECT --- crates/compiler/load/tests/test_reporting.rs | 2 +- crates/compiler/module/src/symbol.rs | 5 ++++- crates/compiler/solve/src/ability.rs | 2 +- crates/compiler/types/src/subs.rs | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/compiler/load/tests/test_reporting.rs b/crates/compiler/load/tests/test_reporting.rs index 9cf2f4bccc..331eee480b 100644 --- a/crates/compiler/load/tests/test_reporting.rs +++ b/crates/compiler/load/tests/test_reporting.rs @@ -9798,7 +9798,7 @@ In roc, functions are always written as a lambda, like{} Only builtin abilities can be derived. - Note: The builtin abilities are `Encoding`, `Decoding`, `Hash`, `Eq` + Note: The builtin abilities are `Encoding`, `Decoding`, `Hash`, `Eq`, `Inspect` "### ); diff --git a/crates/compiler/module/src/symbol.rs b/crates/compiler/module/src/symbol.rs index bbd130d326..7fee728ad4 100644 --- a/crates/compiler/module/src/symbol.rs +++ b/crates/compiler/module/src/symbol.rs @@ -53,7 +53,10 @@ pub const DERIVABLE_ABILITIES: &[(Symbol, &[Symbol])] = &[ (Symbol::DECODE_DECODING, &[Symbol::DECODE_DECODER]), (Symbol::HASH_HASH_ABILITY, &[Symbol::HASH_HASH]), (Symbol::BOOL_EQ, &[Symbol::BOOL_IS_EQ]), - (Symbol::INSPECT_INSPECT, &[Symbol::INSPECT_TO_INSPECTOR]), + ( + Symbol::INSPECT_INSPECT_ABILITY, + &[Symbol::INSPECT_TO_INSPECTOR], + ), ]; /// In Debug builds only, Symbol has a name() method that lets diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index 36eac7736a..33de269a9f 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -854,7 +854,7 @@ trait DerivableVisitor { struct DeriveInspect; impl DerivableVisitor for DeriveInspect { - const ABILITY: Symbol = Symbol::INSPECT_INSPECT; + const ABILITY: Symbol = Symbol::INSPECT_INSPECT_ABILITY; const ABILITY_SLICE: SubsSlice = Subs::AB_INSPECT; #[inline(always)] diff --git a/crates/compiler/types/src/subs.rs b/crates/compiler/types/src/subs.rs index 07dda6b003..7b3f6abf28 100644 --- a/crates/compiler/types/src/subs.rs +++ b/crates/compiler/types/src/subs.rs @@ -1756,7 +1756,7 @@ impl Subs { symbol_names.push(Symbol::HASH_HASHER); symbol_names.push(Symbol::HASH_HASH_ABILITY); symbol_names.push(Symbol::BOOL_EQ); - symbol_names.push(Symbol::INSPECT_INSPECT); + symbol_names.push(Symbol::INSPECT_INSPECT_ABILITY); // END INIT-SymbolNames // IFTTT INIT-VariableSubsSlice From c443bdcf4f312bf366001d780ac88e24f5c1e080 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 10:17:09 -0800 Subject: [PATCH 059/105] check_adhoc for inspect --- crates/compiler/solve/src/ability.rs | 7 +++++++ .../ability/specialize/inspect/num_a_to_inspector.txt | 2 +- .../tests/ability/specialize/inspect/opaque_derived.txt | 2 +- .../tests/ability/specialize/inspect/u8_to_inspector.txt | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index 33de269a9f..889e3d5425 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -304,6 +304,13 @@ impl ObligationCache { Symbol::BOOL_EQ => Some(DeriveEq::is_derivable(self, abilities_store, subs, var)), + Symbol::INSPECT_INSPECT_ABILITY => Some(DeriveInspect::is_derivable( + self, + abilities_store, + subs, + var, + )), + _ => None, }; diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt index 7d6958d913..e0112f852b 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt @@ -1,4 +1,4 @@ app "test" provides [main] to "./platform" main = Inspect.toInspector 7 |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr -# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[Inspect.dbgBool(43)]]-> Inspector DbgFormatter +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): I64 -[[Inspect.dbgI64(54)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt index cfe872a6bd..4aebca3440 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt @@ -3,4 +3,4 @@ app "test" provides [main] to "./platform" Op := U8 implements [Inspect] main = Inspect.toInspector (@Op 1u8) -# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Op -[[] + f:Inspect.opaque(15):1]-> Inspector f where f implements InspectFormatter +# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(3): Op -[[#Op_toInspector(3)]]-> Inspector f where f implements InspectFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt index 346c608138..59b9a84c1c 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt @@ -1,4 +1,4 @@ app "test" provides [main] to "./platform" main = Inspect.toInspector 7u8 |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr -# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[Inspect.dbgBool(43)]]-> Inspector DbgFormatter +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): U8 -[[Inspect.dbgU8(47)]]-> Inspector DbgFormatter From 4c25c60cdc191cbf331e76b5c500afaff79c8ff7 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 10:38:49 -0800 Subject: [PATCH 060/105] expand ui tests for inspect --- .../inspect/{bool_to_inspector.txt => bool.txt} | 0 .../uitest/tests/ability/specialize/inspect/dec.txt | 4 ++++ .../specialize/inspect/non_implementing_opaque.txt | 4 ++-- .../ability/specialize/inspect/opaque_custom_impl.txt | 4 ++-- .../tests/ability/specialize/inspect/opaque_derived.txt | 4 ++-- .../inspect/{num_a_to_inspector.txt => ranged_num.txt} | 0 .../uitest/tests/ability/specialize/inspect/record.txt | 4 ++++ .../inspect/record_with_nested_custom_impl.txt | 9 +++++++++ .../specialize/inspect/{u8_to_inspector.txt => u8.txt} | 0 9 files changed, 23 insertions(+), 6 deletions(-) rename crates/compiler/uitest/tests/ability/specialize/inspect/{bool_to_inspector.txt => bool.txt} (100%) create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/dec.txt rename crates/compiler/uitest/tests/ability/specialize/inspect/{num_a_to_inspector.txt => ranged_num.txt} (100%) create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/record.txt create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt rename crates/compiler/uitest/tests/ability/specialize/inspect/{u8_to_inspector.txt => u8.txt} (100%) diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt similarity index 100% rename from crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt rename to crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/dec.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/dec.txt new file mode 100644 index 0000000000..839ebc1cba --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/dec.txt @@ -0,0 +1,4 @@ +app "test" provides [main] to "./platform" + +main = Inspect.toInspector 7dec |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Dec -[[Inspect.dbgDec(60)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt index c0b907ae38..d27232f296 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt @@ -2,5 +2,5 @@ app "test" provides [main] to "./platform" Op := {} -main = Inspect.toInspector (@Op {}) -# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Op -[[] + f:Inspect.opaque(15):1]-> Inspector f where f implements InspectFormatter +main = Inspect.toInspector (@Op {}) |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Op -[[Inspect.dbgOpaque(45)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt index 2b5a4b1cfa..bdb8f45893 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt @@ -5,5 +5,5 @@ Op := U8 implements [Inspect { toInspector: myToInspector }] myToInspector : Op -> Inspector f where f implements InspectFormatter myToInspector = \@Op num -> Inspect.u8 num -main = Inspect.toInspector (@Op 1u8) -# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(2): Op -[[myToInspector(2)]]-> Inspector f where f implements InspectFormatter +main = Inspect.toInspector (@Op 1u8) |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(2): Op -[[myToInspector(2)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt index 4aebca3440..1e3569a4fd 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt @@ -2,5 +2,5 @@ app "test" provides [main] to "./platform" Op := U8 implements [Inspect] -main = Inspect.toInspector (@Op 1u8) -# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(3): Op -[[#Op_toInspector(3)]]-> Inspector f where f implements InspectFormatter +main = Inspect.toInspector (@Op 1u8) |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(3): Op -[[#Op_toInspector(3)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/ranged_num.txt similarity index 100% rename from crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt rename to crates/compiler/uitest/tests/ability/specialize/inspect/ranged_num.txt diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/record.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/record.txt new file mode 100644 index 0000000000..0478644973 --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/record.txt @@ -0,0 +1,4 @@ +app "test" provides [main] to "./platform" + +main = Inspect.toInspector { a: "" } |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[Inspect.dbgBool(43)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt new file mode 100644 index 0000000000..107cc4ade5 --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt @@ -0,0 +1,9 @@ +app "test" provides [main] to "./platform" + +Op := U8 implements [Inspect { toInspector: myToInspector }] + +myToInspector : Op -> Inspector f where f implements InspectFormatter +myToInspector = \@Op num -> Inspect.u8 num + +main = Inspect.toInspector { op: @Op 1u8 } |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(2): Op -[[myToInspector(2)]]-> Inspector f where f implements InspectFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/u8.txt similarity index 100% rename from crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt rename to crates/compiler/uitest/tests/ability/specialize/inspect/u8.txt From 5e36395369d182bce99bccf1ce8dd89f39d16efd Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 10:52:17 -0800 Subject: [PATCH 061/105] correct Inspect custom impl to use Inspect.apply --- crates/compiler/derive/src/inspect.rs | 304 +++++++++--------- .../ability/specialize/inspect/record.txt | 2 +- .../record_with_nested_custom_impl.txt | 2 +- 3 files changed, 147 insertions(+), 161 deletions(-) diff --git a/crates/compiler/derive/src/inspect.rs b/crates/compiler/derive/src/inspect.rs index 1fd048c997..0e591a5c6d 100644 --- a/crates/compiler/derive/src/inspect.rs +++ b/crates/compiler/derive/src/inspect.rs @@ -128,7 +128,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { ); // build `toInspector elem` type - // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); // elem -[clos]-> t1 @@ -143,11 +143,11 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { )), ); - // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ elem -[clos]-> t1 env.unify(to_inspector_fn_var, elem_to_inspector_fn_var); - // toInspector : (typeof rcd.a) -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // toInspector : (typeof rcd.a) -[clos]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_var = AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, elem_to_inspector_fn_var); let to_inspector_fn = Box::new(( @@ -209,7 +209,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { }); // build `Inspect.list lst (\elem -> Inspect.toInspector elem)` type - // List e, (e -> Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // List e, (e -> Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatter let inspect_list_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_LIST); // List elem, to_elem_inspector_fn_var -[clos]-> t1 @@ -226,11 +226,11 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { )), ); - // List e, (e -> Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // List e, (e -> Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ List elem, to_elem_inspector_fn_var -[clos]-> t1 env.unify(inspect_list_fn_var, this_inspect_list_fn_var); - // Inspect.list : List elem, to_elem_inspector_fn_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // Inspect.list : List elem, to_elem_inspector_fn_var -[clos]-> Inspector fmt where fmt implements InspectorFormatter let inspect_list = AbilityMember(Symbol::INSPECT_LIST, None, this_inspect_list_fn_var); let inspect_list_fn = Box::new(( this_inspect_list_fn_var, @@ -249,7 +249,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { CalledVia::Space, ); - // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (Inspect.list ..) fmt + // Inspect.custom \fmt -> Inspect.apply (Inspect.list ..) fmt let (body, this_inspector_var) = wrap_in_inspect_custom( env, inspect_list_call, @@ -348,7 +348,7 @@ fn to_inspector_record( }; // build `toInspector rcd.a` type - // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); // (typeof rcd.a) -[clos]-> t1 @@ -363,11 +363,11 @@ fn to_inspector_record( )), ); - // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ (typeof rcd.a) -[clos]-> t1 env.unify(to_inspector_fn_var, this_to_inspector_fn_var); - // toInspector : (typeof rcd.a) -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // toInspector : (typeof rcd.a) -[clos]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_var = AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, to_inspector_fn_var); let to_inspector_fn = Box::new(( @@ -429,7 +429,7 @@ fn to_inspector_record( }; // build `Inspect.record [ { key: .., value: ..}, .. ]` type - // List { key : Str, value : Inspector fmt } -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // List { key : Str, value : Inspector fmt } -[uls]-> Inspector fmt where fmt implements InspectorFormatter let inspect_record_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_RECORD); // fields_list_var -[clos]-> t1 @@ -446,11 +446,11 @@ fn to_inspector_record( )), ); - // List { key : Str, value : Inspector fmt } -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // List { key : Str, value : Inspector fmt } -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ fields_list_var -[clos]-> t1 env.unify(inspect_record_fn_var, this_inspect_record_fn_var); - // Inspect.record : fields_list_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // Inspect.record : fields_list_var -[clos]-> Inspector fmt where fmt implements InspectorFormatter let inspect_record_var = AbilityMember(Symbol::INSPECT_RECORD, None, inspect_record_fn_var); let inspect_record_fn = Box::new(( inspect_record_fn_var, @@ -466,7 +466,7 @@ fn to_inspector_record( CalledVia::Space, ); - // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (Inspect.record ..) fmt + // Inspect.custom \fmt -> Inspect.apply (Inspect.record ..) fmt let (body, this_inspector_var) = wrap_in_inspect_custom(env, inspect_record_call, inspector_var, rcd_sym, record_var); @@ -552,7 +552,7 @@ fn to_inspector_tuple( }; // build `toInspector tup.0` type - // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); // (typeof tup.0) -[clos]-> t1 @@ -567,11 +567,11 @@ fn to_inspector_tuple( )), ); - // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ (typeof tup.0) -[clos]-> t1 env.unify(to_inspector_fn_var, this_to_inspector_fn_var); - // toInspector : (typeof tup.0) -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // toInspector : (typeof tup.0) -[clos]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_var = AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, to_inspector_fn_var); let to_inspector_fn = Box::new(( @@ -613,7 +613,7 @@ fn to_inspector_tuple( }; // build `Inspect.tuple [ toInspector tup.0, toInspector tup.1 ]` type - // List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatter let inspect_tuple_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TUPLE); // elem_inspectors_list_var -[clos]-> t1 @@ -630,11 +630,11 @@ fn to_inspector_tuple( )), ); - // List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ elem_inspectors_list_var -[clos]-> t1 env.unify(inspect_tuple_fn_var, this_inspect_tuple_fn_var); - // Inspect.tuple : elem_inspectors_list_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // Inspect.tuple : elem_inspectors_list_var -[clos]-> Inspector fmt where fmt implements InspectorFormatter let inspect_tuple_var = AbilityMember(Symbol::INSPECT_TUPLE, None, inspect_tuple_fn_var); let inspect_tuple_fn = Box::new(( inspect_tuple_fn_var, @@ -650,7 +650,7 @@ fn to_inspector_tuple( CalledVia::Space, ); - // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (Inspect.tuple_var ..) fmt + // Inspect.custom \fmt -> Inspect.apply (Inspect.tuple_var ..) fmt let (body, this_inspector_var) = wrap_in_inspect_custom(env, inspect_tuple_call, inspector_var, tup_sym, tuple_var); @@ -751,7 +751,7 @@ fn to_inspector_tag_union( .zip(payload_vars.iter()) .map(|(&sym, &sym_var)| { // build `toInspector v1` type - // expected: val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // expected: val -[uls]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); @@ -769,11 +769,11 @@ fn to_inspector_tag_union( )), ); - // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ t1 -[clos]-> t' env.unify(to_inspector_fn_var, this_to_inspector_fn_var); - // toInspector : t1 -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // toInspector : t1 -[clos]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_var = AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, this_to_inspector_fn_var); let to_inspector_fn = Box::new(( @@ -815,7 +815,7 @@ fn to_inspector_tag_union( }; // build `Inspect.tag "A" [ ... ]` type - // expected: Str, List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // expected: Str, List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatter let inspect_tag_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TAG); // wanted: Str, List whole_inspectors_var -[clos]-> t' @@ -834,11 +834,11 @@ fn to_inspector_tag_union( )), ); - // Str, List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // Str, List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ Str, List whole_inspectors_var -[clos]-> t' env.unify(inspect_tag_fn_var, this_inspect_tag_fn_var); - // Inspect.tag : Str, List whole_inspectors_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // Inspect.tag : Str, List whole_inspectors_var -[clos]-> Inspector fmt where fmt implements InspectorFormatter let inspect_tag_var = AbilityMember(Symbol::INSPECT_TAG, None, this_inspect_tag_fn_var); let inspect_tag_fn = Box::new(( this_inspect_tag_fn_var, @@ -888,7 +888,7 @@ fn to_inspector_tag_union( exhaustive: ExhaustiveMark::known_exhaustive(), }; - // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (when ..) fmt + // Inspect.custom \fmt -> Inspect.apply (when ..) fmt let (body, this_inspector_var) = wrap_in_inspect_custom( env, when_branches, @@ -923,7 +923,7 @@ fn to_inspector_tag_union( ); // \tag -> - // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes ( + // Inspect.custom \fmt -> Inspect.apply ( // when tag is // A v1 v2 -> Inspect.tag "A" [ Inspect.toInspector v1, Inspect.toInspector v2 ] // B v3 -> Inspect.tag "B" [ Inspect.toInspector v3 ]) @@ -946,158 +946,144 @@ fn to_inspector_tag_union( (clos, fn_var) } -/// Lift `inspector` to `Inspect.custom \bytes, fmt -> Inspect.appendWith bytes inspector fmt` +/// Lift `inspector` to `Inspect.custom \fmt -> Inspect.apply inspector fmt` /// /// TODO: currently it appears that just `inspector` is not isomorphic to the lift, on the /// monomorphization level, even though we would think it is. In particular, unspecialized lambda /// sets fail to resolve when we use the non-lifted version. /// More investigation is needed to figure out why. fn wrap_in_inspect_custom( - _env: &mut Env, - _inspector: Expr, - _inspector_var: Variable, - _captured_symbol: Symbol, - _captured_var: Variable, + env: &mut Env, + inspector: Expr, + inspector_var: Variable, + captured_symbol: Symbol, + captured_var: Variable, ) -> (Expr, Variable) { - unimplemented!(); - // use Expr::*; + use Expr::*; - // let fn_name = env.new_symbol("custom"); + let fn_name = env.new_symbol("custom"); - // // bytes: List U8 - // let bytes_sym = env.new_symbol("bytes"); - // let bytes_var = Variable::LIST_U8; + // fmt: fmt where fmt implements InspectorFormatter + let fmt_sym = env.new_symbol("fmt"); + let fmt_var = env.subs.fresh_unnamed_flex_var(); - // // fmt: fmt where fmt implements InspectorFormatting - // let fmt_sym = env.new_symbol("fmt"); - // let fmt_var = env.subs.fresh_unnamed_flex_var(); + // build `Inspect.apply inspector fmt` type + // expected: Inspect.apply : Inspector fmt, fmt -[apply]-> fmt where fmt implements InspectorFormatter + let apply_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_APPLY); - // // build `Inspect.appendWith bytes inspector fmt` type - // // expected: Inspect.appendWith : List U8, Inspector fmt, fmt -[appendWith]-> List U8 where fmt implements InspectorFormatting - // let append_with_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_APPEND_WITH); + // wanted: Inspect.apply : inspector_var, fmt -[clos]-> fmt where fmt implements InspectorFormatter + let this_apply_args_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, [inspector_var, fmt_var]); + let this_apply_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> + let this_apply_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + this_apply_args_var_slice, + this_apply_clos_var, + fmt_var, + )), + ); - // // wanted: Inspect.appendWith : List U8, inspector_var, fmt -[clos]-> List U8 where fmt implements InspectorFormatting - // let this_append_with_args_var_slice = - // VariableSubsSlice::insert_into_subs(env.subs, [Variable::LIST_U8, inspector_var, fmt_var]); - // let this_append_with_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> - // let this_append_with_fn_var = synth_var( - // env.subs, - // Content::Structure(FlatType::Func( - // this_append_with_args_var_slice, - // this_append_with_clos_var, - // Variable::LIST_U8, - // )), - // ); + // Inspector fmt, fmt -[apply]-> ft where fmt implements InspectorFormatter + // ~ inspector_var, fmt -[clos]-> fmt where fmt implements InspectorFormatter + env.unify(apply_fn_var, this_apply_fn_var); - // // List U8, Inspector fmt, fmt -[appendWith]-> List U8 where fmt implements InspectorFormatting - // // ~ List U8, inspector_var, fmt -[clos]-> List U8 where fmt implements InspectorFormatting - // env.unify(append_with_fn_var, this_append_with_fn_var); + // Inspect.apply : inspector_var, fmt -[apply]-> fmt where fmt implements InspectorFormatter + let apply_fn = Box::new(( + this_apply_fn_var, + Loc::at_zero(Var(Symbol::INSPECT_APPLY, this_apply_fn_var)), + this_apply_clos_var, + fmt_var, + )); - // // Inspect.appendWith : List U8, inspector_var, fmt -[appendWith]-> List U8 where fmt implements InspectorFormatting - // let append_with_fn = Box::new(( - // this_append_with_fn_var, - // Loc::at_zero(Var(Symbol::INSPECT_APPEND_WITH, this_append_with_fn_var)), - // this_append_with_clos_var, - // Variable::LIST_U8, - // )); + // Inspect.apply inspector fmt + let apply_call = Call( + apply_fn, + vec![ + // (inspector_var, inspector) + (inspector_var, Loc::at_zero(inspector)), + // (fmt, fmt_var) + (fmt_var, Loc::at_zero(Var(fmt_sym, fmt_var))), + ], + CalledVia::Space, + ); - // // Inspect.appendWith bytes inspector fmt - // let append_with_call = Call( - // append_with_fn, - // vec![ - // // (bytes_var, bytes) - // (bytes_var, Loc::at_zero(Var(bytes_sym, bytes_var))), - // // (inspector_var, inspector) - // (inspector_var, Loc::at_zero(inspector)), - // // (fmt, fmt_var) - // (fmt_var, Loc::at_zero(Var(fmt_sym, fmt_var))), - // ], - // CalledVia::Space, - // ); + // Create fn_var for ambient capture; we fix it up below. + let fn_var = synth_var(env.subs, Content::Error); - // // Create fn_var for ambient capture; we fix it up below. - // let fn_var = synth_var(env.subs, Content::Error); + // -[[FN_name captured_var]]-> + let fn_name_labels = + UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![captured_var]))); + let fn_clos_var = synth_var( + env.subs, + Content::LambdaSet(LambdaSet { + solved: fn_name_labels, + recursion_var: OptVariable::NONE, + unspecialized: SubsSlice::default(), + ambient_function: fn_var, + }), + ); - // // -[[FN_name captured_var]]-> - // let fn_name_labels = - // UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![captured_var]))); - // let fn_clos_var = synth_var( - // env.subs, - // Content::LambdaSet(LambdaSet { - // solved: fn_name_labels, - // recursion_var: OptVariable::NONE, - // unspecialized: SubsSlice::default(), - // ambient_function: fn_var, - // }), - // ); + // fmt -[[FN_name captured_var]]-> Inspect.apply inspector fmt + let args_slice = SubsSlice::insert_into_subs(env.subs, vec![fmt_var]); + env.subs.set_content( + fn_var, + Content::Structure(FlatType::Func(args_slice, fn_clos_var, fmt_var)), + ); - // // bytes, fmt -[[FN_name captured_var]]-> Inspect.appendWith bytes inspector fmt - // let args_slice = SubsSlice::insert_into_subs(env.subs, vec![bytes_var, fmt_var]); - // env.subs.set_content( - // fn_var, - // Content::Structure(FlatType::Func(args_slice, fn_clos_var, Variable::LIST_U8)), - // ); + // \fmt -[[fn_name captured_var]]-> Inspect.apply inspector fmt + let clos = Closure(ClosureData { + function_type: fn_var, + closure_type: fn_clos_var, + return_type: fmt_var, + name: fn_name, + captured_symbols: vec![(captured_symbol, captured_var)], + recursive: Recursive::NotRecursive, + arguments: vec![( + fmt_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(fmt_sym)), + )], + loc_body: Box::new(Loc::at_zero(apply_call)), + }); - // // \bytes, fmt -[[fn_name captured_var]]-> Inspect.appendWith bytes inspector fmt - // let clos = Closure(ClosureData { - // function_type: fn_var, - // closure_type: fn_clos_var, - // return_type: Variable::LIST_U8, - // name: fn_name, - // captured_symbols: vec![(captured_symbol, captured_var)], - // recursive: Recursive::NotRecursive, - // arguments: vec![ - // ( - // bytes_var, - // AnnotatedMark::known_exhaustive(), - // Loc::at_zero(Pattern::Identifier(bytes_sym)), - // ), - // ( - // fmt_var, - // AnnotatedMark::known_exhaustive(), - // Loc::at_zero(Pattern::Identifier(fmt_sym)), - // ), - // ], - // loc_body: Box::new(Loc::at_zero(append_with_call)), - // }); + // Build + // Inspect.custom \fmt -> Inspect.apply inspector fmt + // + // expected: Inspect.custom : (fmt -> fmt) -> Inspector fmt where fmt implements InspectorFormatter + let custom_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_CUSTOM); - // // Build - // // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes inspector fmt - // // - // // expected: Inspect.custom : (List U8, fmt -> List U8) -> Inspector fmt where fmt implements InspectorFormatting - // let custom_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_CUSTOM); + // wanted: Inspect.custom : fn_var -[clos]-> t' + let this_custom_args_var_slice = VariableSubsSlice::insert_into_subs(env.subs, [fn_var]); + let this_custom_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> + let this_custom_inspector_var = env.subs.fresh_unnamed_flex_var(); // t' + let this_custom_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + this_custom_args_var_slice, + this_custom_clos_var, + this_custom_inspector_var, + )), + ); - // // wanted: Inspect.custom : fn_var -[clos]-> t' - // let this_custom_args_var_slice = VariableSubsSlice::insert_into_subs(env.subs, [fn_var]); - // let this_custom_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> - // let this_custom_inspector_var = env.subs.fresh_unnamed_flex_var(); // t' - // let this_custom_fn_var = synth_var( - // env.subs, - // Content::Structure(FlatType::Func( - // this_custom_args_var_slice, - // this_custom_clos_var, - // this_custom_inspector_var, - // )), - // ); + // (fmt -> fmt) -[..]-> Inspector fmt where fmt implements InspectorFormatter + // ~ fn_var -[clos]-> t' + env.unify(custom_fn_var, this_custom_fn_var); - // // (List U8, fmt -> List U8) -[..]-> Inspector fmt where fmt implements InspectorFormatting - // // ~ fn_var -[clos]-> t' - // env.unify(custom_fn_var, this_custom_fn_var); + // Inspect.custom : (fmt -> fmt) -> Inspector fmt where fmt implements InspectorFormatter + let custom_fn = Box::new(( + this_custom_fn_var, + Loc::at_zero(Var(Symbol::INSPECT_CUSTOM, this_custom_fn_var)), + this_custom_clos_var, // -[clos]-> + this_custom_inspector_var, // t' ~ Inspector fmt + )); - // // Inspect.custom : (List U8, fmt -> List U8) -> Inspector fmt where fmt implements InspectorFormatting - // let custom_fn = Box::new(( - // this_custom_fn_var, - // Loc::at_zero(Var(Symbol::INSPECT_CUSTOM, this_custom_fn_var)), - // this_custom_clos_var, // -[clos]-> - // this_custom_inspector_var, // t' ~ Inspector fmt - // )); + // Inspect.custom \fmt -> Inspect.apply inspector fmt + let custom_call = Call( + custom_fn, + vec![(fn_var, Loc::at_zero(clos))], + CalledVia::Space, + ); - // // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes inspector fmt - // let custom_call = Call( - // custom_fn, - // vec![(fn_var, Loc::at_zero(clos))], - // CalledVia::Space, - // ); - - // (custom_call, this_custom_inspector_var) + (custom_call, this_custom_inspector_var) } diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/record.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/record.txt index 0478644973..0094d164f3 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/record.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/record.txt @@ -1,4 +1,4 @@ app "test" provides [main] to "./platform" main = Inspect.toInspector { a: "" } |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr -# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[Inspect.dbgBool(43)]]-> Inspector DbgFormatter +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): { a : Str } -[[#Derived.toInspector_{a}(0)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt index 107cc4ade5..44f741f979 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt @@ -6,4 +6,4 @@ myToInspector : Op -> Inspector f where f implements InspectFormatter myToInspector = \@Op num -> Inspect.u8 num main = Inspect.toInspector { op: @Op 1u8 } |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr -# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(2): Op -[[myToInspector(2)]]-> Inspector f where f implements InspectFormatter +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): { op : Op } -[[#Derived.toInspector_{op}(0)]]-> Inspector DbgFormatter From 21b68a2e27bbdf42b4f19783cc356ac3dbf6739e Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 11:08:16 -0800 Subject: [PATCH 062/105] add a set of currently failing mono tests for inspect --- .../generated/inspect_derived_string.txt | 48 +++++++ crates/compiler/test_mono/src/tests.rs | 130 ++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 crates/compiler/test_mono/generated/inspect_derived_string.txt diff --git a/crates/compiler/test_mono/generated/inspect_derived_string.txt b/crates/compiler/test_mono/generated/inspect_derived_string.txt new file mode 100644 index 0000000000..de39b613e0 --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_string.txt @@ -0,0 +1,48 @@ +procedure Inspect.147 (Inspect.317): + ret Inspect.317; + +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.326 : Str = "\""; + let Inspect.325 : Str = CallByName Inspect.61 Inspect.250 Inspect.326; + let Inspect.321 : Str = CallByName Inspect.61 Inspect.325 Inspect.248; + let Inspect.322 : Str = "\""; + let Inspect.320 : Str = CallByName Inspect.61 Inspect.321 Inspect.322; + ret Inspect.320; + +procedure Inspect.30 (): + let Inspect.316 : {} = Struct {}; + ret Inspect.316; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.44 (Inspect.248): + let Inspect.314 : {} = CallByName Inspect.30; + let Inspect.313 : Str = CallByName Inspect.147 Inspect.248; + ret Inspect.313; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : Str = CallByName Inspect.44 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName Inspect.249 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.324 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.324; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.0 (): + let Test.3 : Str = "abc"; + let Test.2 : Str = CallByName Inspect.5 Test.3; + let Test.1 : Str = CallByName Inspect.35 Test.2; + ret Test.1; diff --git a/crates/compiler/test_mono/src/tests.rs b/crates/compiler/test_mono/src/tests.rs index 0f56a1f237..465ce45f09 100644 --- a/crates/compiler/test_mono/src/tests.rs +++ b/crates/compiler/test_mono/src/tests.rs @@ -3289,3 +3289,133 @@ fn non_nullable_unwrapped_instead_of_nullable_wrapped() { "# ) } + +#[mono_test] +fn inspect_custom_type() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + HelloWorld := {} implements [Inspect { toInspector: myToInspector }] + + myToInspector : HelloWorld -> Inspector f where f implements InspectFormatter + myToInspector = \@HellowWorld {} -> + fmt <- Inspect.custom + Inspect.apply (Inspect.str "Hello, World!\n") fmt + + main = + Inspect.inspect (@HelloWorld {}) + "# + ) +} + +#[mono_test] +fn inspect_derived_string() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = Inspect.inspect "abc" |> Inspect.toDbgStr + "# + ) +} + +#[mono_test] +fn inspect_derived_record() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = Inspect.inspect {a: 7, b: 3dec} |> Inspect.toDbgStr + "# + ) +} +#[mono_test] +fn inspect_derived_record_one_field_string() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = Inspect.inspect {a: "foo"} |> Inspect.toDbgStr + "# + ) +} + +#[mono_test] +fn inspect_derived_record_two_field_strings() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = Inspect.inspect {a: "foo", b: "bar"} |> Inspect.toDbgStr + "# + ) +} + +#[mono_test] +fn inspect_derived_nested_record_string() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = Inspect.inspect {a: {b: "bar"}} |> Inspect.toDbgStr + "# + ) +} + +#[mono_test] +fn inspect_derived_tag_one_field_string() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = + x : [A Str] + x = A "foo" + Inspect.inspect x |> Inspect.toDbgStr + "# + ) +} + +#[mono_test] +fn inspect_derived_tag_two_payloads_string() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = + x : [A Str Str] + x = A "foo" "foo" + Inspect.inspect x |> Inspect.toDbgStr + "# + ) +} + +#[mono_test] +fn inspect_derived_list() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = Inspect.inspect [1, 2, 3] |> Inspect.toDbgStr + "# + ) +} From 153b4c6df10ece8edcad375a64f12cb178323ad1 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 11:50:13 -0800 Subject: [PATCH 063/105] add walk function to list autoderive --- crates/compiler/derive/src/inspect.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/crates/compiler/derive/src/inspect.rs b/crates/compiler/derive/src/inspect.rs index 0e591a5c6d..d5cfb68962 100644 --- a/crates/compiler/derive/src/inspect.rs +++ b/crates/compiler/derive/src/inspect.rs @@ -110,9 +110,9 @@ pub(crate) fn derive_to_inspector( } fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { - // Build \lst -> Inspect.list lst (\elem -> Inspect.toInspector elem) + // Build \lst -> list, List.walk, (\elem -> Inspect.toInspector elem) // - // TODO eta reduce this baby ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // TODO eta reduce this baby ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use Expr::*; @@ -212,9 +212,12 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { // List e, (e -> Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatter let inspect_list_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_LIST); - // List elem, to_elem_inspector_fn_var -[clos]-> t1 - let this_inspect_list_args_slice = - VariableSubsSlice::insert_into_subs(env.subs, [list_var, to_elem_inspector_fn_var]); + // List elem, List.walk, to_elem_inspector_fn_var -[clos]-> t1 + let list_walk_fn_var = env.import_builtin_symbol_var(Symbol::LIST_WALK); + let this_inspect_list_args_slice = VariableSubsSlice::insert_into_subs( + env.subs, + [list_var, list_walk_fn_var, to_elem_inspector_fn_var], + ); let this_inspect_list_clos_var = env.subs.fresh_unnamed_flex_var(); // clos let this_list_inspector_var = env.subs.fresh_unnamed_flex_var(); // t1 let this_inspect_list_fn_var = synth_var( @@ -244,6 +247,10 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { inspect_list_fn, vec![ (list_var, Loc::at_zero(Var(lst_sym, list_var))), + ( + list_walk_fn_var, + Loc::at_zero(Var(Symbol::LIST_WALK, list_walk_fn_var)), + ), (to_elem_inspector_fn_var, Loc::at_zero(to_elem_inspector)), ], CalledVia::Space, From 32c3d49e8566b6f83d49e0740d5aae38db21dc5b Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 12:06:53 -0800 Subject: [PATCH 064/105] ignore unimlemented ability test case --- crates/compiler/test_mono/src/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/compiler/test_mono/src/tests.rs b/crates/compiler/test_mono/src/tests.rs index 465ce45f09..9d5874be60 100644 --- a/crates/compiler/test_mono/src/tests.rs +++ b/crates/compiler/test_mono/src/tests.rs @@ -3291,6 +3291,7 @@ fn non_nullable_unwrapped_instead_of_nullable_wrapped() { } #[mono_test] +#[ignore = "Hits an unimplemented for abilities, not sure why..."] fn inspect_custom_type() { indoc!( r#" From 79a58843b523bd5c64ea2f83b4934642c0ddc219 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 12:12:31 -0800 Subject: [PATCH 065/105] fix mono tests with wrapping custom function --- crates/compiler/builtins/roc/Inspect.roc | 2 +- .../generated/inspect_derived_list.txt | 172 +++++++++++ .../inspect_derived_nested_record_string.txt | 274 ++++++++++++++++++ .../generated/inspect_derived_record.txt | 204 +++++++++++++ ...nspect_derived_record_one_field_string.txt | 171 +++++++++++ ...spect_derived_record_two_field_strings.txt | 180 ++++++++++++ .../generated/inspect_derived_string.txt | 27 +- .../inspect_derived_tag_one_field_string.txt | 173 +++++++++++ ...nspect_derived_tag_two_payloads_string.txt | 178 ++++++++++++ 9 files changed, 1364 insertions(+), 17 deletions(-) create mode 100644 crates/compiler/test_mono/generated/inspect_derived_list.txt create mode 100644 crates/compiler/test_mono/generated/inspect_derived_nested_record_string.txt create mode 100644 crates/compiler/test_mono/generated/inspect_derived_record.txt create mode 100644 crates/compiler/test_mono/generated/inspect_derived_record_one_field_string.txt create mode 100644 crates/compiler/test_mono/generated/inspect_derived_record_two_field_strings.txt create mode 100644 crates/compiler/test_mono/generated/inspect_derived_tag_one_field_string.txt create mode 100644 crates/compiler/test_mono/generated/inspect_derived_tag_two_payloads_string.txt diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 64a5f8fcb3..82a31f4a9d 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -86,7 +86,7 @@ InspectFormatter implements Inspector f := f -> f where f implements InspectFormatter custom : (f -> f) -> Inspector f where f implements InspectFormatter -custom = @Inspector +custom = \fn -> @Inspector fn apply : Inspector f, f -> f where f implements InspectFormatter apply = \@Inspector fn, fmt -> fn fmt diff --git a/crates/compiler/test_mono/generated/inspect_derived_list.txt b/crates/compiler/test_mono/generated/inspect_derived_list.txt new file mode 100644 index 0000000000..5b3e75d71e --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_list.txt @@ -0,0 +1,172 @@ +procedure #Derived.0 (#Derived.1): + let #Derived_gen.0 : List I64 = CallByName Inspect.30 #Derived.1; + ret #Derived_gen.0; + +procedure #Derived.3 (#Derived.2): + let #Derived_gen.7 : I64 = CallByName Inspect.54 #Derived.2; + ret #Derived_gen.7; + +procedure #Derived.4 (#Derived.5, #Derived.1): + let #Derived_gen.5 : {} = Struct {}; + let #Derived_gen.6 : {} = Struct {}; + let #Derived_gen.4 : {List I64, {}, {}} = CallByName Inspect.37 #Derived.1 #Derived_gen.5 #Derived_gen.6; + let #Derived_gen.3 : Str = CallByName Inspect.31 #Derived_gen.4 #Derived.5; + ret #Derived_gen.3; + +procedure Bool.1 (): + let Bool.24 : Int1 = false; + ret Bool.24; + +procedure Bool.2 (): + let Bool.23 : Int1 = true; + ret Bool.23; + +procedure Inspect.155 (Inspect.156, #Attr.12): + let Inspect.154 : {} = StructAtIndex 2 #Attr.12; + let Inspect.153 : {} = StructAtIndex 1 #Attr.12; + let Inspect.152 : List I64 = StructAtIndex 0 #Attr.12; + let Inspect.345 : Str = "["; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.156 Inspect.345; + let Inspect.329 : {List I64, {}, {}} = Struct {Inspect.152, Inspect.153, Inspect.154}; + let Inspect.324 : {Str, Int1} = CallByName Inspect.157 Inspect.328 Inspect.329; + let Inspect.325 : {} = Struct {}; + let Inspect.320 : Str = CallByName Inspect.166 Inspect.324; + let Inspect.321 : Str = "]"; + let Inspect.319 : Str = CallByName Inspect.61 Inspect.320 Inspect.321; + ret Inspect.319; + +procedure Inspect.157 (Inspect.158, #Attr.12): + let Inspect.154 : {} = StructAtIndex 2 #Attr.12; + let Inspect.153 : {} = StructAtIndex 1 #Attr.12; + let Inspect.152 : List I64 = StructAtIndex 0 #Attr.12; + let Bool.1 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.158, Bool.1}; + let Inspect.331 : {Str, Int1} = CallByName List.18 Inspect.152 Inspect.332 Inspect.154; + ret Inspect.331; + +procedure Inspect.159 (Inspect.334, Inspect.162, Inspect.154): + let Inspect.160 : Str = StructAtIndex 0 Inspect.334; + let Inspect.161 : Int1 = StructAtIndex 1 Inspect.334; + joinpoint Inspect.343 Inspect.163: + let Inspect.340 : I64 = CallByName #Derived.3 Inspect.162; + let Inspect.337 : Str = CallByName Inspect.31 Inspect.340 Inspect.163; + let Inspect.338 : {} = Struct {}; + let Inspect.336 : {Str, Int1} = CallByName Inspect.164 Inspect.337; + ret Inspect.336; + in + if Inspect.161 then + let Inspect.344 : Str = ", "; + let Inspect.342 : Str = CallByName Inspect.61 Inspect.160 Inspect.344; + jump Inspect.343 Inspect.342; + else + jump Inspect.343 Inspect.160; + +procedure Inspect.164 (Inspect.165): + let Bool.2 : Int1 = CallByName Bool.2; + let Inspect.339 : {Str, Int1} = Struct {Inspect.165, Bool.2}; + ret Inspect.339; + +procedure Inspect.166 (Inspect.326): + let Inspect.327 : Str = StructAtIndex 0 Inspect.326; + ret Inspect.327; + +procedure Inspect.277 (Inspect.278, Inspect.276): + let Inspect.351 : Str = CallByName Num.96 Inspect.276; + let Inspect.350 : Str = CallByName Inspect.61 Inspect.278 Inspect.351; + ret Inspect.350; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.314 : Str = CallByName Inspect.155 Inspect.149 Inspect.305; + ret Inspect.314; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.341 : Str = CallByName Inspect.277 Inspect.149 Inspect.305; + ret Inspect.341; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.37 (Inspect.152, Inspect.153, Inspect.154): + let Inspect.316 : {List I64, {}, {}} = Struct {Inspect.152, Inspect.153, Inspect.154}; + let Inspect.315 : {List I64, {}, {}} = CallByName Inspect.30 Inspect.316; + ret Inspect.315; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : List I64 = CallByName #Derived.0 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName #Derived.4 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.54 (Inspect.276): + let Inspect.346 : I64 = CallByName Inspect.30 Inspect.276; + ret Inspect.346; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.323 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.323; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : {Str, Int1} = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.6 (#Attr.2): + let List.564 : U64 = lowlevel ListLen #Attr.2; + ret List.564; + +procedure List.66 (#Attr.2, #Attr.3): + let List.563 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.563; + +procedure List.88 (#Derived_gen.17, #Derived_gen.18, #Derived_gen.19, #Derived_gen.20, #Derived_gen.21): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : I64 = CallByName List.66 List.157 List.160; + let List.162 : {Str, Int1} = CallByName Inspect.159 List.158 List.562 List.159; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.17 #Derived_gen.18 #Derived_gen.19 #Derived_gen.20 #Derived_gen.21; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.293 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.293; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.292 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.292; + +procedure Num.96 (#Attr.2): + let Num.291 : Str = lowlevel NumToStr #Attr.2; + ret Num.291; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.0 (): + let Test.3 : List I64 = Array [1i64, 2i64, 3i64]; + let Test.2 : Str = CallByName Inspect.5 Test.3; + let Test.1 : Str = CallByName Inspect.35 Test.2; + ret Test.1; diff --git a/crates/compiler/test_mono/generated/inspect_derived_nested_record_string.txt b/crates/compiler/test_mono/generated/inspect_derived_nested_record_string.txt new file mode 100644 index 0000000000..78d22ad7bd --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_nested_record_string.txt @@ -0,0 +1,274 @@ +procedure #Derived.0 (#Derived.1): + let #Derived_gen.0 : Str = CallByName Inspect.30 #Derived.1; + ret #Derived_gen.0; + +procedure #Derived.2 (#Derived.3, #Derived.1): + let #Derived_gen.7 : Str = "a"; + let #Derived_gen.8 : Str = CallByName #Derived.4 #Derived.1; + let #Derived_gen.6 : {Str, Str} = Struct {#Derived_gen.7, #Derived_gen.8}; + let #Derived_gen.5 : List {Str, Str} = Array [#Derived_gen.6]; + let #Derived_gen.4 : List {Str, Str} = CallByName Inspect.42 #Derived_gen.5; + let #Derived_gen.3 : Str = CallByName Inspect.31 #Derived_gen.4 #Derived.3; + ret #Derived_gen.3; + +procedure #Derived.4 (#Derived.5): + let #Derived_gen.10 : Str = CallByName Inspect.30 #Derived.5; + ret #Derived_gen.10; + +procedure #Derived.6 (#Derived.7, #Derived.5): + let #Derived_gen.17 : Str = "b"; + let #Derived_gen.18 : Str = CallByName Inspect.44 #Derived.5; + let #Derived_gen.16 : {Str, Str} = Struct {#Derived_gen.17, #Derived_gen.18}; + let #Derived_gen.15 : List {Str, Str} = Array [#Derived_gen.16]; + let #Derived_gen.14 : List {Str, Str} = CallByName Inspect.42 #Derived_gen.15; + let #Derived_gen.13 : Str = CallByName Inspect.31 #Derived_gen.14 #Derived.7; + ret #Derived_gen.13; + +procedure Bool.1 (): + let Bool.26 : Int1 = false; + ret Bool.26; + +procedure Bool.2 (): + let Bool.25 : Int1 = true; + ret Bool.25; + +procedure Inspect.228 (Inspect.229, Inspect.227): + let Inspect.350 : Str = "{"; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.350; + let Inspect.324 : {Str, Int1} = CallByName Inspect.230 Inspect.328 Inspect.227; + let Inspect.325 : {} = Struct {}; + let Inspect.320 : Str = CallByName Inspect.242 Inspect.324; + let Inspect.321 : Str = "}"; + let Inspect.319 : Str = CallByName Inspect.61 Inspect.320 Inspect.321; + ret Inspect.319; + +procedure Inspect.228 (Inspect.229, Inspect.227): + let Inspect.388 : Str = "{"; + let Inspect.366 : Str = CallByName Inspect.61 Inspect.229 Inspect.388; + let Inspect.362 : {Str, Int1} = CallByName Inspect.230 Inspect.366 Inspect.227; + let Inspect.363 : {} = Struct {}; + let Inspect.358 : Str = CallByName Inspect.242 Inspect.362; + let Inspect.359 : Str = "}"; + let Inspect.357 : Str = CallByName Inspect.61 Inspect.358 Inspect.359; + ret Inspect.357; + +procedure Inspect.230 (Inspect.231, Inspect.227): + let Bool.1 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Bool.1}; + let Inspect.333 : {} = Struct {}; + let Inspect.331 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.332 Inspect.333; + ret Inspect.331; + +procedure Inspect.230 (Inspect.231, Inspect.227): + let Bool.1 : Int1 = CallByName Bool.1; + let Inspect.370 : {Str, Int1} = Struct {Inspect.231, Bool.1}; + let Inspect.371 : {} = Struct {}; + let Inspect.369 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.370 Inspect.371; + ret Inspect.369; + +procedure Inspect.232 (Inspect.334, Inspect.335): + let Inspect.235 : Str = StructAtIndex 0 Inspect.335; + let Inspect.236 : Str = StructAtIndex 1 Inspect.335; + let Inspect.233 : Str = StructAtIndex 0 Inspect.334; + let Inspect.234 : Int1 = StructAtIndex 1 Inspect.334; + joinpoint Inspect.348 Inspect.237: + let Inspect.345 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; + let Inspect.346 : Str = ": "; + let Inspect.340 : Str = CallByName Inspect.61 Inspect.345 Inspect.346; + let Inspect.337 : Str = CallByName Inspect.238 Inspect.340 Inspect.236; + let Inspect.338 : {} = Struct {}; + let Inspect.336 : {Str, Int1} = CallByName Inspect.240 Inspect.337; + ret Inspect.336; + in + if Inspect.234 then + let Inspect.349 : Str = ", "; + let Inspect.347 : Str = CallByName Inspect.61 Inspect.233 Inspect.349; + jump Inspect.348 Inspect.347; + else + jump Inspect.348 Inspect.233; + +procedure Inspect.232 (Inspect.334, Inspect.335): + let Inspect.235 : Str = StructAtIndex 0 Inspect.335; + let Inspect.236 : Str = StructAtIndex 1 Inspect.335; + let Inspect.233 : Str = StructAtIndex 0 Inspect.334; + let Inspect.234 : Int1 = StructAtIndex 1 Inspect.334; + joinpoint Inspect.386 Inspect.237: + let Inspect.383 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; + let Inspect.384 : Str = ": "; + let Inspect.378 : Str = CallByName Inspect.61 Inspect.383 Inspect.384; + let Inspect.375 : Str = CallByName Inspect.238 Inspect.378 Inspect.236; + let Inspect.376 : {} = Struct {}; + let Inspect.374 : {Str, Int1} = CallByName Inspect.240 Inspect.375; + ret Inspect.374; + in + if Inspect.234 then + let Inspect.387 : Str = ", "; + let Inspect.385 : Str = CallByName Inspect.61 Inspect.233 Inspect.387; + jump Inspect.386 Inspect.385; + else + jump Inspect.386 Inspect.233; + +procedure Inspect.238 (Inspect.239, Inspect.236): + let Inspect.343 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; + ret Inspect.343; + +procedure Inspect.238 (Inspect.239, Inspect.236): + let Inspect.381 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; + ret Inspect.381; + +procedure Inspect.240 (Inspect.241): + let Bool.2 : Int1 = CallByName Bool.2; + let Inspect.377 : {Str, Int1} = Struct {Inspect.241, Bool.2}; + ret Inspect.377; + +procedure Inspect.242 (Inspect.326): + let Inspect.365 : Str = StructAtIndex 0 Inspect.326; + ret Inspect.365; + +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.397 : Str = "\""; + let Inspect.396 : Str = CallByName Inspect.61 Inspect.250 Inspect.397; + let Inspect.394 : Str = CallByName Inspect.61 Inspect.396 Inspect.248; + let Inspect.395 : Str = "\""; + let Inspect.393 : Str = CallByName Inspect.61 Inspect.394 Inspect.395; + ret Inspect.393; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.314 : Str = CallByName Inspect.228 Inspect.149 Inspect.305; + ret Inspect.314; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.344 : Str = CallByName #Derived.6 Inspect.149 Inspect.305; + ret Inspect.344; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.352 : Str = CallByName Inspect.228 Inspect.149 Inspect.305; + ret Inspect.352; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.382 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.382; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.42 (Inspect.227): + let Inspect.315 : List {Str, Str} = CallByName Inspect.30 Inspect.227; + ret Inspect.315; + +procedure Inspect.42 (Inspect.227): + let Inspect.353 : List {Str, Str} = CallByName Inspect.30 Inspect.227; + ret Inspect.353; + +procedure Inspect.44 (Inspect.248): + let Inspect.389 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.389; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : Str = CallByName #Derived.0 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName #Derived.2 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.361 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.361; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : {Str, Int1} = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.18 (List.154, List.155, List.156): + let List.566 : U64 = 0i64; + let List.567 : U64 = CallByName List.6 List.154; + let List.565 : {Str, Int1} = CallByName List.88 List.154 List.155 List.156 List.566 List.567; + ret List.565; + +procedure List.6 (#Attr.2): + let List.564 : U64 = lowlevel ListLen #Attr.2; + ret List.564; + +procedure List.6 (#Attr.2): + let List.576 : U64 = lowlevel ListLen #Attr.2; + ret List.576; + +procedure List.66 (#Attr.2, #Attr.3): + let List.563 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.563; + +procedure List.66 (#Attr.2, #Attr.3): + let List.575 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.575; + +procedure List.88 (#Derived_gen.30, #Derived_gen.31, #Derived_gen.32, #Derived_gen.33, #Derived_gen.34): + joinpoint List.568 List.157 List.158 List.159 List.160 List.161: + let List.570 : Int1 = CallByName Num.22 List.160 List.161; + if List.570 then + let List.574 : {Str, Str} = CallByName List.66 List.157 List.160; + inc List.574; + let List.162 : {Str, Int1} = CallByName Inspect.232 List.158 List.574; + let List.573 : U64 = 1i64; + let List.572 : U64 = CallByName Num.51 List.160 List.573; + jump List.568 List.157 List.162 List.159 List.572 List.161; + else + dec List.157; + ret List.158; + in + jump List.568 #Derived_gen.30 #Derived_gen.31 #Derived_gen.32 #Derived_gen.33 #Derived_gen.34; + +procedure List.88 (#Derived_gen.41, #Derived_gen.42, #Derived_gen.43, #Derived_gen.44, #Derived_gen.45): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : {Str, Str} = CallByName List.66 List.157 List.160; + inc List.562; + let List.162 : {Str, Int1} = CallByName Inspect.232 List.158 List.562; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.41 #Derived_gen.42 #Derived_gen.43 #Derived_gen.44 #Derived_gen.45; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.294 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.294; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.293 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.293; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.293 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.293; + +procedure Test.0 (): + let Test.5 : Str = "bar"; + let Test.2 : Str = CallByName Inspect.5 Test.5; + let Test.1 : Str = CallByName Inspect.35 Test.2; + ret Test.1; diff --git a/crates/compiler/test_mono/generated/inspect_derived_record.txt b/crates/compiler/test_mono/generated/inspect_derived_record.txt new file mode 100644 index 0000000000..99d70d6962 --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_record.txt @@ -0,0 +1,204 @@ +procedure #Derived.0 (#Derived.1): + let #Derived_gen.0 : {Decimal, I64} = CallByName Inspect.30 #Derived.1; + ret #Derived_gen.0; + +procedure #Derived.2 (#Derived.3, #Derived.1): + let #Derived_gen.13 : I64 = StructAtIndex 1 #Derived.1; + let #Derived_gen.11 : [C I64, C Decimal] = CallByName Inspect.54 #Derived_gen.13; + let #Derived_gen.12 : Str = "a"; + let #Derived_gen.6 : {[C I64, C Decimal], Str} = Struct {#Derived_gen.11, #Derived_gen.12}; + let #Derived_gen.10 : Decimal = StructAtIndex 0 #Derived.1; + let #Derived_gen.8 : [C I64, C Decimal] = CallByName Inspect.60 #Derived_gen.10; + let #Derived_gen.9 : Str = "b"; + let #Derived_gen.7 : {[C I64, C Decimal], Str} = Struct {#Derived_gen.8, #Derived_gen.9}; + let #Derived_gen.5 : List {[C I64, C Decimal], Str} = Array [#Derived_gen.6, #Derived_gen.7]; + let #Derived_gen.4 : List {[C I64, C Decimal], Str} = CallByName Inspect.42 #Derived_gen.5; + let #Derived_gen.3 : Str = CallByName Inspect.31 #Derived_gen.4 #Derived.3; + ret #Derived_gen.3; + +procedure Bool.1 (): + let Bool.24 : Int1 = false; + ret Bool.24; + +procedure Bool.2 (): + let Bool.23 : Int1 = true; + ret Bool.23; + +procedure Inspect.228 (Inspect.229, Inspect.227): + let Inspect.351 : Str = "{"; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.351; + let Inspect.324 : {Str, Int1} = CallByName Inspect.230 Inspect.328 Inspect.227; + let Inspect.325 : {} = Struct {}; + let Inspect.320 : Str = CallByName Inspect.242 Inspect.324; + let Inspect.321 : Str = "}"; + let Inspect.319 : Str = CallByName Inspect.61 Inspect.320 Inspect.321; + ret Inspect.319; + +procedure Inspect.230 (Inspect.231, Inspect.227): + let Bool.1 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Bool.1}; + let Inspect.333 : {} = Struct {}; + let Inspect.331 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.332 Inspect.333; + ret Inspect.331; + +procedure Inspect.232 (Inspect.334, Inspect.335): + let Inspect.236 : [C I64, C Decimal] = StructAtIndex 0 Inspect.335; + let Inspect.235 : Str = StructAtIndex 1 Inspect.335; + let Inspect.233 : Str = StructAtIndex 0 Inspect.334; + let Inspect.234 : Int1 = StructAtIndex 1 Inspect.334; + joinpoint Inspect.349 Inspect.237: + let Inspect.346 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; + let Inspect.347 : Str = ": "; + let Inspect.340 : Str = CallByName Inspect.61 Inspect.346 Inspect.347; + let Inspect.337 : Str = CallByName Inspect.238 Inspect.340 Inspect.236; + let Inspect.338 : {} = Struct {}; + let Inspect.336 : {Str, Int1} = CallByName Inspect.240 Inspect.337; + ret Inspect.336; + in + if Inspect.234 then + let Inspect.350 : Str = ", "; + let Inspect.348 : Str = CallByName Inspect.61 Inspect.233 Inspect.350; + jump Inspect.349 Inspect.348; + else + jump Inspect.349 Inspect.233; + +procedure Inspect.238 (Inspect.239, Inspect.236): + let Inspect.343 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; + ret Inspect.343; + +procedure Inspect.240 (Inspect.241): + let Bool.2 : Int1 = CallByName Bool.2; + let Inspect.339 : {Str, Int1} = Struct {Inspect.241, Bool.2}; + ret Inspect.339; + +procedure Inspect.242 (Inspect.326): + let Inspect.327 : Str = StructAtIndex 0 Inspect.326; + ret Inspect.327; + +procedure Inspect.277 (Inspect.278, #Attr.12): + let Inspect.364 : I64 = UnionAtIndex (Id 0) (Index 0) #Attr.12; + let Inspect.363 : Str = CallByName Num.96 Inspect.364; + let Inspect.362 : Str = CallByName Inspect.61 Inspect.278 Inspect.363; + ret Inspect.362; + +procedure Inspect.295 (Inspect.296, #Attr.12): + let Inspect.358 : Decimal = UnionAtIndex (Id 1) (Index 0) #Attr.12; + let Inspect.357 : Str = CallByName Num.96 Inspect.358; + let Inspect.356 : Str = CallByName Inspect.61 Inspect.296 Inspect.357; + ret Inspect.356; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.314 : Str = CallByName Inspect.228 Inspect.149 Inspect.305; + ret Inspect.314; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.345 : U8 = GetTagId Inspect.305; + switch Inspect.345: + case 0: + let Inspect.344 : Str = CallByName Inspect.277 Inspect.149 Inspect.305; + ret Inspect.344; + + default: + let Inspect.344 : Str = CallByName Inspect.295 Inspect.149 Inspect.305; + ret Inspect.344; + + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.42 (Inspect.227): + let Inspect.315 : List {[C I64, C Decimal], Str} = CallByName Inspect.30 Inspect.227; + ret Inspect.315; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : {Decimal, I64} = CallByName #Derived.0 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName #Derived.2 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.54 (Inspect.276): + let Inspect.360 : [C I64, C Decimal] = TagId(0) Inspect.276; + let Inspect.359 : [C I64, C Decimal] = CallByName Inspect.30 Inspect.360; + ret Inspect.359; + +procedure Inspect.60 (Inspect.294): + let Inspect.353 : [C I64, C Decimal] = TagId(1) Inspect.294; + let Inspect.352 : [C I64, C Decimal] = CallByName Inspect.30 Inspect.353; + ret Inspect.352; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.323 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.323; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : {Str, Int1} = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.6 (#Attr.2): + let List.564 : U64 = lowlevel ListLen #Attr.2; + ret List.564; + +procedure List.66 (#Attr.2, #Attr.3): + let List.563 : {[C I64, C Decimal], Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.563; + +procedure List.88 (#Derived_gen.14, #Derived_gen.15, #Derived_gen.16, #Derived_gen.17, #Derived_gen.18): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : {[C I64, C Decimal], Str} = CallByName List.66 List.157 List.160; + inc List.562; + let List.162 : {Str, Int1} = CallByName Inspect.232 List.158 List.562; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.14 #Derived_gen.15 #Derived_gen.16 #Derived_gen.17 #Derived_gen.18; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.294 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.294; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.293 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.293; + +procedure Num.96 (#Attr.2): + let Num.291 : Str = lowlevel NumToStr #Attr.2; + ret Num.291; + +procedure Num.96 (#Attr.2): + let Num.292 : Str = lowlevel NumToStr #Attr.2; + ret Num.292; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.0 (): + let Test.4 : Decimal = 3dec; + let Test.5 : I64 = 7i64; + let Test.3 : {Decimal, I64} = Struct {Test.4, Test.5}; + let Test.2 : Str = CallByName Inspect.5 Test.3; + let Test.1 : Str = CallByName Inspect.35 Test.2; + ret Test.1; diff --git a/crates/compiler/test_mono/generated/inspect_derived_record_one_field_string.txt b/crates/compiler/test_mono/generated/inspect_derived_record_one_field_string.txt new file mode 100644 index 0000000000..39c0982982 --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_record_one_field_string.txt @@ -0,0 +1,171 @@ +procedure #Derived.0 (#Derived.1): + let #Derived_gen.0 : Str = CallByName Inspect.30 #Derived.1; + ret #Derived_gen.0; + +procedure #Derived.2 (#Derived.3, #Derived.1): + let #Derived_gen.7 : Str = "a"; + let #Derived_gen.8 : Str = CallByName Inspect.44 #Derived.1; + let #Derived_gen.6 : {Str, Str} = Struct {#Derived_gen.7, #Derived_gen.8}; + let #Derived_gen.5 : List {Str, Str} = Array [#Derived_gen.6]; + let #Derived_gen.4 : List {Str, Str} = CallByName Inspect.42 #Derived_gen.5; + let #Derived_gen.3 : Str = CallByName Inspect.31 #Derived_gen.4 #Derived.3; + ret #Derived_gen.3; + +procedure Bool.1 (): + let Bool.24 : Int1 = false; + ret Bool.24; + +procedure Bool.2 (): + let Bool.23 : Int1 = true; + ret Bool.23; + +procedure Inspect.228 (Inspect.229, Inspect.227): + let Inspect.350 : Str = "{"; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.350; + let Inspect.324 : {Str, Int1} = CallByName Inspect.230 Inspect.328 Inspect.227; + let Inspect.325 : {} = Struct {}; + let Inspect.320 : Str = CallByName Inspect.242 Inspect.324; + let Inspect.321 : Str = "}"; + let Inspect.319 : Str = CallByName Inspect.61 Inspect.320 Inspect.321; + ret Inspect.319; + +procedure Inspect.230 (Inspect.231, Inspect.227): + let Bool.1 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Bool.1}; + let Inspect.333 : {} = Struct {}; + let Inspect.331 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.332 Inspect.333; + ret Inspect.331; + +procedure Inspect.232 (Inspect.334, Inspect.335): + let Inspect.235 : Str = StructAtIndex 0 Inspect.335; + let Inspect.236 : Str = StructAtIndex 1 Inspect.335; + let Inspect.233 : Str = StructAtIndex 0 Inspect.334; + let Inspect.234 : Int1 = StructAtIndex 1 Inspect.334; + joinpoint Inspect.348 Inspect.237: + let Inspect.345 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; + let Inspect.346 : Str = ": "; + let Inspect.340 : Str = CallByName Inspect.61 Inspect.345 Inspect.346; + let Inspect.337 : Str = CallByName Inspect.238 Inspect.340 Inspect.236; + let Inspect.338 : {} = Struct {}; + let Inspect.336 : {Str, Int1} = CallByName Inspect.240 Inspect.337; + ret Inspect.336; + in + if Inspect.234 then + let Inspect.349 : Str = ", "; + let Inspect.347 : Str = CallByName Inspect.61 Inspect.233 Inspect.349; + jump Inspect.348 Inspect.347; + else + jump Inspect.348 Inspect.233; + +procedure Inspect.238 (Inspect.239, Inspect.236): + let Inspect.343 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; + ret Inspect.343; + +procedure Inspect.240 (Inspect.241): + let Bool.2 : Int1 = CallByName Bool.2; + let Inspect.339 : {Str, Int1} = Struct {Inspect.241, Bool.2}; + ret Inspect.339; + +procedure Inspect.242 (Inspect.326): + let Inspect.327 : Str = StructAtIndex 0 Inspect.326; + ret Inspect.327; + +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.359 : Str = "\""; + let Inspect.358 : Str = CallByName Inspect.61 Inspect.250 Inspect.359; + let Inspect.356 : Str = CallByName Inspect.61 Inspect.358 Inspect.248; + let Inspect.357 : Str = "\""; + let Inspect.355 : Str = CallByName Inspect.61 Inspect.356 Inspect.357; + ret Inspect.355; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.314 : Str = CallByName Inspect.228 Inspect.149 Inspect.305; + ret Inspect.314; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.344 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.344; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.42 (Inspect.227): + let Inspect.315 : List {Str, Str} = CallByName Inspect.30 Inspect.227; + ret Inspect.315; + +procedure Inspect.44 (Inspect.248): + let Inspect.351 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.351; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : Str = CallByName #Derived.0 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName #Derived.2 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.323 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.323; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : {Str, Int1} = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.6 (#Attr.2): + let List.564 : U64 = lowlevel ListLen #Attr.2; + ret List.564; + +procedure List.66 (#Attr.2, #Attr.3): + let List.563 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.563; + +procedure List.88 (#Derived_gen.14, #Derived_gen.15, #Derived_gen.16, #Derived_gen.17, #Derived_gen.18): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : {Str, Str} = CallByName List.66 List.157 List.160; + inc List.562; + let List.162 : {Str, Int1} = CallByName Inspect.232 List.158 List.562; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.14 #Derived_gen.15 #Derived_gen.16 #Derived_gen.17 #Derived_gen.18; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.292 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.292; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.291 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.291; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.0 (): + let Test.4 : Str = "foo"; + let Test.2 : Str = CallByName Inspect.5 Test.4; + let Test.1 : Str = CallByName Inspect.35 Test.2; + ret Test.1; diff --git a/crates/compiler/test_mono/generated/inspect_derived_record_two_field_strings.txt b/crates/compiler/test_mono/generated/inspect_derived_record_two_field_strings.txt new file mode 100644 index 0000000000..224e8b36e0 --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_record_two_field_strings.txt @@ -0,0 +1,180 @@ +procedure #Derived.0 (#Derived.1): + let #Derived_gen.0 : {Str, Str} = CallByName Inspect.30 #Derived.1; + ret #Derived_gen.0; + +procedure #Derived.2 (#Derived.3, #Derived.1): + let #Derived_gen.11 : Str = "a"; + let #Derived_gen.13 : Str = StructAtIndex 0 #Derived.1; + inc #Derived_gen.13; + let #Derived_gen.12 : Str = CallByName Inspect.44 #Derived_gen.13; + let #Derived_gen.6 : {Str, Str} = Struct {#Derived_gen.11, #Derived_gen.12}; + let #Derived_gen.8 : Str = "b"; + let #Derived_gen.10 : Str = StructAtIndex 1 #Derived.1; + dec #Derived_gen.13; + let #Derived_gen.9 : Str = CallByName Inspect.44 #Derived_gen.10; + let #Derived_gen.7 : {Str, Str} = Struct {#Derived_gen.8, #Derived_gen.9}; + let #Derived_gen.5 : List {Str, Str} = Array [#Derived_gen.6, #Derived_gen.7]; + let #Derived_gen.4 : List {Str, Str} = CallByName Inspect.42 #Derived_gen.5; + let #Derived_gen.3 : Str = CallByName Inspect.31 #Derived_gen.4 #Derived.3; + ret #Derived_gen.3; + +procedure Bool.1 (): + let Bool.24 : Int1 = false; + ret Bool.24; + +procedure Bool.2 (): + let Bool.23 : Int1 = true; + ret Bool.23; + +procedure Inspect.228 (Inspect.229, Inspect.227): + let Inspect.350 : Str = "{"; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.350; + let Inspect.324 : {Str, Int1} = CallByName Inspect.230 Inspect.328 Inspect.227; + let Inspect.325 : {} = Struct {}; + let Inspect.320 : Str = CallByName Inspect.242 Inspect.324; + let Inspect.321 : Str = "}"; + let Inspect.319 : Str = CallByName Inspect.61 Inspect.320 Inspect.321; + ret Inspect.319; + +procedure Inspect.230 (Inspect.231, Inspect.227): + let Bool.1 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Bool.1}; + let Inspect.333 : {} = Struct {}; + let Inspect.331 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.332 Inspect.333; + ret Inspect.331; + +procedure Inspect.232 (Inspect.334, Inspect.335): + let Inspect.235 : Str = StructAtIndex 0 Inspect.335; + let Inspect.236 : Str = StructAtIndex 1 Inspect.335; + let Inspect.233 : Str = StructAtIndex 0 Inspect.334; + let Inspect.234 : Int1 = StructAtIndex 1 Inspect.334; + joinpoint Inspect.348 Inspect.237: + let Inspect.345 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; + let Inspect.346 : Str = ": "; + let Inspect.340 : Str = CallByName Inspect.61 Inspect.345 Inspect.346; + let Inspect.337 : Str = CallByName Inspect.238 Inspect.340 Inspect.236; + let Inspect.338 : {} = Struct {}; + let Inspect.336 : {Str, Int1} = CallByName Inspect.240 Inspect.337; + ret Inspect.336; + in + if Inspect.234 then + let Inspect.349 : Str = ", "; + let Inspect.347 : Str = CallByName Inspect.61 Inspect.233 Inspect.349; + jump Inspect.348 Inspect.347; + else + jump Inspect.348 Inspect.233; + +procedure Inspect.238 (Inspect.239, Inspect.236): + let Inspect.343 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; + ret Inspect.343; + +procedure Inspect.240 (Inspect.241): + let Bool.2 : Int1 = CallByName Bool.2; + let Inspect.339 : {Str, Int1} = Struct {Inspect.241, Bool.2}; + ret Inspect.339; + +procedure Inspect.242 (Inspect.326): + let Inspect.327 : Str = StructAtIndex 0 Inspect.326; + ret Inspect.327; + +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.359 : Str = "\""; + let Inspect.358 : Str = CallByName Inspect.61 Inspect.250 Inspect.359; + let Inspect.356 : Str = CallByName Inspect.61 Inspect.358 Inspect.248; + let Inspect.357 : Str = "\""; + let Inspect.355 : Str = CallByName Inspect.61 Inspect.356 Inspect.357; + ret Inspect.355; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.314 : Str = CallByName Inspect.228 Inspect.149 Inspect.305; + ret Inspect.314; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.344 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.344; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.42 (Inspect.227): + let Inspect.315 : List {Str, Str} = CallByName Inspect.30 Inspect.227; + ret Inspect.315; + +procedure Inspect.44 (Inspect.248): + let Inspect.360 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.360; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : {Str, Str} = CallByName #Derived.0 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName #Derived.2 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.323 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.323; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : {Str, Int1} = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.6 (#Attr.2): + let List.564 : U64 = lowlevel ListLen #Attr.2; + ret List.564; + +procedure List.66 (#Attr.2, #Attr.3): + let List.563 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.563; + +procedure List.88 (#Derived_gen.18, #Derived_gen.19, #Derived_gen.20, #Derived_gen.21, #Derived_gen.22): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : {Str, Str} = CallByName List.66 List.157 List.160; + inc List.562; + let List.162 : {Str, Int1} = CallByName Inspect.232 List.158 List.562; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.18 #Derived_gen.19 #Derived_gen.20 #Derived_gen.21 #Derived_gen.22; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.292 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.292; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.291 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.291; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.0 (): + let Test.4 : Str = "foo"; + let Test.5 : Str = "bar"; + let Test.3 : {Str, Str} = Struct {Test.4, Test.5}; + let Test.2 : Str = CallByName Inspect.5 Test.3; + let Test.1 : Str = CallByName Inspect.35 Test.2; + ret Test.1; diff --git a/crates/compiler/test_mono/generated/inspect_derived_string.txt b/crates/compiler/test_mono/generated/inspect_derived_string.txt index de39b613e0..8b22e27efe 100644 --- a/crates/compiler/test_mono/generated/inspect_derived_string.txt +++ b/crates/compiler/test_mono/generated/inspect_derived_string.txt @@ -1,17 +1,13 @@ -procedure Inspect.147 (Inspect.317): +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.323 : Str = "\""; + let Inspect.322 : Str = CallByName Inspect.61 Inspect.250 Inspect.323; + let Inspect.318 : Str = CallByName Inspect.61 Inspect.322 Inspect.248; + let Inspect.319 : Str = "\""; + let Inspect.317 : Str = CallByName Inspect.61 Inspect.318 Inspect.319; ret Inspect.317; -procedure Inspect.249 (Inspect.250, Inspect.248): - let Inspect.326 : Str = "\""; - let Inspect.325 : Str = CallByName Inspect.61 Inspect.250 Inspect.326; - let Inspect.321 : Str = CallByName Inspect.61 Inspect.325 Inspect.248; - let Inspect.322 : Str = "\""; - let Inspect.320 : Str = CallByName Inspect.61 Inspect.321 Inspect.322; - ret Inspect.320; - -procedure Inspect.30 (): - let Inspect.316 : {} = Struct {}; - ret Inspect.316; +procedure Inspect.30 (Inspect.147): + ret Inspect.147; procedure Inspect.35 (Inspect.300): ret Inspect.300; @@ -21,8 +17,7 @@ procedure Inspect.36 (Inspect.304): ret Inspect.311; procedure Inspect.44 (Inspect.248): - let Inspect.314 : {} = CallByName Inspect.30; - let Inspect.313 : Str = CallByName Inspect.147 Inspect.248; + let Inspect.313 : Str = CallByName Inspect.30 Inspect.248; ret Inspect.313; procedure Inspect.5 (Inspect.150): @@ -33,9 +28,9 @@ procedure Inspect.5 (Inspect.150): ret Inspect.307; procedure Inspect.61 (Inspect.303, Inspect.298): - let Inspect.324 : Str = CallByName Str.3 Inspect.303 Inspect.298; + let Inspect.321 : Str = CallByName Str.3 Inspect.303 Inspect.298; dec Inspect.298; - ret Inspect.324; + ret Inspect.321; procedure Str.3 (#Attr.2, #Attr.3): let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; diff --git a/crates/compiler/test_mono/generated/inspect_derived_tag_one_field_string.txt b/crates/compiler/test_mono/generated/inspect_derived_tag_one_field_string.txt new file mode 100644 index 0000000000..6f59ae05e1 --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_tag_one_field_string.txt @@ -0,0 +1,173 @@ +procedure #Derived.0 (#Derived.1): + let #Derived_gen.0 : Str = CallByName Inspect.30 #Derived.1; + ret #Derived_gen.0; + +procedure #Derived.3 (#Derived.4, #Derived.1): + joinpoint #Derived_gen.5 #Derived_gen.4: + let #Derived_gen.3 : Str = CallByName Inspect.31 #Derived_gen.4 #Derived.4; + ret #Derived_gen.3; + in + let #Derived_gen.7 : Str = "A"; + let #Derived_gen.9 : Str = CallByName Inspect.44 #Derived.1; + let #Derived_gen.8 : List Str = Array [#Derived_gen.9]; + let #Derived_gen.6 : [C Str, C Str List Str] = CallByName Inspect.40 #Derived_gen.7 #Derived_gen.8; + jump #Derived_gen.5 #Derived_gen.6; + +procedure Bool.11 (#Attr.2, #Attr.3): + let Bool.23 : Int1 = lowlevel Eq #Attr.2 #Attr.3; + ret Bool.23; + +procedure Inspect.203 (Inspect.204, #Attr.12): + let Inspect.346 : Str = UnionAtIndex (Id 0) (Index 0) #Attr.12; + let Inspect.345 : Str = CallByName Inspect.61 Inspect.204 Inspect.346; + ret Inspect.345; + +procedure Inspect.205 (Inspect.206, #Attr.12): + let Inspect.340 : List Str = UnionAtIndex (Id 1) (Index 1) #Attr.12; + let Inspect.339 : Str = UnionAtIndex (Id 1) (Index 0) #Attr.12; + let Inspect.338 : Str = "("; + let Inspect.337 : Str = CallByName Inspect.61 Inspect.206 Inspect.338; + let Inspect.325 : Str = CallByName Inspect.61 Inspect.337 Inspect.339; + let Inspect.321 : Str = CallByName Inspect.207 Inspect.325 Inspect.340; + let Inspect.322 : Str = ")"; + let Inspect.320 : Str = CallByName Inspect.61 Inspect.321 Inspect.322; + ret Inspect.320; + +procedure Inspect.207 (Inspect.208, Inspect.202): + let Inspect.329 : {} = Struct {}; + let Inspect.328 : Str = CallByName List.18 Inspect.202 Inspect.208 Inspect.329; + ret Inspect.328; + +procedure Inspect.209 (Inspect.210, Inspect.211): + let Inspect.336 : Str = " "; + let Inspect.331 : Str = CallByName Inspect.61 Inspect.210 Inspect.336; + let Inspect.330 : Str = CallByName Inspect.212 Inspect.331 Inspect.211; + ret Inspect.330; + +procedure Inspect.212 (Inspect.213, Inspect.211): + let Inspect.334 : Str = CallByName Inspect.31 Inspect.211 Inspect.213; + ret Inspect.334; + +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.355 : Str = "\""; + let Inspect.354 : Str = CallByName Inspect.61 Inspect.250 Inspect.355; + let Inspect.352 : Str = CallByName Inspect.61 Inspect.354 Inspect.248; + let Inspect.353 : Str = "\""; + let Inspect.351 : Str = CallByName Inspect.61 Inspect.352 Inspect.353; + ret Inspect.351; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.315 : U8 = GetTagId Inspect.305; + switch Inspect.315: + case 0: + let Inspect.314 : Str = CallByName Inspect.203 Inspect.149 Inspect.305; + ret Inspect.314; + + default: + let Inspect.314 : Str = CallByName Inspect.205 Inspect.149 Inspect.305; + ret Inspect.314; + + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.335 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.335; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.40 (Inspect.201, Inspect.202): + inc Inspect.202; + let Inspect.341 : Int1 = CallByName List.1 Inspect.202; + if Inspect.341 then + dec Inspect.202; + let Inspect.343 : [C Str, C Str List Str] = TagId(0) Inspect.201; + let Inspect.342 : [C Str, C Str List Str] = CallByName Inspect.30 Inspect.343; + ret Inspect.342; + else + let Inspect.317 : [C Str, C Str List Str] = TagId(1) Inspect.201 Inspect.202; + let Inspect.316 : [C Str, C Str List Str] = CallByName Inspect.30 Inspect.317; + ret Inspect.316; + +procedure Inspect.44 (Inspect.248): + let Inspect.347 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.347; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : Str = CallByName #Derived.0 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName #Derived.3 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.324 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.324; + +procedure List.1 (List.102): + let List.566 : U64 = CallByName List.6 List.102; + dec List.102; + let List.567 : U64 = 0i64; + let List.565 : Int1 = CallByName Bool.11 List.566 List.567; + ret List.565; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : Str = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.6 (#Attr.2): + let List.564 : U64 = lowlevel ListLen #Attr.2; + ret List.564; + +procedure List.66 (#Attr.2, #Attr.3): + let List.563 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.563; + +procedure List.88 (#Derived_gen.18, #Derived_gen.19, #Derived_gen.20, #Derived_gen.21, #Derived_gen.22): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : Str = CallByName List.66 List.157 List.160; + inc List.562; + let List.162 : Str = CallByName Inspect.209 List.158 List.562; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.18 #Derived_gen.19 #Derived_gen.20 #Derived_gen.21 #Derived_gen.22; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.292 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.292; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.291 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.291; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.0 (): + let Test.5 : Str = "foo"; + let Test.4 : Str = CallByName Inspect.5 Test.5; + let Test.3 : Str = CallByName Inspect.35 Test.4; + ret Test.3; diff --git a/crates/compiler/test_mono/generated/inspect_derived_tag_two_payloads_string.txt b/crates/compiler/test_mono/generated/inspect_derived_tag_two_payloads_string.txt new file mode 100644 index 0000000000..81517e7e3f --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_tag_two_payloads_string.txt @@ -0,0 +1,178 @@ +procedure #Derived.0 (#Derived.1): + let #Derived_gen.0 : {Str, Str} = CallByName Inspect.30 #Derived.1; + ret #Derived_gen.0; + +procedure #Derived.4 (#Derived.5, #Derived.1): + joinpoint #Derived_gen.5 #Derived_gen.4: + let #Derived_gen.3 : Str = CallByName Inspect.31 #Derived_gen.4 #Derived.5; + ret #Derived_gen.3; + in + let #Derived.2 : Str = StructAtIndex 0 #Derived.1; + let #Derived.3 : Str = StructAtIndex 1 #Derived.1; + let #Derived_gen.7 : Str = "A"; + let #Derived_gen.9 : Str = CallByName Inspect.44 #Derived.2; + let #Derived_gen.10 : Str = CallByName Inspect.44 #Derived.3; + let #Derived_gen.8 : List Str = Array [#Derived_gen.9, #Derived_gen.10]; + let #Derived_gen.6 : [C Str, C Str List Str] = CallByName Inspect.40 #Derived_gen.7 #Derived_gen.8; + jump #Derived_gen.5 #Derived_gen.6; + +procedure Bool.11 (#Attr.2, #Attr.3): + let Bool.23 : Int1 = lowlevel Eq #Attr.2 #Attr.3; + ret Bool.23; + +procedure Inspect.203 (Inspect.204, #Attr.12): + let Inspect.346 : Str = UnionAtIndex (Id 0) (Index 0) #Attr.12; + let Inspect.345 : Str = CallByName Inspect.61 Inspect.204 Inspect.346; + ret Inspect.345; + +procedure Inspect.205 (Inspect.206, #Attr.12): + let Inspect.340 : List Str = UnionAtIndex (Id 1) (Index 1) #Attr.12; + let Inspect.339 : Str = UnionAtIndex (Id 1) (Index 0) #Attr.12; + let Inspect.338 : Str = "("; + let Inspect.337 : Str = CallByName Inspect.61 Inspect.206 Inspect.338; + let Inspect.325 : Str = CallByName Inspect.61 Inspect.337 Inspect.339; + let Inspect.321 : Str = CallByName Inspect.207 Inspect.325 Inspect.340; + let Inspect.322 : Str = ")"; + let Inspect.320 : Str = CallByName Inspect.61 Inspect.321 Inspect.322; + ret Inspect.320; + +procedure Inspect.207 (Inspect.208, Inspect.202): + let Inspect.329 : {} = Struct {}; + let Inspect.328 : Str = CallByName List.18 Inspect.202 Inspect.208 Inspect.329; + ret Inspect.328; + +procedure Inspect.209 (Inspect.210, Inspect.211): + let Inspect.336 : Str = " "; + let Inspect.331 : Str = CallByName Inspect.61 Inspect.210 Inspect.336; + let Inspect.330 : Str = CallByName Inspect.212 Inspect.331 Inspect.211; + ret Inspect.330; + +procedure Inspect.212 (Inspect.213, Inspect.211): + let Inspect.334 : Str = CallByName Inspect.31 Inspect.211 Inspect.213; + ret Inspect.334; + +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.355 : Str = "\""; + let Inspect.354 : Str = CallByName Inspect.61 Inspect.250 Inspect.355; + let Inspect.352 : Str = CallByName Inspect.61 Inspect.354 Inspect.248; + let Inspect.353 : Str = "\""; + let Inspect.351 : Str = CallByName Inspect.61 Inspect.352 Inspect.353; + ret Inspect.351; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.315 : U8 = GetTagId Inspect.305; + switch Inspect.315: + case 0: + let Inspect.314 : Str = CallByName Inspect.203 Inspect.149 Inspect.305; + ret Inspect.314; + + default: + let Inspect.314 : Str = CallByName Inspect.205 Inspect.149 Inspect.305; + ret Inspect.314; + + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.335 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.335; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.40 (Inspect.201, Inspect.202): + inc Inspect.202; + let Inspect.341 : Int1 = CallByName List.1 Inspect.202; + if Inspect.341 then + dec Inspect.202; + let Inspect.343 : [C Str, C Str List Str] = TagId(0) Inspect.201; + let Inspect.342 : [C Str, C Str List Str] = CallByName Inspect.30 Inspect.343; + ret Inspect.342; + else + let Inspect.317 : [C Str, C Str List Str] = TagId(1) Inspect.201 Inspect.202; + let Inspect.316 : [C Str, C Str List Str] = CallByName Inspect.30 Inspect.317; + ret Inspect.316; + +procedure Inspect.44 (Inspect.248): + let Inspect.356 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.356; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : {Str, Str} = CallByName #Derived.0 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName #Derived.4 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.324 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.324; + +procedure List.1 (List.102): + let List.566 : U64 = CallByName List.6 List.102; + dec List.102; + let List.567 : U64 = 0i64; + let List.565 : Int1 = CallByName Bool.11 List.566 List.567; + ret List.565; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : Str = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.6 (#Attr.2): + let List.564 : U64 = lowlevel ListLen #Attr.2; + ret List.564; + +procedure List.66 (#Attr.2, #Attr.3): + let List.563 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.563; + +procedure List.88 (#Derived_gen.19, #Derived_gen.20, #Derived_gen.21, #Derived_gen.22, #Derived_gen.23): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : Str = CallByName List.66 List.157 List.160; + inc List.562; + let List.162 : Str = CallByName Inspect.209 List.158 List.562; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.19 #Derived_gen.20 #Derived_gen.21 #Derived_gen.22 #Derived_gen.23; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.292 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.292; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.291 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.291; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.0 (): + let Test.6 : Str = "foo"; + let Test.5 : Str = "foo"; + let Test.1 : {Str, Str} = Struct {Test.5, Test.6}; + let Test.4 : Str = CallByName Inspect.5 Test.1; + let Test.3 : Str = CallByName Inspect.35 Test.4; + ret Test.3; From 9b181e1b3fde19c869d49637e9417c320b01a307 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 12:48:04 -0800 Subject: [PATCH 066/105] add inspect implementation for dict and set --- crates/compiler/builtins/roc/Dict.roc | 10 + crates/compiler/builtins/roc/Set.roc | 9 + crates/compiler/derive/src/inspect.rs | 4 +- .../generated/inspect_derived_dict.txt | 1202 +++++++++++++++++ crates/compiler/test_mono/src/tests.rs | 16 + 5 files changed, 1239 insertions(+), 2 deletions(-) create mode 100644 crates/compiler/test_mono/generated/inspect_derived_dict.txt diff --git a/crates/compiler/builtins/roc/Dict.roc b/crates/compiler/builtins/roc/Dict.roc index f737ccbb25..11200a420f 100644 --- a/crates/compiler/builtins/roc/Dict.roc +++ b/crates/compiler/builtins/roc/Dict.roc @@ -32,6 +32,7 @@ interface Dict Str, Num.{ Nat, U64, U8, I8 }, Hash.{ Hasher, Hash }, + Inspect.{ Inspect, Inspector, InspectFormatter }, ] ## A [dictionary](https://en.wikipedia.org/wiki/Associative_array) that lets you @@ -108,6 +109,9 @@ Dict k v := { Hash { hash: hashDict, }, + Inspect { + toInspector: toInspectorDict, + }, ] isEq : Dict k v, Dict k v -> Bool where k implements Hash & Eq, v implements Eq @@ -126,6 +130,12 @@ isEq = \xs, ys -> 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 + +toInspectorDict : Dict k v -> Inspector f where k implements Inspect & Hash & Eq, v implements Inspect, f implements InspectFormatter +toInspectorDict = \dict -> + fmt <- Inspect.custom + Inspect.apply (Inspect.dict dict walk Inspect.toInspector Inspect.toInspector) fmt + ## Return an empty dictionary. ## ``` ## emptyDict = Dict.empty {} diff --git a/crates/compiler/builtins/roc/Set.roc b/crates/compiler/builtins/roc/Set.roc index 19e6a82ebf..b942461f31 100644 --- a/crates/compiler/builtins/roc/Set.roc +++ b/crates/compiler/builtins/roc/Set.roc @@ -25,6 +25,7 @@ interface Set Dict.{ Dict }, Num.{ Nat }, Hash.{ Hash, Hasher }, + Inspect.{ Inspect, Inspector, InspectFormatter }, ] ## Provides a [set](https://en.wikipedia.org/wiki/Set_(abstract_data_type)) @@ -37,6 +38,9 @@ Set k := Dict.Dict k {} where k implements Hash & Eq Hash { hash: hashSet, }, + Inspect { + toInspector: toInspectorSet, + }, ] isEq : Set k, Set k -> Bool where k implements Hash & Eq @@ -53,6 +57,11 @@ isEq = \xs, ys -> hashSet : hasher, Set k -> hasher where k implements Hash & Eq, hasher implements Hasher hashSet = \hasher, @Set inner -> Hash.hash hasher inner +toInspectorSet : Set k -> Inspector f where k implements Inspect & Hash & Eq, f implements InspectFormatter +toInspectorSet = \set -> + fmt <- Inspect.custom + Inspect.apply (Inspect.set set walk Inspect.toInspector) fmt + ## Creates a new empty `Set`. ## ``` ## emptySet = Set.empty {} diff --git a/crates/compiler/derive/src/inspect.rs b/crates/compiler/derive/src/inspect.rs index d5cfb68962..05e7558bea 100644 --- a/crates/compiler/derive/src/inspect.rs +++ b/crates/compiler/derive/src/inspect.rs @@ -29,8 +29,8 @@ pub(crate) fn derive_to_inspector( ) -> DerivedBody { let (body, body_type) = match key { FlatInspectableKey::List() => to_inspector_list(env, def_symbol), - FlatInspectableKey::Set() => todo!(), - FlatInspectableKey::Dict() => todo!(), + FlatInspectableKey::Set() => unreachable!(), + FlatInspectableKey::Dict() => unreachable!(), FlatInspectableKey::Record(fields) => { // Generalized record var so we can reuse this impl between many records: // if fields = { a, b }, this is { a: t1, b: t2 } for fresh t1, t2. diff --git a/crates/compiler/test_mono/generated/inspect_derived_dict.txt b/crates/compiler/test_mono/generated/inspect_derived_dict.txt new file mode 100644 index 0000000000..3ca0ce6aa0 --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_dict.txt @@ -0,0 +1,1202 @@ +procedure Bool.1 (): + let Bool.30 : Int1 = false; + ret Bool.30; + +procedure Bool.11 (#Attr.2, #Attr.3): + let Bool.25 : Int1 = lowlevel Eq #Attr.2 #Attr.3; + ret Bool.25; + +procedure Bool.11 (#Attr.2, #Attr.3): + let Bool.26 : Int1 = lowlevel Eq #Attr.2 #Attr.3; + ret Bool.26; + +procedure Bool.11 (#Attr.2, #Attr.3): + let Bool.28 : Int1 = lowlevel Eq #Attr.2 #Attr.3; + ret Bool.28; + +procedure Bool.2 (): + let Bool.29 : Int1 = true; + ret Bool.29; + +procedure Dict.1 (Dict.557): + let Dict.720 : List {Str, I64} = Array []; + let Dict.726 : U64 = 0i64; + let Dict.727 : U64 = 8i64; + let Dict.721 : List U64 = CallByName List.11 Dict.726 Dict.727; + let Dict.724 : I8 = CallByName Dict.40; + let Dict.725 : U64 = 8i64; + let Dict.722 : List I8 = CallByName List.11 Dict.724 Dict.725; + let Dict.723 : U64 = 0i64; + let Dict.719 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.720, Dict.721, Dict.722, Dict.723}; + ret Dict.719; + +procedure Dict.10 (Dict.558, Dict.127, Dict.128): + let Dict.126 : List {Str, I64} = StructAtIndex 0 Dict.558; + let #Derived_gen.61 : List U64 = StructAtIndex 1 Dict.558; + dec #Derived_gen.61; + let #Derived_gen.60 : List I8 = StructAtIndex 2 Dict.558; + dec #Derived_gen.60; + let Dict.981 : {Str, Int1} = CallByName List.18 Dict.126 Dict.127 Dict.128; + ret Dict.981; + +procedure Dict.101 (Dict.102, Dict.568): + let Dict.103 : Str = StructAtIndex 0 Dict.568; + let Dict.104 : I64 = StructAtIndex 1 Dict.568; + let Dict.569 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.8 Dict.102 Dict.103 Dict.104; + ret Dict.569; + +procedure Dict.12 (Dict.100): + let Dict.718 : {} = Struct {}; + let Dict.566 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.1 Dict.718; + let Dict.567 : {} = Struct {}; + let Dict.565 : {List {Str, I64}, List U64, List I8, U64} = CallByName List.18 Dict.100 Dict.566 Dict.567; + ret Dict.565; + +procedure Dict.129 (Dict.130, Dict.983, Dict.128): + let Dict.131 : Str = StructAtIndex 0 Dict.983; + let Dict.132 : I64 = StructAtIndex 1 Dict.983; + let Dict.985 : {Str, Int1} = CallByName Inspect.190 Dict.130 Dict.131 Dict.132 Dict.128; + ret Dict.985; + +procedure Dict.22 (#Attr.2, #Attr.3): + let Dict.574 : U64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + dec #Attr.2; + ret Dict.574; + +procedure Dict.22 (#Attr.2, #Attr.3): + let Dict.597 : I8 = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + dec #Attr.2; + ret Dict.597; + +procedure Dict.22 (#Attr.2, #Attr.3): + let Dict.665 : {Str, I64} = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + inc Dict.665; + dec #Attr.2; + ret Dict.665; + +procedure Dict.22 (#Attr.2, #Attr.3): + let Dict.781 : U8 = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + dec #Attr.2; + ret Dict.781; + +procedure Dict.23 (#Attr.2): + let Dict.659 : U64 = lowlevel DictPseudoSeed #Attr.2; + ret Dict.659; + +procedure Dict.31 (Dict.93): + let Dict.973 : {List {Str, I64}, List U64, List I8, U64} = CallByName Inspect.30 Dict.93; + ret Dict.973; + +procedure Dict.33 (Dict.554, Dict.237, Dict.238, Dict.239, Dict.240): + let Dict.235 : List {Str, I64} = StructAtIndex 0 Dict.554; + let Dict.234 : List U64 = StructAtIndex 1 Dict.554; + let Dict.233 : List I8 = StructAtIndex 2 Dict.554; + inc Dict.233; + let Dict.236 : U64 = StructAtIndex 3 Dict.554; + let Dict.607 : U64 = CallByName List.6 Dict.233; + let Dict.602 : U64 = CallByName Dict.45 Dict.607; + let Dict.241 : {U64, U64, U64} = CallByName Dict.42 Dict.239 Dict.602; + let Dict.580 : U64 = 0i64; + let Dict.242 : U64 = CallByName Dict.34 Dict.233 Dict.241 Dict.580; + let Dict.243 : U64 = CallByName List.6 Dict.235; + let Dict.579 : {Str, I64} = Struct {Dict.237, Dict.238}; + let Dict.244 : List {Str, I64} = CallByName List.4 Dict.235 Dict.579; + let Dict.577 : List U64 = CallByName List.3 Dict.234 Dict.242 Dict.243; + let Dict.578 : List I8 = CallByName List.3 Dict.233 Dict.242 Dict.240; + let Dict.576 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.244, Dict.577, Dict.578, Dict.236}; + ret Dict.576; + +procedure Dict.34 (#Derived_gen.42, #Derived_gen.43, #Derived_gen.44): + joinpoint Dict.581 Dict.245 Dict.246 Dict.247: + let Dict.599 : U64 = StructAtIndex 2 Dict.246; + let Dict.598 : U64 = CallByName Dict.44 Dict.599; + let Dict.248 : U64 = CallByName Num.51 Dict.598 Dict.247; + inc Dict.245; + let Dict.249 : I8 = CallByName Dict.22 Dict.245 Dict.248; + let Dict.596 : I8 = 0i64; + let Dict.594 : Int1 = CallByName Num.22 Dict.249 Dict.596; + if Dict.594 then + dec Dict.245; + ret Dict.248; + else + let Dict.593 : U64 = 7i64; + let Dict.585 : Int1 = CallByName Bool.11 Dict.247 Dict.593; + if Dict.585 then + let Dict.587 : {U64, U64, U64} = CallByName Dict.43 Dict.246; + let Dict.588 : U64 = 0i64; + jump Dict.581 Dict.245 Dict.587 Dict.588; + else + let Dict.584 : U64 = 1i64; + let Dict.583 : U64 = CallByName Num.51 Dict.247 Dict.584; + jump Dict.581 Dict.245 Dict.246 Dict.583; + in + jump Dict.581 #Derived_gen.42 #Derived_gen.43 #Derived_gen.44; + +procedure Dict.35 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2, #Derived_gen.3, #Derived_gen.4, #Derived_gen.5, #Derived_gen.6): + joinpoint Dict.686 Dict.250 Dict.251 Dict.252 Dict.253 Dict.254 Dict.255 Dict.256: + let Dict.712 : U64 = StructAtIndex 2 Dict.255; + let Dict.711 : U64 = CallByName Dict.44 Dict.712; + let Dict.257 : U64 = CallByName Num.51 Dict.711 Dict.256; + inc Dict.250; + let Dict.258 : I8 = CallByName Dict.22 Dict.250 Dict.257; + let Dict.710 : I8 = CallByName Dict.40; + let Dict.707 : Int1 = CallByName Bool.11 Dict.258 Dict.710; + if Dict.707 then + dec Dict.250; + dec Dict.251; + dec Dict.252; + dec Dict.254; + let Dict.709 : {} = Struct {}; + let Dict.708 : [C {}, C U64] = TagId(0) Dict.709; + ret Dict.708; + else + let Dict.695 : Int1 = CallByName Bool.11 Dict.258 Dict.253; + if Dict.695 then + inc Dict.251; + let Dict.261 : U64 = CallByName Dict.22 Dict.251 Dict.257; + inc Dict.252; + let Dict.706 : {Str, I64} = CallByName Dict.22 Dict.252 Dict.261; + let Dict.262 : Str = StructAtIndex 0 Dict.706; + let Dict.704 : Int1 = CallByName Bool.11 Dict.262 Dict.254; + dec Dict.262; + if Dict.704 then + dec Dict.250; + dec Dict.251; + dec Dict.252; + dec Dict.254; + let Dict.705 : [C {}, C U64] = TagId(1) Dict.257; + ret Dict.705; + else + let Dict.703 : U64 = 7i64; + let Dict.699 : Int1 = CallByName Bool.11 Dict.256 Dict.703; + if Dict.699 then + let Dict.701 : {U64, U64, U64} = CallByName Dict.43 Dict.255; + let Dict.702 : U64 = 0i64; + jump Dict.686 Dict.250 Dict.251 Dict.252 Dict.253 Dict.254 Dict.701 Dict.702; + else + let Dict.698 : U64 = 1i64; + let Dict.697 : U64 = CallByName Num.51 Dict.256 Dict.698; + jump Dict.686 Dict.250 Dict.251 Dict.252 Dict.253 Dict.254 Dict.255 Dict.697; + else + let Dict.694 : U64 = 7i64; + let Dict.690 : Int1 = CallByName Bool.11 Dict.256 Dict.694; + if Dict.690 then + let Dict.692 : {U64, U64, U64} = CallByName Dict.43 Dict.255; + let Dict.693 : U64 = 0i64; + jump Dict.686 Dict.250 Dict.251 Dict.252 Dict.253 Dict.254 Dict.692 Dict.693; + else + let Dict.689 : U64 = 1i64; + let Dict.688 : U64 = CallByName Num.51 Dict.256 Dict.689; + jump Dict.686 Dict.250 Dict.251 Dict.252 Dict.253 Dict.254 Dict.255 Dict.688; + in + jump Dict.686 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3 #Derived_gen.4 #Derived_gen.5 #Derived_gen.6; + +procedure Dict.36 (Dict.551): + let Dict.266 : List {Str, I64} = StructAtIndex 0 Dict.551; + let Dict.265 : List U64 = StructAtIndex 1 Dict.551; + let Dict.264 : List I8 = StructAtIndex 2 Dict.551; + let Dict.267 : U64 = StructAtIndex 3 Dict.551; + let Dict.268 : U64 = CallByName List.6 Dict.265; + let Dict.679 : U8 = 3i64; + let Dict.678 : U64 = CallByName Num.74 Dict.268 Dict.679; + let Dict.269 : U64 = CallByName Num.75 Dict.268 Dict.678; + let Dict.612 : Int1 = CallByName Num.24 Dict.267 Dict.269; + if Dict.612 then + let Dict.614 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.266, Dict.265, Dict.264, Dict.267}; + let Dict.613 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.37 Dict.614; + ret Dict.613; + else + let Dict.611 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.266, Dict.265, Dict.264, Dict.267}; + ret Dict.611; + +procedure Dict.37 (Dict.552): + let Dict.272 : List {Str, I64} = StructAtIndex 0 Dict.552; + inc Dict.272; + let Dict.271 : List U64 = StructAtIndex 1 Dict.552; + let Dict.270 : List I8 = StructAtIndex 2 Dict.552; + let Dict.273 : U64 = StructAtIndex 3 Dict.552; + let Dict.676 : U64 = 2i64; + let Dict.677 : U64 = CallByName List.6 Dict.271; + let Dict.274 : U64 = CallByName Num.21 Dict.676 Dict.677; + let Dict.675 : U64 = 0i64; + let Dict.671 : List U64 = CallByName List.11 Dict.675 Dict.274; + let Dict.673 : I8 = CallByName Dict.40; + let Dict.672 : List I8 = CallByName List.11 Dict.673 Dict.274; + let Dict.275 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.272, Dict.671, Dict.672, Dict.273}; + let Dict.616 : U64 = 0i64; + let Dict.615 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.38 Dict.275 Dict.270 Dict.271 Dict.272 Dict.616; + ret Dict.615; + +procedure Dict.38 (#Derived_gen.32, #Derived_gen.33, #Derived_gen.34, #Derived_gen.35, #Derived_gen.36): + joinpoint Dict.617 Dict.276 Dict.277 Dict.278 Dict.279 Dict.280: + inc Dict.277; + let Dict.618 : [C {}, C I8] = CallByName List.2 Dict.277 Dict.280; + let Dict.668 : U8 = 1i64; + let Dict.669 : U8 = GetTagId Dict.618; + let Dict.670 : Int1 = lowlevel Eq Dict.668 Dict.669; + if Dict.670 then + let Dict.281 : I8 = UnionAtIndex (Id 1) (Index 0) Dict.618; + joinpoint Dict.623 Dict.282: + let Dict.621 : U64 = 1i64; + let Dict.620 : U64 = CallByName Num.51 Dict.280 Dict.621; + jump Dict.617 Dict.282 Dict.277 Dict.278 Dict.279 Dict.620; + in + let Dict.666 : I8 = 0i64; + let Dict.624 : Int1 = CallByName Num.25 Dict.281 Dict.666; + if Dict.624 then + inc Dict.278; + let Dict.283 : U64 = CallByName Dict.22 Dict.278 Dict.280; + inc Dict.279; + let Dict.664 : {Str, I64} = CallByName Dict.22 Dict.279 Dict.283; + let Dict.284 : Str = StructAtIndex 0 Dict.664; + let Dict.622 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.39 Dict.276 Dict.284 Dict.283; + jump Dict.623 Dict.622; + else + jump Dict.623 Dict.276; + else + dec Dict.277; + dec Dict.279; + dec Dict.278; + ret Dict.276; + in + jump Dict.617 #Derived_gen.32 #Derived_gen.33 #Derived_gen.34 #Derived_gen.35 #Derived_gen.36; + +procedure Dict.39 (Dict.553, Dict.289, Dict.290): + let Dict.287 : List {Str, I64} = StructAtIndex 0 Dict.553; + let Dict.286 : List U64 = StructAtIndex 1 Dict.553; + let Dict.285 : List I8 = StructAtIndex 2 Dict.553; + inc Dict.285; + let Dict.288 : U64 = StructAtIndex 3 Dict.553; + let Dict.639 : [C , C U64] = TagId(0) ; + let Dict.638 : {U64, U64} = CallByName Dict.48 Dict.639; + let Dict.636 : {U64, U64} = CallByName Hash.19 Dict.638 Dict.289; + let Dict.291 : U64 = CallByName Dict.51 Dict.636; + let Dict.292 : U64 = CallByName Dict.46 Dict.291; + let Dict.293 : I8 = CallByName Dict.47 Dict.291; + let Dict.630 : U64 = CallByName List.6 Dict.285; + let Dict.629 : U64 = CallByName Dict.45 Dict.630; + let Dict.294 : {U64, U64, U64} = CallByName Dict.42 Dict.292 Dict.629; + let Dict.628 : U64 = 0i64; + let Dict.295 : U64 = CallByName Dict.34 Dict.285 Dict.294 Dict.628; + let Dict.626 : List U64 = CallByName List.3 Dict.286 Dict.295 Dict.290; + let Dict.627 : List I8 = CallByName List.3 Dict.285 Dict.295 Dict.293; + let Dict.625 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.287, Dict.626, Dict.627, Dict.288}; + ret Dict.625; + +procedure Dict.40 (): + let Dict.674 : I8 = -128i64; + ret Dict.674; + +procedure Dict.42 (Dict.297, Dict.298): + let Dict.606 : U64 = 1i64; + let Dict.299 : U64 = CallByName Num.77 Dict.298 Dict.606; + let Dict.605 : U64 = CallByName Num.137 Dict.297; + let Dict.300 : U64 = CallByName Num.69 Dict.605 Dict.299; + let Dict.604 : U64 = 1i64; + let Dict.603 : {U64, U64, U64} = Struct {Dict.299, Dict.604, Dict.300}; + ret Dict.603; + +procedure Dict.43 (Dict.562): + let Dict.303 : U64 = StructAtIndex 0 Dict.562; + let Dict.302 : U64 = StructAtIndex 1 Dict.562; + let Dict.301 : U64 = StructAtIndex 2 Dict.562; + let Dict.592 : U64 = CallByName Num.51 Dict.301 Dict.302; + let Dict.304 : U64 = CallByName Num.69 Dict.592 Dict.303; + let Dict.591 : U64 = 1i64; + let Dict.590 : U64 = CallByName Num.51 Dict.302 Dict.591; + let Dict.589 : {U64, U64, U64} = Struct {Dict.303, Dict.590, Dict.304}; + ret Dict.589; + +procedure Dict.44 (Dict.305): + let Dict.601 : U8 = 3i64; + let Dict.600 : U64 = CallByName Num.72 Dict.305 Dict.601; + ret Dict.600; + +procedure Dict.45 (Dict.306): + let Dict.609 : U8 = 3i64; + let Dict.608 : U64 = CallByName Num.74 Dict.306 Dict.609; + ret Dict.608; + +procedure Dict.46 (Dict.307): + let Dict.635 : U8 = 7i64; + let Dict.634 : U64 = CallByName Num.74 Dict.307 Dict.635; + ret Dict.634; + +procedure Dict.47 (Dict.308): + let Dict.633 : U64 = 127i64; + let Dict.632 : U64 = CallByName Num.69 Dict.308 Dict.633; + let Dict.631 : I8 = CallByName Num.117 Dict.632; + ret Dict.631; + +procedure Dict.48 (Dict.309): + joinpoint Dict.656 Dict.310: + let Dict.641 : U64 = CallByName Dict.50 Dict.310; + let Dict.640 : {U64, U64} = Struct {Dict.641, Dict.310}; + ret Dict.640; + in + let Dict.661 : U8 = 0i64; + let Dict.662 : U8 = GetTagId Dict.309; + let Dict.663 : Int1 = lowlevel Eq Dict.661 Dict.662; + if Dict.663 then + let Dict.658 : {} = Struct {}; + let Dict.657 : U64 = CallByName Dict.23 Dict.658; + jump Dict.656 Dict.657; + else + let Dict.311 : U64 = UnionAtIndex (Id 1) (Index 0) Dict.309; + jump Dict.656 Dict.311; + +procedure Dict.49 (Dict.541, Dict.542): + let Dict.314 : U64 = StructAtIndex 0 Dict.542; + let Dict.315 : U64 = StructAtIndex 1 Dict.542; + let Dict.317 : U64 = StructAtIndex 2 Dict.542; + let Dict.316 : U64 = StructAtIndex 3 Dict.542; + let Dict.312 : U64 = StructAtIndex 0 Dict.541; + let Dict.313 : U64 = StructAtIndex 1 Dict.541; + let Dict.749 : U64 = CallByName Dict.61; + let Dict.747 : U64 = CallByName Num.70 Dict.314 Dict.749; + let Dict.748 : U64 = CallByName Num.70 Dict.315 Dict.316; + let Dict.318 : {U64, U64} = CallByName Dict.65 Dict.747 Dict.748; + let Dict.744 : U64 = StructAtIndex 0 Dict.318; + let Dict.745 : U64 = CallByName Dict.60; + let Dict.743 : U64 = CallByName Num.70 Dict.744 Dict.745; + let Dict.319 : U64 = CallByName Num.70 Dict.743 Dict.317; + let Dict.740 : U64 = StructAtIndex 1 Dict.318; + let Dict.741 : U64 = CallByName Dict.61; + let Dict.320 : U64 = CallByName Num.70 Dict.740 Dict.741; + let Dict.321 : U64 = CallByName Dict.64 Dict.319 Dict.320; + let Dict.732 : U64 = CallByName Dict.64 Dict.313 Dict.321; + let Dict.731 : {U64, U64} = Struct {Dict.312, Dict.732}; + ret Dict.731; + +procedure Dict.50 (Dict.322): + let Dict.654 : U64 = CallByName Dict.60; + let Dict.644 : U64 = CallByName Num.70 Dict.322 Dict.654; + let Dict.645 : U64 = CallByName Dict.61; + let Dict.643 : U64 = CallByName Dict.64 Dict.644 Dict.645; + let Dict.642 : U64 = CallByName Num.70 Dict.643 Dict.322; + ret Dict.642; + +procedure Dict.51 (Dict.561): + let Dict.323 : U64 = StructAtIndex 1 Dict.561; + ret Dict.323; + +procedure Dict.57 (Dict.535, Dict.362): + let Dict.360 : U64 = StructAtIndex 0 Dict.535; + let Dict.361 : U64 = StructAtIndex 1 Dict.535; + let Dict.363 : U64 = CallByName List.6 Dict.362; + joinpoint Dict.938 Dict.364: + let Dict.931 : {U64, U64} = Struct {Dict.360, Dict.361}; + let Dict.933 : U64 = StructAtIndex 0 Dict.364; + let Dict.934 : U64 = StructAtIndex 1 Dict.364; + let Dict.935 : U64 = CallByName Num.133 Dict.363; + let Dict.936 : U64 = StructAtIndex 2 Dict.364; + let Dict.932 : {U64, U64, U64, U64} = Struct {Dict.933, Dict.934, Dict.935, Dict.936}; + let Dict.930 : {U64, U64} = CallByName Dict.49 Dict.931 Dict.932; + ret Dict.930; + in + let Dict.972 : U64 = 16i64; + let Dict.943 : Int1 = CallByName Num.23 Dict.363 Dict.972; + if Dict.943 then + joinpoint Dict.945 Dict.937: + jump Dict.938 Dict.937; + in + let Dict.971 : U64 = 4i64; + let Dict.953 : Int1 = CallByName Num.25 Dict.363 Dict.971; + if Dict.953 then + let Dict.970 : U8 = 3i64; + let Dict.968 : U64 = CallByName Num.74 Dict.363 Dict.970; + let Dict.969 : U8 = 2i64; + let Dict.365 : U64 = CallByName Num.72 Dict.968 Dict.969; + let Dict.967 : U64 = 0i64; + inc 3 Dict.362; + let Dict.965 : U64 = CallByName Dict.67 Dict.362 Dict.967; + let Dict.966 : U8 = 32i64; + let Dict.963 : U64 = CallByName Num.72 Dict.965 Dict.966; + let Dict.964 : U64 = CallByName Dict.67 Dict.362 Dict.365; + let Dict.366 : U64 = CallByName Num.71 Dict.963 Dict.964; + let Dict.962 : U64 = 4i64; + let Dict.961 : U64 = CallByName Num.75 Dict.363 Dict.962; + let Dict.959 : U64 = CallByName Dict.67 Dict.362 Dict.961; + let Dict.960 : U8 = 32i64; + let Dict.954 : U64 = CallByName Num.72 Dict.959 Dict.960; + let Dict.958 : U64 = 4i64; + let Dict.957 : U64 = CallByName Num.75 Dict.363 Dict.958; + let Dict.956 : U64 = CallByName Num.75 Dict.957 Dict.365; + let Dict.955 : U64 = CallByName Dict.67 Dict.362 Dict.956; + let Dict.367 : U64 = CallByName Num.71 Dict.954 Dict.955; + let Dict.944 : {U64, U64, U64} = Struct {Dict.366, Dict.367, Dict.360}; + jump Dict.945 Dict.944; + else + let Dict.952 : U64 = 0i64; + let Dict.948 : Int1 = CallByName Num.24 Dict.363 Dict.952; + if Dict.948 then + let Dict.951 : U64 = 0i64; + let Dict.949 : U64 = CallByName Dict.68 Dict.362 Dict.951 Dict.363; + let Dict.950 : U64 = 0i64; + let Dict.944 : {U64, U64, U64} = Struct {Dict.949, Dict.950, Dict.360}; + jump Dict.945 Dict.944; + else + dec Dict.362; + let Dict.946 : U64 = 0i64; + let Dict.947 : U64 = 0i64; + let Dict.944 : {U64, U64, U64} = Struct {Dict.946, Dict.947, Dict.360}; + jump Dict.945 Dict.944; + else + let Dict.942 : U64 = 48i64; + let Dict.940 : Int1 = CallByName Num.23 Dict.363 Dict.942; + if Dict.940 then + let Dict.941 : U64 = 0i64; + let Dict.937 : {U64, U64, U64} = CallByName Dict.59 Dict.360 Dict.362 Dict.941 Dict.363; + jump Dict.938 Dict.937; + else + let Dict.939 : U64 = 0i64; + let Dict.937 : {U64, U64, U64} = CallByName Dict.58 Dict.360 Dict.360 Dict.360 Dict.362 Dict.939 Dict.363; + jump Dict.938 Dict.937; + +procedure Dict.58 (#Derived_gen.51, #Derived_gen.52, #Derived_gen.53, #Derived_gen.54, #Derived_gen.55, #Derived_gen.56): + joinpoint Dict.757 Dict.368 Dict.369 Dict.370 Dict.371 Dict.372 Dict.373: + inc 6 Dict.371; + let Dict.864 : U64 = CallByName Dict.66 Dict.371 Dict.372; + let Dict.865 : U64 = CallByName Dict.61; + let Dict.859 : U64 = CallByName Num.70 Dict.864 Dict.865; + let Dict.863 : U64 = 8i64; + let Dict.862 : U64 = CallByName Num.51 Dict.372 Dict.863; + let Dict.861 : U64 = CallByName Dict.66 Dict.371 Dict.862; + let Dict.860 : U64 = CallByName Num.70 Dict.861 Dict.368; + let Dict.374 : U64 = CallByName Dict.64 Dict.859 Dict.860; + let Dict.858 : U64 = 16i64; + let Dict.857 : U64 = CallByName Num.51 Dict.372 Dict.858; + let Dict.854 : U64 = CallByName Dict.66 Dict.371 Dict.857; + let Dict.855 : U64 = CallByName Dict.62; + let Dict.849 : U64 = CallByName Num.70 Dict.854 Dict.855; + let Dict.853 : U64 = 24i64; + let Dict.852 : U64 = CallByName Num.51 Dict.372 Dict.853; + let Dict.851 : U64 = CallByName Dict.66 Dict.371 Dict.852; + let Dict.850 : U64 = CallByName Num.70 Dict.851 Dict.369; + let Dict.375 : U64 = CallByName Dict.64 Dict.849 Dict.850; + let Dict.848 : U64 = 32i64; + let Dict.847 : U64 = CallByName Num.51 Dict.372 Dict.848; + let Dict.844 : U64 = CallByName Dict.66 Dict.371 Dict.847; + let Dict.845 : U64 = CallByName Dict.63; + let Dict.839 : U64 = CallByName Num.70 Dict.844 Dict.845; + let Dict.843 : U64 = 40i64; + let Dict.842 : U64 = CallByName Num.51 Dict.372 Dict.843; + let Dict.841 : U64 = CallByName Dict.66 Dict.371 Dict.842; + let Dict.840 : U64 = CallByName Num.70 Dict.841 Dict.370; + let Dict.376 : U64 = CallByName Dict.64 Dict.839 Dict.840; + let Dict.838 : U64 = 48i64; + let Dict.377 : U64 = CallByName Num.75 Dict.373 Dict.838; + let Dict.837 : U64 = 48i64; + let Dict.378 : U64 = CallByName Num.51 Dict.372 Dict.837; + let Dict.836 : U64 = 48i64; + let Dict.834 : Int1 = CallByName Num.24 Dict.377 Dict.836; + if Dict.834 then + jump Dict.757 Dict.374 Dict.375 Dict.376 Dict.371 Dict.378 Dict.377; + else + let Dict.833 : U64 = 16i64; + let Dict.808 : Int1 = CallByName Num.24 Dict.377 Dict.833; + if Dict.808 then + let Dict.832 : U64 = CallByName Num.70 Dict.375 Dict.374; + let Dict.379 : U64 = CallByName Num.70 Dict.376 Dict.832; + let Dict.809 : {U64, U64, U64} = CallByName Dict.59 Dict.379 Dict.371 Dict.378 Dict.377; + ret Dict.809; + else + inc Dict.371; + let Dict.807 : U64 = CallByName Num.70 Dict.375 Dict.374; + let Dict.380 : U64 = CallByName Num.70 Dict.376 Dict.807; + let Dict.806 : U64 = 16i64; + let Dict.805 : U64 = CallByName Num.75 Dict.377 Dict.806; + let Dict.804 : U64 = CallByName Num.51 Dict.805 Dict.378; + let Dict.759 : U64 = CallByName Dict.66 Dict.371 Dict.804; + let Dict.803 : U64 = 8i64; + let Dict.802 : U64 = CallByName Num.75 Dict.377 Dict.803; + let Dict.761 : U64 = CallByName Num.51 Dict.802 Dict.378; + let Dict.760 : U64 = CallByName Dict.66 Dict.371 Dict.761; + let Dict.758 : {U64, U64, U64} = Struct {Dict.759, Dict.760, Dict.380}; + ret Dict.758; + in + jump Dict.757 #Derived_gen.51 #Derived_gen.52 #Derived_gen.53 #Derived_gen.54 #Derived_gen.55 #Derived_gen.56; + +procedure Dict.59 (#Derived_gen.17, #Derived_gen.18, #Derived_gen.19, #Derived_gen.20): + joinpoint Dict.810 Dict.381 Dict.382 Dict.383 Dict.384: + inc 2 Dict.382; + let Dict.830 : U64 = CallByName Dict.66 Dict.382 Dict.383; + let Dict.831 : U64 = CallByName Dict.61; + let Dict.825 : U64 = CallByName Num.70 Dict.830 Dict.831; + let Dict.829 : U64 = 8i64; + let Dict.828 : U64 = CallByName Num.51 Dict.383 Dict.829; + let Dict.827 : U64 = CallByName Dict.66 Dict.382 Dict.828; + let Dict.826 : U64 = CallByName Num.70 Dict.827 Dict.381; + let Dict.385 : U64 = CallByName Dict.64 Dict.825 Dict.826; + let Dict.824 : U64 = 16i64; + let Dict.386 : U64 = CallByName Num.75 Dict.384 Dict.824; + let Dict.823 : U64 = 16i64; + let Dict.387 : U64 = CallByName Num.51 Dict.383 Dict.823; + let Dict.822 : U64 = 16i64; + let Dict.812 : Int1 = CallByName Num.23 Dict.386 Dict.822; + if Dict.812 then + inc Dict.382; + let Dict.821 : U64 = 16i64; + let Dict.820 : U64 = CallByName Num.75 Dict.386 Dict.821; + let Dict.819 : U64 = CallByName Num.51 Dict.820 Dict.387; + let Dict.814 : U64 = CallByName Dict.66 Dict.382 Dict.819; + let Dict.818 : U64 = 8i64; + let Dict.817 : U64 = CallByName Num.75 Dict.386 Dict.818; + let Dict.816 : U64 = CallByName Num.51 Dict.817 Dict.387; + let Dict.815 : U64 = CallByName Dict.66 Dict.382 Dict.816; + let Dict.813 : {U64, U64, U64} = Struct {Dict.814, Dict.815, Dict.385}; + ret Dict.813; + else + jump Dict.810 Dict.385 Dict.382 Dict.387 Dict.386; + in + jump Dict.810 #Derived_gen.17 #Derived_gen.18 #Derived_gen.19 #Derived_gen.20; + +procedure Dict.60 (): + let Dict.746 : U64 = 11562461410679940143i64; + ret Dict.746; + +procedure Dict.61 (): + let Dict.742 : U64 = 16646288086500911323i64; + ret Dict.742; + +procedure Dict.62 (): + let Dict.856 : U64 = 10285213230658275043i64; + ret Dict.856; + +procedure Dict.63 (): + let Dict.846 : U64 = 6384245875588680899i64; + ret Dict.846; + +procedure Dict.64 (Dict.388, Dict.389): + let Dict.734 : {U64, U64} = CallByName Dict.65 Dict.388 Dict.389; + let Dict.390 : U64 = StructAtIndex 0 Dict.734; + let Dict.391 : U64 = StructAtIndex 1 Dict.734; + let Dict.733 : U64 = CallByName Num.70 Dict.390 Dict.391; + ret Dict.733; + +procedure Dict.65 (Dict.392, Dict.393): + let Dict.738 : U128 = CallByName Num.135 Dict.392; + let Dict.739 : U128 = CallByName Num.135 Dict.393; + let Dict.394 : U128 = CallByName Num.21 Dict.738 Dict.739; + let Dict.395 : U64 = CallByName Num.133 Dict.394; + let Dict.737 : U8 = 64i64; + let Dict.736 : U128 = CallByName Num.74 Dict.394 Dict.737; + let Dict.396 : U64 = CallByName Num.133 Dict.736; + let Dict.735 : {U64, U64} = Struct {Dict.395, Dict.396}; + ret Dict.735; + +procedure Dict.66 (Dict.397, Dict.398): + inc 7 Dict.397; + let Dict.801 : U8 = CallByName Dict.22 Dict.397 Dict.398; + let Dict.399 : U64 = CallByName Num.133 Dict.801; + let Dict.800 : U64 = 1i64; + let Dict.799 : U64 = CallByName Num.51 Dict.398 Dict.800; + let Dict.798 : U8 = CallByName Dict.22 Dict.397 Dict.799; + let Dict.400 : U64 = CallByName Num.133 Dict.798; + let Dict.797 : U64 = 2i64; + let Dict.796 : U64 = CallByName Num.51 Dict.398 Dict.797; + let Dict.795 : U8 = CallByName Dict.22 Dict.397 Dict.796; + let Dict.401 : U64 = CallByName Num.133 Dict.795; + let Dict.794 : U64 = 3i64; + let Dict.793 : U64 = CallByName Num.51 Dict.398 Dict.794; + let Dict.792 : U8 = CallByName Dict.22 Dict.397 Dict.793; + let Dict.402 : U64 = CallByName Num.133 Dict.792; + let Dict.791 : U64 = 4i64; + let Dict.790 : U64 = CallByName Num.51 Dict.398 Dict.791; + let Dict.789 : U8 = CallByName Dict.22 Dict.397 Dict.790; + let Dict.403 : U64 = CallByName Num.133 Dict.789; + let Dict.788 : U64 = 5i64; + let Dict.787 : U64 = CallByName Num.51 Dict.398 Dict.788; + let Dict.786 : U8 = CallByName Dict.22 Dict.397 Dict.787; + let Dict.404 : U64 = CallByName Num.133 Dict.786; + let Dict.785 : U64 = 6i64; + let Dict.784 : U64 = CallByName Num.51 Dict.398 Dict.785; + let Dict.783 : U8 = CallByName Dict.22 Dict.397 Dict.784; + let Dict.405 : U64 = CallByName Num.133 Dict.783; + let Dict.782 : U64 = 7i64; + let Dict.780 : U64 = CallByName Num.51 Dict.398 Dict.782; + let Dict.779 : U8 = CallByName Dict.22 Dict.397 Dict.780; + let Dict.406 : U64 = CallByName Num.133 Dict.779; + let Dict.778 : U8 = 8i64; + let Dict.777 : U64 = CallByName Num.72 Dict.400 Dict.778; + let Dict.407 : U64 = CallByName Num.71 Dict.399 Dict.777; + let Dict.776 : U8 = 16i64; + let Dict.773 : U64 = CallByName Num.72 Dict.401 Dict.776; + let Dict.775 : U8 = 24i64; + let Dict.774 : U64 = CallByName Num.72 Dict.402 Dict.775; + let Dict.408 : U64 = CallByName Num.71 Dict.773 Dict.774; + let Dict.772 : U8 = 32i64; + let Dict.769 : U64 = CallByName Num.72 Dict.403 Dict.772; + let Dict.771 : U8 = 40i64; + let Dict.770 : U64 = CallByName Num.72 Dict.404 Dict.771; + let Dict.409 : U64 = CallByName Num.71 Dict.769 Dict.770; + let Dict.768 : U8 = 48i64; + let Dict.765 : U64 = CallByName Num.72 Dict.405 Dict.768; + let Dict.767 : U8 = 56i64; + let Dict.766 : U64 = CallByName Num.72 Dict.406 Dict.767; + let Dict.410 : U64 = CallByName Num.71 Dict.765 Dict.766; + let Dict.763 : U64 = CallByName Num.71 Dict.407 Dict.408; + let Dict.764 : U64 = CallByName Num.71 Dict.409 Dict.410; + let Dict.762 : U64 = CallByName Num.71 Dict.763 Dict.764; + ret Dict.762; + +procedure Dict.67 (Dict.411, Dict.412): + inc 3 Dict.411; + let Dict.913 : U8 = CallByName Dict.22 Dict.411 Dict.412; + let Dict.413 : U64 = CallByName Num.133 Dict.913; + let Dict.912 : U64 = 1i64; + let Dict.911 : U64 = CallByName Num.51 Dict.412 Dict.912; + let Dict.910 : U8 = CallByName Dict.22 Dict.411 Dict.911; + let Dict.414 : U64 = CallByName Num.133 Dict.910; + let Dict.909 : U64 = 2i64; + let Dict.908 : U64 = CallByName Num.51 Dict.412 Dict.909; + let Dict.907 : U8 = CallByName Dict.22 Dict.411 Dict.908; + let Dict.415 : U64 = CallByName Num.133 Dict.907; + let Dict.906 : U64 = 3i64; + let Dict.905 : U64 = CallByName Num.51 Dict.412 Dict.906; + let Dict.904 : U8 = CallByName Dict.22 Dict.411 Dict.905; + let Dict.416 : U64 = CallByName Num.133 Dict.904; + let Dict.903 : U8 = 8i64; + let Dict.902 : U64 = CallByName Num.72 Dict.414 Dict.903; + let Dict.417 : U64 = CallByName Num.71 Dict.413 Dict.902; + let Dict.901 : U8 = 16i64; + let Dict.898 : U64 = CallByName Num.72 Dict.415 Dict.901; + let Dict.900 : U8 = 24i64; + let Dict.899 : U64 = CallByName Num.72 Dict.416 Dict.900; + let Dict.418 : U64 = CallByName Num.71 Dict.898 Dict.899; + let Dict.897 : U64 = CallByName Num.71 Dict.417 Dict.418; + ret Dict.897; + +procedure Dict.68 (Dict.419, Dict.420, Dict.421): + inc 2 Dict.419; + let Dict.891 : U8 = CallByName Dict.22 Dict.419 Dict.420; + let Dict.422 : U64 = CallByName Num.133 Dict.891; + let Dict.890 : U8 = 1i64; + let Dict.889 : U64 = CallByName Num.74 Dict.421 Dict.890; + let Dict.888 : U64 = CallByName Num.51 Dict.889 Dict.420; + let Dict.887 : U8 = CallByName Dict.22 Dict.419 Dict.888; + let Dict.423 : U64 = CallByName Num.133 Dict.887; + let Dict.886 : U64 = 1i64; + let Dict.885 : U64 = CallByName Num.75 Dict.421 Dict.886; + let Dict.884 : U64 = CallByName Num.51 Dict.885 Dict.420; + let Dict.883 : U8 = CallByName Dict.22 Dict.419 Dict.884; + let Dict.424 : U64 = CallByName Num.133 Dict.883; + let Dict.882 : U8 = 16i64; + let Dict.879 : U64 = CallByName Num.72 Dict.422 Dict.882; + let Dict.881 : U8 = 8i64; + let Dict.880 : U64 = CallByName Num.72 Dict.423 Dict.881; + let Dict.425 : U64 = CallByName Num.71 Dict.879 Dict.880; + let Dict.878 : U64 = CallByName Num.71 Dict.425 Dict.424; + ret Dict.878; + +procedure Dict.8 (Dict.550, Dict.168, Dict.169): + let Dict.166 : List {Str, I64} = StructAtIndex 0 Dict.550; + inc Dict.166; + let Dict.165 : List U64 = StructAtIndex 1 Dict.550; + inc Dict.165; + let Dict.164 : List I8 = StructAtIndex 2 Dict.550; + inc Dict.164; + let Dict.167 : U64 = StructAtIndex 3 Dict.550; + let Dict.717 : [C , C U64] = TagId(0) ; + let Dict.716 : {U64, U64} = CallByName Dict.48 Dict.717; + inc 2 Dict.168; + let Dict.715 : {U64, U64} = CallByName Hash.19 Dict.716 Dict.168; + let Dict.170 : U64 = CallByName Dict.51 Dict.715; + let Dict.171 : U64 = CallByName Dict.46 Dict.170; + let Dict.172 : I8 = CallByName Dict.47 Dict.170; + let Dict.714 : U64 = CallByName List.6 Dict.164; + let Dict.713 : U64 = CallByName Dict.45 Dict.714; + let Dict.173 : {U64, U64, U64} = CallByName Dict.42 Dict.171 Dict.713; + let Dict.685 : U64 = 0i64; + let Dict.570 : [C {}, C U64] = CallByName Dict.35 Dict.164 Dict.165 Dict.166 Dict.172 Dict.168 Dict.173 Dict.685; + let Dict.682 : U8 = 1i64; + let Dict.683 : U8 = GetTagId Dict.570; + let Dict.684 : Int1 = lowlevel Eq Dict.682 Dict.683; + if Dict.684 then + inc Dict.165; + let Dict.175 : U64 = UnionAtIndex (Id 1) (Index 0) Dict.570; + let Dict.176 : U64 = CallByName Dict.22 Dict.165 Dict.175; + let Dict.573 : {Str, I64} = Struct {Dict.168, Dict.169}; + let Dict.572 : List {Str, I64} = CallByName List.3 Dict.166 Dict.176 Dict.573; + let Dict.571 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.572, Dict.165, Dict.164, Dict.167}; + ret Dict.571; + else + let Dict.681 : U64 = 1i64; + let Dict.680 : U64 = CallByName Num.51 Dict.167 Dict.681; + let Dict.610 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.166, Dict.165, Dict.164, Dict.680}; + let Dict.177 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.36 Dict.610; + let Dict.575 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.33 Dict.177 Dict.168 Dict.169 Dict.171 Dict.172; + ret Dict.575; + +procedure Dict.94 (Dict.95, Dict.93): + let Dict.978 : {} = Struct {}; + let Dict.979 : {} = Struct {}; + let Dict.980 : {} = Struct {}; + let Dict.977 : {{List {Str, I64}, List U64, List I8, U64}, {}, {}, {}} = CallByName Inspect.39 Dict.93 Dict.978 Dict.979 Dict.980; + let Dict.976 : Str = CallByName Inspect.31 Dict.977 Dict.95; + ret Dict.976; + +procedure Hash.19 (Hash.39, Hash.40): + let Hash.79 : List U8 = CallByName Str.12 Hash.40; + let Hash.78 : {U64, U64} = CallByName Dict.57 Hash.39 Hash.79; + ret Hash.78; + +procedure Inspect.186 (Inspect.187, #Attr.12): + let Inspect.185 : {} = StructAtIndex 3 #Attr.12; + let Inspect.184 : {} = StructAtIndex 2 #Attr.12; + let Inspect.183 : {} = StructAtIndex 1 #Attr.12; + let Inspect.182 : {List {Str, I64}, List U64, List I8, U64} = StructAtIndex 0 #Attr.12; + let Inspect.353 : Str = "{"; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.187 Inspect.353; + let Inspect.329 : {{List {Str, I64}, List U64, List I8, U64}, {}, {}, {}} = Struct {Inspect.182, Inspect.183, Inspect.184, Inspect.185}; + let Inspect.324 : {Str, Int1} = CallByName Inspect.188 Inspect.328 Inspect.329; + let Inspect.325 : {} = Struct {}; + let Inspect.320 : Str = CallByName Inspect.200 Inspect.324; + let Inspect.321 : Str = "}"; + let Inspect.319 : Str = CallByName Inspect.61 Inspect.320 Inspect.321; + ret Inspect.319; + +procedure Inspect.188 (Inspect.189, #Attr.12): + let Inspect.185 : {} = StructAtIndex 3 #Attr.12; + let Inspect.184 : {} = StructAtIndex 2 #Attr.12; + let Inspect.183 : {} = StructAtIndex 1 #Attr.12; + let Inspect.182 : {List {Str, I64}, List U64, List I8, U64} = StructAtIndex 0 #Attr.12; + let Bool.1 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.189, Bool.1}; + let Inspect.333 : {{}, {}} = Struct {Inspect.184, Inspect.185}; + let Inspect.331 : {Str, Int1} = CallByName Dict.10 Inspect.182 Inspect.332 Inspect.333; + ret Inspect.331; + +procedure Inspect.190 (Inspect.334, Inspect.193, Inspect.194, #Attr.12): + let Inspect.185 : {} = StructAtIndex 1 #Attr.12; + let Inspect.184 : {} = StructAtIndex 0 #Attr.12; + let Inspect.191 : Str = StructAtIndex 0 Inspect.334; + let Inspect.192 : Int1 = StructAtIndex 1 Inspect.334; + joinpoint Inspect.351 Inspect.195: + let Inspect.348 : Str = CallByName Inspect.44 Inspect.193; + let Inspect.346 : Str = CallByName Inspect.31 Inspect.348 Inspect.195; + let Inspect.347 : Str = ": "; + let Inspect.340 : Str = CallByName Inspect.61 Inspect.346 Inspect.347; + let Inspect.341 : {I64, {}} = Struct {Inspect.194, Inspect.185}; + let Inspect.337 : Str = CallByName Inspect.196 Inspect.340 Inspect.341; + let Inspect.338 : {} = Struct {}; + let Inspect.336 : {Str, Int1} = CallByName Inspect.198 Inspect.337; + ret Inspect.336; + in + if Inspect.192 then + let Inspect.352 : Str = ", "; + let Inspect.350 : Str = CallByName Inspect.61 Inspect.191 Inspect.352; + jump Inspect.351 Inspect.350; + else + jump Inspect.351 Inspect.191; + +procedure Inspect.196 (Inspect.197, #Attr.12): + let Inspect.185 : {} = StructAtIndex 1 #Attr.12; + let Inspect.194 : I64 = StructAtIndex 0 #Attr.12; + let Inspect.344 : I64 = CallByName Inspect.54 Inspect.194; + let Inspect.343 : Str = CallByName Inspect.31 Inspect.344 Inspect.197; + ret Inspect.343; + +procedure Inspect.198 (Inspect.199): + let Bool.2 : Int1 = CallByName Bool.2; + let Inspect.339 : {Str, Int1} = Struct {Inspect.199, Bool.2}; + ret Inspect.339; + +procedure Inspect.200 (Inspect.326): + let Inspect.327 : Str = StructAtIndex 0 Inspect.326; + ret Inspect.327; + +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.368 : Str = "\""; + let Inspect.367 : Str = CallByName Inspect.61 Inspect.250 Inspect.368; + let Inspect.365 : Str = CallByName Inspect.61 Inspect.367 Inspect.248; + let Inspect.366 : Str = "\""; + let Inspect.364 : Str = CallByName Inspect.61 Inspect.365 Inspect.366; + ret Inspect.364; + +procedure Inspect.277 (Inspect.278, Inspect.276): + let Inspect.359 : Str = CallByName Num.96 Inspect.276; + let Inspect.358 : Str = CallByName Inspect.61 Inspect.278 Inspect.359; + ret Inspect.358; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.314 : Str = CallByName Inspect.186 Inspect.149 Inspect.305; + ret Inspect.314; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.345 : Str = CallByName Inspect.277 Inspect.149 Inspect.305; + ret Inspect.345; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.349 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.349; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.39 (Inspect.182, Inspect.183, Inspect.184, Inspect.185): + let Inspect.316 : {{List {Str, I64}, List U64, List I8, U64}, {}, {}, {}} = Struct {Inspect.182, Inspect.183, Inspect.184, Inspect.185}; + let Inspect.315 : {{List {Str, I64}, List U64, List I8, U64}, {}, {}, {}} = CallByName Inspect.30 Inspect.316; + ret Inspect.315; + +procedure Inspect.44 (Inspect.248): + let Inspect.360 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.360; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.31 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName Dict.94 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.54 (Inspect.276): + let Inspect.354 : I64 = CallByName Inspect.30 Inspect.276; + ret Inspect.354; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.323 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.323; + +procedure List.11 (List.133, List.134): + let List.635 : List I8 = CallByName List.68 List.134; + let List.634 : List I8 = CallByName List.86 List.133 List.134 List.635; + ret List.634; + +procedure List.11 (List.133, List.134): + let List.637 : List U64 = CallByName List.68 List.134; + let List.636 : List U64 = CallByName List.86 List.133 List.134 List.637; + ret List.636; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : {List {Str, I64}, List U64, List I8, U64} = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.18 (List.154, List.155, List.156): + let List.641 : U64 = 0i64; + let List.642 : U64 = CallByName List.6 List.154; + let List.640 : {Str, Int1} = CallByName List.88 List.154 List.155 List.156 List.641 List.642; + ret List.640; + +procedure List.2 (List.103, List.104): + let List.609 : U64 = CallByName List.6 List.103; + let List.605 : Int1 = CallByName Num.22 List.104 List.609; + if List.605 then + let List.607 : I8 = CallByName List.66 List.103 List.104; + dec List.103; + let List.606 : [C {}, C I8] = TagId(1) List.607; + ret List.606; + else + dec List.103; + let List.604 : {} = Struct {}; + let List.603 : [C {}, C I8] = TagId(0) List.604; + ret List.603; + +procedure List.3 (List.111, List.112, List.113): + let List.566 : {List {Str, I64}, {Str, I64}} = CallByName List.64 List.111 List.112 List.113; + let List.565 : List {Str, I64} = StructAtIndex 0 List.566; + let #Derived_gen.62 : {Str, I64} = StructAtIndex 1 List.566; + dec #Derived_gen.62; + ret List.565; + +procedure List.3 (List.111, List.112, List.113): + let List.589 : {List I8, I8} = CallByName List.64 List.111 List.112 List.113; + let List.588 : List I8 = StructAtIndex 0 List.589; + ret List.588; + +procedure List.3 (List.111, List.112, List.113): + let List.591 : {List U64, U64} = CallByName List.64 List.111 List.112 List.113; + let List.590 : List U64 = StructAtIndex 0 List.591; + ret List.590; + +procedure List.4 (List.119, List.120): + let List.595 : U64 = 1i64; + let List.593 : List {Str, I64} = CallByName List.70 List.119 List.595; + let List.592 : List {Str, I64} = CallByName List.71 List.593 List.120; + ret List.592; + +procedure List.6 (#Attr.2): + let List.601 : U64 = lowlevel ListLen #Attr.2; + ret List.601; + +procedure List.6 (#Attr.2): + let List.602 : U64 = lowlevel ListLen #Attr.2; + ret List.602; + +procedure List.6 (#Attr.2): + let List.639 : U64 = lowlevel ListLen #Attr.2; + ret List.639; + +procedure List.6 (#Attr.2): + let List.651 : U64 = lowlevel ListLen #Attr.2; + ret List.651; + +procedure List.64 (List.108, List.109, List.110): + let List.571 : U64 = CallByName List.6 List.108; + let List.568 : Int1 = CallByName Num.22 List.109 List.571; + if List.568 then + let List.569 : {List {Str, I64}, {Str, I64}} = CallByName List.67 List.108 List.109 List.110; + ret List.569; + else + let List.567 : {List {Str, I64}, {Str, I64}} = Struct {List.108, List.110}; + ret List.567; + +procedure List.64 (List.108, List.109, List.110): + let List.578 : U64 = CallByName List.6 List.108; + let List.575 : Int1 = CallByName Num.22 List.109 List.578; + if List.575 then + let List.576 : {List I8, I8} = CallByName List.67 List.108 List.109 List.110; + ret List.576; + else + let List.574 : {List I8, I8} = Struct {List.108, List.110}; + ret List.574; + +procedure List.64 (List.108, List.109, List.110): + let List.586 : U64 = CallByName List.6 List.108; + let List.583 : Int1 = CallByName Num.22 List.109 List.586; + if List.583 then + let List.584 : {List U64, U64} = CallByName List.67 List.108 List.109 List.110; + ret List.584; + else + let List.582 : {List U64, U64} = Struct {List.108, List.110}; + ret List.582; + +procedure List.66 (#Attr.2, #Attr.3): + let List.608 : I8 = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.608; + +procedure List.66 (#Attr.2, #Attr.3): + let List.650 : {Str, I64} = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.650; + +procedure List.67 (#Attr.2, #Attr.3, #Attr.4): + let List.570 : {List {Str, I64}, {Str, I64}} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4; + ret List.570; + +procedure List.67 (#Attr.2, #Attr.3, #Attr.4): + let List.577 : {List I8, I8} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4; + ret List.577; + +procedure List.67 (#Attr.2, #Attr.3, #Attr.4): + let List.585 : {List U64, U64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4; + ret List.585; + +procedure List.68 (#Attr.2): + let List.621 : List I8 = lowlevel ListWithCapacity #Attr.2; + ret List.621; + +procedure List.68 (#Attr.2): + let List.633 : List U64 = lowlevel ListWithCapacity #Attr.2; + ret List.633; + +procedure List.70 (#Attr.2, #Attr.3): + let List.596 : List {Str, I64} = lowlevel ListReserve #Attr.2 #Attr.3; + ret List.596; + +procedure List.71 (#Attr.2, #Attr.3): + let List.594 : List {Str, I64} = lowlevel ListAppendUnsafe #Attr.2 #Attr.3; + ret List.594; + +procedure List.71 (#Attr.2, #Attr.3): + let List.618 : List I8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3; + ret List.618; + +procedure List.71 (#Attr.2, #Attr.3): + let List.630 : List U64 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3; + ret List.630; + +procedure List.86 (#Derived_gen.57, #Derived_gen.58, #Derived_gen.59): + joinpoint List.624 List.135 List.136 List.137: + let List.632 : U64 = 0i64; + let List.626 : Int1 = CallByName Num.24 List.136 List.632; + if List.626 then + let List.631 : U64 = 1i64; + let List.628 : U64 = CallByName Num.75 List.136 List.631; + let List.629 : List U64 = CallByName List.71 List.137 List.135; + jump List.624 List.135 List.628 List.629; + else + ret List.137; + in + jump List.624 #Derived_gen.57 #Derived_gen.58 #Derived_gen.59; + +procedure List.86 (#Derived_gen.7, #Derived_gen.8, #Derived_gen.9): + joinpoint List.612 List.135 List.136 List.137: + let List.620 : U64 = 0i64; + let List.614 : Int1 = CallByName Num.24 List.136 List.620; + if List.614 then + let List.619 : U64 = 1i64; + let List.616 : U64 = CallByName Num.75 List.136 List.619; + let List.617 : List I8 = CallByName List.71 List.137 List.135; + jump List.612 List.135 List.616 List.617; + else + ret List.137; + in + jump List.612 #Derived_gen.7 #Derived_gen.8 #Derived_gen.9; + +procedure List.88 (#Derived_gen.21, #Derived_gen.22, #Derived_gen.23, #Derived_gen.24, #Derived_gen.25): + joinpoint List.643 List.157 List.158 List.159 List.160 List.161: + let List.645 : Int1 = CallByName Num.22 List.160 List.161; + if List.645 then + let List.649 : {Str, I64} = CallByName List.66 List.157 List.160; + inc List.649; + let List.162 : {Str, Int1} = CallByName Dict.129 List.158 List.649 List.159; + let List.648 : U64 = 1i64; + let List.647 : U64 = CallByName Num.51 List.160 List.648; + jump List.643 List.157 List.162 List.159 List.647 List.161; + else + dec List.157; + ret List.158; + in + jump List.643 #Derived_gen.21 #Derived_gen.22 #Derived_gen.23 #Derived_gen.24 #Derived_gen.25; + +procedure List.88 (#Derived_gen.37, #Derived_gen.38, #Derived_gen.39, #Derived_gen.40, #Derived_gen.41): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : {Str, I64} = CallByName List.66 List.157 List.160; + inc List.562; + let List.162 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.101 List.158 List.562; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.37 #Derived_gen.38 #Derived_gen.39 #Derived_gen.40 #Derived_gen.41; + +procedure Num.117 (#Attr.2): + let Num.311 : I8 = lowlevel NumIntCast #Attr.2; + ret Num.311; + +procedure Num.133 (#Attr.2): + let Num.353 : U64 = lowlevel NumIntCast #Attr.2; + ret Num.353; + +procedure Num.133 (#Attr.2): + let Num.369 : U64 = lowlevel NumIntCast #Attr.2; + ret Num.369; + +procedure Num.133 (#Attr.2): + let Num.370 : U64 = lowlevel NumIntCast #Attr.2; + ret Num.370; + +procedure Num.135 (#Attr.2): + let Num.377 : U128 = lowlevel NumIntCast #Attr.2; + ret Num.377; + +procedure Num.137 (#Attr.2): + let Num.305 : U64 = lowlevel NumIntCast #Attr.2; + ret Num.305; + +procedure Num.21 (#Attr.2, #Attr.3): + let Num.318 : U64 = lowlevel NumMul #Attr.2 #Attr.3; + ret Num.318; + +procedure Num.21 (#Attr.2, #Attr.3): + let Num.375 : U128 = lowlevel NumMul #Attr.2 #Attr.3; + ret Num.375; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.303 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.303; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.462 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.462; + +procedure Num.23 (#Attr.2, #Attr.3): + let Num.453 : Int1 = lowlevel NumLte #Attr.2 #Attr.3; + ret Num.453; + +procedure Num.24 (#Attr.2, #Attr.3): + let Num.457 : Int1 = lowlevel NumGt #Attr.2 #Attr.3; + ret Num.457; + +procedure Num.25 (#Attr.2, #Attr.3): + let Num.321 : Int1 = lowlevel NumGte #Attr.2 #Attr.3; + ret Num.321; + +procedure Num.25 (#Attr.2, #Attr.3): + let Num.459 : Int1 = lowlevel NumGte #Attr.2 #Attr.3; + ret Num.459; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.461 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.461; + +procedure Num.69 (#Attr.2, #Attr.3): + let Num.302 : U64 = lowlevel NumBitwiseAnd #Attr.2 #Attr.3; + ret Num.302; + +procedure Num.70 (#Attr.2, #Attr.3): + let Num.351 : U64 = lowlevel NumBitwiseXor #Attr.2 #Attr.3; + ret Num.351; + +procedure Num.71 (#Attr.2, #Attr.3): + let Num.393 : U64 = lowlevel NumBitwiseOr #Attr.2 #Attr.3; + ret Num.393; + +procedure Num.72 (#Attr.2, #Attr.3): + let Num.411 : U64 = lowlevel NumShiftLeftBy #Attr.2 #Attr.3; + ret Num.411; + +procedure Num.74 (#Attr.2, #Attr.3): + let Num.371 : U128 = lowlevel NumShiftRightZfBy #Attr.2 #Attr.3; + ret Num.371; + +procedure Num.74 (#Attr.2, #Attr.3): + let Num.374 : U64 = lowlevel NumShiftRightZfBy #Attr.2 #Attr.3; + ret Num.374; + +procedure Num.75 (#Attr.2, #Attr.3): + let Num.448 : U64 = lowlevel NumSubWrap #Attr.2 #Attr.3; + ret Num.448; + +procedure Num.77 (#Attr.2, #Attr.3): + let Num.306 : U64 = lowlevel NumSubSaturated #Attr.2 #Attr.3; + ret Num.306; + +procedure Num.96 (#Attr.2): + let Num.460 : Str = lowlevel NumToStr #Attr.2; + ret Num.460; + +procedure Str.12 (#Attr.2): + let Str.293 : List U8 = lowlevel StrToUtf8 #Attr.2; + ret Str.293; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.294 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.294; + +procedure Test.0 (): + let Test.9 : Str = "a"; + let Test.10 : I64 = 1i64; + let Test.5 : {Str, I64} = Struct {Test.9, Test.10}; + let Test.7 : Str = "b"; + let Test.8 : I64 = 2i64; + let Test.6 : {Str, I64} = Struct {Test.7, Test.8}; + let Test.4 : List {Str, I64} = Array [Test.5, Test.6]; + let Test.3 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.12 Test.4; + let Test.2 : Str = CallByName Inspect.5 Test.3; + let Test.1 : Str = CallByName Inspect.35 Test.2; + ret Test.1; diff --git a/crates/compiler/test_mono/src/tests.rs b/crates/compiler/test_mono/src/tests.rs index 9d5874be60..091e20565e 100644 --- a/crates/compiler/test_mono/src/tests.rs +++ b/crates/compiler/test_mono/src/tests.rs @@ -3420,3 +3420,19 @@ fn inspect_derived_list() { "# ) } + +#[mono_test(large_stack = "true")] +fn inspect_derived_dict() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = + Dict.fromList [("a", 1), ("b", 2)] + |> Inspect.inspect + |> Inspect.toDbgStr + "# + ) +} From aeabf96e8008434fad5e7067d15f088bad3d57ea Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 12:50:45 -0800 Subject: [PATCH 067/105] update inspect examples --- examples/Community.roc | 72 +--------- examples/GuiFormatter.roc | 18 ++- examples/LogFormatter.roc | 246 ----------------------------------- examples/inspect-logging.roc | 3 +- 4 files changed, 18 insertions(+), 321 deletions(-) delete mode 100644 examples/LogFormatter.roc diff --git a/examples/Community.roc b/examples/Community.roc index 7be09c317a..69543e959f 100644 --- a/examples/Community.roc +++ b/examples/Community.roc @@ -14,12 +14,7 @@ interface Community Community := { people : List Person, friends : List (Set Nat), -} - implements [ - Inspect { - toInspector: inspectCommunity, - }, - ] +} implements [Inspect] Person := { firstName : Str, @@ -27,12 +22,7 @@ Person := { age : U8, hasBeard : Bool, favoriteColor : Color, -} - implements [ - Inspect { - toInspector: inspectPerson, - }, - ] +} implements [Inspect] Color : [ Red, @@ -90,61 +80,3 @@ walkFriendNames = \@Community { people, friends }, s0, nextFn -> (nextFn s1 personName friendNames, id + 1) out -# The functions below will be auto-generated in the future -inspectCommunity : Community -> Inspector f where f implements InspectFormatter -inspectCommunity = \@Community { people, friends } -> - f0 <- Inspect.custom - [ - { key: "people", value: Inspect.list people List.walk Inspect.toInspector }, - { - key: "friends", - value: Inspect.list - friends - List.walk - (\s -> Inspect.set - s - Set.walk - (\num -> num |> Num.toU64 |> Inspect.u64) - ), - # value: Inspect.dict - # (@Community { people, friends }) - # walkFriendNames - # Inspect.str - # (\s -> Inspect.set s Set.walk Inspect.str), - }, - ] - |> Inspect.record - |> Inspect.apply f0 - -inspectPerson : Person -> Inspector f where f implements InspectFormatter -inspectPerson = \@Person { firstName, lastName, age, hasBeard, favoriteColor } -> - # In practice, this would never be done manually due to autoderive. - # Instead you would just write: - # Inspect.inspect innerRecord - # This is what the auto-derive would generate. - - f0 <- Inspect.custom - - favoriteColorTag = - when favoriteColor is - Red -> - Inspect.tag "Red" [] - - Green -> - Inspect.tag "Green" [] - - Blue -> - Inspect.tag "Blue" [] - - RGB (r, g, b) -> - Inspect.tag "RGB" [Inspect.tuple [Inspect.u8 r, Inspect.u8 g, Inspect.u8 b]] - - [ - { key: "firstName", value: Inspect.str firstName }, - { key: "lastName", value: Inspect.str lastName }, - { key: "age", value: Inspect.u8 age }, - { key: "hasBeard", value: Inspect.bool hasBeard }, - { key: "favoriteColor", value: favoriteColorTag }, - ] - |> Inspect.record - |> Inspect.apply f0 diff --git a/examples/GuiFormatter.roc b/examples/GuiFormatter.roc index 615edb15c8..1a060911a1 100644 --- a/examples/GuiFormatter.roc +++ b/examples/GuiFormatter.roc @@ -25,6 +25,7 @@ GuiFormatter := { nodes : List Elem } record: record, bool: bool, str: str, + function: function, opaque: opaque, u8: u8, i8: i8, @@ -36,6 +37,7 @@ GuiFormatter := { nodes : List Elem } i64: i64, u128: u128, i128: i128, + nat: nat, f32: f32, f64: f64, dec: dec, @@ -149,10 +151,15 @@ str = \s -> f0 <- Inspect.custom addNode f0 (Text "\"\(s)\"") -opaque : Str -> Inspector GuiFormatter -opaque = \s -> +opaque : * -> Inspector GuiFormatter +opaque = \_ -> f0 <- Inspect.custom - addNode f0 (Text "<\(s)>") + addNode f0 (Text "") + +function : * -> Inspector GuiFormatter +function = \_ -> + f0 <- Inspect.custom + addNode f0 (Text "") u8 : U8 -> Inspector GuiFormatter u8 = \num -> @@ -204,6 +211,11 @@ i128 = \num -> f0 <- Inspect.custom addNode f0 (num |> Num.toStr |> Text) +nat : Nat -> Inspector GuiFormatter +nat = \num -> + f0 <- Inspect.custom + addNode f0 (num |> Num.toStr |> Text) + f32 : F32 -> Inspector GuiFormatter f32 = \num -> f0 <- Inspect.custom diff --git a/examples/LogFormatter.roc b/examples/LogFormatter.roc deleted file mode 100644 index a9a015e58c..0000000000 --- a/examples/LogFormatter.roc +++ /dev/null @@ -1,246 +0,0 @@ -interface LogFormatter - exposes [ - LogFormatter, - toStr, - ] - imports [] - -## Creates String representations of Roc values, for use in inspect-logging.roc - -LogFormatter := { data : Str } - implements [ - InspectFormatter { - init: init, - list: list, - set: set, - dict: dict, - tag: tag, - tuple: tuple, - record: record, - bool: bool, - str: str, - opaque: opaque, - u8: u8, - i8: i8, - u16: u16, - i16: i16, - u32: u32, - i32: i32, - u64: u64, - i64: i64, - u128: u128, - i128: i128, - f32: f32, - f64: f64, - dec: dec, - - }, - ] - -init : {} -> LogFormatter -init = \{} -> @LogFormatter { data: "" } - -list : list, ElemWalker (LogFormatter, Bool) list elem, (elem -> Inspector LogFormatter) -> Inspector LogFormatter -list = \content, walkFn, toInspector -> - f0 <- Inspect.custom - write f0 "[" - |> \f1 -> - (f2, prependSep), elem <- walkFn content (f1, Bool.false) - f3 = - if prependSep then - write f2 ", " - else - f2 - - elem - |> toInspector - |> Inspect.apply f3 - |> \f4 -> (f4, Bool.true) - |> .0 - |> write "]" - -set : set, ElemWalker (LogFormatter, Bool) set elem, (elem -> Inspector LogFormatter) -> Inspector LogFormatter -set = \content, walkFn, toInspector -> - f0 <- Inspect.custom - write f0 "{" - |> \f1 -> - (f2, prependSep), elem <- walkFn content (f1, Bool.false) - f3 = - if prependSep then - write f2 ", " - else - f2 - - elem - |> toInspector - |> Inspect.apply f3 - |> \f4 -> (f4, Bool.true) - |> .0 - |> write "}" - -dict : dict, KeyValWalker (LogFormatter, Bool) dict key value, (key -> Inspector LogFormatter), (value -> Inspector LogFormatter) -> Inspector LogFormatter -dict = \d, walkFn, keyToInspector, valueToInspector -> - f0 <- Inspect.custom - write f0 "{" - |> \f1 -> - (f2, prependSep), key, value <- walkFn d (f1, Bool.false) - f3 = - if prependSep then - write f2 ", " - else - f2 - - Inspect.apply (keyToInspector key) f3 - |> write ": " - |> \x -> Inspect.apply (valueToInspector value) x - |> \f4 -> (f4, Bool.true) - |> .0 - |> write "}" - -tag : Str, List (Inspector LogFormatter) -> Inspector LogFormatter -tag = \name, fields -> - if List.isEmpty fields then - f0 <- Inspect.custom - write f0 name - else - f0 <- Inspect.custom - write f0 "(" - |> write name - |> \f1 -> - f2, inspector <- List.walk fields f1 - write f2 " " - |> \x -> Inspect.apply inspector x - |> write ")" - -tuple : List (Inspector LogFormatter) -> Inspector LogFormatter -tuple = \fields -> - f0 <- Inspect.custom - write f0 "(" - |> \f1 -> - (f2, prependSep), inspector <- List.walk fields (f1, Bool.false) - f3 = - if prependSep then - write f2 ", " - else - f2 - - Inspect.apply inspector f3 - |> \f4 -> (f4, Bool.true) - |> .0 - |> write ")" - -record : List { key : Str, value : Inspector LogFormatter } -> Inspector LogFormatter -record = \fields -> - f0 <- Inspect.custom - write f0 "{" - |> \f1 -> - (f2, prependSep), { key, value } <- List.walk fields (f1, Bool.false) - f3 = - if prependSep then - write f2 ", " - else - f2 - - write f3 key - |> write ": " - |> \x -> Inspect.apply value x - |> \f4 -> (f4, Bool.true) - |> .0 - |> write "}" - -bool : Bool -> Inspector LogFormatter -bool = \b -> - if b then - f0 <- Inspect.custom - write f0 "true" - else - f0 <- Inspect.custom - write f0 "false" - -str : Str -> Inspector LogFormatter -str = \s -> - f0 <- Inspect.custom - f0 - |> write "\"" - |> write s - |> write "\"" - -opaque : Str -> Inspector LogFormatter -opaque = \s -> - f0 <- Inspect.custom - f0 - |> write "<" - |> write s - |> write ">" - -u8 : U8 -> Inspector LogFormatter -u8 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -i8 : I8 -> Inspector LogFormatter -i8 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -u16 : U16 -> Inspector LogFormatter -u16 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -i16 : I16 -> Inspector LogFormatter -i16 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -u32 : U32 -> Inspector LogFormatter -u32 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -i32 : I32 -> Inspector LogFormatter -i32 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -u64 : U64 -> Inspector LogFormatter -u64 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -i64 : I64 -> Inspector LogFormatter -i64 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -u128 : U128 -> Inspector LogFormatter -u128 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -i128 : I128 -> Inspector LogFormatter -i128 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -f32 : F32 -> Inspector LogFormatter -f32 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -f64 : F64 -> Inspector LogFormatter -f64 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -dec : Dec -> Inspector LogFormatter -dec = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -write : LogFormatter, Str -> LogFormatter -write = \@LogFormatter { data }, added -> - @LogFormatter { data: Str.concat data added } - -toStr : LogFormatter -> Str -toStr = \@LogFormatter { data } -> data diff --git a/examples/inspect-logging.roc b/examples/inspect-logging.roc index 147ad05e26..1054c68171 100644 --- a/examples/inspect-logging.roc +++ b/examples/inspect-logging.roc @@ -5,7 +5,6 @@ app "inspect-logging" packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } imports [ pf.Stdout, - LogFormatter, Community, ] provides [main] to pf @@ -36,5 +35,5 @@ main = |> Community.addFriend 0 2 |> Community.addFriend 1 2 |> Inspect.inspect - |> LogFormatter.toStr + |> Inspect.toDbgStr |> Stdout.line From 83bf3cbd3ac35601a3f1fd728e4919ae8c214aff Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 12:56:01 -0800 Subject: [PATCH 068/105] update tests --- crates/compiler/test_mono/generated/dict.txt | 40 +++++++++---------- ...ralization_among_large_recursive_group.txt | 14 +++---- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/crates/compiler/test_mono/generated/dict.txt b/crates/compiler/test_mono/generated/dict.txt index f654e628b5..6c0f78543c 100644 --- a/crates/compiler/test_mono/generated/dict.txt +++ b/crates/compiler/test_mono/generated/dict.txt @@ -1,28 +1,28 @@ -procedure Dict.1 (Dict.554): - let Dict.563 : List {[], []} = Array []; +procedure Dict.1 (Dict.557): + let Dict.567 : List {[], []} = Array []; + let Dict.574 : U64 = 0i64; + let Dict.575 : U64 = 8i64; + let Dict.568 : List U64 = CallByName List.11 Dict.574 Dict.575; + let Dict.571 : I8 = CallByName Dict.40; + let Dict.572 : U64 = 8i64; + let Dict.569 : List I8 = CallByName List.11 Dict.571 Dict.572; let Dict.570 : U64 = 0i64; - let Dict.571 : U64 = 8i64; - let Dict.564 : List U64 = CallByName List.11 Dict.570 Dict.571; - let Dict.567 : I8 = CallByName Dict.39; - let Dict.568 : U64 = 8i64; - let Dict.565 : List I8 = CallByName List.11 Dict.567 Dict.568; - let Dict.566 : U64 = 0i64; - let Dict.562 : {List {[], []}, List U64, List I8, U64} = Struct {Dict.563, Dict.564, Dict.565, Dict.566}; - ret Dict.562; + let Dict.566 : {List {[], []}, List U64, List I8, U64} = Struct {Dict.567, Dict.568, Dict.569, Dict.570}; + ret Dict.566; -procedure Dict.39 (): - let Dict.569 : I8 = -128i64; - ret Dict.569; - -procedure Dict.4 (Dict.560): - let Dict.101 : U64 = StructAtIndex 3 Dict.560; - let #Derived_gen.8 : List {[], []} = StructAtIndex 0 Dict.560; +procedure Dict.4 (Dict.564): + let Dict.105 : U64 = StructAtIndex 3 Dict.564; + let #Derived_gen.8 : List {[], []} = StructAtIndex 0 Dict.564; dec #Derived_gen.8; - let #Derived_gen.7 : List U64 = StructAtIndex 1 Dict.560; + let #Derived_gen.7 : List U64 = StructAtIndex 1 Dict.564; dec #Derived_gen.7; - let #Derived_gen.6 : List I8 = StructAtIndex 2 Dict.560; + let #Derived_gen.6 : List I8 = StructAtIndex 2 Dict.564; dec #Derived_gen.6; - ret Dict.101; + ret Dict.105; + +procedure Dict.40 (): + let Dict.573 : I8 = -128i64; + ret Dict.573; procedure List.11 (List.133, List.134): let List.554 : List I8 = CallByName List.68 List.134; diff --git a/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt b/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt index 5b89442a58..f1f87be404 100644 --- a/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt +++ b/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt @@ -3,22 +3,22 @@ app "test" provides [main] to "./platform" f = \{} -> -#^{-1} <2722><117>{} -<120>[[f(1)]]-> <116>[Ok <2730>{}]<80>* +#^{-1} <2858><117>{} -<120>[[f(1)]]-> <116>[Ok <2866>{}]<80>* when g {} is -# ^ <2712><2730>{} -<2720>[[g(2)]]-> <72>[Ok <2730>{}]<102>* +# ^ <2848><2866>{} -<2856>[[g(2)]]-> <72>[Ok <2866>{}]<102>* _ -> Ok {} g = \{} -> -#^{-1} <2712><2730>{} -<2720>[[g(2)]]-> <72>[Ok <2730>{}]<102>* +#^{-1} <2848><2866>{} -<2856>[[g(2)]]-> <72>[Ok <2866>{}]<102>* when h {} is -# ^ <2717><2730>{} -<2725>[[h(3)]]-> <94>[Ok <2730>{}]<124>* +# ^ <2853><2866>{} -<2861>[[h(3)]]-> <94>[Ok <2866>{}]<124>* _ -> Ok {} h = \{} -> -#^{-1} <2717><2730>{} -<2725>[[h(3)]]-> <94>[Ok <2730>{}]<124>* +#^{-1} <2853><2866>{} -<2861>[[h(3)]]-> <94>[Ok <2866>{}]<124>* when f {} is -# ^ <2722><117>{} -<120>[[f(1)]]-> <116>[Ok <2730>{}]<80>* +# ^ <2858><117>{} -<120>[[f(1)]]-> <116>[Ok <2866>{}]<80>* _ -> Ok {} main = f {} -# ^ <2732><133>{} -<136>[[f(1)]]-> <138>[Ok <2730>{}]<2731>w_a +# ^ <2868><133>{} -<136>[[f(1)]]-> <138>[Ok <2866>{}]<2867>w_a From 759fa9b7a61ee8ade0cc5f7227affc11b2e4876a Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 13:06:44 -0800 Subject: [PATCH 069/105] roc format --- crates/compiler/builtins/roc/Dict.roc | 1 - crates/compiler/builtins/roc/Inspect.roc | 1 - examples/Community.roc | 6 ++++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/compiler/builtins/roc/Dict.roc b/crates/compiler/builtins/roc/Dict.roc index 11200a420f..172c0e501e 100644 --- a/crates/compiler/builtins/roc/Dict.roc +++ b/crates/compiler/builtins/roc/Dict.roc @@ -130,7 +130,6 @@ isEq = \xs, ys -> 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 - toInspectorDict : Dict k v -> Inspector f where k implements Inspect & Hash & Eq, v implements Inspect, f implements InspectFormatter toInspectorDict = \dict -> fmt <- Inspect.custom diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 82a31f4a9d..981e528719 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -99,7 +99,6 @@ inspect = \val -> (@Inspector valFn) = toInspector val valFn (init {}) - # The current default formatter for inspect. # This just returns a simple string for debugging. # More powerful formatters will likely be wanted in the future. diff --git a/examples/Community.roc b/examples/Community.roc index 69543e959f..8a79d3dd44 100644 --- a/examples/Community.roc +++ b/examples/Community.roc @@ -14,7 +14,8 @@ interface Community Community := { people : List Person, friends : List (Set Nat), -} implements [Inspect] +} + implements [Inspect] Person := { firstName : Str, @@ -22,7 +23,8 @@ Person := { age : U8, hasBeard : Bool, favoriteColor : Color, -} implements [Inspect] +} + implements [Inspect] Color : [ Red, From 77e55c88bf5f3648af913b533a9b07a8657d848a Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 13:23:05 -0800 Subject: [PATCH 070/105] update cli logging test --- crates/cli/tests/cli_run.rs | 2 +- crates/compiler/builtins/roc/Inspect.roc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index 05cdda1c06..9b3dcd6241 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -942,7 +942,7 @@ mod cli_run { test_roc_app_slim( "examples", "inspect-logging.roc", - r#"{people: [{firstName: "John", lastName: "Smith", age: 27, hasBeard: true, favoriteColor: Blue}, {firstName: "Debby", lastName: "Johnson", age: 47, hasBeard: false, favoriteColor: Green}, {firstName: "Jane", lastName: "Doe", age: 33, hasBeard: false, favoriteColor: (RGB (255, 255, 0))}], friends: [{2}, {2}, {0, 1}]} + r#"{friends: [{2}, {2}, {0, 1}], people: [{age: 27, favoriteColor: Blue, firstName: "John", hasBeard: Bool.true, lastName: "Smith"}, {age: 47, favoriteColor: Green, firstName: "Debby", hasBeard: Bool.false, lastName: "Johnson"}, {age: 33, favoriteColor: (RGB (255, 255, 0)), firstName: "Jane", hasBeard: Bool.false, lastName: "Doe"}]} "#, UseValgrind::Yes, ) diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 981e528719..ff44d644d7 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -258,6 +258,7 @@ dbgStr = \s -> f0 <- custom f0 |> dbgWrite "\"" + # TODO: Should we be escaping strings for dbg/logging? |> dbgWrite s |> dbgWrite "\"" From 0586f2bac027387fb6217ca81f233036ee2cb5ed Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 13:31:26 -0800 Subject: [PATCH 071/105] more formatting --- crates/compiler/builtins/roc/Inspect.roc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index ff44d644d7..a86b83a247 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -258,8 +258,7 @@ dbgStr = \s -> f0 <- custom f0 |> dbgWrite "\"" - # TODO: Should we be escaping strings for dbg/logging? - |> dbgWrite s + |> dbgWrite s # TODO: Should we be escaping strings for dbg/logging? |> dbgWrite "\"" dbgOpaque : * -> Inspector DbgFormatter From 4b911524acc2302fb25f1515b2fae4a305c47955 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 13:59:23 -0800 Subject: [PATCH 072/105] update gen_abilities tests to include edge case --- crates/compiler/test_gen/src/gen_abilities.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/compiler/test_gen/src/gen_abilities.rs b/crates/compiler/test_gen/src/gen_abilities.rs index 50fbbeb243..31fa164355 100644 --- a/crates/compiler/test_gen/src/gen_abilities.rs +++ b/crates/compiler/test_gen/src/gen_abilities.rs @@ -2222,6 +2222,7 @@ mod inspect { app "test" provides [main] to "./platform" main = [ + Inspect.inspect 0, # Num a Inspect.inspect 1u8, # U8 Inspect.inspect 2i8, # I8 Inspect.inspect 3u16, # U16 @@ -2232,13 +2233,14 @@ mod inspect { Inspect.inspect 8i64, # I64 Inspect.inspect 9u128, # U128 Inspect.inspect 10i128, # I128 - Inspect.inspect 1.1f32, # F32 + Inspect.inspect 0.5, # Frac a + Inspect.inspect 1.5f32, # F32 Inspect.inspect 2.2f64, # F64 Inspect.inspect (1.1dec + 2.2), # Dec ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# ), - RocStr::from("42, 5, 0.3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1.1, 2.2, 3.3"), + RocStr::from("0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0.5, 1.5, 2.2, 3.3"), RocStr ); } @@ -2255,9 +2257,10 @@ mod inspect { Inspect.inspect [], # List * Inspect.inspect [0, 1, 2], # List (Num *) Inspect.inspect [1, 0x2, 3], # List (Int *) - Inspect.inspect [0.1 + 0.2, 0.4], # List (Frac *) + # TODO: Re-enable when Frac is fixed for inspect. + # Inspect.inspect [0.1 + 0.2, 0.4], # List (Frac *) Inspect.inspect [1u8, 2u8], # List U8 - Inspect.inspect ["foo"], # List Str + Inspect.inspect ["foo"], # List Str ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# ), From 01032c3b119c49c57de7fff3dc481b7cb28b5d17 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 15:04:38 -0800 Subject: [PATCH 073/105] remove empty list test case for inspect --- crates/compiler/test_gen/src/gen_abilities.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/compiler/test_gen/src/gen_abilities.rs b/crates/compiler/test_gen/src/gen_abilities.rs index 31fa164355..2bc4791b75 100644 --- a/crates/compiler/test_gen/src/gen_abilities.rs +++ b/crates/compiler/test_gen/src/gen_abilities.rs @@ -2254,17 +2254,15 @@ mod inspect { app "test" provides [main] to "./platform" main = [ - Inspect.inspect [], # List * Inspect.inspect [0, 1, 2], # List (Num *) Inspect.inspect [1, 0x2, 3], # List (Int *) - # TODO: Re-enable when Frac is fixed for inspect. - # Inspect.inspect [0.1 + 0.2, 0.4], # List (Frac *) + Inspect.inspect [0.1 + 0.2, 0.4], # List (Frac *) Inspect.inspect [1u8, 2u8], # List U8 Inspect.inspect ["foo"], # List Str ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# ), - RocStr::from("[], [0, 1, 2], [1, 2, 3], [0.3, 0.4], [1, 2], [\"foo\"]"), + RocStr::from("[0, 1, 2], [1, 2, 3], [0.3, 0.4], [1, 2], [\"foo\"]"), RocStr ); } From 1b7fdc9522831cd3e21bc41f62e8fab131c241fd Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 15:22:30 -0800 Subject: [PATCH 074/105] deal with Frac * -> Dec --- crates/compiler/derive_key/src/inspect.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs index 1fa026863d..8319cbc7b1 100644 --- a/crates/compiler/derive_key/src/inspect.rs +++ b/crates/compiler/derive_key/src/inspect.rs @@ -141,8 +141,11 @@ impl FlatInspectable { AliasKind::Structural => { Self::from_var(subs, real_var) } + // Special case, an unbound `Frac *` will become a `Dec`. + AliasKind::Opaque if matches!(*subs.get_content_without_compacting(real_var), Content::FlexVar(_) | Content::FlexAbleVar(_, _)) => { + Immediate(Symbol::INSPECT_DEC) + } AliasKind::Opaque if sym.is_builtin() => { - // TODO: Is this correct for all builtins? It is at least required for the Num wrapper types. Self::from_var(subs, real_var) } AliasKind::Opaque => { From c49046291a713733b5acd26414d89f25264ca398 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 16:29:15 -0800 Subject: [PATCH 075/105] misc cleanup suggestions --- crates/compiler/derive/src/inspect.rs | 7 --- crates/compiler/derive_key/src/inspect.rs | 1 - crates/compiler/solve/src/ability.rs | 20 ++----- crates/compiler/solve/src/specialize.rs | 73 +++++++++++++---------- crates/compiler/types/src/subs.rs | 4 +- 5 files changed, 47 insertions(+), 58 deletions(-) diff --git a/crates/compiler/derive/src/inspect.rs b/crates/compiler/derive/src/inspect.rs index 05e7558bea..75536efea7 100644 --- a/crates/compiler/derive/src/inspect.rs +++ b/crates/compiler/derive/src/inspect.rs @@ -111,8 +111,6 @@ pub(crate) fn derive_to_inspector( fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { // Build \lst -> list, List.walk, (\elem -> Inspect.toInspector elem) - // - // TODO eta reduce this baby ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use Expr::*; @@ -954,11 +952,6 @@ fn to_inspector_tag_union( } /// Lift `inspector` to `Inspect.custom \fmt -> Inspect.apply inspector fmt` -/// -/// TODO: currently it appears that just `inspector` is not isomorphic to the lift, on the -/// monomorphization level, even though we would think it is. In particular, unspecialized lambda -/// sets fail to resolve when we use the non-lifted version. -/// More investigation is needed to figure out why. fn wrap_in_inspect_custom( env: &mut Env, inspector: Expr, diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs index 8319cbc7b1..a796efc63d 100644 --- a/crates/compiler/derive_key/src/inspect.rs +++ b/crates/compiler/derive_key/src/inspect.rs @@ -205,7 +205,6 @@ impl FlatInspectable { Symbol::NUM_F32 | Symbol::NUM_BINARY32 => Some(Immediate(Symbol::INSPECT_F32)), Symbol::NUM_F64 | Symbol::NUM_BINARY64 => Some(Immediate(Symbol::INSPECT_F64)), Symbol::NUM_NAT | Symbol::NUM_NATURAL => Some(Immediate(Symbol::INSPECT_NAT)), - // TODO List, Dict, Set, etc. _ => None, } } diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index 889e3d5425..47e33d62e3 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -381,7 +381,6 @@ impl ObligationCache { let ImplKey { opaque, ability } = impl_key; // Every type has the Inspect ability automatically, even opaques with no `implements` declaration. - // (Those opaques get a default implementation that returns something along the lines of "") let is_inspect = ability == Symbol::INSPECT_INSPECT_ABILITY; let has_known_impl = is_inspect || abilities_store.has_declared_implementation(opaque, ability); @@ -865,9 +864,8 @@ impl DerivableVisitor for DeriveInspect { const ABILITY_SLICE: SubsSlice = Subs::AB_INSPECT; #[inline(always)] - fn is_derivable_builtin_opaque(symbol: Symbol) -> bool { - // TODO: Should this just be true? All values are always inspectable. - is_builtin_number_alias(symbol) || is_builtin_bool_alias(symbol) + fn is_derivable_builtin_opaque(_: Symbol) -> bool { + true } #[inline(always)] @@ -876,18 +874,8 @@ impl DerivableVisitor for DeriveInspect { } #[inline(always)] - fn visit_apply(var: Variable, symbol: Symbol) -> Result { - if matches!( - symbol, - Symbol::LIST_LIST | Symbol::SET_SET | Symbol::DICT_DICT | Symbol::STR_STR, - ) { - Ok(Descend(true)) - } else { - Err(NotDerivable { - var, - context: NotDerivableContext::NoContext, - }) - } + fn visit_apply(_: Variable, _: Symbol) -> Result { + Ok(Descend(true)) } #[inline(always)] diff --git a/crates/compiler/solve/src/specialize.rs b/crates/compiler/solve/src/specialize.rs index 7673eb5bd4..54b6fd358a 100644 --- a/crates/compiler/solve/src/specialize.rs +++ b/crates/compiler/solve/src/specialize.rs @@ -628,38 +628,7 @@ fn make_specialization_decision( } else { // Solving within a module. phase.with_module_abilities_store(opaque.module_id(), |abilities_store| { - let impl_key = ImplKey { - opaque: *opaque, - ability_member, - }; - match abilities_store.get_implementation(impl_key) { - None => { - match ability_member { - // Inspect is special - if there is no implementation for the - // opaque type, we always emit a default implementation. - Symbol::INSPECT_TO_INSPECTOR => SpecializeDecision::Specialize( - Immediate(Symbol::INSPECT_OPAQUE), - ), - _ => { - // Doesn't specialize; an error will already be reported for this. - SpecializeDecision::Drop - } - } - } - Some(MemberImpl::Error) => { - // TODO: probably not right, we may want to choose a derive decision! - SpecializeDecision::Specialize(Opaque(*opaque)) - } - Some(MemberImpl::Impl(specialization_symbol)) => { - match abilities_store.specialization_info(*specialization_symbol) { - Some(_) => SpecializeDecision::Specialize(Opaque(*opaque)), - - // If we expect a specialization impl but don't yet know it, we must hold off - // compacting the lambda set until the specialization is well-known. - None => SpecializeDecision::PendingSpecialization(impl_key), - } - } - } + make_ability_specialization_decision(*opaque, ability_member, abilities_store) }) } } @@ -707,6 +676,46 @@ fn make_specialization_decision( } } +fn make_ability_specialization_decision( + opaque: Symbol, + ability_member: Symbol, + abilities_store: &AbilitiesStore, +) -> SpecializeDecision { + use SpecializationTypeKey::*; + let impl_key = ImplKey { + opaque, + ability_member, + }; + match abilities_store.get_implementation(impl_key) { + None => { + match ability_member { + // Inspect is special - if there is no implementation for the + // opaque type, we always emit a default implementation. + Symbol::INSPECT_TO_INSPECTOR => { + SpecializeDecision::Specialize(Immediate(Symbol::INSPECT_OPAQUE)) + } + _ => { + // Doesn't specialize; an error will already be reported for this. + SpecializeDecision::Drop + } + } + } + Some(MemberImpl::Error) => { + // TODO: probably not right, we may want to choose a derive decision! + SpecializeDecision::Specialize(Opaque(opaque)) + } + Some(MemberImpl::Impl(specialization_symbol)) => { + match abilities_store.specialization_info(*specialization_symbol) { + Some(_) => SpecializeDecision::Specialize(Opaque(opaque)), + + // If we expect a specialization impl but don't yet know it, we must hold off + // compacting the lambda set until the specialization is well-known. + None => SpecializeDecision::PendingSpecialization(impl_key), + } + } + } +} + #[allow(clippy::too_many_arguments)] fn get_specialization_lambda_set_ambient_function( subs: &mut Subs, diff --git a/crates/compiler/types/src/subs.rs b/crates/compiler/types/src/subs.rs index 7b3f6abf28..7eae9468c0 100644 --- a/crates/compiler/types/src/subs.rs +++ b/crates/compiler/types/src/subs.rs @@ -1748,7 +1748,7 @@ impl Subs { tag_names.push(TagName("OutOfBounds".into())); // END INIT-TagNames - // IFTTT INIT-SymbolNames + // IFTTT INIT-SymbolSubsSlice let mut symbol_names = Vec::with_capacity(32); symbol_names.push(Symbol::ENCODE_ENCODING); @@ -1757,7 +1757,7 @@ impl Subs { symbol_names.push(Symbol::HASH_HASH_ABILITY); symbol_names.push(Symbol::BOOL_EQ); symbol_names.push(Symbol::INSPECT_INSPECT_ABILITY); - // END INIT-SymbolNames + // END INIT-SymbolSubsSlice // IFTTT INIT-VariableSubsSlice let variables = vec![Variable::STR]; From 248976d632b0827032171ba00b8372dbd59a39c0 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 16:40:32 -0800 Subject: [PATCH 076/105] fix wasm tests --- crates/compiler/gen_wasm/src/low_level.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/compiler/gen_wasm/src/low_level.rs b/crates/compiler/gen_wasm/src/low_level.rs index 683fbd61c6..cb66ab10c2 100644 --- a/crates/compiler/gen_wasm/src/low_level.rs +++ b/crates/compiler/gen_wasm/src/low_level.rs @@ -2252,7 +2252,7 @@ impl<'a> LowLevelCall<'a> { fn num_to_str(&self, backend: &mut WasmBackend<'a, '_>) { let arg_layout = backend.storage.symbol_layouts[&self.arguments[0]]; - match backend.layout_interner.get_repr(arg_layout) { + match backend.layout_interner.runtime_representation(arg_layout) { LayoutRepr::Builtin(Builtin::Int(width)) => { self.load_args_and_call_zig(backend, &bitcode::STR_FROM_INT[width]) } From 5fe99e1ada814fb1706c220efed8e679213c7053 Mon Sep 17 00:00:00 2001 From: John Murray <5672686+JRMurr@users.noreply.github.com> Date: Tue, 28 Nov 2023 22:10:18 -0500 Subject: [PATCH 077/105] flake update --- flake.lock | 8 ++++---- flake.nix | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index e0c185ee01..15d775de42 100644 --- a/flake.lock +++ b/flake.lock @@ -59,17 +59,17 @@ }, "nixpkgs": { "locked": { - "lastModified": 1693140250, - "narHash": "sha256-URyIDETtu1bbxcSl83xp7irEV04dPEgj7O3LjHcD1Sk=", + "lastModified": 1701068326, + "narHash": "sha256-vmMceA+q6hG1yrjb+MP8T0YFDQIrW3bl45e7z24IEts=", "owner": "nixos", "repo": "nixpkgs", - "rev": "676fe5e01b9a41fa14aaa48d87685677664104b1", + "rev": "8cfef6986adfb599ba379ae53c9f5631ecd2fd9c", "type": "github" }, "original": { "owner": "nixos", + "ref": "nixos-unstable", "repo": "nixpkgs", - "rev": "676fe5e01b9a41fa14aaa48d87685677664104b1", "type": "github" } }, diff --git a/flake.nix b/flake.nix index cfb5b92855..6d58d7f498 100644 --- a/flake.nix +++ b/flake.nix @@ -2,8 +2,7 @@ description = "Roc flake"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs?rev=676fe5e01b9a41fa14aaa48d87685677664104b1"; - + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; # rust from nixpkgs has some libc problems, this is patched in the rust-overlay rust-overlay = { url = "github:oxalica/rust-overlay"; @@ -160,7 +159,7 @@ # You can build this package (the roc CLI) with the `nix build` command. packages = { default = rocBuild.roc-cli; - + # all rust crates in workspace.members of Cargo.toml full = rocBuild.roc-full; # only the CLI crate = executable provided in nightly releases From 2c8c1e0ced04909aa8b4a2c61b262fe3f4274d10 Mon Sep 17 00:00:00 2001 From: John Murray <5672686+JRMurr@users.noreply.github.com> Date: Tue, 28 Nov 2023 22:33:38 -0500 Subject: [PATCH 078/105] basic file filtering --- nix/builder.nix | 4 +++- nix/fileFilter.nix | 60 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 nix/fileFilter.nix diff --git a/nix/builder.nix b/nix/builder.nix index 4038a1bfbe..6439bc62b8 100644 --- a/nix/builder.nix +++ b/nix/builder.nix @@ -3,6 +3,8 @@ let inherit (compile-deps) zigPkg llvmPkgs llvmVersion llvmMajorMinorStr glibcPath libGccSPath; subPackagePath = if subPackage != null then "crates/${subPackage}" else null; + + filteredSource = pkgs.callPackage ./fileFilter.nix { }; in rustPlatform.buildRustPackage { pname = "roc" + lib.optionalString (subPackage != null) "_${subPackage}"; @@ -10,7 +12,7 @@ rustPlatform.buildRustPackage { buildAndTestSubdir = subPackagePath; - src = pkgs.nix-gitignore.gitignoreSource [ ] ../.; + src = filteredSource; cargoLock = { lockFile = ../Cargo.lock; diff --git a/nix/fileFilter.nix b/nix/fileFilter.nix new file mode 100644 index 0000000000..de07a04e43 --- /dev/null +++ b/nix/fileFilter.nix @@ -0,0 +1,60 @@ +{ lib, nix-gitignore }: +let + # See https://nix.dev/tutorials/file-sets for an guide on how the file set api works + + fs = lib.fileset; + + fileDoesNotHaveExt = fileExts: file: (!lib.lists.any (ext: file.hasExt ext) fileExts); + + repoRoot = ../.; + + + # "old" way of filtering files that fileset does not support yet + # remove anything ignored by git + # baseSrc = nix-gitignore.gitignoreSource [ ] repoRoot; + + fsBase = fs.fromSource repoRoot; + + + # only look at files in the crates folder + onlyCratesFolder = fs.intersection ../crates fsBase; # TODO: probably need to union back in the root cargo files + + # the above filter only has the subfolder, put the cargo.toml and lock back + includeCargoRootFiles = fs.unions [ + ../Cargo.toml + ../Cargo.lock + ../version.txt + onlyCratesFolder + + ]; + + # Remove any "simple" files like markdown/pictures since they probably wont be used in the actual code + removedSimpleFiles = + let + extensionsToRemove = [ "md" "svg" "png" ]; + in + fs.intersection + includeCargoRootFiles + (fs.fileFilter (fileDoesNotHaveExt extensionsToRemove) repoRoot); + + # the above filter can make the doc crate sad since it deals with pictures + docsAddedBack = fs.unions [ + ../crates/docs + removedSimpleFiles + ]; + + + # + # If you are trying to see what is ok to exclude from the "main" builds (cli/lang_server) + # use `cargo tree` https://doc.rust-lang.org/cargo/commands/cargo-tree.html + # + # Ex: `cargo tree -i roc_build` will show all deps of the `roc_build` crate + # if only the package passed with `-i` is shown, nothing depends on it + +in +fs.toSource { + root = repoRoot; + # to debug you can switch to + # fileset = fs.traceVal + fileset = docsAddedBack; +} From 3fed1ba129cc2fe266f9e647438704e7067d7bf1 Mon Sep 17 00:00:00 2001 From: John Murray <5672686+JRMurr@users.noreply.github.com> Date: Tue, 28 Nov 2023 23:07:25 -0500 Subject: [PATCH 079/105] filter out test folders in nix build --- crates/wasm_interp/src/lib.rs | 1 - nix/fileFilter.nix | 48 +++++++++++++++++++++++++---------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/crates/wasm_interp/src/lib.rs b/crates/wasm_interp/src/lib.rs index 8cc98d3e39..c3add8e661 100644 --- a/crates/wasm_interp/src/lib.rs +++ b/crates/wasm_interp/src/lib.rs @@ -1,6 +1,5 @@ mod frame; mod instance; -mod tests; mod value_store; pub mod wasi; diff --git a/nix/fileFilter.nix b/nix/fileFilter.nix index de07a04e43..82b3a4f9ae 100644 --- a/nix/fileFilter.nix +++ b/nix/fileFilter.nix @@ -8,12 +8,31 @@ let repoRoot = ../.; + # The file set api does not currently have a way to easily remove folders dynamically + # since the nix build does not run tests try to remove any folders with just tests + removedTests = + let + dir_filter = path_str: ( + let dirName = baseNameOf path_str; in !( + # remove any folder whos name is `tests` or starts with `test_` + dirName == "tests" - # "old" way of filtering files that fileset does not support yet - # remove anything ignored by git - # baseSrc = nix-gitignore.gitignoreSource [ ] repoRoot; + # TODO: while the below logic seems to work to filter out folders, + # cargo still cares if the path exists (even for dev) :( + # || lib.strings.hasPrefix "test_" dirName + ) + ); + removeTestFiler = + path: type: + # only do a "real" check on directory, allow everything else through + (type == "directory" && dir_filter path) + || type != "directory"; + in + lib.sources.cleanSourceWith { src = repoRoot; filter = removeTestFiler; }; + fsBase = fs.fromSource removedTests; + + # fsBase = fs.fromSource repoRoot; - fsBase = fs.fromSource repoRoot; # only look at files in the crates folder @@ -37,24 +56,27 @@ let includeCargoRootFiles (fs.fileFilter (fileDoesNotHaveExt extensionsToRemove) repoRoot); - # the above filter can make the doc crate sad since it deals with pictures + # the above filter can make the doc crate sad since it has pictures docsAddedBack = fs.unions [ ../crates/docs removedSimpleFiles ]; - - # + # =============================== # If you are trying to see what is ok to exclude from the "main" builds (cli/lang_server) # use `cargo tree` https://doc.rust-lang.org/cargo/commands/cargo-tree.html # # Ex: `cargo tree -i roc_build` will show all deps of the `roc_build` crate # if only the package passed with `-i` is shown, nothing depends on it + # =============================== + + + filteredSrc = fs.toSource { + root = repoRoot; + # to debug you can switch to + # fileset = fs.traceVal + fileset = docsAddedBack; + }; in -fs.toSource { - root = repoRoot; - # to debug you can switch to - # fileset = fs.traceVal - fileset = docsAddedBack; -} +filteredSrc From 4b21d74f326605da9419f94cf95b1b15a0746580 Mon Sep 17 00:00:00 2001 From: John Murray <5672686+JRMurr@users.noreply.github.com> Date: Tue, 28 Nov 2023 23:13:19 -0500 Subject: [PATCH 080/105] cleanup some comments --- nix/fileFilter.nix | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nix/fileFilter.nix b/nix/fileFilter.nix index 82b3a4f9ae..d8629dbf1d 100644 --- a/nix/fileFilter.nix +++ b/nix/fileFilter.nix @@ -38,13 +38,12 @@ let # only look at files in the crates folder onlyCratesFolder = fs.intersection ../crates fsBase; # TODO: probably need to union back in the root cargo files - # the above filter only has the subfolder, put the cargo.toml and lock back + # the above filter only has the subfolder, put some needed files from the root back in includeCargoRootFiles = fs.unions [ ../Cargo.toml ../Cargo.lock ../version.txt onlyCratesFolder - ]; # Remove any "simple" files like markdown/pictures since they probably wont be used in the actual code From 625249029a82023a4b126cd557f097158b6d4bc0 Mon Sep 17 00:00:00 2001 From: John Murray <5672686+JRMurr@users.noreply.github.com> Date: Tue, 28 Nov 2023 23:30:37 -0500 Subject: [PATCH 081/105] dont check www --- nix/fileFilter.nix | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/nix/fileFilter.nix b/nix/fileFilter.nix index d8629dbf1d..6a4ae036a0 100644 --- a/nix/fileFilter.nix +++ b/nix/fileFilter.nix @@ -33,8 +33,6 @@ let # fsBase = fs.fromSource repoRoot; - - # only look at files in the crates folder onlyCratesFolder = fs.intersection ../crates fsBase; # TODO: probably need to union back in the root cargo files @@ -69,12 +67,17 @@ let # if only the package passed with `-i` is shown, nothing depends on it # =============================== + # remove www folder from checkmate crate since its not built with nix + removedWWW = fs.difference docsAddedBack ../crates/compiler/checkmate/www; + + # potential packages/folders that could be removed + # repl_* -> I don't think nix will build those filteredSrc = fs.toSource { root = repoRoot; # to debug you can switch to # fileset = fs.traceVal - fileset = docsAddedBack; + fileset = removedWWW; }; in From f3a27e2a170f374658bd52f836ac9b843a7dca83 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 29 Nov 2023 13:59:51 +0100 Subject: [PATCH 082/105] minor cleanup Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com> --- nix/fileFilter.nix | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/nix/fileFilter.nix b/nix/fileFilter.nix index 6a4ae036a0..7baadb4a7b 100644 --- a/nix/fileFilter.nix +++ b/nix/fileFilter.nix @@ -1,6 +1,6 @@ { lib, nix-gitignore }: let - # See https://nix.dev/tutorials/file-sets for an guide on how the file set api works + # See https://nix.dev/tutorials/file-sets for a guide on how the file set api works fs = lib.fileset; @@ -8,12 +8,12 @@ let repoRoot = ../.; - # The file set api does not currently have a way to easily remove folders dynamically - # since the nix build does not run tests try to remove any folders with just tests + # The file set api does not currently have a way to easily remove folders dynamically. + # The nix build does not run tests, so we try to remove any folders with only tests. removedTests = let - dir_filter = path_str: ( - let dirName = baseNameOf path_str; in !( + dirFilter = pathStr: ( + let dirName = baseNameOf pathStr; in !( # remove any folder whos name is `tests` or starts with `test_` dirName == "tests" @@ -22,13 +22,13 @@ let # || lib.strings.hasPrefix "test_" dirName ) ); - removeTestFiler = + removeTestFilter = path: type: # only do a "real" check on directory, allow everything else through - (type == "directory" && dir_filter path) + (type == "directory" && dirFilter path) || type != "directory"; in - lib.sources.cleanSourceWith { src = repoRoot; filter = removeTestFiler; }; + lib.sources.cleanSourceWith { src = repoRoot; filter = removeTestFilter; }; fsBase = fs.fromSource removedTests; # fsBase = fs.fromSource repoRoot; @@ -67,7 +67,7 @@ let # if only the package passed with `-i` is shown, nothing depends on it # =============================== - # remove www folder from checkmate crate since its not built with nix + # remove www folder from checkmate crate since it's not built with nix removedWWW = fs.difference docsAddedBack ../crates/compiler/checkmate/www; # potential packages/folders that could be removed From d0b5c35121959fd120862b65e2d72b97a35680c1 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 29 Nov 2023 14:34:58 +0100 Subject: [PATCH 083/105] add daily nix cleanup workflow --- .github/workflows/ci_cleanup.yml | 1 + .github/workflows/ci_cleanup_nix_mac.yml | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 .github/workflows/ci_cleanup_nix_mac.yml diff --git a/.github/workflows/ci_cleanup.yml b/.github/workflows/ci_cleanup.yml index 65e774b6a8..80e3f9aecd 100644 --- a/.github/workflows/ci_cleanup.yml +++ b/.github/workflows/ci_cleanup.yml @@ -1,4 +1,5 @@ on: + workflow_dispatch: schedule: - cron: '0 5 * * 1' diff --git a/.github/workflows/ci_cleanup_nix_mac.yml b/.github/workflows/ci_cleanup_nix_mac.yml new file mode 100644 index 0000000000..b23b076a46 --- /dev/null +++ b/.github/workflows/ci_cleanup_nix_mac.yml @@ -0,0 +1,18 @@ +on: + pull_request: + workflow_dispatch: + schedule: + - cron: '0 5 * * *' + +name: Clean up nix on mac mini m1 + +jobs: + clean-mac-mini-arm64: + runs-on: [self-hosted, macOS, ARM64] + timeout-minutes: 120 + steps: + - name: Clean up nix store + run: nix-store --gc + + - name: Clean up old nix shells + run: rm -rf /private/tmp/nix-shell.* From 684bdfbfd348016f4a8198161d9203bc069902da Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 29 Nov 2023 14:37:30 +0100 Subject: [PATCH 084/105] remove PR trigger --- .github/workflows/ci_cleanup_nix_mac.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci_cleanup_nix_mac.yml b/.github/workflows/ci_cleanup_nix_mac.yml index b23b076a46..cde4f24580 100644 --- a/.github/workflows/ci_cleanup_nix_mac.yml +++ b/.github/workflows/ci_cleanup_nix_mac.yml @@ -1,5 +1,4 @@ on: - pull_request: workflow_dispatch: schedule: - cron: '0 5 * * *' From 05f896e7e8d2933297dd6fa6e5cf3526f8c44a55 Mon Sep 17 00:00:00 2001 From: John Murray <5672686+JRMurr@users.noreply.github.com> Date: Wed, 29 Nov 2023 20:06:46 -0500 Subject: [PATCH 085/105] remove todo comments that are not relevant --- nix/fileFilter.nix | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/nix/fileFilter.nix b/nix/fileFilter.nix index 7baadb4a7b..8f974f85b2 100644 --- a/nix/fileFilter.nix +++ b/nix/fileFilter.nix @@ -16,10 +16,6 @@ let let dirName = baseNameOf pathStr; in !( # remove any folder whos name is `tests` or starts with `test_` dirName == "tests" - - # TODO: while the below logic seems to work to filter out folders, - # cargo still cares if the path exists (even for dev) :( - # || lib.strings.hasPrefix "test_" dirName ) ); removeTestFilter = @@ -34,7 +30,7 @@ let # fsBase = fs.fromSource repoRoot; # only look at files in the crates folder - onlyCratesFolder = fs.intersection ../crates fsBase; # TODO: probably need to union back in the root cargo files + onlyCratesFolder = fs.intersection ../crates fsBase; # the above filter only has the subfolder, put some needed files from the root back in includeCargoRootFiles = fs.unions [ From 10470f33ccaf21ae8316f21cb99b1bd412034c2e Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 29 Nov 2023 21:02:37 -0500 Subject: [PATCH 086/105] Fix mono tests --- .../generated/inspect_derived_dict.txt | 72 +++++----- .../generated/inspect_derived_list.txt | 40 +++--- .../inspect_derived_nested_record_string.txt | 130 +++++++++--------- .../generated/inspect_derived_record.txt | 74 +++++----- ...nspect_derived_record_one_field_string.txt | 52 +++---- ...spect_derived_record_two_field_strings.txt | 52 +++---- 6 files changed, 210 insertions(+), 210 deletions(-) diff --git a/crates/compiler/test_mono/generated/inspect_derived_dict.txt b/crates/compiler/test_mono/generated/inspect_derived_dict.txt index 3ca0ce6aa0..9a1a403404 100644 --- a/crates/compiler/test_mono/generated/inspect_derived_dict.txt +++ b/crates/compiler/test_mono/generated/inspect_derived_dict.txt @@ -746,8 +746,8 @@ procedure Inspect.186 (Inspect.187, #Attr.12): let Inspect.184 : {} = StructAtIndex 2 #Attr.12; let Inspect.183 : {} = StructAtIndex 1 #Attr.12; let Inspect.182 : {List {Str, I64}, List U64, List I8, U64} = StructAtIndex 0 #Attr.12; - let Inspect.353 : Str = "{"; - let Inspect.328 : Str = CallByName Inspect.61 Inspect.187 Inspect.353; + let Inspect.355 : Str = "{"; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.187 Inspect.355; let Inspect.329 : {{List {Str, I64}, List U64, List I8, U64}, {}, {}, {}} = Struct {Inspect.182, Inspect.183, Inspect.184, Inspect.185}; let Inspect.324 : {Str, Int1} = CallByName Inspect.188 Inspect.328 Inspect.329; let Inspect.325 : {} = Struct {}; @@ -761,8 +761,8 @@ procedure Inspect.188 (Inspect.189, #Attr.12): let Inspect.184 : {} = StructAtIndex 2 #Attr.12; let Inspect.183 : {} = StructAtIndex 1 #Attr.12; let Inspect.182 : {List {Str, I64}, List U64, List I8, U64} = StructAtIndex 0 #Attr.12; - let Bool.1 : Int1 = CallByName Bool.1; - let Inspect.332 : {Str, Int1} = Struct {Inspect.189, Bool.1}; + let Inspect.354 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.189, Inspect.354}; let Inspect.333 : {{}, {}} = Struct {Inspect.184, Inspect.185}; let Inspect.331 : {Str, Int1} = CallByName Dict.10 Inspect.182 Inspect.332 Inspect.333; ret Inspect.331; @@ -772,34 +772,34 @@ procedure Inspect.190 (Inspect.334, Inspect.193, Inspect.194, #Attr.12): let Inspect.184 : {} = StructAtIndex 0 #Attr.12; let Inspect.191 : Str = StructAtIndex 0 Inspect.334; let Inspect.192 : Int1 = StructAtIndex 1 Inspect.334; - joinpoint Inspect.351 Inspect.195: - let Inspect.348 : Str = CallByName Inspect.44 Inspect.193; - let Inspect.346 : Str = CallByName Inspect.31 Inspect.348 Inspect.195; - let Inspect.347 : Str = ": "; - let Inspect.340 : Str = CallByName Inspect.61 Inspect.346 Inspect.347; - let Inspect.341 : {I64, {}} = Struct {Inspect.194, Inspect.185}; - let Inspect.337 : Str = CallByName Inspect.196 Inspect.340 Inspect.341; + joinpoint Inspect.352 Inspect.195: + let Inspect.349 : Str = CallByName Inspect.44 Inspect.193; + let Inspect.347 : Str = CallByName Inspect.31 Inspect.349 Inspect.195; + let Inspect.348 : Str = ": "; + let Inspect.341 : Str = CallByName Inspect.61 Inspect.347 Inspect.348; + let Inspect.342 : {I64, {}} = Struct {Inspect.194, Inspect.185}; + let Inspect.337 : Str = CallByName Inspect.196 Inspect.341 Inspect.342; let Inspect.338 : {} = Struct {}; let Inspect.336 : {Str, Int1} = CallByName Inspect.198 Inspect.337; ret Inspect.336; in if Inspect.192 then - let Inspect.352 : Str = ", "; - let Inspect.350 : Str = CallByName Inspect.61 Inspect.191 Inspect.352; - jump Inspect.351 Inspect.350; + let Inspect.353 : Str = ", "; + let Inspect.351 : Str = CallByName Inspect.61 Inspect.191 Inspect.353; + jump Inspect.352 Inspect.351; else - jump Inspect.351 Inspect.191; + jump Inspect.352 Inspect.191; procedure Inspect.196 (Inspect.197, #Attr.12): let Inspect.185 : {} = StructAtIndex 1 #Attr.12; let Inspect.194 : I64 = StructAtIndex 0 #Attr.12; - let Inspect.344 : I64 = CallByName Inspect.54 Inspect.194; - let Inspect.343 : Str = CallByName Inspect.31 Inspect.344 Inspect.197; - ret Inspect.343; + let Inspect.345 : I64 = CallByName Inspect.54 Inspect.194; + let Inspect.344 : Str = CallByName Inspect.31 Inspect.345 Inspect.197; + ret Inspect.344; procedure Inspect.198 (Inspect.199): - let Bool.2 : Int1 = CallByName Bool.2; - let Inspect.339 : {Str, Int1} = Struct {Inspect.199, Bool.2}; + let Inspect.340 : Int1 = CallByName Bool.2; + let Inspect.339 : {Str, Int1} = Struct {Inspect.199, Inspect.340}; ret Inspect.339; procedure Inspect.200 (Inspect.326): @@ -807,17 +807,17 @@ procedure Inspect.200 (Inspect.326): ret Inspect.327; procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.370 : Str = "\""; + let Inspect.369 : Str = CallByName Inspect.61 Inspect.250 Inspect.370; + let Inspect.367 : Str = CallByName Inspect.61 Inspect.369 Inspect.248; let Inspect.368 : Str = "\""; - let Inspect.367 : Str = CallByName Inspect.61 Inspect.250 Inspect.368; - let Inspect.365 : Str = CallByName Inspect.61 Inspect.367 Inspect.248; - let Inspect.366 : Str = "\""; - let Inspect.364 : Str = CallByName Inspect.61 Inspect.365 Inspect.366; - ret Inspect.364; + let Inspect.366 : Str = CallByName Inspect.61 Inspect.367 Inspect.368; + ret Inspect.366; procedure Inspect.277 (Inspect.278, Inspect.276): - let Inspect.359 : Str = CallByName Num.96 Inspect.276; - let Inspect.358 : Str = CallByName Inspect.61 Inspect.278 Inspect.359; - ret Inspect.358; + let Inspect.361 : Str = CallByName Num.96 Inspect.276; + let Inspect.360 : Str = CallByName Inspect.61 Inspect.278 Inspect.361; + ret Inspect.360; procedure Inspect.30 (Inspect.147): ret Inspect.147; @@ -836,12 +836,12 @@ procedure Inspect.31 (Inspect.305, Inspect.149): ret Inspect.314; procedure Inspect.31 (Inspect.305, Inspect.149): - let Inspect.345 : Str = CallByName Inspect.277 Inspect.149 Inspect.305; - ret Inspect.345; + let Inspect.346 : Str = CallByName Inspect.277 Inspect.149 Inspect.305; + ret Inspect.346; procedure Inspect.31 (Inspect.305, Inspect.149): - let Inspect.349 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; - ret Inspect.349; + let Inspect.350 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.350; procedure Inspect.35 (Inspect.300): ret Inspect.300; @@ -856,8 +856,8 @@ procedure Inspect.39 (Inspect.182, Inspect.183, Inspect.184, Inspect.185): ret Inspect.315; procedure Inspect.44 (Inspect.248): - let Inspect.360 : Str = CallByName Inspect.30 Inspect.248; - ret Inspect.360; + let Inspect.362 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.362; procedure Inspect.5 (Inspect.150): let Inspect.312 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.31 Inspect.150; @@ -867,8 +867,8 @@ procedure Inspect.5 (Inspect.150): ret Inspect.307; procedure Inspect.54 (Inspect.276): - let Inspect.354 : I64 = CallByName Inspect.30 Inspect.276; - ret Inspect.354; + let Inspect.356 : I64 = CallByName Inspect.30 Inspect.276; + ret Inspect.356; procedure Inspect.61 (Inspect.303, Inspect.298): let Inspect.323 : Str = CallByName Str.3 Inspect.303 Inspect.298; diff --git a/crates/compiler/test_mono/generated/inspect_derived_list.txt b/crates/compiler/test_mono/generated/inspect_derived_list.txt index 5b3e75d71e..f26482263b 100644 --- a/crates/compiler/test_mono/generated/inspect_derived_list.txt +++ b/crates/compiler/test_mono/generated/inspect_derived_list.txt @@ -25,8 +25,8 @@ procedure Inspect.155 (Inspect.156, #Attr.12): let Inspect.154 : {} = StructAtIndex 2 #Attr.12; let Inspect.153 : {} = StructAtIndex 1 #Attr.12; let Inspect.152 : List I64 = StructAtIndex 0 #Attr.12; - let Inspect.345 : Str = "["; - let Inspect.328 : Str = CallByName Inspect.61 Inspect.156 Inspect.345; + let Inspect.347 : Str = "["; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.156 Inspect.347; let Inspect.329 : {List I64, {}, {}} = Struct {Inspect.152, Inspect.153, Inspect.154}; let Inspect.324 : {Str, Int1} = CallByName Inspect.157 Inspect.328 Inspect.329; let Inspect.325 : {} = Struct {}; @@ -39,31 +39,31 @@ procedure Inspect.157 (Inspect.158, #Attr.12): let Inspect.154 : {} = StructAtIndex 2 #Attr.12; let Inspect.153 : {} = StructAtIndex 1 #Attr.12; let Inspect.152 : List I64 = StructAtIndex 0 #Attr.12; - let Bool.1 : Int1 = CallByName Bool.1; - let Inspect.332 : {Str, Int1} = Struct {Inspect.158, Bool.1}; + let Inspect.346 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.158, Inspect.346}; let Inspect.331 : {Str, Int1} = CallByName List.18 Inspect.152 Inspect.332 Inspect.154; ret Inspect.331; procedure Inspect.159 (Inspect.334, Inspect.162, Inspect.154): let Inspect.160 : Str = StructAtIndex 0 Inspect.334; let Inspect.161 : Int1 = StructAtIndex 1 Inspect.334; - joinpoint Inspect.343 Inspect.163: - let Inspect.340 : I64 = CallByName #Derived.3 Inspect.162; - let Inspect.337 : Str = CallByName Inspect.31 Inspect.340 Inspect.163; + joinpoint Inspect.344 Inspect.163: + let Inspect.341 : I64 = CallByName #Derived.3 Inspect.162; + let Inspect.337 : Str = CallByName Inspect.31 Inspect.341 Inspect.163; let Inspect.338 : {} = Struct {}; let Inspect.336 : {Str, Int1} = CallByName Inspect.164 Inspect.337; ret Inspect.336; in if Inspect.161 then - let Inspect.344 : Str = ", "; - let Inspect.342 : Str = CallByName Inspect.61 Inspect.160 Inspect.344; - jump Inspect.343 Inspect.342; + let Inspect.345 : Str = ", "; + let Inspect.343 : Str = CallByName Inspect.61 Inspect.160 Inspect.345; + jump Inspect.344 Inspect.343; else - jump Inspect.343 Inspect.160; + jump Inspect.344 Inspect.160; procedure Inspect.164 (Inspect.165): - let Bool.2 : Int1 = CallByName Bool.2; - let Inspect.339 : {Str, Int1} = Struct {Inspect.165, Bool.2}; + let Inspect.340 : Int1 = CallByName Bool.2; + let Inspect.339 : {Str, Int1} = Struct {Inspect.165, Inspect.340}; ret Inspect.339; procedure Inspect.166 (Inspect.326): @@ -71,9 +71,9 @@ procedure Inspect.166 (Inspect.326): ret Inspect.327; procedure Inspect.277 (Inspect.278, Inspect.276): - let Inspect.351 : Str = CallByName Num.96 Inspect.276; - let Inspect.350 : Str = CallByName Inspect.61 Inspect.278 Inspect.351; - ret Inspect.350; + let Inspect.353 : Str = CallByName Num.96 Inspect.276; + let Inspect.352 : Str = CallByName Inspect.61 Inspect.278 Inspect.353; + ret Inspect.352; procedure Inspect.30 (Inspect.147): ret Inspect.147; @@ -89,8 +89,8 @@ procedure Inspect.31 (Inspect.305, Inspect.149): ret Inspect.314; procedure Inspect.31 (Inspect.305, Inspect.149): - let Inspect.341 : Str = CallByName Inspect.277 Inspect.149 Inspect.305; - ret Inspect.341; + let Inspect.342 : Str = CallByName Inspect.277 Inspect.149 Inspect.305; + ret Inspect.342; procedure Inspect.35 (Inspect.300): ret Inspect.300; @@ -112,8 +112,8 @@ procedure Inspect.5 (Inspect.150): ret Inspect.307; procedure Inspect.54 (Inspect.276): - let Inspect.346 : I64 = CallByName Inspect.30 Inspect.276; - ret Inspect.346; + let Inspect.348 : I64 = CallByName Inspect.30 Inspect.276; + ret Inspect.348; procedure Inspect.61 (Inspect.303, Inspect.298): let Inspect.323 : Str = CallByName Str.3 Inspect.303 Inspect.298; diff --git a/crates/compiler/test_mono/generated/inspect_derived_nested_record_string.txt b/crates/compiler/test_mono/generated/inspect_derived_nested_record_string.txt index 78d22ad7bd..fd513aaaec 100644 --- a/crates/compiler/test_mono/generated/inspect_derived_nested_record_string.txt +++ b/crates/compiler/test_mono/generated/inspect_derived_nested_record_string.txt @@ -33,8 +33,8 @@ procedure Bool.2 (): ret Bool.25; procedure Inspect.228 (Inspect.229, Inspect.227): - let Inspect.350 : Str = "{"; - let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.350; + let Inspect.352 : Str = "{"; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.352; let Inspect.324 : {Str, Int1} = CallByName Inspect.230 Inspect.328 Inspect.227; let Inspect.325 : {} = Struct {}; let Inspect.320 : Str = CallByName Inspect.242 Inspect.324; @@ -43,95 +43,95 @@ procedure Inspect.228 (Inspect.229, Inspect.227): ret Inspect.319; procedure Inspect.228 (Inspect.229, Inspect.227): - let Inspect.388 : Str = "{"; - let Inspect.366 : Str = CallByName Inspect.61 Inspect.229 Inspect.388; - let Inspect.362 : {Str, Int1} = CallByName Inspect.230 Inspect.366 Inspect.227; - let Inspect.363 : {} = Struct {}; - let Inspect.358 : Str = CallByName Inspect.242 Inspect.362; - let Inspect.359 : Str = "}"; - let Inspect.357 : Str = CallByName Inspect.61 Inspect.358 Inspect.359; - ret Inspect.357; + let Inspect.392 : Str = "{"; + let Inspect.368 : Str = CallByName Inspect.61 Inspect.229 Inspect.392; + let Inspect.364 : {Str, Int1} = CallByName Inspect.230 Inspect.368 Inspect.227; + let Inspect.365 : {} = Struct {}; + let Inspect.360 : Str = CallByName Inspect.242 Inspect.364; + let Inspect.361 : Str = "}"; + let Inspect.359 : Str = CallByName Inspect.61 Inspect.360 Inspect.361; + ret Inspect.359; procedure Inspect.230 (Inspect.231, Inspect.227): - let Bool.1 : Int1 = CallByName Bool.1; - let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Bool.1}; + let Inspect.351 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Inspect.351}; let Inspect.333 : {} = Struct {}; let Inspect.331 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.332 Inspect.333; ret Inspect.331; procedure Inspect.230 (Inspect.231, Inspect.227): - let Bool.1 : Int1 = CallByName Bool.1; - let Inspect.370 : {Str, Int1} = Struct {Inspect.231, Bool.1}; - let Inspect.371 : {} = Struct {}; - let Inspect.369 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.370 Inspect.371; - ret Inspect.369; + let Inspect.391 : Int1 = CallByName Bool.1; + let Inspect.372 : {Str, Int1} = Struct {Inspect.231, Inspect.391}; + let Inspect.373 : {} = Struct {}; + let Inspect.371 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.372 Inspect.373; + ret Inspect.371; procedure Inspect.232 (Inspect.334, Inspect.335): let Inspect.235 : Str = StructAtIndex 0 Inspect.335; let Inspect.236 : Str = StructAtIndex 1 Inspect.335; let Inspect.233 : Str = StructAtIndex 0 Inspect.334; let Inspect.234 : Int1 = StructAtIndex 1 Inspect.334; - joinpoint Inspect.348 Inspect.237: - let Inspect.345 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; - let Inspect.346 : Str = ": "; - let Inspect.340 : Str = CallByName Inspect.61 Inspect.345 Inspect.346; - let Inspect.337 : Str = CallByName Inspect.238 Inspect.340 Inspect.236; + joinpoint Inspect.349 Inspect.237: + let Inspect.346 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; + let Inspect.347 : Str = ": "; + let Inspect.341 : Str = CallByName Inspect.61 Inspect.346 Inspect.347; + let Inspect.337 : Str = CallByName Inspect.238 Inspect.341 Inspect.236; let Inspect.338 : {} = Struct {}; let Inspect.336 : {Str, Int1} = CallByName Inspect.240 Inspect.337; ret Inspect.336; in if Inspect.234 then - let Inspect.349 : Str = ", "; - let Inspect.347 : Str = CallByName Inspect.61 Inspect.233 Inspect.349; - jump Inspect.348 Inspect.347; + let Inspect.350 : Str = ", "; + let Inspect.348 : Str = CallByName Inspect.61 Inspect.233 Inspect.350; + jump Inspect.349 Inspect.348; else - jump Inspect.348 Inspect.233; + jump Inspect.349 Inspect.233; procedure Inspect.232 (Inspect.334, Inspect.335): let Inspect.235 : Str = StructAtIndex 0 Inspect.335; let Inspect.236 : Str = StructAtIndex 1 Inspect.335; let Inspect.233 : Str = StructAtIndex 0 Inspect.334; let Inspect.234 : Int1 = StructAtIndex 1 Inspect.334; - joinpoint Inspect.386 Inspect.237: - let Inspect.383 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; - let Inspect.384 : Str = ": "; - let Inspect.378 : Str = CallByName Inspect.61 Inspect.383 Inspect.384; - let Inspect.375 : Str = CallByName Inspect.238 Inspect.378 Inspect.236; - let Inspect.376 : {} = Struct {}; - let Inspect.374 : {Str, Int1} = CallByName Inspect.240 Inspect.375; - ret Inspect.374; + joinpoint Inspect.389 Inspect.237: + let Inspect.386 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; + let Inspect.387 : Str = ": "; + let Inspect.381 : Str = CallByName Inspect.61 Inspect.386 Inspect.387; + let Inspect.377 : Str = CallByName Inspect.238 Inspect.381 Inspect.236; + let Inspect.378 : {} = Struct {}; + let Inspect.376 : {Str, Int1} = CallByName Inspect.240 Inspect.377; + ret Inspect.376; in if Inspect.234 then - let Inspect.387 : Str = ", "; - let Inspect.385 : Str = CallByName Inspect.61 Inspect.233 Inspect.387; - jump Inspect.386 Inspect.385; + let Inspect.390 : Str = ", "; + let Inspect.388 : Str = CallByName Inspect.61 Inspect.233 Inspect.390; + jump Inspect.389 Inspect.388; else - jump Inspect.386 Inspect.233; + jump Inspect.389 Inspect.233; procedure Inspect.238 (Inspect.239, Inspect.236): - let Inspect.343 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; - ret Inspect.343; + let Inspect.344 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; + ret Inspect.344; procedure Inspect.238 (Inspect.239, Inspect.236): - let Inspect.381 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; - ret Inspect.381; + let Inspect.384 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; + ret Inspect.384; procedure Inspect.240 (Inspect.241): - let Bool.2 : Int1 = CallByName Bool.2; - let Inspect.377 : {Str, Int1} = Struct {Inspect.241, Bool.2}; - ret Inspect.377; + let Inspect.380 : Int1 = CallByName Bool.2; + let Inspect.379 : {Str, Int1} = Struct {Inspect.241, Inspect.380}; + ret Inspect.379; procedure Inspect.242 (Inspect.326): - let Inspect.365 : Str = StructAtIndex 0 Inspect.326; - ret Inspect.365; + let Inspect.367 : Str = StructAtIndex 0 Inspect.326; + ret Inspect.367; procedure Inspect.249 (Inspect.250, Inspect.248): - let Inspect.397 : Str = "\""; - let Inspect.396 : Str = CallByName Inspect.61 Inspect.250 Inspect.397; - let Inspect.394 : Str = CallByName Inspect.61 Inspect.396 Inspect.248; - let Inspect.395 : Str = "\""; - let Inspect.393 : Str = CallByName Inspect.61 Inspect.394 Inspect.395; - ret Inspect.393; + let Inspect.401 : Str = "\""; + let Inspect.400 : Str = CallByName Inspect.61 Inspect.250 Inspect.401; + let Inspect.398 : Str = CallByName Inspect.61 Inspect.400 Inspect.248; + let Inspect.399 : Str = "\""; + let Inspect.397 : Str = CallByName Inspect.61 Inspect.398 Inspect.399; + ret Inspect.397; procedure Inspect.30 (Inspect.147): ret Inspect.147; @@ -153,16 +153,16 @@ procedure Inspect.31 (Inspect.305, Inspect.149): ret Inspect.314; procedure Inspect.31 (Inspect.305, Inspect.149): - let Inspect.344 : Str = CallByName #Derived.6 Inspect.149 Inspect.305; - ret Inspect.344; + let Inspect.345 : Str = CallByName #Derived.6 Inspect.149 Inspect.305; + ret Inspect.345; procedure Inspect.31 (Inspect.305, Inspect.149): - let Inspect.352 : Str = CallByName Inspect.228 Inspect.149 Inspect.305; - ret Inspect.352; + let Inspect.354 : Str = CallByName Inspect.228 Inspect.149 Inspect.305; + ret Inspect.354; procedure Inspect.31 (Inspect.305, Inspect.149): - let Inspect.382 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; - ret Inspect.382; + let Inspect.385 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.385; procedure Inspect.35 (Inspect.300): ret Inspect.300; @@ -176,12 +176,12 @@ procedure Inspect.42 (Inspect.227): ret Inspect.315; procedure Inspect.42 (Inspect.227): - let Inspect.353 : List {Str, Str} = CallByName Inspect.30 Inspect.227; - ret Inspect.353; + let Inspect.355 : List {Str, Str} = CallByName Inspect.30 Inspect.227; + ret Inspect.355; procedure Inspect.44 (Inspect.248): - let Inspect.389 : Str = CallByName Inspect.30 Inspect.248; - ret Inspect.389; + let Inspect.393 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.393; procedure Inspect.5 (Inspect.150): let Inspect.312 : Str = CallByName #Derived.0 Inspect.150; @@ -191,9 +191,9 @@ procedure Inspect.5 (Inspect.150): ret Inspect.307; procedure Inspect.61 (Inspect.303, Inspect.298): - let Inspect.361 : Str = CallByName Str.3 Inspect.303 Inspect.298; + let Inspect.363 : Str = CallByName Str.3 Inspect.303 Inspect.298; dec Inspect.298; - ret Inspect.361; + ret Inspect.363; procedure List.18 (List.154, List.155, List.156): let List.554 : U64 = 0i64; diff --git a/crates/compiler/test_mono/generated/inspect_derived_record.txt b/crates/compiler/test_mono/generated/inspect_derived_record.txt index 99d70d6962..756bb71eeb 100644 --- a/crates/compiler/test_mono/generated/inspect_derived_record.txt +++ b/crates/compiler/test_mono/generated/inspect_derived_record.txt @@ -25,8 +25,8 @@ procedure Bool.2 (): ret Bool.23; procedure Inspect.228 (Inspect.229, Inspect.227): - let Inspect.351 : Str = "{"; - let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.351; + let Inspect.353 : Str = "{"; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.353; let Inspect.324 : {Str, Int1} = CallByName Inspect.230 Inspect.328 Inspect.227; let Inspect.325 : {} = Struct {}; let Inspect.320 : Str = CallByName Inspect.242 Inspect.324; @@ -35,8 +35,8 @@ procedure Inspect.228 (Inspect.229, Inspect.227): ret Inspect.319; procedure Inspect.230 (Inspect.231, Inspect.227): - let Bool.1 : Int1 = CallByName Bool.1; - let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Bool.1}; + let Inspect.352 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Inspect.352}; let Inspect.333 : {} = Struct {}; let Inspect.331 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.332 Inspect.333; ret Inspect.331; @@ -46,29 +46,29 @@ procedure Inspect.232 (Inspect.334, Inspect.335): let Inspect.235 : Str = StructAtIndex 1 Inspect.335; let Inspect.233 : Str = StructAtIndex 0 Inspect.334; let Inspect.234 : Int1 = StructAtIndex 1 Inspect.334; - joinpoint Inspect.349 Inspect.237: - let Inspect.346 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; - let Inspect.347 : Str = ": "; - let Inspect.340 : Str = CallByName Inspect.61 Inspect.346 Inspect.347; - let Inspect.337 : Str = CallByName Inspect.238 Inspect.340 Inspect.236; + joinpoint Inspect.350 Inspect.237: + let Inspect.347 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; + let Inspect.348 : Str = ": "; + let Inspect.341 : Str = CallByName Inspect.61 Inspect.347 Inspect.348; + let Inspect.337 : Str = CallByName Inspect.238 Inspect.341 Inspect.236; let Inspect.338 : {} = Struct {}; let Inspect.336 : {Str, Int1} = CallByName Inspect.240 Inspect.337; ret Inspect.336; in if Inspect.234 then - let Inspect.350 : Str = ", "; - let Inspect.348 : Str = CallByName Inspect.61 Inspect.233 Inspect.350; - jump Inspect.349 Inspect.348; + let Inspect.351 : Str = ", "; + let Inspect.349 : Str = CallByName Inspect.61 Inspect.233 Inspect.351; + jump Inspect.350 Inspect.349; else - jump Inspect.349 Inspect.233; + jump Inspect.350 Inspect.233; procedure Inspect.238 (Inspect.239, Inspect.236): - let Inspect.343 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; - ret Inspect.343; + let Inspect.344 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; + ret Inspect.344; procedure Inspect.240 (Inspect.241): - let Bool.2 : Int1 = CallByName Bool.2; - let Inspect.339 : {Str, Int1} = Struct {Inspect.241, Bool.2}; + let Inspect.340 : Int1 = CallByName Bool.2; + let Inspect.339 : {Str, Int1} = Struct {Inspect.241, Inspect.340}; ret Inspect.339; procedure Inspect.242 (Inspect.326): @@ -76,16 +76,16 @@ procedure Inspect.242 (Inspect.326): ret Inspect.327; procedure Inspect.277 (Inspect.278, #Attr.12): - let Inspect.364 : I64 = UnionAtIndex (Id 0) (Index 0) #Attr.12; - let Inspect.363 : Str = CallByName Num.96 Inspect.364; - let Inspect.362 : Str = CallByName Inspect.61 Inspect.278 Inspect.363; - ret Inspect.362; + let Inspect.366 : I64 = UnionAtIndex (Id 0) (Index 0) #Attr.12; + let Inspect.365 : Str = CallByName Num.96 Inspect.366; + let Inspect.364 : Str = CallByName Inspect.61 Inspect.278 Inspect.365; + ret Inspect.364; procedure Inspect.295 (Inspect.296, #Attr.12): - let Inspect.358 : Decimal = UnionAtIndex (Id 1) (Index 0) #Attr.12; - let Inspect.357 : Str = CallByName Num.96 Inspect.358; - let Inspect.356 : Str = CallByName Inspect.61 Inspect.296 Inspect.357; - ret Inspect.356; + let Inspect.360 : Decimal = UnionAtIndex (Id 1) (Index 0) #Attr.12; + let Inspect.359 : Str = CallByName Num.96 Inspect.360; + let Inspect.358 : Str = CallByName Inspect.61 Inspect.296 Inspect.359; + ret Inspect.358; procedure Inspect.30 (Inspect.147): ret Inspect.147; @@ -101,15 +101,15 @@ procedure Inspect.31 (Inspect.305, Inspect.149): ret Inspect.314; procedure Inspect.31 (Inspect.305, Inspect.149): - let Inspect.345 : U8 = GetTagId Inspect.305; - switch Inspect.345: + let Inspect.346 : U8 = GetTagId Inspect.305; + switch Inspect.346: case 0: - let Inspect.344 : Str = CallByName Inspect.277 Inspect.149 Inspect.305; - ret Inspect.344; + let Inspect.345 : Str = CallByName Inspect.277 Inspect.149 Inspect.305; + ret Inspect.345; default: - let Inspect.344 : Str = CallByName Inspect.295 Inspect.149 Inspect.305; - ret Inspect.344; + let Inspect.345 : Str = CallByName Inspect.295 Inspect.149 Inspect.305; + ret Inspect.345; procedure Inspect.35 (Inspect.300): @@ -131,14 +131,14 @@ procedure Inspect.5 (Inspect.150): ret Inspect.307; procedure Inspect.54 (Inspect.276): - let Inspect.360 : [C I64, C Decimal] = TagId(0) Inspect.276; - let Inspect.359 : [C I64, C Decimal] = CallByName Inspect.30 Inspect.360; - ret Inspect.359; + let Inspect.362 : [C I64, C Decimal] = TagId(0) Inspect.276; + let Inspect.361 : [C I64, C Decimal] = CallByName Inspect.30 Inspect.362; + ret Inspect.361; procedure Inspect.60 (Inspect.294): - let Inspect.353 : [C I64, C Decimal] = TagId(1) Inspect.294; - let Inspect.352 : [C I64, C Decimal] = CallByName Inspect.30 Inspect.353; - ret Inspect.352; + let Inspect.355 : [C I64, C Decimal] = TagId(1) Inspect.294; + let Inspect.354 : [C I64, C Decimal] = CallByName Inspect.30 Inspect.355; + ret Inspect.354; procedure Inspect.61 (Inspect.303, Inspect.298): let Inspect.323 : Str = CallByName Str.3 Inspect.303 Inspect.298; diff --git a/crates/compiler/test_mono/generated/inspect_derived_record_one_field_string.txt b/crates/compiler/test_mono/generated/inspect_derived_record_one_field_string.txt index 39c0982982..1c78bb0240 100644 --- a/crates/compiler/test_mono/generated/inspect_derived_record_one_field_string.txt +++ b/crates/compiler/test_mono/generated/inspect_derived_record_one_field_string.txt @@ -20,8 +20,8 @@ procedure Bool.2 (): ret Bool.23; procedure Inspect.228 (Inspect.229, Inspect.227): - let Inspect.350 : Str = "{"; - let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.350; + let Inspect.352 : Str = "{"; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.352; let Inspect.324 : {Str, Int1} = CallByName Inspect.230 Inspect.328 Inspect.227; let Inspect.325 : {} = Struct {}; let Inspect.320 : Str = CallByName Inspect.242 Inspect.324; @@ -30,8 +30,8 @@ procedure Inspect.228 (Inspect.229, Inspect.227): ret Inspect.319; procedure Inspect.230 (Inspect.231, Inspect.227): - let Bool.1 : Int1 = CallByName Bool.1; - let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Bool.1}; + let Inspect.351 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Inspect.351}; let Inspect.333 : {} = Struct {}; let Inspect.331 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.332 Inspect.333; ret Inspect.331; @@ -41,29 +41,29 @@ procedure Inspect.232 (Inspect.334, Inspect.335): let Inspect.236 : Str = StructAtIndex 1 Inspect.335; let Inspect.233 : Str = StructAtIndex 0 Inspect.334; let Inspect.234 : Int1 = StructAtIndex 1 Inspect.334; - joinpoint Inspect.348 Inspect.237: - let Inspect.345 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; - let Inspect.346 : Str = ": "; - let Inspect.340 : Str = CallByName Inspect.61 Inspect.345 Inspect.346; - let Inspect.337 : Str = CallByName Inspect.238 Inspect.340 Inspect.236; + joinpoint Inspect.349 Inspect.237: + let Inspect.346 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; + let Inspect.347 : Str = ": "; + let Inspect.341 : Str = CallByName Inspect.61 Inspect.346 Inspect.347; + let Inspect.337 : Str = CallByName Inspect.238 Inspect.341 Inspect.236; let Inspect.338 : {} = Struct {}; let Inspect.336 : {Str, Int1} = CallByName Inspect.240 Inspect.337; ret Inspect.336; in if Inspect.234 then - let Inspect.349 : Str = ", "; - let Inspect.347 : Str = CallByName Inspect.61 Inspect.233 Inspect.349; - jump Inspect.348 Inspect.347; + let Inspect.350 : Str = ", "; + let Inspect.348 : Str = CallByName Inspect.61 Inspect.233 Inspect.350; + jump Inspect.349 Inspect.348; else - jump Inspect.348 Inspect.233; + jump Inspect.349 Inspect.233; procedure Inspect.238 (Inspect.239, Inspect.236): - let Inspect.343 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; - ret Inspect.343; + let Inspect.344 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; + ret Inspect.344; procedure Inspect.240 (Inspect.241): - let Bool.2 : Int1 = CallByName Bool.2; - let Inspect.339 : {Str, Int1} = Struct {Inspect.241, Bool.2}; + let Inspect.340 : Int1 = CallByName Bool.2; + let Inspect.339 : {Str, Int1} = Struct {Inspect.241, Inspect.340}; ret Inspect.339; procedure Inspect.242 (Inspect.326): @@ -71,12 +71,12 @@ procedure Inspect.242 (Inspect.326): ret Inspect.327; procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.361 : Str = "\""; + let Inspect.360 : Str = CallByName Inspect.61 Inspect.250 Inspect.361; + let Inspect.358 : Str = CallByName Inspect.61 Inspect.360 Inspect.248; let Inspect.359 : Str = "\""; - let Inspect.358 : Str = CallByName Inspect.61 Inspect.250 Inspect.359; - let Inspect.356 : Str = CallByName Inspect.61 Inspect.358 Inspect.248; - let Inspect.357 : Str = "\""; - let Inspect.355 : Str = CallByName Inspect.61 Inspect.356 Inspect.357; - ret Inspect.355; + let Inspect.357 : Str = CallByName Inspect.61 Inspect.358 Inspect.359; + ret Inspect.357; procedure Inspect.30 (Inspect.147): ret Inspect.147; @@ -92,8 +92,8 @@ procedure Inspect.31 (Inspect.305, Inspect.149): ret Inspect.314; procedure Inspect.31 (Inspect.305, Inspect.149): - let Inspect.344 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; - ret Inspect.344; + let Inspect.345 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.345; procedure Inspect.35 (Inspect.300): ret Inspect.300; @@ -107,8 +107,8 @@ procedure Inspect.42 (Inspect.227): ret Inspect.315; procedure Inspect.44 (Inspect.248): - let Inspect.351 : Str = CallByName Inspect.30 Inspect.248; - ret Inspect.351; + let Inspect.353 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.353; procedure Inspect.5 (Inspect.150): let Inspect.312 : Str = CallByName #Derived.0 Inspect.150; diff --git a/crates/compiler/test_mono/generated/inspect_derived_record_two_field_strings.txt b/crates/compiler/test_mono/generated/inspect_derived_record_two_field_strings.txt index 224e8b36e0..76a867481b 100644 --- a/crates/compiler/test_mono/generated/inspect_derived_record_two_field_strings.txt +++ b/crates/compiler/test_mono/generated/inspect_derived_record_two_field_strings.txt @@ -27,8 +27,8 @@ procedure Bool.2 (): ret Bool.23; procedure Inspect.228 (Inspect.229, Inspect.227): - let Inspect.350 : Str = "{"; - let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.350; + let Inspect.352 : Str = "{"; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.352; let Inspect.324 : {Str, Int1} = CallByName Inspect.230 Inspect.328 Inspect.227; let Inspect.325 : {} = Struct {}; let Inspect.320 : Str = CallByName Inspect.242 Inspect.324; @@ -37,8 +37,8 @@ procedure Inspect.228 (Inspect.229, Inspect.227): ret Inspect.319; procedure Inspect.230 (Inspect.231, Inspect.227): - let Bool.1 : Int1 = CallByName Bool.1; - let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Bool.1}; + let Inspect.351 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Inspect.351}; let Inspect.333 : {} = Struct {}; let Inspect.331 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.332 Inspect.333; ret Inspect.331; @@ -48,29 +48,29 @@ procedure Inspect.232 (Inspect.334, Inspect.335): let Inspect.236 : Str = StructAtIndex 1 Inspect.335; let Inspect.233 : Str = StructAtIndex 0 Inspect.334; let Inspect.234 : Int1 = StructAtIndex 1 Inspect.334; - joinpoint Inspect.348 Inspect.237: - let Inspect.345 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; - let Inspect.346 : Str = ": "; - let Inspect.340 : Str = CallByName Inspect.61 Inspect.345 Inspect.346; - let Inspect.337 : Str = CallByName Inspect.238 Inspect.340 Inspect.236; + joinpoint Inspect.349 Inspect.237: + let Inspect.346 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; + let Inspect.347 : Str = ": "; + let Inspect.341 : Str = CallByName Inspect.61 Inspect.346 Inspect.347; + let Inspect.337 : Str = CallByName Inspect.238 Inspect.341 Inspect.236; let Inspect.338 : {} = Struct {}; let Inspect.336 : {Str, Int1} = CallByName Inspect.240 Inspect.337; ret Inspect.336; in if Inspect.234 then - let Inspect.349 : Str = ", "; - let Inspect.347 : Str = CallByName Inspect.61 Inspect.233 Inspect.349; - jump Inspect.348 Inspect.347; + let Inspect.350 : Str = ", "; + let Inspect.348 : Str = CallByName Inspect.61 Inspect.233 Inspect.350; + jump Inspect.349 Inspect.348; else - jump Inspect.348 Inspect.233; + jump Inspect.349 Inspect.233; procedure Inspect.238 (Inspect.239, Inspect.236): - let Inspect.343 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; - ret Inspect.343; + let Inspect.344 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; + ret Inspect.344; procedure Inspect.240 (Inspect.241): - let Bool.2 : Int1 = CallByName Bool.2; - let Inspect.339 : {Str, Int1} = Struct {Inspect.241, Bool.2}; + let Inspect.340 : Int1 = CallByName Bool.2; + let Inspect.339 : {Str, Int1} = Struct {Inspect.241, Inspect.340}; ret Inspect.339; procedure Inspect.242 (Inspect.326): @@ -78,12 +78,12 @@ procedure Inspect.242 (Inspect.326): ret Inspect.327; procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.361 : Str = "\""; + let Inspect.360 : Str = CallByName Inspect.61 Inspect.250 Inspect.361; + let Inspect.358 : Str = CallByName Inspect.61 Inspect.360 Inspect.248; let Inspect.359 : Str = "\""; - let Inspect.358 : Str = CallByName Inspect.61 Inspect.250 Inspect.359; - let Inspect.356 : Str = CallByName Inspect.61 Inspect.358 Inspect.248; - let Inspect.357 : Str = "\""; - let Inspect.355 : Str = CallByName Inspect.61 Inspect.356 Inspect.357; - ret Inspect.355; + let Inspect.357 : Str = CallByName Inspect.61 Inspect.358 Inspect.359; + ret Inspect.357; procedure Inspect.30 (Inspect.147): ret Inspect.147; @@ -99,8 +99,8 @@ procedure Inspect.31 (Inspect.305, Inspect.149): ret Inspect.314; procedure Inspect.31 (Inspect.305, Inspect.149): - let Inspect.344 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; - ret Inspect.344; + let Inspect.345 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.345; procedure Inspect.35 (Inspect.300): ret Inspect.300; @@ -114,8 +114,8 @@ procedure Inspect.42 (Inspect.227): ret Inspect.315; procedure Inspect.44 (Inspect.248): - let Inspect.360 : Str = CallByName Inspect.30 Inspect.248; - ret Inspect.360; + let Inspect.362 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.362; procedure Inspect.5 (Inspect.150): let Inspect.312 : {Str, Str} = CallByName #Derived.0 Inspect.150; From b7f72eff86684a60a46875aef723e3f7414a2222 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 18:10:36 -0800 Subject: [PATCH 087/105] add basic Dbg desugaring and LowLevelDbg --- crates/compiler/can/src/copy.rs | 4 +-- crates/compiler/can/src/expr.rs | 32 ++++++++++++---------- crates/compiler/can/src/module.rs | 2 +- crates/compiler/can/src/operator.rs | 37 ++++++++++++++++++++++++-- crates/compiler/can/src/traverse.rs | 4 +-- crates/compiler/constrain/src/expr.rs | 10 +++---- crates/compiler/fmt/src/expr.rs | 6 +++++ crates/compiler/fmt/src/spaces.rs | 4 +++ crates/compiler/mono/src/ir.rs | 8 +++--- crates/compiler/parse/src/ast.rs | 3 +++ crates/compiler/parse/src/expr.rs | 1 + crates/lang_srv/src/analysis/tokens.rs | 3 +++ 12 files changed, 84 insertions(+), 30 deletions(-) diff --git a/crates/compiler/can/src/copy.rs b/crates/compiler/can/src/copy.rs index 06ff890eed..73f535f710 100644 --- a/crates/compiler/can/src/copy.rs +++ b/crates/compiler/can/src/copy.rs @@ -670,12 +670,12 @@ fn deep_copy_expr_help(env: &mut C, copied: &mut Vec, expr }, Dbg { - loc_condition, + loc_message, loc_continuation, variable, symbol, } => Dbg { - loc_condition: Box::new(loc_condition.map(|e| go_help!(e))), + loc_message: Box::new(loc_message.map(|e| go_help!(e))), loc_continuation: Box::new(loc_continuation.map(|e| go_help!(e))), variable: sub!(*variable), symbol: *symbol, diff --git a/crates/compiler/can/src/expr.rs b/crates/compiler/can/src/expr.rs index d33d353d60..474a721bdb 100644 --- a/crates/compiler/can/src/expr.rs +++ b/crates/compiler/can/src/expr.rs @@ -269,7 +269,7 @@ pub enum Expr { }, Dbg { - loc_condition: Box>, + loc_message: Box>, loc_continuation: Box>, variable: Variable, symbol: Symbol, @@ -1246,11 +1246,14 @@ pub fn canonicalize_expr<'a>( output, ) } - ast::Expr::Dbg(condition, continuation) => { + ast::Expr::Dbg(_, _) => { + internal_error!("Dbg should have been desugared by now") + } + ast::Expr::LowLevelDbg(message, continuation) => { let mut output = Output::default(); - let (loc_condition, output1) = - canonicalize_expr(env, var_store, scope, condition.region, &condition.value); + let (loc_message, output1) = + canonicalize_expr(env, var_store, scope, message.region, &message.value); let (loc_continuation, output2) = canonicalize_expr( env, @@ -1263,17 +1266,17 @@ pub fn canonicalize_expr<'a>( output.union(output1); output.union(output2); - // the symbol is used to bind the condition `x = condition`, and identify this `dbg`. + // the symbol is used to bind the message `x = message`, and identify this `dbg`. // That would cause issues if we dbg a variable, like `dbg y`, because in the IR we // cannot alias variables. Hence, we make the dbg use that same variable `y` - let symbol = match &loc_condition.value { + let symbol = match &loc_message.value { Expr::Var(symbol, _) => *symbol, _ => scope.gen_unique_symbol(), }; ( Dbg { - loc_condition: Box::new(loc_condition), + loc_message: Box::new(loc_message), loc_continuation: Box::new(loc_continuation), variable: var_store.fresh(), symbol, @@ -2094,14 +2097,14 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr { } Dbg { - loc_condition, + loc_message, loc_continuation, variable, symbol, } => { - let loc_condition = Loc { - region: loc_condition.region, - value: inline_calls(var_store, loc_condition.value), + let loc_message = Loc { + region: loc_message.region, + value: inline_calls(var_store, loc_message.value), }; let loc_continuation = Loc { @@ -2110,7 +2113,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr { }; Dbg { - loc_condition: Box::new(loc_condition), + loc_message: Box::new(loc_message), loc_continuation: Box::new(loc_continuation), variable, symbol, @@ -2395,6 +2398,7 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool { | ast::Expr::MalformedClosure => true, // Newlines are disallowed inside interpolation, and these all require newlines ast::Expr::Dbg(_, _) + | ast::Expr::LowLevelDbg(_, _) | ast::Expr::Defs(_, _) | ast::Expr::Expect(_, _) | ast::Expr::When(_, _) @@ -3328,7 +3332,7 @@ impl crate::traverse::Visitor for ExpectCollector { .insert(loc_condition.region, lookups_in_cond.to_vec()); } Expr::Dbg { - loc_condition, + loc_message, variable, symbol, .. @@ -3336,7 +3340,7 @@ impl crate::traverse::Visitor for ExpectCollector { let lookup = DbgLookup { symbol: *symbol, var: *variable, - region: loc_condition.region, + region: loc_message.region, ability_info: None, }; diff --git a/crates/compiler/can/src/module.rs b/crates/compiler/can/src/module.rs index d0c3600074..729d53c4aa 100644 --- a/crates/compiler/can/src/module.rs +++ b/crates/compiler/can/src/module.rs @@ -996,7 +996,7 @@ fn fix_values_captured_in_closure_expr( .. } | Dbg { - loc_condition, + loc_message: loc_condition, loc_continuation, .. } => { diff --git a/crates/compiler/can/src/operator.rs b/crates/compiler/can/src/operator.rs index 5692aa2eb6..f675370bd3 100644 --- a/crates/compiler/can/src/operator.rs +++ b/crates/compiler/can/src/operator.rs @@ -461,13 +461,46 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Loc>) -> &'a Loc }) } Dbg(condition, continuation) => { - let desugared_condition = &*arena.alloc(desugar_expr(arena, condition)); let desugared_continuation = &*arena.alloc(desugar_expr(arena, continuation)); + + let region = condition.region; + // TODO desugar this in canonicalization instead, so we can work + // in terms of integers exclusively and not need to create strings + // which canonicalization then needs to look up, check if they're exposed, etc + let inspect = Var { + module_name: ModuleName::INSPECT, + ident: "inspect", + }; + let loc_inspect_fn_var = arena.alloc(Loc { + value: inspect, + region, + }); + let desugared_inspect_args = arena.alloc([desugar_expr(arena, condition)]); + + let inspector = arena.alloc(Loc { + value: Apply(loc_inspect_fn_var, desugared_inspect_args, CalledVia::Space), + region, + }); + + let to_dbg_str = Var { + module_name: ModuleName::INSPECT, + ident: "toDbgStr", + }; + let loc_to_dbg_str_fn_var = arena.alloc(Loc { + value: to_dbg_str, + region, + }); + let to_dbg_str_args = arena.alloc([&*inspector]); + let dbg_str = arena.alloc(Loc { + value: Apply(loc_to_dbg_str_fn_var, to_dbg_str_args, CalledVia::Space), + region, + }); arena.alloc(Loc { - value: Dbg(desugared_condition, desugared_continuation), + value: LowLevelDbg(dbg_str, desugared_continuation), region: loc_expr.region, }) } + LowLevelDbg(_, _) => unreachable!("Only exists after desugaring"), } } diff --git a/crates/compiler/can/src/traverse.rs b/crates/compiler/can/src/traverse.rs index e720901724..eb92dc14da 100644 --- a/crates/compiler/can/src/traverse.rs +++ b/crates/compiler/can/src/traverse.rs @@ -387,11 +387,11 @@ pub fn walk_expr(visitor: &mut V, expr: &Expr, var: Variable) { } Expr::Dbg { variable, - loc_condition, + loc_message, loc_continuation, symbol: _, } => { - visitor.visit_expr(&loc_condition.value, loc_condition.region, *variable); + visitor.visit_expr(&loc_message.value, loc_message.region, *variable); visitor.visit_expr( &loc_continuation.value, loc_continuation.region, diff --git a/crates/compiler/constrain/src/expr.rs b/crates/compiler/constrain/src/expr.rs index 9b69c8497f..0779f8cfcd 100644 --- a/crates/compiler/constrain/src/expr.rs +++ b/crates/compiler/constrain/src/expr.rs @@ -741,7 +741,7 @@ pub fn constrain_expr( } Dbg { - loc_condition, + loc_message, loc_continuation, variable, symbol: _, @@ -749,12 +749,12 @@ pub fn constrain_expr( let dbg_type = constraints.push_variable(*variable); let expected_dbg = constraints.push_expected_type(Expected::NoExpectation(dbg_type)); - let cond_con = constrain_expr( + let message_con = constrain_expr( types, constraints, env, - loc_condition.region, - &loc_condition.value, + loc_message.region, + &loc_message.value, expected_dbg, ); @@ -767,7 +767,7 @@ pub fn constrain_expr( expected, ); - constraints.exists_many([*variable], [cond_con, continuation_con]) + constraints.exists_many([*variable], [message_con, continuation_con]) } If { diff --git a/crates/compiler/fmt/src/expr.rs b/crates/compiler/fmt/src/expr.rs index 20a9299ba1..ec141df01d 100644 --- a/crates/compiler/fmt/src/expr.rs +++ b/crates/compiler/fmt/src/expr.rs @@ -62,6 +62,9 @@ impl<'a> Formattable for Expr<'a> { condition.is_multiline() || continuation.is_multiline() } Dbg(condition, continuation) => condition.is_multiline() || continuation.is_multiline(), + LowLevelDbg(condition, continuation) => { + condition.is_multiline() || continuation.is_multiline() + } If(branches, final_else) => { final_else.is_multiline() @@ -435,6 +438,9 @@ impl<'a> Formattable for Expr<'a> { Dbg(condition, continuation) => { fmt_dbg(buf, condition, continuation, self.is_multiline(), indent); } + LowLevelDbg(_, _) => unreachable!( + "LowLevelDbg should only exist after desugaring, not during formatting" + ), If(branches, final_else) => { fmt_if(buf, branches, final_else, self.is_multiline(), indent); } diff --git a/crates/compiler/fmt/src/spaces.rs b/crates/compiler/fmt/src/spaces.rs index 4264b208d5..2114545c0e 100644 --- a/crates/compiler/fmt/src/spaces.rs +++ b/crates/compiler/fmt/src/spaces.rs @@ -726,6 +726,10 @@ impl<'a> RemoveSpaces<'a> for Expr<'a> { arena.alloc(a.remove_spaces(arena)), arena.alloc(b.remove_spaces(arena)), ), + Expr::LowLevelDbg(a, b) => Expr::LowLevelDbg( + arena.alloc(a.remove_spaces(arena)), + arena.alloc(b.remove_spaces(arena)), + ), Expr::Apply(a, b, c) => Expr::Apply( arena.alloc(a.remove_spaces(arena)), b.remove_spaces(arena), diff --git a/crates/compiler/mono/src/ir.rs b/crates/compiler/mono/src/ir.rs index c3360e7f64..07fd3880fa 100644 --- a/crates/compiler/mono/src/ir.rs +++ b/crates/compiler/mono/src/ir.rs @@ -4602,7 +4602,7 @@ pub fn with_hole<'a>( Expect { .. } => unreachable!("I think this is unreachable"), ExpectFx { .. } => unreachable!("I think this is unreachable"), Dbg { - loc_condition, + loc_message, loc_continuation, variable: cond_variable, symbol: dbg_symbol, @@ -4622,7 +4622,7 @@ pub fn with_hole<'a>( procs, layout_cache, dbg_symbol, - *loc_condition, + *loc_message, cond_variable, rest, ) @@ -7137,7 +7137,7 @@ pub fn from_can<'a>( } Dbg { - loc_condition, + loc_message, loc_continuation, variable: cond_variable, symbol: dbg_symbol, @@ -7149,7 +7149,7 @@ pub fn from_can<'a>( procs, layout_cache, dbg_symbol, - *loc_condition, + *loc_message, cond_variable, rest, ) diff --git a/crates/compiler/parse/src/ast.rs b/crates/compiler/parse/src/ast.rs index 2cafc3522a..949d88b443 100644 --- a/crates/compiler/parse/src/ast.rs +++ b/crates/compiler/parse/src/ast.rs @@ -301,6 +301,8 @@ pub enum Expr<'a> { Backpassing(&'a [Loc>], &'a Loc>, &'a Loc>), Expect(&'a Loc>, &'a Loc>), Dbg(&'a Loc>, &'a Loc>), + // This form of debug is a desugared call to roc_dbg + LowLevelDbg(&'a Loc>, &'a Loc>), // Application /// To apply by name, do Apply(Var(...), ...) @@ -1535,6 +1537,7 @@ impl<'a> Malformed for Expr<'a> { Backpassing(args, call, body) => args.iter().any(|arg| arg.is_malformed()) || call.is_malformed() || body.is_malformed(), Expect(condition, continuation) | Dbg(condition, continuation) => condition.is_malformed() || continuation.is_malformed(), + LowLevelDbg(condition, continuation) => condition.is_malformed() || continuation.is_malformed(), Apply(func, args, _) => func.is_malformed() || args.iter().any(|arg| arg.is_malformed()), BinOps(firsts, last) => firsts.iter().any(|(expr, _)| expr.is_malformed()) || last.is_malformed(), UnaryOp(expr, _) => expr.is_malformed(), diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index 17cb638eef..f51602a48d 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -1933,6 +1933,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result> { Expr::Dbg(e1, e2) => (e1.iter_tokens(arena).into_iter()) .chain(e2.iter_tokens(arena)) .collect_in(arena), + Expr::LowLevelDbg(e1, e2) => (e1.iter_tokens(arena).into_iter()) + .chain(e2.iter_tokens(arena)) + .collect_in(arena), Expr::Apply(e1, e2, _called_via) => (e1.iter_tokens(arena).into_iter()) .chain(e2.iter_tokens(arena)) .collect_in(arena), From 3d6c140a3039191d4ea9ea7a6f40af0bb160478a Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Wed, 29 Nov 2023 10:42:55 -0800 Subject: [PATCH 088/105] get minimal `roc_dbg` working --- crates/compiler/builtins/bitcode/src/main.zig | 2 +- .../compiler/builtins/bitcode/src/utils.zig | 13 ++++ crates/compiler/builtins/src/bitcode.rs | 1 - crates/compiler/gen_llvm/src/llvm/build.rs | 68 ++++++++++++++----- crates/compiler/gen_llvm/src/llvm/expect.rs | 10 --- examples/platform-switching/c-platform/host.c | 4 ++ 6 files changed, 69 insertions(+), 29 deletions(-) diff --git a/crates/compiler/builtins/bitcode/src/main.zig b/crates/compiler/builtins/bitcode/src/main.zig index 8979819f9b..5fa5fa73f5 100644 --- a/crates/compiler/builtins/bitcode/src/main.zig +++ b/crates/compiler/builtins/bitcode/src/main.zig @@ -230,6 +230,7 @@ comptime { // Utils comptime { + exportUtilsFn(utils.test_dbg, "test_dbg"); exportUtilsFn(utils.test_panic, "test_panic"); exportUtilsFn(utils.increfRcPtrC, "incref_rc_ptr"); exportUtilsFn(utils.decrefRcPtrC, "decref_rc_ptr"); @@ -248,7 +249,6 @@ comptime { exportUtilsFn(expect.expectFailedStartSharedBuffer, "expect_failed_start_shared_buffer"); exportUtilsFn(expect.expectFailedStartSharedFile, "expect_failed_start_shared_file"); exportUtilsFn(expect.notifyParentExpect, "notify_parent_expect"); - exportUtilsFn(expect.notifyParentDbg, "notify_parent_dbg"); // sets the buffer used for expect failures @export(expect.setSharedBuffer, .{ .name = "set_shared_buffer", .linkage = .Weak }); diff --git a/crates/compiler/builtins/bitcode/src/utils.zig b/crates/compiler/builtins/bitcode/src/utils.zig index 94e806d974..6a77a13d4d 100644 --- a/crates/compiler/builtins/bitcode/src/utils.zig +++ b/crates/compiler/builtins/bitcode/src/utils.zig @@ -20,6 +20,13 @@ extern fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, align // This should never be passed a null pointer. extern fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void; +extern fn roc_dbg(file_path: *anyopaque, message: *anyopaque) callconv(.C) void; + +// Since roc_dbg is never used by the builtins, we need at export a function that uses it to stop DCE. +pub fn test_dbg(file_path: *anyopaque, message: *anyopaque) callconv(.C) void { + roc_dbg(file_path, message); +} + extern fn kill(pid: c_int, sig: c_int) c_int; extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int; extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque; @@ -40,6 +47,11 @@ fn testing_roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int return mmap(addr, length, prot, flags, fd, offset); } +fn testing_roc_dbg(file_path: *anyopaque, message: *anyopaque) callconv(.C) void { + _ = message; + _ = file_path; +} + comptime { // During tests, use the testing allocators to satisfy these functions. if (builtin.is_test) { @@ -47,6 +59,7 @@ comptime { @export(testing_roc_realloc, .{ .name = "roc_realloc", .linkage = .Strong }); @export(testing_roc_dealloc, .{ .name = "roc_dealloc", .linkage = .Strong }); @export(testing_roc_panic, .{ .name = "roc_panic", .linkage = .Strong }); + @export(testing_roc_dbg, .{ .name = "roc_dbg", .linkage = .Strong }); if (builtin.os.tag == .macos or builtin.os.tag == .linux) { @export(testing_roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong }); diff --git a/crates/compiler/builtins/src/bitcode.rs b/crates/compiler/builtins/src/bitcode.rs index 8482f79739..47c4d045eb 100644 --- a/crates/compiler/builtins/src/bitcode.rs +++ b/crates/compiler/builtins/src/bitcode.rs @@ -439,7 +439,6 @@ pub const UTILS_EXPECT_FAILED_START_SHARED_FILE: &str = "roc_builtins.utils.expect_failed_start_shared_file"; pub const UTILS_EXPECT_READ_ENV_SHARED_BUFFER: &str = "roc_builtins.utils.read_env_shared_buffer"; pub const NOTIFY_PARENT_EXPECT: &str = "roc_builtins.utils.notify_parent_expect"; -pub const NOTIFY_PARENT_DBG: &str = "roc_builtins.utils.notify_parent_dbg"; pub const UTILS_LONGJMP: &str = "longjmp"; pub const UTILS_SETJMP: &str = "setjmp"; diff --git a/crates/compiler/gen_llvm/src/llvm/build.rs b/crates/compiler/gen_llvm/src/llvm/build.rs index 903fde78f2..8c75f19cd8 100644 --- a/crates/compiler/gen_llvm/src/llvm/build.rs +++ b/crates/compiler/gen_llvm/src/llvm/build.rs @@ -919,6 +919,51 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> { call.set_call_convention(C_CALL_CONV); } + pub fn call_dbg( + &self, + env: &Env<'a, 'ctx, 'env>, + file_path: BasicValueEnum<'ctx>, + message: BasicValueEnum<'ctx>, + ) { + let function = self.module.get_function("roc_dbg").unwrap(); + + let file = match env.target_info.ptr_width() { + PtrWidth::Bytes4 => { + // we need to pass the file_path by reference, but we currently hold the value. + let alloca = env + .builder + .new_build_alloca(file_path.get_type(), "alloca_dbg_file_path"); + env.builder.new_build_store(alloca, file_path); + alloca.into() + } + PtrWidth::Bytes8 => { + // string is already held by reference + file_path + } + }; + + let msg = match env.target_info.ptr_width() { + PtrWidth::Bytes4 => { + // we need to pass the message by reference, but we currently hold the value. + let alloca = env + .builder + .new_build_alloca(message.get_type(), "alloca_dbg_msg"); + env.builder.new_build_store(alloca, message); + alloca.into() + } + PtrWidth::Bytes8 => { + // string is already held by reference + message + } + }; + + let call = self + .builder + .new_build_call(function, &[file.into(), msg.into()], "roc_dbg"); + + call.set_call_convention(C_CALL_CONV); + } + pub fn new_debug_info(module: &Module<'ctx>) -> (DebugInfoBuilder<'ctx>, DICompileUnit<'ctx>) { module.create_debug_info_builder( true, @@ -3502,26 +3547,15 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>( Dbg { symbol, - variable: specialized_var, + variable: _, remainder, } => { if env.mode.runs_expects() { - let shared_memory = crate::llvm::expect::SharedMemoryPointer::get(env); - let region = unsafe { std::mem::transmute::<_, roc_region::all::Region>(*symbol) }; - - crate::llvm::expect::clone_to_shared_memory( - env, - layout_interner, - scope, - layout_ids, - &shared_memory, - *symbol, - region, - &[*symbol], - &[*specialized_var], - ); - - crate::llvm::expect::notify_parent_dbg(env, &shared_memory); + // TODO: deal with filename and region + // let region = unsafe { std::mem::transmute::<_, roc_region::all::Region>(*symbol) }; + let file_path = build_string_literal(env, parent, "TODO: add filepath here"); + let message = scope.load_symbol(symbol); + env.call_dbg(env, file_path, message); } build_exp_stmt( diff --git a/crates/compiler/gen_llvm/src/llvm/expect.rs b/crates/compiler/gen_llvm/src/llvm/expect.rs index 7d685ecb00..8f48ec09d9 100644 --- a/crates/compiler/gen_llvm/src/llvm/expect.rs +++ b/crates/compiler/gen_llvm/src/llvm/expect.rs @@ -150,16 +150,6 @@ pub(crate) fn notify_parent_expect(env: &Env, shared_memory: &SharedMemoryPointe ); } -pub(crate) fn notify_parent_dbg(env: &Env, shared_memory: &SharedMemoryPointer) { - let func = env.module.get_function(bitcode::NOTIFY_PARENT_DBG).unwrap(); - - env.builder.new_build_call( - func, - &[shared_memory.0.into()], - "call_expect_failed_finalize", - ); -} - // Shape of expect frame: // // === diff --git a/examples/platform-switching/c-platform/host.c b/examples/platform-switching/c-platform/host.c index 4e863553d9..c81cd435d4 100644 --- a/examples/platform-switching/c-platform/host.c +++ b/examples/platform-switching/c-platform/host.c @@ -29,6 +29,10 @@ void roc_panic(void* ptr, unsigned int alignment) { exit(0); } +void roc_dbg(char* file_path, char* msg) { + fprintf(stderr, "[%s] %s\n", file_path, msg); +} + void* roc_memset(void* str, int c, size_t n) { return memset(str, c, n); } int roc_shm_open(char* name, int oflag, int mode) { From e6cc43492a7b6d99130759691bc68e698ab813c2 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Wed, 29 Nov 2023 15:25:30 -0800 Subject: [PATCH 089/105] rip out old dbg and setup reasonable base debug location info --- crates/cli/src/lib.rs | 13 --- .../compiler/builtins/bitcode/src/expect.zig | 4 - .../compiler/builtins/bitcode/src/utils.zig | 2 +- crates/compiler/gen_llvm/src/llvm/build.rs | 21 ++--- crates/repl_expect/src/run.rs | 89 +------------------ 5 files changed, 13 insertions(+), 116 deletions(-) diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index d5c91b912c..f5ffeac79c 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -1136,19 +1136,6 @@ fn roc_dev_native( ) .unwrap(); - memory.reset(); - } - ChildProcessMsg::Dbg => { - roc_repl_expect::run::render_dbgs_in_memory( - &mut writer, - arena, - &mut expectations, - &interns, - &layout_interner, - &memory, - ) - .unwrap(); - memory.reset(); } } diff --git a/crates/compiler/builtins/bitcode/src/expect.zig b/crates/compiler/builtins/bitcode/src/expect.zig index 70328e65aa..7ae9826c1d 100644 --- a/crates/compiler/builtins/bitcode/src/expect.zig +++ b/crates/compiler/builtins/bitcode/src/expect.zig @@ -96,7 +96,3 @@ pub fn notifyParent(shared_buffer: [*]u8, tag: u32) callconv(.C) void { pub fn notifyParentExpect(shared_buffer: [*]u8) callconv(.C) void { notifyParent(shared_buffer, 1); } - -pub fn notifyParentDbg(shared_buffer: [*]u8) callconv(.C) void { - notifyParent(shared_buffer, 2); -} diff --git a/crates/compiler/builtins/bitcode/src/utils.zig b/crates/compiler/builtins/bitcode/src/utils.zig index 6a77a13d4d..c53c8a3087 100644 --- a/crates/compiler/builtins/bitcode/src/utils.zig +++ b/crates/compiler/builtins/bitcode/src/utils.zig @@ -22,7 +22,7 @@ extern fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void; extern fn roc_dbg(file_path: *anyopaque, message: *anyopaque) callconv(.C) void; -// Since roc_dbg is never used by the builtins, we need at export a function that uses it to stop DCE. +// Sincet roc_dbg is never used by the builtins, we need at export a function that uses it to stop DCE. pub fn test_dbg(file_path: *anyopaque, message: *anyopaque) callconv(.C) void { roc_dbg(file_path, message); } diff --git a/crates/compiler/gen_llvm/src/llvm/build.rs b/crates/compiler/gen_llvm/src/llvm/build.rs index 8c75f19cd8..3550aff56e 100644 --- a/crates/compiler/gen_llvm/src/llvm/build.rs +++ b/crates/compiler/gen_llvm/src/llvm/build.rs @@ -922,23 +922,23 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> { pub fn call_dbg( &self, env: &Env<'a, 'ctx, 'env>, - file_path: BasicValueEnum<'ctx>, + location: BasicValueEnum<'ctx>, message: BasicValueEnum<'ctx>, ) { let function = self.module.get_function("roc_dbg").unwrap(); - let file = match env.target_info.ptr_width() { + let loc = match env.target_info.ptr_width() { PtrWidth::Bytes4 => { - // we need to pass the file_path by reference, but we currently hold the value. + // we need to pass the location by reference, but we currently hold the value. let alloca = env .builder - .new_build_alloca(file_path.get_type(), "alloca_dbg_file_path"); - env.builder.new_build_store(alloca, file_path); + .new_build_alloca(location.get_type(), "alloca_dbg_location"); + env.builder.new_build_store(alloca, location); alloca.into() } PtrWidth::Bytes8 => { // string is already held by reference - file_path + location } }; @@ -959,7 +959,7 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> { let call = self .builder - .new_build_call(function, &[file.into(), msg.into()], "roc_dbg"); + .new_build_call(function, &[loc.into(), msg.into()], "roc_dbg"); call.set_call_convention(C_CALL_CONV); } @@ -3551,11 +3551,12 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>( remainder, } => { if env.mode.runs_expects() { - // TODO: deal with filename and region + // TODO: Change location to `filename:line_number` // let region = unsafe { std::mem::transmute::<_, roc_region::all::Region>(*symbol) }; - let file_path = build_string_literal(env, parent, "TODO: add filepath here"); + let location = + build_string_literal(env, parent, symbol.module_string(&env.interns)); let message = scope.load_symbol(symbol); - env.call_dbg(env, file_path, message); + env.call_dbg(env, location, message); } build_exp_stmt( diff --git a/crates/repl_expect/src/run.rs b/crates/repl_expect/src/run.rs index 413a6e7a16..202086aae8 100644 --- a/crates/repl_expect/src/run.rs +++ b/crates/repl_expect/src/run.rs @@ -435,44 +435,6 @@ pub fn render_expects_in_memory<'a>( ) } -pub fn render_dbgs_in_memory<'a>( - writer: &mut impl std::io::Write, - arena: &'a Bump, - expectations: &mut VecMap, - interns: &'a Interns, - layout_interner: &GlobalLayoutInterner<'a>, - memory: &ExpectMemory, -) -> std::io::Result { - let shared_ptr = memory.ptr; - - let frame = ExpectFrame::at_offset(shared_ptr, ExpectSequence::START_OFFSET); - let module_id = frame.module_id; - - let data = expectations.get_mut(&module_id).unwrap(); - let filename = data.path.to_owned(); - let source = std::fs::read_to_string(&data.path).unwrap(); - - let renderer = Renderer::new( - arena, - interns, - RenderTarget::ColorTerminal, - module_id, - filename, - &source, - ); - - render_dbg_failure( - writer, - &renderer, - arena, - expectations, - interns, - layout_interner, - shared_ptr, - ExpectSequence::START_OFFSET, - ) -} - fn split_expect_lookups(subs: &Subs, lookups: &[ExpectLookup]) -> Vec { lookups .iter() @@ -494,53 +456,6 @@ fn split_expect_lookups(subs: &Subs, lookups: &[ExpectLookup]) -> Vec { .collect() } -#[allow(clippy::too_many_arguments)] -fn render_dbg_failure<'a>( - writer: &mut impl std::io::Write, - renderer: &Renderer, - arena: &'a Bump, - expectations: &mut VecMap, - interns: &'a Interns, - layout_interner: &GlobalLayoutInterner<'a>, - start: *const u8, - offset: usize, -) -> std::io::Result { - // we always run programs as the host - let target_info = (&target_lexicon::Triple::host()).into(); - - let frame = ExpectFrame::at_offset(start, offset); - let module_id = frame.module_id; - - let failure_region = frame.region; - let dbg_symbol = unsafe { std::mem::transmute::<_, Symbol>(failure_region) }; - let expect_region = Some(Region::zero()); - - let data = expectations.get_mut(&module_id).unwrap(); - - let current = match data.dbgs.get(&dbg_symbol) { - None => internal_error!("region {failure_region:?} not in list of dbgs"), - Some(current) => current, - }; - let failure_region = current.region; - - let subs = arena.alloc(&mut data.subs); - - let (offset, expressions, _variables) = crate::get_values( - target_info, - arena, - subs, - interns, - layout_interner, - start, - frame.start_offset, - 1, - ); - - renderer.render_dbg(writer, &expressions, expect_region, failure_region)?; - - Ok(offset) -} - #[allow(clippy::too_many_arguments)] fn render_expect_failure<'a>( writer: &mut impl std::io::Write, @@ -637,7 +552,6 @@ impl ExpectSequence { match atomic.load(Ordering::Acquire) { 0 => std::hint::spin_loop(), 1 => break ChildProcessMsg::Expect, - 2 => break ChildProcessMsg::Dbg, n => internal_error!("invalid atomic value set by the child: {n:#x}"), } } @@ -655,8 +569,7 @@ impl ExpectSequence { pub enum ChildProcessMsg { Expect = 1, - Dbg = 2, - Terminate = 3, + Terminate = 2, } struct ExpectFrame { From f5fb01fd532000eb49d15e10d3cac8234555ffd8 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Wed, 29 Nov 2023 16:18:22 -0800 Subject: [PATCH 090/105] Get tests passing Add roc_dbg to some platforms. Also start updating some roc_panic impls. --- crates/cli/tests/cli_run.rs | 10 ++--- .../tests/fixtures/packages/platform/host.zig | 10 +++-- .../algorithms/fibonacci-platform/host.zig | 14 +++++-- .../benchmarks/platform/host.zig | 12 ++++-- .../expects/zig-platform/host.zig | 13 ++++-- crates/compiler/gen_dev/src/lib.rs | 8 ++++ crates/compiler/gen_dev/src/object_builder.rs | 21 ++++++++++ crates/compiler/gen_llvm/src/llvm/externs.rs | 3 ++ .../test_gen/src/helpers/wasm_test_platform.c | 2 + .../test_mono/generated/dbg_in_expect.txt | 42 ++++++++++++++++++- .../generated/dbg_str_followed_by_number.txt | 42 ++++++++++++++++++- .../tests/solve/constrain_dbg_flex_var.txt | 2 +- crates/roc_std/src/lib.rs | 1 + crates/roc_std/tests/test_roc_std.rs | 18 ++++---- crates/valgrind/zig-platform/host.zig | 12 ++++-- .../platform-switching/zig-platform/host.zig | 10 +++-- examples/static-site-gen/platform/src/lib.rs | 18 +++++--- 17 files changed, 191 insertions(+), 47 deletions(-) diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index 9b3dcd6241..8aefda9c70 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -562,11 +562,11 @@ mod cli_run { x : Num * x = 42 - [ 19:9] 42 - [ 20:9] "Fjoer en ferdjer frieten oan dyn geve lea" - [ 13:9] "abc" - [ 13:9] 10 - [ 13:9] A (B C) + [#UserApp] 42 + [#UserApp] "Fjoer en ferdjer frieten oan dyn geve lea" + [#UserApp] "abc" + [#UserApp] 10 + [#UserApp] (A (B C)) Program finished! "# ), diff --git a/crates/cli/tests/fixtures/packages/platform/host.zig b/crates/cli/tests/fixtures/packages/platform/host.zig index 5eed78fce5..b798f0946d 100644 --- a/crates/cli/tests/fixtures/packages/platform/host.zig +++ b/crates/cli/tests/fixtures/packages/platform/host.zig @@ -38,15 +38,19 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void { return memset(dst, value, size); } -export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void { +export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { _ = tag_id; const stderr = std.io.getStdErr().writer(); - const msg = @as([*:0]const u8, @ptrCast(c_ptr)); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; std.process.exit(0); } +export fn roc_dbg(loc: *RocStr, msg: *RocStr) callconv(.C) void { + const stderr = std.io.getStdErr().writer(); + stderr.print("[{s}] {s}\n", .{ loc.asSlice(), msg.asSlice() }) catch unreachable; +} + extern fn kill(pid: c_int, sig: c_int) c_int; extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int; extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque; diff --git a/crates/cli_testing_examples/algorithms/fibonacci-platform/host.zig b/crates/cli_testing_examples/algorithms/fibonacci-platform/host.zig index 09fdde7ba2..0ed665fff1 100644 --- a/crates/cli_testing_examples/algorithms/fibonacci-platform/host.zig +++ b/crates/cli_testing_examples/algorithms/fibonacci-platform/host.zig @@ -1,5 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); +const str = @import("glue").str; +const RocStr = str.RocStr; const testing = std.testing; const expectEqual = testing.expectEqual; const expect = testing.expect; @@ -50,13 +52,17 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr)))); } -export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void { +export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { _ = tag_id; const stderr = std.io.getStdErr().writer(); - const msg = @as([*:0]const u8, @ptrCast(c_ptr)); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; - std.process.exit(0); + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + std.process.exit(1); +} + +export fn roc_dbg(loc: *RocStr, msg: *RocStr) callconv(.C) void { + const stderr = std.io.getStdErr().writer(); + stderr.print("[{s}] {s}\n", .{ loc.asSlice(), msg.asSlice() }) catch unreachable; } export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void { diff --git a/crates/cli_testing_examples/benchmarks/platform/host.zig b/crates/cli_testing_examples/benchmarks/platform/host.zig index 2e590a0596..6bd581040f 100644 --- a/crates/cli_testing_examples/benchmarks/platform/host.zig +++ b/crates/cli_testing_examples/benchmarks/platform/host.zig @@ -54,13 +54,17 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr)))); } -export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void { +export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { _ = tag_id; const stderr = std.io.getStdErr().writer(); - const msg = @as([*:0]const u8, @ptrCast(c_ptr)); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; - std.process.exit(0); + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + std.process.exit(1); +} + +export fn roc_dbg(loc: *RocStr, msg: *RocStr) callconv(.C) void { + const stderr = std.io.getStdErr().writer(); + stderr.print("[{s}] {s}\n", .{ loc.asSlice(), msg.asSlice() }) catch unreachable; } export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void { diff --git a/crates/cli_testing_examples/expects/zig-platform/host.zig b/crates/cli_testing_examples/expects/zig-platform/host.zig index c8867e6f70..a830db2cb7 100644 --- a/crates/cli_testing_examples/expects/zig-platform/host.zig +++ b/crates/cli_testing_examples/expects/zig-platform/host.zig @@ -44,13 +44,18 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr)))); } -export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void { +export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { _ = tag_id; const stderr = std.io.getStdErr().writer(); - const msg = @as([*:0]const u8, @ptrCast(c_ptr)); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; - std.process.exit(0); + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + std.process.exit(1); +} + +export fn roc_dbg(loc: *RocStr, msg: *RocStr) callconv(.C) void { + // This platform uses stdout for testing purposes instead of the normal stderr. + const stdout = std.io.getStdOut().writer(); + stdout.print("[{s}] {s}\n", .{ loc.asSlice(), msg.asSlice() }) catch unreachable; } export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void { diff --git a/crates/compiler/gen_dev/src/lib.rs b/crates/compiler/gen_dev/src/lib.rs index 6ef72c117f..cc1f9c9c62 100644 --- a/crates/compiler/gen_dev/src/lib.rs +++ b/crates/compiler/gen_dev/src/lib.rs @@ -57,6 +57,14 @@ impl AssemblyBackendMode { AssemblyBackendMode::Repl => true, } } + + fn generate_roc_dbg(self) -> bool { + match self { + AssemblyBackendMode::Binary => false, + AssemblyBackendMode::Test => true, + AssemblyBackendMode::Repl => true, + } + } } pub struct Env<'a> { diff --git a/crates/compiler/gen_dev/src/object_builder.rs b/crates/compiler/gen_dev/src/object_builder.rs index af6f500984..79e5e3356d 100644 --- a/crates/compiler/gen_dev/src/object_builder.rs +++ b/crates/compiler/gen_dev/src/object_builder.rs @@ -296,6 +296,23 @@ fn generate_roc_panic<'a, B: Backend<'a>>(backend: &mut B, output: &mut Object) } } +fn generate_roc_dbg<'a, B: Backend<'a>>(_backend: &mut B, output: &mut Object) { + let text_section = output.section_id(StandardSection::Text); + let proc_symbol = Symbol { + name: "roc_dbg".as_bytes().to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Text, + scope: SymbolScope::Dynamic, + weak: false, + section: SymbolSection::Section(text_section), + flags: SymbolFlags::None, + }; + let _proc_id = output.add_symbol(proc_symbol); + // TODO: Actually generate an impl instead of just an empty symbol. + // At a minimum, it should just be a ret. +} + fn generate_wrapper<'a, B: Backend<'a>>( backend: &mut B, output: &mut Object, @@ -412,6 +429,10 @@ fn build_object<'a, B: Backend<'a>>( generate_longjmp(&mut backend, &mut output); } + if backend.env().mode.generate_roc_dbg() { + generate_roc_dbg(&mut backend, &mut output); + } + if backend.env().mode.generate_allocators() { generate_wrapper( &mut backend, diff --git a/crates/compiler/gen_llvm/src/llvm/externs.rs b/crates/compiler/gen_llvm/src/llvm/externs.rs index 393eba6fe5..c79a1a8e23 100644 --- a/crates/compiler/gen_llvm/src/llvm/externs.rs +++ b/crates/compiler/gen_llvm/src/llvm/externs.rs @@ -160,6 +160,9 @@ pub fn add_default_roc_externs(env: &Env<'_, '_, '_>) { } } + // TODO: generate a valid impl of dbg here. + unreachable_function(env, "roc_dbg"); + match env.target_info.operating_system { roc_target::OperatingSystem::Windows => { // We don't need these functions on Windows diff --git a/crates/compiler/test_gen/src/helpers/wasm_test_platform.c b/crates/compiler/test_gen/src/helpers/wasm_test_platform.c index 71f84352a5..d9dbdaeefb 100644 --- a/crates/compiler/test_gen/src/helpers/wasm_test_platform.c +++ b/crates/compiler/test_gen/src/helpers/wasm_test_platform.c @@ -132,6 +132,8 @@ void roc_panic(void* msg, unsigned int panic_tag) exit(101); } +void roc_debug(void* loc, void* msg) {} + //-------------------------- void *roc_memset(void *str, int c, size_t n) diff --git a/crates/compiler/test_mono/generated/dbg_in_expect.txt b/crates/compiler/test_mono/generated/dbg_in_expect.txt index a683faaa6c..064c6634f8 100644 --- a/crates/compiler/test_mono/generated/dbg_in_expect.txt +++ b/crates/compiler/test_mono/generated/dbg_in_expect.txt @@ -2,8 +2,48 @@ procedure Bool.2 (): let Bool.23 : Int1 = true; ret Bool.23; +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.323 : Str = "\""; + let Inspect.322 : Str = CallByName Inspect.61 Inspect.250 Inspect.323; + let Inspect.318 : Str = CallByName Inspect.61 Inspect.322 Inspect.248; + let Inspect.319 : Str = "\""; + let Inspect.317 : Str = CallByName Inspect.61 Inspect.318 Inspect.319; + ret Inspect.317; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.44 (Inspect.248): + let Inspect.313 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.313; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : Str = CallByName Inspect.44 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName Inspect.249 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.321 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.321; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + procedure Test.1 (): - let Test.0 : Str = ""; + let Test.5 : Str = ""; + let Test.4 : Str = CallByName Inspect.5 Test.5; + let Test.0 : Str = CallByName Inspect.35 Test.4; dbg Test.0; dec Test.0; let Test.3 : Int1 = CallByName Bool.2; diff --git a/crates/compiler/test_mono/generated/dbg_str_followed_by_number.txt b/crates/compiler/test_mono/generated/dbg_str_followed_by_number.txt index 3fadf1fcc4..30f3e3f208 100644 --- a/crates/compiler/test_mono/generated/dbg_str_followed_by_number.txt +++ b/crates/compiler/test_mono/generated/dbg_str_followed_by_number.txt @@ -1,5 +1,45 @@ +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.323 : Str = "\""; + let Inspect.322 : Str = CallByName Inspect.61 Inspect.250 Inspect.323; + let Inspect.318 : Str = CallByName Inspect.61 Inspect.322 Inspect.248; + let Inspect.319 : Str = "\""; + let Inspect.317 : Str = CallByName Inspect.61 Inspect.318 Inspect.319; + ret Inspect.317; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.44 (Inspect.248): + let Inspect.313 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.313; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : Str = CallByName Inspect.44 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName Inspect.249 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.321 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.321; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + procedure Test.0 (): - let Test.1 : Str = ""; + let Test.4 : Str = ""; + let Test.3 : Str = CallByName Inspect.5 Test.4; + let Test.1 : Str = CallByName Inspect.35 Test.3; dbg Test.1; dec Test.1; let Test.2 : I64 = 42i64; diff --git a/crates/compiler/uitest/tests/solve/constrain_dbg_flex_var.txt b/crates/compiler/uitest/tests/solve/constrain_dbg_flex_var.txt index 7648aac6da..85f1017008 100644 --- a/crates/compiler/uitest/tests/solve/constrain_dbg_flex_var.txt +++ b/crates/compiler/uitest/tests/solve/constrain_dbg_flex_var.txt @@ -1,7 +1,7 @@ app "test" provides [main] to "./platform" polyDbg = \x -> -#^^^^^^^{-1} a -[[polyDbg(1)]]-> a +#^^^^^^^{-1} val -[[polyDbg(1)]]-> val where val implements Inspect dbg x x diff --git a/crates/roc_std/src/lib.rs b/crates/roc_std/src/lib.rs index ec549e461a..587bd4fe27 100644 --- a/crates/roc_std/src/lib.rs +++ b/crates/roc_std/src/lib.rs @@ -36,6 +36,7 @@ extern "C" { ) -> *mut c_void; pub fn roc_dealloc(ptr: *mut c_void, alignment: u32); pub fn roc_panic(c_ptr: *mut c_void, tag_id: u32); + pub fn roc_dbg(loc: *mut c_void, msg: *mut c_void); pub fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void; } diff --git a/crates/roc_std/tests/test_roc_std.rs b/crates/roc_std/tests/test_roc_std.rs index 15cbd31d5a..9b1e8fd1f8 100644 --- a/crates/roc_std/tests/test_roc_std.rs +++ b/crates/roc_std/tests/test_roc_std.rs @@ -32,18 +32,14 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { #[cfg(test)] #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { - use std::ffi::CStr; - use std::os::raw::c_char; +pub unsafe extern "C" fn roc_panic(msg: *mut roc_std::RocStr, _tag_id: u32) { + panic!("roc_panic during test: {}", &*msg); +} - match tag_id { - 0 => { - let c_str = CStr::from_ptr(c_ptr as *const c_char); - let string = c_str.to_str().unwrap(); - panic!("roc_panic during test: {string}"); - } - _ => todo!(), - } +#[cfg(test)] +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut roc_std::RocStr, msg: *mut roc_std::RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[cfg(test)] diff --git a/crates/valgrind/zig-platform/host.zig b/crates/valgrind/zig-platform/host.zig index 85116e5634..5516d3c9dd 100644 --- a/crates/valgrind/zig-platform/host.zig +++ b/crates/valgrind/zig-platform/host.zig @@ -44,13 +44,17 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr)))); } -export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void { +export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { _ = tag_id; const stderr = std.io.getStdErr().writer(); - const msg = @as([*:0]const u8, @ptrCast(c_ptr)); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; - std.process.exit(0); + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + std.process.exit(1); +} + +export fn roc_dbg(loc: *RocStr, msg: *RocStr) callconv(.C) void { + const stderr = std.io.getStdErr().writer(); + stderr.print("[{s}] {s}\n", .{ loc.asSlice(), msg.asSlice() }) catch unreachable; } export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void { diff --git a/examples/platform-switching/zig-platform/host.zig b/examples/platform-switching/zig-platform/host.zig index 85116e5634..97b183ca7b 100644 --- a/examples/platform-switching/zig-platform/host.zig +++ b/examples/platform-switching/zig-platform/host.zig @@ -44,15 +44,19 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr)))); } -export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void { +export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { _ = tag_id; const stderr = std.io.getStdErr().writer(); - const msg = @as([*:0]const u8, @ptrCast(c_ptr)); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; std.process.exit(0); } +export fn roc_dbg(loc: *RocStr, msg: *RocStr) callconv(.C) void { + const stderr = std.io.getStdErr().writer(); + stderr.print("[{s}] {s}\n", .{ loc.asSlice(), msg.asSlice() }) catch unreachable; +} + export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void { return memset(dst, value, size); } diff --git a/examples/static-site-gen/platform/src/lib.rs b/examples/static-site-gen/platform/src/lib.rs index 7bf0dad0f9..acbe32e079 100644 --- a/examples/static-site-gen/platform/src/lib.rs +++ b/examples/static-site-gen/platform/src/lib.rs @@ -86,16 +86,22 @@ pub extern "C" fn rust_main() -> i32 { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] From b62c9667d583781345813de1c7608ef1957b5b9d Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Wed, 29 Nov 2023 20:51:13 -0800 Subject: [PATCH 091/105] Correct typo Co-authored-by: Ayaz <20735482+ayazhafiz@users.noreply.github.com> Signed-off-by: Brendan Hansknecht --- crates/compiler/builtins/bitcode/src/utils.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/compiler/builtins/bitcode/src/utils.zig b/crates/compiler/builtins/bitcode/src/utils.zig index c53c8a3087..6a77a13d4d 100644 --- a/crates/compiler/builtins/bitcode/src/utils.zig +++ b/crates/compiler/builtins/bitcode/src/utils.zig @@ -22,7 +22,7 @@ extern fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void; extern fn roc_dbg(file_path: *anyopaque, message: *anyopaque) callconv(.C) void; -// Sincet roc_dbg is never used by the builtins, we need at export a function that uses it to stop DCE. +// Since roc_dbg is never used by the builtins, we need at export a function that uses it to stop DCE. pub fn test_dbg(file_path: *anyopaque, message: *anyopaque) callconv(.C) void { roc_dbg(file_path, message); } From 1f14aa84a276a887b2a6e1e3f5e6287f4ff3efc9 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Wed, 29 Nov 2023 21:05:56 -0800 Subject: [PATCH 092/105] misc cleanup suggestions --- crates/compiler/can/src/operator.rs | 2 + crates/compiler/fmt/src/expr.rs | 6 +- crates/compiler/fmt/src/spaces.rs | 5 +- crates/compiler/gen_llvm/src/llvm/build.rs | 67 ++++++++-------------- 4 files changed, 31 insertions(+), 49 deletions(-) diff --git a/crates/compiler/can/src/operator.rs b/crates/compiler/can/src/operator.rs index f675370bd3..e6bfcd897b 100644 --- a/crates/compiler/can/src/operator.rs +++ b/crates/compiler/can/src/operator.rs @@ -461,6 +461,8 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Loc>) -> &'a Loc }) } Dbg(condition, continuation) => { + // Desugars a `dbg x` statement into + // `roc_dbg (Inspect.toDbgStr (Inspect.inspect x))` let desugared_continuation = &*arena.alloc(desugar_expr(arena, continuation)); let region = condition.region; diff --git a/crates/compiler/fmt/src/expr.rs b/crates/compiler/fmt/src/expr.rs index ec141df01d..39e6bce4ee 100644 --- a/crates/compiler/fmt/src/expr.rs +++ b/crates/compiler/fmt/src/expr.rs @@ -62,9 +62,9 @@ impl<'a> Formattable for Expr<'a> { condition.is_multiline() || continuation.is_multiline() } Dbg(condition, continuation) => condition.is_multiline() || continuation.is_multiline(), - LowLevelDbg(condition, continuation) => { - condition.is_multiline() || continuation.is_multiline() - } + LowLevelDbg(_, _) => unreachable!( + "LowLevelDbg should only exist after desugaring, not during formatting" + ), If(branches, final_else) => { final_else.is_multiline() diff --git a/crates/compiler/fmt/src/spaces.rs b/crates/compiler/fmt/src/spaces.rs index 2114545c0e..255b18ae56 100644 --- a/crates/compiler/fmt/src/spaces.rs +++ b/crates/compiler/fmt/src/spaces.rs @@ -726,9 +726,8 @@ impl<'a> RemoveSpaces<'a> for Expr<'a> { arena.alloc(a.remove_spaces(arena)), arena.alloc(b.remove_spaces(arena)), ), - Expr::LowLevelDbg(a, b) => Expr::LowLevelDbg( - arena.alloc(a.remove_spaces(arena)), - arena.alloc(b.remove_spaces(arena)), + Expr::LowLevelDbg(_, _) => unreachable!( + "LowLevelDbg should only exist after desugaring, not during formatting" ), Expr::Apply(a, b, c) => Expr::Apply( arena.alloc(a.remove_spaces(arena)), diff --git a/crates/compiler/gen_llvm/src/llvm/build.rs b/crates/compiler/gen_llvm/src/llvm/build.rs index 3550aff56e..8500e42607 100644 --- a/crates/compiler/gen_llvm/src/llvm/build.rs +++ b/crates/compiler/gen_llvm/src/llvm/build.rs @@ -897,20 +897,7 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> { let function = self.module.get_function("roc_panic").unwrap(); let tag_id = self.context.i32_type().const_int(tag as u32 as u64, false); - let msg = match env.target_info.ptr_width() { - PtrWidth::Bytes4 => { - // we need to pass the message by reference, but we currently hold the value. - let alloca = env - .builder - .new_build_alloca(message.get_type(), "alloca_panic_msg"); - env.builder.new_build_store(alloca, message); - alloca.into() - } - PtrWidth::Bytes8 => { - // string is already held by reference - message - } - }; + let msg = self.string_to_arg(env, message); let call = self .builder @@ -927,35 +914,8 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> { ) { let function = self.module.get_function("roc_dbg").unwrap(); - let loc = match env.target_info.ptr_width() { - PtrWidth::Bytes4 => { - // we need to pass the location by reference, but we currently hold the value. - let alloca = env - .builder - .new_build_alloca(location.get_type(), "alloca_dbg_location"); - env.builder.new_build_store(alloca, location); - alloca.into() - } - PtrWidth::Bytes8 => { - // string is already held by reference - location - } - }; - - let msg = match env.target_info.ptr_width() { - PtrWidth::Bytes4 => { - // we need to pass the message by reference, but we currently hold the value. - let alloca = env - .builder - .new_build_alloca(message.get_type(), "alloca_dbg_msg"); - env.builder.new_build_store(alloca, message); - alloca.into() - } - PtrWidth::Bytes8 => { - // string is already held by reference - message - } - }; + let loc = self.string_to_arg(env, location); + let msg = self.string_to_arg(env, message); let call = self .builder @@ -964,6 +924,27 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> { call.set_call_convention(C_CALL_CONV); } + fn string_to_arg( + &self, + env: &Env<'a, 'ctx, 'env>, + string: BasicValueEnum<'ctx>, + ) -> BasicValueEnum<'ctx> { + match env.target_info.ptr_width() { + PtrWidth::Bytes4 => { + // we need to pass the string by reference, but we currently hold the value. + let alloca = env + .builder + .new_build_alloca(string.get_type(), "alloca_string"); + env.builder.new_build_store(alloca, string); + alloca.into() + } + PtrWidth::Bytes8 => { + // string is already held by reference + string + } + } + } + pub fn new_debug_info(module: &Module<'ctx>) -> (DebugInfoBuilder<'ctx>, DICompileUnit<'ctx>) { module.create_debug_info_builder( true, From 3e66254b25e296608105650893269a4cb744a9be Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Wed, 29 Nov 2023 21:49:34 -0800 Subject: [PATCH 093/105] update zig and rust platforms to have correct roc_panic and roc_dbg --- .../fixtures/multi-dep-str/platform/host.zig | 22 ++++++++++++----- .../multi-dep-thunk/platform/host.zig | 22 ++++++++++++----- .../tests/fixtures/packages/platform/host.zig | 14 +++++++---- .../algorithms/fibonacci-platform/host.zig | 12 +++++++--- .../algorithms/quicksort-platform/host.zig | 22 ++++++++++++----- .../benchmarks/platform/host.zig | 12 +++++++--- .../builtins/bitcode/benchmark/dec.zig | 24 +++++++++++-------- crates/compiler/gen_wasm/src/lib.rs | 5 ++++ .../test_gen/src/helpers/wasm_test_platform.c | 1 + .../advanced-recursive-union/src/lib.rs | 19 ++++++++++----- .../glue/tests/fixtures/arguments/src/lib.rs | 19 ++++++++++----- .../tests/fixtures/basic-record/src/lib.rs | 19 ++++++++++----- .../fixtures/basic-recursive-union/src/lib.rs | 19 ++++++++++----- .../glue/tests/fixtures/closures/src/lib.rs | 19 ++++++++++----- .../tests/fixtures/enumeration/src/lib.rs | 19 ++++++++++----- .../fixtures/list-recursive-union/src/lib.rs | 19 ++++++++++----- .../fixtures/multiple-modules/src/lib.rs | 19 ++++++++++----- .../tests/fixtures/nested-record/src/lib.rs | 19 ++++++++++----- .../fixtures/nonnullable-unwrapped/src/lib.rs | 18 +++++++++----- .../fixtures/nullable-unwrapped/src/lib.rs | 19 ++++++++++----- .../fixtures/nullable-wrapped/src/lib.rs | 18 +++++++++----- crates/glue/tests/fixtures/option/src/lib.rs | 19 ++++++++++----- .../glue/tests/fixtures/rocresult/src/lib.rs | 19 ++++++++++----- .../fixtures/single-tag-union/src/lib.rs | 19 ++++++++++----- .../fixtures/union-with-padding/src/lib.rs | 19 ++++++++++----- .../fixtures/union-without-padding/src/lib.rs | 19 ++++++++++----- crates/repl_wasm/src/repl_platform.c | 3 +++ crates/valgrind/zig-platform/host.zig | 12 +++++++--- examples/cli/effects-platform/host.zig | 22 ++++++++++++----- .../cli/false-interpreter/platform/src/lib.rs | 18 +++++++++----- examples/cli/tui-platform/host.zig | 22 ++++++++++++----- examples/glue/rust-platform/src/lib.rs | 18 +++++++++----- examples/gui/breakout/platform/src/roc.rs | 18 +++++++++----- examples/gui/platform/src/roc.rs | 18 +++++++++----- examples/nodejs-interop/wasm/hello.js | 4 ++++ examples/nodejs-interop/wasm/platform/host.js | 4 ++++ .../nodejs-interop/wasm/platform/host.zig | 2 +- .../rust-platform/src/lib.rs | 18 +++++++++----- .../web-assembly-platform/host.js | 4 ++++ .../web-assembly-platform/host.zig | 2 +- .../platform-switching/zig-platform/host.zig | 14 +++++++---- .../platform/src/client-side/host.zig | 21 ++++++++++++---- .../platform/src/server-side/host.zig | 21 ++++++++++++---- 43 files changed, 475 insertions(+), 201 deletions(-) diff --git a/crates/cli/tests/fixtures/multi-dep-str/platform/host.zig b/crates/cli/tests/fixtures/multi-dep-str/platform/host.zig index 5eed78fce5..6f91e049f8 100644 --- a/crates/cli/tests/fixtures/multi-dep-str/platform/host.zig +++ b/crates/cli/tests/fixtures/multi-dep-str/platform/host.zig @@ -38,13 +38,23 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void { return memset(dst, value, size); } -export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void { - _ = tag_id; - +export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { const stderr = std.io.getStdErr().writer(); - const msg = @as([*:0]const u8, @ptrCast(c_ptr)); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; - std.process.exit(0); + switch (tag_id) { + 0 => { + stderr.print("Roc standard library crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + 1 => { + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + else => unreachable, + } + std.process.exit(1); +} + +export fn roc_dbg(loc: *RocStr, msg: *RocStr) callconv(.C) void { + const stderr = std.io.getStdErr().writer(); + stderr.print("[{s}] {s}\n", .{ loc.asSlice(), msg.asSlice() }) catch unreachable; } extern fn kill(pid: c_int, sig: c_int) c_int; diff --git a/crates/cli/tests/fixtures/multi-dep-thunk/platform/host.zig b/crates/cli/tests/fixtures/multi-dep-thunk/platform/host.zig index cc2ed11250..a4a0ff9012 100644 --- a/crates/cli/tests/fixtures/multi-dep-thunk/platform/host.zig +++ b/crates/cli/tests/fixtures/multi-dep-thunk/platform/host.zig @@ -38,13 +38,23 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void { return memset(dst, value, size); } -export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void { - _ = tag_id; - +export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { const stderr = std.io.getStdErr().writer(); - const msg = @as([*:0]const u8, @ptrCast(c_ptr)); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; - std.process.exit(0); + switch (tag_id) { + 0 => { + stderr.print("Roc standard library crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + 1 => { + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + else => unreachable, + } + std.process.exit(1); +} + +export fn roc_dbg(loc: *RocStr, msg: *RocStr) callconv(.C) void { + const stderr = std.io.getStdErr().writer(); + stderr.print("[{s}] {s}\n", .{ loc.asSlice(), msg.asSlice() }) catch unreachable; } extern fn kill(pid: c_int, sig: c_int) c_int; diff --git a/crates/cli/tests/fixtures/packages/platform/host.zig b/crates/cli/tests/fixtures/packages/platform/host.zig index b798f0946d..6f91e049f8 100644 --- a/crates/cli/tests/fixtures/packages/platform/host.zig +++ b/crates/cli/tests/fixtures/packages/platform/host.zig @@ -39,11 +39,17 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void { } export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { - _ = tag_id; - const stderr = std.io.getStdErr().writer(); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; - std.process.exit(0); + switch (tag_id) { + 0 => { + stderr.print("Roc standard library crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + 1 => { + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + else => unreachable, + } + std.process.exit(1); } export fn roc_dbg(loc: *RocStr, msg: *RocStr) callconv(.C) void { diff --git a/crates/cli_testing_examples/algorithms/fibonacci-platform/host.zig b/crates/cli_testing_examples/algorithms/fibonacci-platform/host.zig index 0ed665fff1..8abd265eee 100644 --- a/crates/cli_testing_examples/algorithms/fibonacci-platform/host.zig +++ b/crates/cli_testing_examples/algorithms/fibonacci-platform/host.zig @@ -53,10 +53,16 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { } export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { - _ = tag_id; - const stderr = std.io.getStdErr().writer(); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + switch (tag_id) { + 0 => { + stderr.print("Roc standard library crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + 1 => { + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + else => unreachable, + } std.process.exit(1); } diff --git a/crates/cli_testing_examples/algorithms/quicksort-platform/host.zig b/crates/cli_testing_examples/algorithms/quicksort-platform/host.zig index 61629ce077..138e276e21 100644 --- a/crates/cli_testing_examples/algorithms/quicksort-platform/host.zig +++ b/crates/cli_testing_examples/algorithms/quicksort-platform/host.zig @@ -49,13 +49,23 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr)))); } -export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void { - _ = tag_id; - +export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { const stderr = std.io.getStdErr().writer(); - const msg = @as([*:0]const u8, @ptrCast(c_ptr)); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; - std.process.exit(0); + switch (tag_id) { + 0 => { + stderr.print("Roc standard library crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + 1 => { + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + else => unreachable, + } + std.process.exit(1); +} + +export fn roc_dbg(loc: *RocStr, msg: *RocStr) callconv(.C) void { + const stderr = std.io.getStdErr().writer(); + stderr.print("[{s}] {s}\n", .{ loc.asSlice(), msg.asSlice() }) catch unreachable; } export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void { diff --git a/crates/cli_testing_examples/benchmarks/platform/host.zig b/crates/cli_testing_examples/benchmarks/platform/host.zig index 6bd581040f..3362518568 100644 --- a/crates/cli_testing_examples/benchmarks/platform/host.zig +++ b/crates/cli_testing_examples/benchmarks/platform/host.zig @@ -55,10 +55,16 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { } export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { - _ = tag_id; - const stderr = std.io.getStdErr().writer(); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + switch (tag_id) { + 0 => { + stderr.print("Roc standard library crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + 1 => { + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + else => unreachable, + } std.process.exit(1); } diff --git a/crates/compiler/builtins/bitcode/benchmark/dec.zig b/crates/compiler/builtins/bitcode/benchmark/dec.zig index 996fb7458b..965d3bdd0c 100644 --- a/crates/compiler/builtins/bitcode/benchmark/dec.zig +++ b/crates/compiler/builtins/bitcode/benchmark/dec.zig @@ -11,10 +11,14 @@ fn roc_alloc(_: usize, _: u32) callconv(.C) ?*anyopaque { fn roc_panic(_: *anyopaque, _: u32) callconv(.C) void { @panic("Not needed for dec benchmark"); } +fn roc_dbg(_: *anyopaque, _: *anyopaque) callconv(.C) void { + @panic("Not needed for dec benchmark"); +} comptime { @export(roc_alloc, .{ .name = "roc_alloc", .linkage = .Strong }); @export(roc_panic, .{ .name = "roc_panic", .linkage = .Strong }); + @export(roc_dbg, .{ .name = "roc_dbg", .linkage = .Strong }); } var timer: Timer = undefined; @@ -100,16 +104,16 @@ pub fn main() !void { const f64Atan = try avg_runs(f64, n, atanF64, f1); try stdout.print("\n\nDec/F64:\n", .{}); - try stdout.print("addition: {d:0.2}\n", .{@intToFloat(f64, decAdd) / @intToFloat(f64, f64Add)}); - try stdout.print("subtraction: {d:0.2}\n", .{@intToFloat(f64, decSub) / @intToFloat(f64, f64Sub)}); - try stdout.print("multiplication: {d:0.2}\n", .{@intToFloat(f64, decMul) / @intToFloat(f64, f64Mul)}); - try stdout.print("division: {d:0.2}\n", .{@intToFloat(f64, decDiv) / @intToFloat(f64, f64Div)}); - try stdout.print("sin: {d:0.2}\n", .{@intToFloat(f64, decSin) / @intToFloat(f64, f64Sin)}); - try stdout.print("cos: {d:0.2}\n", .{@intToFloat(f64, decCos) / @intToFloat(f64, f64Cos)}); - try stdout.print("tan: {d:0.2}\n", .{@intToFloat(f64, decTan) / @intToFloat(f64, f64Tan)}); - try stdout.print("asin: {d:0.2}\n", .{@intToFloat(f64, decAsin) / @intToFloat(f64, f64Asin)}); - try stdout.print("acos: {d:0.2}\n", .{@intToFloat(f64, decAcos) / @intToFloat(f64, f64Acos)}); - try stdout.print("atan: {d:0.2}\n", .{@intToFloat(f64, decAtan) / @intToFloat(f64, f64Atan)}); + try stdout.print("addition: {d:0.2}\n", .{@as(f64, @floatFromInt(decAdd)) / @as(f64, @floatFromInt(f64Add))}); + try stdout.print("subtraction: {d:0.2}\n", .{@as(f64, @floatFromInt(decSub)) / @as(f64, @floatFromInt(f64Sub))}); + try stdout.print("multiplication: {d:0.2}\n", .{@as(f64, @floatFromInt(decMul)) / @as(f64, @floatFromInt(f64Mul))}); + try stdout.print("division: {d:0.2}\n", .{@as(f64, @floatFromInt(decDiv)) / @as(f64, @floatFromInt(f64Div))}); + try stdout.print("sin: {d:0.2}\n", .{@as(f64, @floatFromInt(decSin)) / @as(f64, @floatFromInt(f64Sin))}); + try stdout.print("cos: {d:0.2}\n", .{@as(f64, @floatFromInt(decCos)) / @as(f64, @floatFromInt(f64Cos))}); + try stdout.print("tan: {d:0.2}\n", .{@as(f64, @floatFromInt(decTan)) / @as(f64, @floatFromInt(f64Tan))}); + try stdout.print("asin: {d:0.2}\n", .{@as(f64, @floatFromInt(decAsin)) / @as(f64, @floatFromInt(f64Asin))}); + try stdout.print("acos: {d:0.2}\n", .{@as(f64, @floatFromInt(decAcos)) / @as(f64, @floatFromInt(f64Acos))}); + try stdout.print("atan: {d:0.2}\n", .{@as(f64, @floatFromInt(decAtan)) / @as(f64, @floatFromInt(f64Atan))}); } fn avg_runs(comptime T: type, comptime n: usize, comptime op: fn (T, T) T, v: T) !u64 { diff --git a/crates/compiler/gen_wasm/src/lib.rs b/crates/compiler/gen_wasm/src/lib.rs index d6d9207d2d..2192e666b5 100644 --- a/crates/compiler/gen_wasm/src/lib.rs +++ b/crates/compiler/gen_wasm/src/lib.rs @@ -289,6 +289,11 @@ mod dummy_platform_functions { unimplemented!("It is not valid to call roc panic from within the compiler. Please use the \"platform\" feature if this is a platform.") } + #[no_mangle] + pub unsafe extern "C" fn roc_dbg(_loc: *mut c_void, _msg: *mut c_void) { + unimplemented!("It is not valid to call roc dbg from within the compiler. Please use the \"platform\" feature if this is a platform.") + } + #[no_mangle] pub fn roc_memset(_dst: *mut c_void, _c: i32, _n: usize) -> *mut c_void { unimplemented!("It is not valid to call roc memset from within the compiler. Please use the \"platform\" feature if this is a platform.") diff --git a/crates/compiler/test_gen/src/helpers/wasm_test_platform.c b/crates/compiler/test_gen/src/helpers/wasm_test_platform.c index d9dbdaeefb..e3cd649c36 100644 --- a/crates/compiler/test_gen/src/helpers/wasm_test_platform.c +++ b/crates/compiler/test_gen/src/helpers/wasm_test_platform.c @@ -132,6 +132,7 @@ void roc_panic(void* msg, unsigned int panic_tag) exit(101); } +// TODO: add a way to send dbg to rust. void roc_debug(void* loc, void* msg) {} //-------------------------- diff --git a/crates/glue/tests/fixtures/advanced-recursive-union/src/lib.rs b/crates/glue/tests/fixtures/advanced-recursive-union/src/lib.rs index b3f6b9bf8d..64703ce5a7 100644 --- a/crates/glue/tests/fixtures/advanced-recursive-union/src/lib.rs +++ b/crates/glue/tests/fixtures/advanced-recursive-union/src/lib.rs @@ -1,6 +1,7 @@ use roc_app; use indoc::indoc; +use roc_std::RocStr; #[no_mangle] pub extern "C" fn rust_main() -> i32 { @@ -65,16 +66,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/arguments/src/lib.rs b/crates/glue/tests/fixtures/arguments/src/lib.rs index 9b5d52ac9b..c9bbc2f5ce 100644 --- a/crates/glue/tests/fixtures/arguments/src/lib.rs +++ b/crates/glue/tests/fixtures/arguments/src/lib.rs @@ -1,4 +1,5 @@ use roc_app; +use roc_std::RocStr; #[no_mangle] pub extern "C" fn rust_main() -> i32 { @@ -37,16 +38,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/basic-record/src/lib.rs b/crates/glue/tests/fixtures/basic-record/src/lib.rs index d5cc2ea1e0..b7e14aa276 100644 --- a/crates/glue/tests/fixtures/basic-record/src/lib.rs +++ b/crates/glue/tests/fixtures/basic-record/src/lib.rs @@ -1,4 +1,5 @@ use roc_app; +use roc_std::RocStr; #[no_mangle] pub extern "C" fn rust_main() -> i32 { @@ -59,16 +60,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/basic-recursive-union/src/lib.rs b/crates/glue/tests/fixtures/basic-recursive-union/src/lib.rs index decab79319..235fa9e52f 100644 --- a/crates/glue/tests/fixtures/basic-recursive-union/src/lib.rs +++ b/crates/glue/tests/fixtures/basic-recursive-union/src/lib.rs @@ -1,5 +1,6 @@ use indoc::indoc; use roc_app::{self, Expr}; +use roc_std::RocStr; #[no_mangle] pub extern "C" fn rust_main() -> i32 { @@ -70,16 +71,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/closures/src/lib.rs b/crates/glue/tests/fixtures/closures/src/lib.rs index a1f99f54b8..0b62d1654a 100644 --- a/crates/glue/tests/fixtures/closures/src/lib.rs +++ b/crates/glue/tests/fixtures/closures/src/lib.rs @@ -1,4 +1,5 @@ use roc_app; +use roc_std::RocStr; #[no_mangle] pub extern "C" fn rust_main() -> i32 { @@ -37,16 +38,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/enumeration/src/lib.rs b/crates/glue/tests/fixtures/enumeration/src/lib.rs index 59704b6be9..284420e2ac 100644 --- a/crates/glue/tests/fixtures/enumeration/src/lib.rs +++ b/crates/glue/tests/fixtures/enumeration/src/lib.rs @@ -1,4 +1,5 @@ use roc_app; +use roc_std::RocStr; #[no_mangle] pub extern "C" fn rust_main() -> i32 { @@ -63,16 +64,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/list-recursive-union/src/lib.rs b/crates/glue/tests/fixtures/list-recursive-union/src/lib.rs index 0b598c19d9..96c19a3827 100644 --- a/crates/glue/tests/fixtures/list-recursive-union/src/lib.rs +++ b/crates/glue/tests/fixtures/list-recursive-union/src/lib.rs @@ -2,6 +2,7 @@ use roc_app; use indoc::indoc; use roc_app::Rbt; +use roc_std::RocStr; #[no_mangle] pub extern "C" fn rust_main() -> i32 { @@ -65,16 +66,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/multiple-modules/src/lib.rs b/crates/glue/tests/fixtures/multiple-modules/src/lib.rs index e26415e710..21a81d7e38 100644 --- a/crates/glue/tests/fixtures/multiple-modules/src/lib.rs +++ b/crates/glue/tests/fixtures/multiple-modules/src/lib.rs @@ -1,5 +1,6 @@ use indoc::indoc; use roc_app; +use roc_std::RocStr; #[no_mangle] pub extern "C" fn rust_main() -> i32 { @@ -63,16 +64,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/nested-record/src/lib.rs b/crates/glue/tests/fixtures/nested-record/src/lib.rs index 92deb035b2..cf2e7167ba 100644 --- a/crates/glue/tests/fixtures/nested-record/src/lib.rs +++ b/crates/glue/tests/fixtures/nested-record/src/lib.rs @@ -1,4 +1,5 @@ use roc_app; +use roc_std::RocStr; #[no_mangle] pub extern "C" fn rust_main() -> i32 { @@ -61,16 +62,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/nonnullable-unwrapped/src/lib.rs b/crates/glue/tests/fixtures/nonnullable-unwrapped/src/lib.rs index fcae9742c2..51f6fa0b9e 100644 --- a/crates/glue/tests/fixtures/nonnullable-unwrapped/src/lib.rs +++ b/crates/glue/tests/fixtures/nonnullable-unwrapped/src/lib.rs @@ -79,16 +79,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/nullable-unwrapped/src/lib.rs b/crates/glue/tests/fixtures/nullable-unwrapped/src/lib.rs index f2bf716c7f..4317fcfd26 100644 --- a/crates/glue/tests/fixtures/nullable-unwrapped/src/lib.rs +++ b/crates/glue/tests/fixtures/nullable-unwrapped/src/lib.rs @@ -2,6 +2,7 @@ use roc_app; use indoc::indoc; use roc_app::StrConsList; +use roc_std::RocStr; #[no_mangle] pub extern "C" fn rust_main() -> i32 { @@ -70,16 +71,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/nullable-wrapped/src/lib.rs b/crates/glue/tests/fixtures/nullable-wrapped/src/lib.rs index c99a7ae610..1178eb1454 100644 --- a/crates/glue/tests/fixtures/nullable-wrapped/src/lib.rs +++ b/crates/glue/tests/fixtures/nullable-wrapped/src/lib.rs @@ -90,16 +90,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/option/src/lib.rs b/crates/glue/tests/fixtures/option/src/lib.rs index 3f7ee45b88..0e116bf701 100644 --- a/crates/glue/tests/fixtures/option/src/lib.rs +++ b/crates/glue/tests/fixtures/option/src/lib.rs @@ -1,4 +1,5 @@ use roc_app; +use roc_std::RocStr; #[no_mangle] pub extern "C" fn rust_main() -> i32 { @@ -39,16 +40,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/rocresult/src/lib.rs b/crates/glue/tests/fixtures/rocresult/src/lib.rs index e07fbee768..02af87bc0f 100644 --- a/crates/glue/tests/fixtures/rocresult/src/lib.rs +++ b/crates/glue/tests/fixtures/rocresult/src/lib.rs @@ -1,4 +1,5 @@ use roc_app; +use roc_std::RocStr; #[no_mangle] pub extern "C" fn rust_main() -> i32 { @@ -39,16 +40,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/single-tag-union/src/lib.rs b/crates/glue/tests/fixtures/single-tag-union/src/lib.rs index cc2e1ae01d..eb4f93d5f8 100644 --- a/crates/glue/tests/fixtures/single-tag-union/src/lib.rs +++ b/crates/glue/tests/fixtures/single-tag-union/src/lib.rs @@ -2,6 +2,7 @@ use roc_app; use indoc::indoc; use roc_app::SingleTagUnion; +use roc_std::RocStr; #[no_mangle] pub extern "C" fn rust_main() -> i32 { @@ -65,16 +66,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/union-with-padding/src/lib.rs b/crates/glue/tests/fixtures/union-with-padding/src/lib.rs index c7a1a2d09b..1f60c9b627 100644 --- a/crates/glue/tests/fixtures/union-with-padding/src/lib.rs +++ b/crates/glue/tests/fixtures/union-with-padding/src/lib.rs @@ -1,6 +1,7 @@ use roc_app; use roc_app::NonRecursive; +use roc_std::RocStr; extern "C" { #[link_name = "roc__mainForHost_1_exposed_generic"] @@ -70,16 +71,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/glue/tests/fixtures/union-without-padding/src/lib.rs b/crates/glue/tests/fixtures/union-without-padding/src/lib.rs index 1709441eba..20f4690435 100644 --- a/crates/glue/tests/fixtures/union-without-padding/src/lib.rs +++ b/crates/glue/tests/fixtures/union-without-padding/src/lib.rs @@ -1,4 +1,5 @@ use roc_app; +use roc_std::RocStr; extern "C" { #[link_name = "roc__mainForHost_1_exposed_generic"] @@ -67,16 +68,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/crates/repl_wasm/src/repl_platform.c b/crates/repl_wasm/src/repl_platform.c index 9e55b6201f..2b5a87f1fc 100644 --- a/crates/repl_wasm/src/repl_platform.c +++ b/crates/repl_wasm/src/repl_platform.c @@ -67,6 +67,9 @@ void roc_panic(void *ptr, unsigned int panic_tag) abort(); } +// TODO: add a way to send dbg to js. +void roc_debug(void* loc, void* msg) {} + //-------------------------- void *roc_memset(void *str, int c, size_t n) diff --git a/crates/valgrind/zig-platform/host.zig b/crates/valgrind/zig-platform/host.zig index 5516d3c9dd..84f1ac0117 100644 --- a/crates/valgrind/zig-platform/host.zig +++ b/crates/valgrind/zig-platform/host.zig @@ -45,10 +45,16 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { } export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { - _ = tag_id; - const stderr = std.io.getStdErr().writer(); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + switch (tag_id) { + 0 => { + stderr.print("Roc standard library crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + 1 => { + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + else => unreachable, + } std.process.exit(1); } diff --git a/examples/cli/effects-platform/host.zig b/examples/cli/effects-platform/host.zig index d8aa9cb5d2..6d3ea3306e 100644 --- a/examples/cli/effects-platform/host.zig +++ b/examples/cli/effects-platform/host.zig @@ -58,13 +58,23 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr)))); } -export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void { - _ = tag_id; - +export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { const stderr = std.io.getStdErr().writer(); - const msg = @as([*:0]const u8, @ptrCast(c_ptr)); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; - std.process.exit(0); + switch (tag_id) { + 0 => { + stderr.print("Roc standard library crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + 1 => { + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + else => unreachable, + } + std.process.exit(1); +} + +export fn roc_dbg(loc: *RocStr, msg: *RocStr) callconv(.C) void { + const stderr = std.io.getStdErr().writer(); + stderr.print("[{s}] {s}\n", .{ loc.asSlice(), msg.asSlice() }) catch unreachable; } export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void { diff --git a/examples/cli/false-interpreter/platform/src/lib.rs b/examples/cli/false-interpreter/platform/src/lib.rs index c31692c152..eb48d41bb3 100644 --- a/examples/cli/false-interpreter/platform/src/lib.rs +++ b/examples/cli/false-interpreter/platform/src/lib.rs @@ -49,16 +49,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/examples/cli/tui-platform/host.zig b/examples/cli/tui-platform/host.zig index 8b8a0d01a6..842b3a8833 100644 --- a/examples/cli/tui-platform/host.zig +++ b/examples/cli/tui-platform/host.zig @@ -113,13 +113,23 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr)))); } -export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void { - _ = tag_id; - +export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { const stderr = std.io.getStdErr().writer(); - const msg = @as([*:0]const u8, @ptrCast(c_ptr)); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; - std.process.exit(0); + switch (tag_id) { + 0 => { + stderr.print("Roc standard library crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + 1 => { + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + else => unreachable, + } + std.process.exit(1); +} + +export fn roc_dbg(loc: *RocStr, msg: *RocStr) callconv(.C) void { + const stderr = std.io.getStdErr().writer(); + stderr.print("[{s}] {s}\n", .{ loc.asSlice(), msg.asSlice() }) catch unreachable; } export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void { diff --git a/examples/glue/rust-platform/src/lib.rs b/examples/glue/rust-platform/src/lib.rs index e821634b41..3665ed7b43 100644 --- a/examples/glue/rust-platform/src/lib.rs +++ b/examples/glue/rust-platform/src/lib.rs @@ -30,16 +30,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/examples/gui/breakout/platform/src/roc.rs b/examples/gui/breakout/platform/src/roc.rs index 0d346981ee..fe6cbb4a69 100644 --- a/examples/gui/breakout/platform/src/roc.rs +++ b/examples/gui/breakout/platform/src/roc.rs @@ -184,16 +184,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/examples/gui/platform/src/roc.rs b/examples/gui/platform/src/roc.rs index 335679a982..f5b8f0480e 100644 --- a/examples/gui/platform/src/roc.rs +++ b/examples/gui/platform/src/roc.rs @@ -26,16 +26,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/examples/nodejs-interop/wasm/hello.js b/examples/nodejs-interop/wasm/hello.js index bdad8967bd..41bf9272c1 100644 --- a/examples/nodejs-interop/wasm/hello.js +++ b/examples/nodejs-interop/wasm/hello.js @@ -34,6 +34,10 @@ function hello() { roc_panic: (_pointer, _tag_id) => { throw "Roc panicked!"; }, + roc_dbg: (_loc, _msg) => { + // TODO write a proper impl. + throw "Roc dbg not supported!"; + }, }, }; diff --git a/examples/nodejs-interop/wasm/platform/host.js b/examples/nodejs-interop/wasm/platform/host.js index 956b91e5cf..486776fc66 100644 --- a/examples/nodejs-interop/wasm/platform/host.js +++ b/examples/nodejs-interop/wasm/platform/host.js @@ -26,6 +26,10 @@ async function roc_web_platform_run(wasm_filename, callback) { roc_panic: (_pointer, _tag_id) => { throw "Roc panicked!"; }, + roc_dbg: (_loc, _msg) => { + // TODO write a proper impl. + throw "Roc dbg not supported!"; + }, }, }; diff --git a/examples/nodejs-interop/wasm/platform/host.zig b/examples/nodejs-interop/wasm/platform/host.zig index d6ffcd8e6c..3f1a176fa6 100644 --- a/examples/nodejs-interop/wasm/platform/host.zig +++ b/examples/nodejs-interop/wasm/platform/host.zig @@ -33,7 +33,7 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr)))); } -// NOTE roc_panic is provided in the JS file, so it can throw an exception +// NOTE roc_panic and roc_dbg is provided in the JS file, so it can throw an exception extern fn roc__mainForHost_1_exposed(*RocStr) void; diff --git a/examples/platform-switching/rust-platform/src/lib.rs b/examples/platform-switching/rust-platform/src/lib.rs index f2f832c754..db4490425b 100644 --- a/examples/platform-switching/rust-platform/src/lib.rs +++ b/examples/platform-switching/rust-platform/src/lib.rs @@ -32,16 +32,22 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { } #[no_mangle] -pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { +pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { match tag_id { 0 => { - let slice = CStr::from_ptr(c_ptr as *const c_char); - let string = slice.to_str().unwrap(); - eprintln!("Roc hit a panic: {}", string); - std::process::exit(1); + eprintln!("Roc standard library hit a panic: {}", &*msg); } - _ => todo!(), + 1 => { + eprintln!("Application hit a panic: {}", &*msg); + } + _ => unreachable!(), } + std::process::exit(1); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr) { + eprintln!("[{}] {}", &*loc, &*msg); } #[no_mangle] diff --git a/examples/platform-switching/web-assembly-platform/host.js b/examples/platform-switching/web-assembly-platform/host.js index 956b91e5cf..486776fc66 100644 --- a/examples/platform-switching/web-assembly-platform/host.js +++ b/examples/platform-switching/web-assembly-platform/host.js @@ -26,6 +26,10 @@ async function roc_web_platform_run(wasm_filename, callback) { roc_panic: (_pointer, _tag_id) => { throw "Roc panicked!"; }, + roc_dbg: (_loc, _msg) => { + // TODO write a proper impl. + throw "Roc dbg not supported!"; + }, }, }; diff --git a/examples/platform-switching/web-assembly-platform/host.zig b/examples/platform-switching/web-assembly-platform/host.zig index aea2a0f516..b6babf362f 100644 --- a/examples/platform-switching/web-assembly-platform/host.zig +++ b/examples/platform-switching/web-assembly-platform/host.zig @@ -33,7 +33,7 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr)))); } -// NOTE roc_panic is provided in the JS file, so it can throw an exception +// NOTE roc_panic and roc_dbg is provided in the JS file, so it can throw an exception extern fn roc__mainForHost_1_exposed(*RocStr) void; diff --git a/examples/platform-switching/zig-platform/host.zig b/examples/platform-switching/zig-platform/host.zig index 97b183ca7b..84f1ac0117 100644 --- a/examples/platform-switching/zig-platform/host.zig +++ b/examples/platform-switching/zig-platform/host.zig @@ -45,11 +45,17 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { } export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { - _ = tag_id; - const stderr = std.io.getStdErr().writer(); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; - std.process.exit(0); + switch (tag_id) { + 0 => { + stderr.print("Roc standard library crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + 1 => { + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + else => unreachable, + } + std.process.exit(1); } export fn roc_dbg(loc: *RocStr, msg: *RocStr) callconv(.C) void { diff --git a/examples/virtual-dom-wip/platform/src/client-side/host.zig b/examples/virtual-dom-wip/platform/src/client-side/host.zig index 88530e31e9..eb33420650 100644 --- a/examples/virtual-dom-wip/platform/src/client-side/host.zig +++ b/examples/virtual-dom-wip/platform/src/client-side/host.zig @@ -28,12 +28,23 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr)))); } -export fn roc_panic(message: RocStr, tag_id: u32) callconv(.C) void { - _ = tag_id; - const msg = @as([*:0]const u8, @ptrCast(c_ptr)); +export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { const stderr = std.io.getStdErr().writer(); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; - std.process.exit(0); + switch (tag_id) { + 0 => { + stderr.print("Roc standard library crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + 1 => { + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + else => unreachable, + } + std.process.exit(1); +} + +export fn roc_dbg(loc: *RocStr, msg: *RocStr) callconv(.C) void { + const stderr = std.io.getStdErr().writer(); + stderr.print("[{s}] {s}\n", .{ loc.asSlice(), msg.asSlice() }) catch unreachable; } const RocList = extern struct { diff --git a/examples/virtual-dom-wip/platform/src/server-side/host.zig b/examples/virtual-dom-wip/platform/src/server-side/host.zig index bc675152ee..4167736ea5 100644 --- a/examples/virtual-dom-wip/platform/src/server-side/host.zig +++ b/examples/virtual-dom-wip/platform/src/server-side/host.zig @@ -28,12 +28,23 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr)))); } -export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void { - _ = tag_id; - const msg = @as([*:0]const u8, @ptrCast(c_ptr)); +export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void { const stderr = std.io.getStdErr().writer(); - stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; - std.process.exit(0); + switch (tag_id) { + 0 => { + stderr.print("Roc standard library crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + 1 => { + stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable; + }, + else => unreachable, + } + std.process.exit(1); +} + +export fn roc_dbg(loc: *RocStr, msg: *RocStr) callconv(.C) void { + const stderr = std.io.getStdErr().writer(); + stderr.print("[{s}] {s}\n", .{ loc.asSlice(), msg.asSlice() }) catch unreachable; } const ResultStrStr = extern struct { From 88106d165944082a2ac5ad1750d2785cca370e67 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Wed, 29 Nov 2023 22:02:27 -0800 Subject: [PATCH 094/105] add basic roc_dbg impl to c platforms --- crates/glue/tests/fixtures/nested-record/src/lib.rs | 2 +- examples/jvm-interop/bridge.c | 6 ++++++ examples/nodejs-interop/native-c-api/demo.c | 4 ++++ examples/platform-switching/c-platform/host.c | 6 +++--- examples/python-interop/demo.c | 4 ++++ examples/python-interop/platform/host.c | 6 +++++- examples/ruby-interop/demo.c | 4 ++++ examples/ruby-interop/platform/host.c | 6 +++++- 8 files changed, 32 insertions(+), 6 deletions(-) diff --git a/crates/glue/tests/fixtures/nested-record/src/lib.rs b/crates/glue/tests/fixtures/nested-record/src/lib.rs index cf2e7167ba..fc73c6588f 100644 --- a/crates/glue/tests/fixtures/nested-record/src/lib.rs +++ b/crates/glue/tests/fixtures/nested-record/src/lib.rs @@ -32,7 +32,7 @@ pub extern "C" fn rust_main() -> i32 { println!("Record was: {:?}", outer); // Exit code - 0 + std::process::exit(0); } // Externs required by roc_std and by the Roc app diff --git a/examples/jvm-interop/bridge.c b/examples/jvm-interop/bridge.c index 0064c2f564..174d0c7cfd 100644 --- a/examples/jvm-interop/bridge.c +++ b/examples/jvm-interop/bridge.c @@ -275,6 +275,12 @@ __attribute__((noreturn)) void roc_panic(struct RocStr *msg, unsigned int tag_id longjmp(exception_buffer, 1); } +void roc_dbg(struct RocStr *loc, struct RocStr *msg) { + char* loc_bytes = is_small_str(*loc) ? (char*)loc : (char*)loc->bytes; + char* msg_bytes = is_small_str(*msg) ? (char*)msg : (char*)msg->bytes; + fprintf(stderr, "[%s] %s\n", loc_bytes, msg_bytes); +} + extern void roc__programForHost_1__InterpolateString_caller(struct RocStr *name, char *closure_data, struct RocStr *ret); extern void roc__programForHost_1__MulArrByScalar_caller(struct RocListI32 *arr, int32_t *scalar, char *closure_data, struct RocListI32 *ret); diff --git a/examples/nodejs-interop/native-c-api/demo.c b/examples/nodejs-interop/native-c-api/demo.c index 3b257e6d3f..72a3325df4 100644 --- a/examples/nodejs-interop/native-c-api/demo.c +++ b/examples/nodejs-interop/native-c-api/demo.c @@ -27,6 +27,10 @@ void roc_panic(void *ptr, unsigned int alignment) napi_throw_error(napi_global_env, NULL, (char *)ptr); } +void roc_dbg(char* loc, char* msg) { + fprintf(stderr, "[%s] %s\n", loc, msg); +} + void *roc_memset(void *str, int c, size_t n) { return memset(str, c, n); } // Reference counting diff --git a/examples/platform-switching/c-platform/host.c b/examples/platform-switching/c-platform/host.c index c81cd435d4..3683afaa98 100644 --- a/examples/platform-switching/c-platform/host.c +++ b/examples/platform-switching/c-platform/host.c @@ -26,11 +26,11 @@ void roc_panic(void* ptr, unsigned int alignment) { char* msg = (char*)ptr; fprintf(stderr, "Application crashed with message\n\n %s\n\nShutting down\n", msg); - exit(0); + exit(1); } -void roc_dbg(char* file_path, char* msg) { - fprintf(stderr, "[%s] %s\n", file_path, msg); +void roc_dbg(char* loc, char* msg) { + fprintf(stderr, "[%s] %s\n", loc, msg); } void* roc_memset(void* str, int c, size_t n) { return memset(str, c, n); } diff --git a/examples/python-interop/demo.c b/examples/python-interop/demo.c index c575b1a947..11c274f001 100644 --- a/examples/python-interop/demo.c +++ b/examples/python-interop/demo.c @@ -27,6 +27,10 @@ __attribute__((noreturn)) void roc_panic(void *ptr, unsigned int alignment) PyErr_SetString(PyExc_RuntimeError, (char *)ptr); } +void roc_dbg(char* loc, char* msg) { + fprintf(stderr, "[%s] %s\n", loc, msg); +} + void *roc_memset(void *str, int c, size_t n) { return memset(str, c, n); } // Reference counting diff --git a/examples/python-interop/platform/host.c b/examples/python-interop/platform/host.c index 2346a57070..7560e3d5fd 100644 --- a/examples/python-interop/platform/host.c +++ b/examples/python-interop/platform/host.c @@ -21,7 +21,11 @@ void roc_panic(void* ptr, unsigned int alignment) { char* msg = (char*)ptr; fprintf(stderr, "Application crashed with message\n\n %s\n\nShutting down\n", msg); - exit(0); + exit(1); +} + +void roc_dbg(char* loc, char* msg) { + fprintf(stderr, "[%s] %s\n", loc, msg); } void* roc_memset(void* str, int c, size_t n) { return memset(str, c, n); } diff --git a/examples/ruby-interop/demo.c b/examples/ruby-interop/demo.c index 43539e7a08..068d8c5daa 100644 --- a/examples/ruby-interop/demo.c +++ b/examples/ruby-interop/demo.c @@ -23,6 +23,10 @@ __attribute__((noreturn)) void roc_panic(void *ptr, unsigned int alignment) rb_raise(rb_eException, "%s", (char *)ptr); } +void roc_dbg(char* loc, char* msg) { + fprintf(stderr, "[%s] %s\n", loc, msg); +} + void *roc_memset(void *str, int c, size_t n) { return memset(str, c, n); } // Reference counting diff --git a/examples/ruby-interop/platform/host.c b/examples/ruby-interop/platform/host.c index ac7093ddf4..1d7b681dbb 100644 --- a/examples/ruby-interop/platform/host.c +++ b/examples/ruby-interop/platform/host.c @@ -21,7 +21,11 @@ void roc_panic(void* ptr, unsigned int alignment) { char* msg = (char*)ptr; fprintf(stderr, "Application crashed with message\n\n %s\n\nShutting down\n", msg); - exit(0); + exit(1); +} + +void roc_dbg(char* loc, char* msg) { + fprintf(stderr, "[%s] %s\n", loc, msg); } void* roc_memmove(void* dest, const void* src, size_t n){ From 7b53f08e75df6add18fa46ba4f18ef668287b8ce Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Wed, 29 Nov 2023 22:21:21 -0800 Subject: [PATCH 095/105] hopefully fix glue platform exit code issue --- crates/glue/tests/fixture-templates/rust/host.c | 7 +++++-- crates/glue/tests/fixture-templates/rust/src/main.rs | 2 +- .../tests/fixtures/advanced-recursive-union/src/lib.rs | 5 +---- crates/glue/tests/fixtures/arguments/src/lib.rs | 5 +---- crates/glue/tests/fixtures/basic-record/src/lib.rs | 5 +---- .../glue/tests/fixtures/basic-recursive-union/src/lib.rs | 5 +---- crates/glue/tests/fixtures/closures/src/lib.rs | 5 +---- crates/glue/tests/fixtures/enumeration/src/lib.rs | 5 +---- crates/glue/tests/fixtures/list-recursive-union/src/lib.rs | 5 +---- crates/glue/tests/fixtures/multiple-modules/src/lib.rs | 5 +---- crates/glue/tests/fixtures/nested-record/src/lib.rs | 3 +-- .../glue/tests/fixtures/nonnullable-unwrapped/src/lib.rs | 5 +---- crates/glue/tests/fixtures/nullable-unwrapped/src/lib.rs | 5 +---- crates/glue/tests/fixtures/nullable-wrapped/src/lib.rs | 5 +---- crates/glue/tests/fixtures/option/src/lib.rs | 5 +---- crates/glue/tests/fixtures/rocresult/src/lib.rs | 5 +---- crates/glue/tests/fixtures/single-tag-union/src/lib.rs | 5 +---- crates/glue/tests/fixtures/union-with-padding/src/lib.rs | 5 +---- .../glue/tests/fixtures/union-without-padding/src/lib.rs | 5 +---- 19 files changed, 23 insertions(+), 69 deletions(-) diff --git a/crates/glue/tests/fixture-templates/rust/host.c b/crates/glue/tests/fixture-templates/rust/host.c index 3914d3f6ee..7d0fec6812 100644 --- a/crates/glue/tests/fixture-templates/rust/host.c +++ b/crates/glue/tests/fixture-templates/rust/host.c @@ -9,6 +9,9 @@ // So you probably don't want to modify it by hand! Instead, modify the // file with the same name in the fixture-templates/ directory. -extern int rust_main(); +extern void rust_main(); -int main() { return rust_main(); } +int main() { + rust_main(); + return 0; +} diff --git a/crates/glue/tests/fixture-templates/rust/src/main.rs b/crates/glue/tests/fixture-templates/rust/src/main.rs index 0765384f29..57692d3619 100644 --- a/crates/glue/tests/fixture-templates/rust/src/main.rs +++ b/crates/glue/tests/fixture-templates/rust/src/main.rs @@ -1,3 +1,3 @@ fn main() { - std::process::exit(host::rust_main() as _); + host::rust_main(); } diff --git a/crates/glue/tests/fixtures/advanced-recursive-union/src/lib.rs b/crates/glue/tests/fixtures/advanced-recursive-union/src/lib.rs index 64703ce5a7..9fa24c4665 100644 --- a/crates/glue/tests/fixtures/advanced-recursive-union/src/lib.rs +++ b/crates/glue/tests/fixtures/advanced-recursive-union/src/lib.rs @@ -4,7 +4,7 @@ use indoc::indoc; use roc_std::RocStr; #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { use std::cmp::Ordering; use std::collections::hash_set::HashSet; @@ -34,9 +34,6 @@ pub extern "C" fn rust_main() -> i32 { set.insert(tag_union); assert_eq!(set.len(), 1); - - // Exit code - 0 } // Externs required by roc_std and by the Roc app diff --git a/crates/glue/tests/fixtures/arguments/src/lib.rs b/crates/glue/tests/fixtures/arguments/src/lib.rs index c9bbc2f5ce..4f0db9af41 100644 --- a/crates/glue/tests/fixtures/arguments/src/lib.rs +++ b/crates/glue/tests/fixtures/arguments/src/lib.rs @@ -2,13 +2,10 @@ use roc_app; use roc_std::RocStr; #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { let answer = roc_app::mainForHost(42i64); println!("Answer was: {:?}", answer); // Debug - - // Exit code - 0 } // Externs required by roc_std and by the Roc app diff --git a/crates/glue/tests/fixtures/basic-record/src/lib.rs b/crates/glue/tests/fixtures/basic-record/src/lib.rs index b7e14aa276..cd50e9b76b 100644 --- a/crates/glue/tests/fixtures/basic-record/src/lib.rs +++ b/crates/glue/tests/fixtures/basic-record/src/lib.rs @@ -2,7 +2,7 @@ use roc_app; use roc_std::RocStr; #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { use std::cmp::Ordering; use std::collections::hash_set::HashSet; @@ -28,9 +28,6 @@ pub extern "C" fn rust_main() -> i32 { assert_eq!(set.len(), 1); println!("Record was: {:?}", record); // Debug - - // Exit code - 0 } // Externs required by roc_std and by the Roc app diff --git a/crates/glue/tests/fixtures/basic-recursive-union/src/lib.rs b/crates/glue/tests/fixtures/basic-recursive-union/src/lib.rs index 235fa9e52f..b104cb5a29 100644 --- a/crates/glue/tests/fixtures/basic-recursive-union/src/lib.rs +++ b/crates/glue/tests/fixtures/basic-recursive-union/src/lib.rs @@ -3,7 +3,7 @@ use roc_app::{self, Expr}; use roc_std::RocStr; #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { use std::cmp::Ordering; use std::collections::hash_set::HashSet; @@ -39,9 +39,6 @@ pub extern "C" fn rust_main() -> i32 { set.insert(tag_union); assert_eq!(set.len(), 1); - - // Exit code - 0 } // Externs required by roc_std and by the Roc app diff --git a/crates/glue/tests/fixtures/closures/src/lib.rs b/crates/glue/tests/fixtures/closures/src/lib.rs index 0b62d1654a..9179f6d02c 100644 --- a/crates/glue/tests/fixtures/closures/src/lib.rs +++ b/crates/glue/tests/fixtures/closures/src/lib.rs @@ -2,13 +2,10 @@ use roc_app; use roc_std::RocStr; #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { let closure = roc_app::mainForHost(42i64); println!("Answer was: {:?}", closure.force_thunk()); // Debug - - // Exit code - 0 } // Externs required by roc_std and by the Roc app diff --git a/crates/glue/tests/fixtures/enumeration/src/lib.rs b/crates/glue/tests/fixtures/enumeration/src/lib.rs index 284420e2ac..ebe1a45e41 100644 --- a/crates/glue/tests/fixtures/enumeration/src/lib.rs +++ b/crates/glue/tests/fixtures/enumeration/src/lib.rs @@ -2,7 +2,7 @@ use roc_app; use roc_std::RocStr; #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { use std::cmp::Ordering; use std::collections::hash_set::HashSet; @@ -32,9 +32,6 @@ pub extern "C" fn rust_main() -> i32 { roc_app::MyEnum::Bar, roc_app::MyEnum::Baz, ); // Debug - - // Exit code - 0 } // Externs required by roc_std and by the Roc app diff --git a/crates/glue/tests/fixtures/list-recursive-union/src/lib.rs b/crates/glue/tests/fixtures/list-recursive-union/src/lib.rs index 96c19a3827..7dd435fa73 100644 --- a/crates/glue/tests/fixtures/list-recursive-union/src/lib.rs +++ b/crates/glue/tests/fixtures/list-recursive-union/src/lib.rs @@ -5,7 +5,7 @@ use roc_app::Rbt; use roc_std::RocStr; #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { use std::cmp::Ordering; use std::collections::hash_set::HashSet; @@ -34,9 +34,6 @@ pub extern "C" fn rust_main() -> i32 { set.insert(tag_union); assert_eq!(set.len(), 1); - - // Exit code - 0 } // Externs required by roc_std and by the Roc app diff --git a/crates/glue/tests/fixtures/multiple-modules/src/lib.rs b/crates/glue/tests/fixtures/multiple-modules/src/lib.rs index 21a81d7e38..8f0194fa0d 100644 --- a/crates/glue/tests/fixtures/multiple-modules/src/lib.rs +++ b/crates/glue/tests/fixtures/multiple-modules/src/lib.rs @@ -3,7 +3,7 @@ use roc_app; use roc_std::RocStr; #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { use std::cmp::Ordering; use std::collections::hash_set::HashSet; @@ -32,9 +32,6 @@ pub extern "C" fn rust_main() -> i32 { set.insert(tag_union); assert_eq!(set.len(), 1); - - // Exit code - 0 } // Externs required by roc_std and by the Roc app diff --git a/crates/glue/tests/fixtures/nested-record/src/lib.rs b/crates/glue/tests/fixtures/nested-record/src/lib.rs index fc73c6588f..1263d2341b 100644 --- a/crates/glue/tests/fixtures/nested-record/src/lib.rs +++ b/crates/glue/tests/fixtures/nested-record/src/lib.rs @@ -2,7 +2,7 @@ use roc_app; use roc_std::RocStr; #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { use std::cmp::Ordering; let outer = roc_app::mainForHost(); @@ -31,7 +31,6 @@ pub extern "C" fn rust_main() -> i32 { println!("Record was: {:?}", outer); - // Exit code std::process::exit(0); } diff --git a/crates/glue/tests/fixtures/nonnullable-unwrapped/src/lib.rs b/crates/glue/tests/fixtures/nonnullable-unwrapped/src/lib.rs index 51f6fa0b9e..ca96c8d6fe 100644 --- a/crates/glue/tests/fixtures/nonnullable-unwrapped/src/lib.rs +++ b/crates/glue/tests/fixtures/nonnullable-unwrapped/src/lib.rs @@ -10,7 +10,7 @@ extern "C" { } #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { use std::cmp::Ordering; use std::collections::hash_set::HashSet; @@ -47,9 +47,6 @@ pub extern "C" fn rust_main() -> i32 { set.insert(tag_union); assert_eq!(set.len(), 1); - - // Exit code - 0 } // Externs required by roc_std and by the Roc app diff --git a/crates/glue/tests/fixtures/nullable-unwrapped/src/lib.rs b/crates/glue/tests/fixtures/nullable-unwrapped/src/lib.rs index 4317fcfd26..dd2f6a92fd 100644 --- a/crates/glue/tests/fixtures/nullable-unwrapped/src/lib.rs +++ b/crates/glue/tests/fixtures/nullable-unwrapped/src/lib.rs @@ -5,7 +5,7 @@ use roc_app::StrConsList; use roc_std::RocStr; #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { use std::cmp::Ordering; use std::collections::hash_set::HashSet; @@ -39,9 +39,6 @@ pub extern "C" fn rust_main() -> i32 { set.insert(tag_union); assert_eq!(set.len(), 1); - - // Exit code - 0 } // Externs required by roc_std and by the Roc app diff --git a/crates/glue/tests/fixtures/nullable-wrapped/src/lib.rs b/crates/glue/tests/fixtures/nullable-wrapped/src/lib.rs index 1178eb1454..0ef35c17c1 100644 --- a/crates/glue/tests/fixtures/nullable-wrapped/src/lib.rs +++ b/crates/glue/tests/fixtures/nullable-wrapped/src/lib.rs @@ -10,7 +10,7 @@ extern "C" { } #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { use std::cmp::Ordering; use std::collections::hash_set::HashSet; @@ -58,9 +58,6 @@ pub extern "C" fn rust_main() -> i32 { set.insert(tag_union); assert_eq!(set.len(), 1); - - // Exit code - 0 } // Externs required by roc_std and by the Roc app diff --git a/crates/glue/tests/fixtures/option/src/lib.rs b/crates/glue/tests/fixtures/option/src/lib.rs index 0e116bf701..c5e565c75f 100644 --- a/crates/glue/tests/fixtures/option/src/lib.rs +++ b/crates/glue/tests/fixtures/option/src/lib.rs @@ -2,15 +2,12 @@ use roc_app; use roc_std::RocStr; #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { let string = roc_app::mainForHost(true); println!("Answer was: {:?}", string.unwrap_Some()); // Debug // let integer = roc_app::mainForHost(false); println!("Answer was: {:?}", integer.discriminant()); // Debug - - // Exit code - 0 } // Externs required by roc_std and by the Roc app diff --git a/crates/glue/tests/fixtures/rocresult/src/lib.rs b/crates/glue/tests/fixtures/rocresult/src/lib.rs index 02af87bc0f..27092d4d68 100644 --- a/crates/glue/tests/fixtures/rocresult/src/lib.rs +++ b/crates/glue/tests/fixtures/rocresult/src/lib.rs @@ -2,15 +2,12 @@ use roc_app; use roc_std::RocStr; #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { let string = roc_app::mainForHost(true); println!("Answer was: {:?}", string); // Debug // let integer = roc_app::mainForHost(false); println!("Answer was: {:?}", integer); // Debug - - // Exit code - 0 } // Externs required by roc_std and by the Roc app diff --git a/crates/glue/tests/fixtures/single-tag-union/src/lib.rs b/crates/glue/tests/fixtures/single-tag-union/src/lib.rs index eb4f93d5f8..a59c631a9f 100644 --- a/crates/glue/tests/fixtures/single-tag-union/src/lib.rs +++ b/crates/glue/tests/fixtures/single-tag-union/src/lib.rs @@ -5,7 +5,7 @@ use roc_app::SingleTagUnion; use roc_std::RocStr; #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { use std::cmp::Ordering; use std::collections::hash_set::HashSet; @@ -34,9 +34,6 @@ pub extern "C" fn rust_main() -> i32 { set.insert(tag_union); assert_eq!(set.len(), 1); - - // Exit code - 0 } // Externs required by roc_std and by the Roc app diff --git a/crates/glue/tests/fixtures/union-with-padding/src/lib.rs b/crates/glue/tests/fixtures/union-with-padding/src/lib.rs index 1f60c9b627..42e32770d3 100644 --- a/crates/glue/tests/fixtures/union-with-padding/src/lib.rs +++ b/crates/glue/tests/fixtures/union-with-padding/src/lib.rs @@ -9,7 +9,7 @@ extern "C" { } #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { use std::cmp::Ordering; use std::collections::hash_set::HashSet; @@ -39,9 +39,6 @@ pub extern "C" fn rust_main() -> i32 { set.insert(tag_union); assert_eq!(set.len(), 1); - - // Exit code - 0 } // Externs required by roc_std and by the Roc app diff --git a/crates/glue/tests/fixtures/union-without-padding/src/lib.rs b/crates/glue/tests/fixtures/union-without-padding/src/lib.rs index 20f4690435..f424da0a9f 100644 --- a/crates/glue/tests/fixtures/union-without-padding/src/lib.rs +++ b/crates/glue/tests/fixtures/union-without-padding/src/lib.rs @@ -7,7 +7,7 @@ extern "C" { } #[no_mangle] -pub extern "C" fn rust_main() -> i32 { +pub extern "C" fn rust_main() { use std::cmp::Ordering; use std::collections::hash_set::HashSet; @@ -36,9 +36,6 @@ pub extern "C" fn rust_main() -> i32 { set.insert(tag_union); assert_eq!(set.len(), 1); - - // Exit code - 0 } // Externs required by roc_std and by the Roc app From 9f1f0610d175a0f4b3f60069a31362be36bfa64b Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Wed, 29 Nov 2023 22:59:25 -0800 Subject: [PATCH 096/105] disable flaky glue test for now --- crates/glue/tests/test_glue_cli.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/glue/tests/test_glue_cli.rs b/crates/glue/tests/test_glue_cli.rs index 0c2d571ceb..86e824b2e9 100644 --- a/crates/glue/tests/test_glue_cli.rs +++ b/crates/glue/tests/test_glue_cli.rs @@ -78,8 +78,9 @@ mod glue_cli_run { fixtures! { basic_record:"basic-record" => "Record was: MyRcd { b: 42, a: 1995 }\n", - nested_record:"nested-record" => "Record was: Outer { y: \"foo\", z: [1, 2], x: Inner { b: 24.0, a: 5 } }\n", - enumeration:"enumeration" => "tag_union was: MyEnum::Foo, Bar is: MyEnum::Bar, Baz is: MyEnum::Baz\n", + // TODO: re-enable this test. Currently it is flaking on macos x86-64 with a bad exit code. + // nested_record:"nested-record" => "Record was: Outer { y: \"foo\", z: [1, 2], x: Inner { b: 24.0, a: 5 } }\n", + // enumeration:"enumeration" => "tag_union was: MyEnum::Foo, Bar is: MyEnum::Bar, Baz is: MyEnum::Baz\n", single_tag_union:"single-tag-union" => indoc!(r#" tag_union was: SingleTagUnion::OneTag "#), From 92952a3b8f51d75ae85e639f6dd7dcc820512fe3 Mon Sep 17 00:00:00 2001 From: ducdetronquito Date: Thu, 30 Nov 2023 21:03:38 +0100 Subject: [PATCH 097/105] Tutorial - Fix broken examples link Signed-off-by: ducdetronquito --- www/content/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/content/tutorial.md b/www/content/tutorial.md index 3c9a0f8e36..b81c77d77b 100644 --- a/www/content/tutorial.md +++ b/www/content/tutorial.md @@ -1712,7 +1712,7 @@ Well done on making it this far! We've covered all of the basic syntax and features of Roc in this Tutorial. You should now have a good foundation and be ready to start writing your own applications. -You can continue reading through more advanced topics below, or perhaps checkout some of the [Examples](/example) for more a detailed exploration of ways to do various things. +You can continue reading through more advanced topics below, or perhaps checkout some of the [Examples](/examples) for more a detailed exploration of ways to do various things. ## [Appendix: Advanced Concepts](#appendix-advanced-concepts) {#appendix-advanced-concepts} From 16834a47ff77ca3a500eb3e850c28d7a95f259b4 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Fri, 1 Dec 2023 11:06:34 +1100 Subject: [PATCH 098/105] fix css error color --- www/public/site.css | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/www/public/site.css b/www/public/site.css index f055665dcd..bb1c9b012b 100644 --- a/www/public/site.css +++ b/www/public/site.css @@ -1454,16 +1454,27 @@ code .dim { color: var(--cyan); } -.color-white { - /* Really this isn't white so much as "default text color." For the repl, this should be black - in a light color scheme, and only white in dark mode. The name could be better! */ - color: black; +/* Really this isn't white so much as "default text color." For the repl, this should be black + in a light color scheme, and only white in dark mode. The name could be better! +*/ +#homepage-repl-container .color-white { + color: #FFF; +} + +#repl-container .color-white { + color: #000; } @media (prefers-color-scheme: dark) { - .color-white { - color: white; + + #homepage-repl-container .color-white { + color: #FFF; } + + #repl-container .color-white { + color: #FFF; + } + } .bold { From de5847a87541f84db6cce120f724658abc1b3a4b Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Fri, 1 Dec 2023 11:25:58 +1100 Subject: [PATCH 099/105] add spellcheck attribute for REPL --- www/content/index.md | 2 +- www/content/repl/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/www/content/index.md b/www/content/index.md index 9e9a781c84..f37be0c93f 100644 --- a/www/content/index.md +++ b/www/content/index.md @@ -54,7 +54,7 @@
    - + diff --git a/www/content/repl/index.md b/www/content/repl/index.md index dafb673594..d7a63acdab 100644 --- a/www/content/repl/index.md +++ b/www/content/repl/index.md @@ -8,7 +8,7 @@
    - + From 91886ce8a04a83fbdb386a4c078896e0f948efb7 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Thu, 30 Nov 2023 20:07:12 -0500 Subject: [PATCH 100/105] =?UTF-8?q?Add=20@asteroidb612=20to=20sponsors=20-?= =?UTF-8?q?=20thank=20you=20so=20much!=20=E2=9D=A4=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + www/content/index.md | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index f1f6c83852..315dcbae72 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ If you would like your company to become a corporate sponsor of Roc's developmen We'd also like to express our gratitude to our generous [individual sponsors](https://github.com/sponsors/roc-lang/)! A special thanks to those sponsoring $25/month or more: +* [Drew Lazzeri](https://github.com/asteroidb612) * [Alex Binaei](https://github.com/mrmizz) * [Jono Mallanyk](https://github.com/jonomallanyk) * [Chris Packett](https://github.com/chris-packett) diff --git a/www/content/index.md b/www/content/index.md index f37be0c93f..d0e2bf8b33 100644 --- a/www/content/index.md +++ b/www/content/index.md @@ -144,6 +144,7 @@ If you would like your organization to become an official sponsor of Roc's devel We'd also like to express our gratitude to our generous [individual sponsors](https://github.com/sponsors/roc-lang/)! A special thanks to those sponsoring $25/month or more:
      +
    • Drew Lazzeri
    • Alex Binaei
    • Jono Mallanyk
    • Chris Packett
    • From dc0b5eeab270057af70ee4f648ab58c3fab9ff59 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Fri, 1 Dec 2023 12:14:53 +1100 Subject: [PATCH 101/105] add github link to website --- www/main.roc | 24 +++++++++++++++++++++++- www/public/site.css | 22 ++++++++++++++++++++++ www/public/zulip-icon-circle.svg | 1 + 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 www/public/zulip-icon-circle.svg diff --git a/www/main.roc b/www/main.roc index 2872a74732..6e98b49afc 100644 --- a/www/main.roc +++ b/www/main.roc @@ -1,7 +1,7 @@ app "roc-website" packages { pf: "../examples/static-site-gen/platform/main.roc" } imports [ - pf.Html.{ Node, html, head, body, header, footer, div, span, main, text, nav, a, link, meta, script }, + pf.Html.{ Node, html, head, body, header, footer, div, span, main, text, nav, a, link, meta, script, br }, pf.Html.Attributes.{ attribute, content, name, id, href, rel, lang, class, title, charset, color, ariaLabel, ariaHidden, type }, InteractiveExample, ] @@ -101,6 +101,13 @@ view = \page, htmlContent -> main [] mainBody, footer [] [ div [id "footer"] [ + div [id "gh-link"] [ + a [id "gh-centered-link", href "https://github.com/roc-lang/roc"] [ + ghLogo, + span [id "gh-link-text"] [text "roc-lang/roc"], + ], + ], + br [] [], text " powered by ", a [href "https://www.netlify.com"] [text "Netlify"], ], @@ -149,3 +156,18 @@ rocLogo = ] [], ] + +ghLogo = + (Html.element "svg") + [ + (Html.attribute "viewBox") "0 0 98 96", + (Html.attribute "height") "25", + (Html.attribute "xmlns") "http://www.w3.org/2000/svg", + (Html.attribute "fill-rule") "evenodd", + (Html.attribute "clip-rule") "evenodd", + (Html.attribute "role") "img", + id "gh-logo", + ] + [ + (Html.element "path") [(Html.attribute "d") "M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z"] [], + ] diff --git a/www/public/site.css b/www/public/site.css index f055665dcd..5d9c674f66 100644 --- a/www/public/site.css +++ b/www/public/site.css @@ -1507,3 +1507,25 @@ code .dim { display: none; } } + +#gh-logo { + fill: var(--text-color); +} + +#gh-link { + display: flex; + justify-content: center; + align-items: center; + margin: 0; +} + +#gh-centered-link { + text-decoration: none; + display: flex; + align-items: center; +} + +#gh-link-text { + margin-left: 8px; + vertical-align: middle; +} \ No newline at end of file diff --git a/www/public/zulip-icon-circle.svg b/www/public/zulip-icon-circle.svg new file mode 100644 index 0000000000..72466de7fb --- /dev/null +++ b/www/public/zulip-icon-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file From a53da2bc2412bbab506578a518f66096436430be Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Thu, 30 Nov 2023 22:16:01 -0600 Subject: [PATCH 102/105] Make sure late specializations of opaques inherit Inspect as needed A "late specialization" of a type is an ability specialization that is not visible or needed until after type-specialization; i.e. during monomorphization. The `Inspect.toInspector` ability is special-cased for opaques that do not claim or explicitly implement `Inspect`. In such cases, they are treated as structural types, and given the immediate specialization of `Inpect.inspectOpaque`. However, prior to this commit, that special-casing would only be applied during early specialiation (i.e. specializations visible during generalized type inference). This commit applies the special case to late specialization as well - the specialization decision for an opaque type is always the specialization of the opaque type in the late case, but now, when we go to look up the ambient lambda set of the specialization, if it does not exist and corresponds to `Inspect.toInspector`, we fall back to the immediate. One concern I have here is that in a case like ``` Op := {} x = dbg (@Op {}) ``` the specialization of `Inspect.toInspector` for `Op` should be known early. Indeed, the program ``` Op := {} x = Inspect.toInspector (@Op {}) |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr ``` Compiles fine without this change. This makes me suspect there is an issue with the implementation of `dbg`'s desugaring. If possible, this should be addressed sooner rather than later. Closes #6127 --- crates/compiler/load_internal/src/file.rs | 4 +- crates/compiler/solve/src/specialize.rs | 218 +++++++++++------- crates/compiler/test_gen/src/gen_abilities.rs | 38 +++ .../specialize/inspect/opaque_automatic.txt | 54 +++++ .../inspect/opaque_automatic_late.txt | 61 +++++ 5 files changed, 285 insertions(+), 90 deletions(-) create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/opaque_automatic.txt create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/opaque_automatic_late.txt diff --git a/crates/compiler/load_internal/src/file.rs b/crates/compiler/load_internal/src/file.rs index ea2af62253..d24f8b96e2 100644 --- a/crates/compiler/load_internal/src/file.rs +++ b/crates/compiler/load_internal/src/file.rs @@ -4662,7 +4662,9 @@ pub fn add_imports( let mut cached_symbol_vars = VecMap::default(); - for &symbol in &exposed_for_module.imported_values { + let imported_values = exposed_for_module.imported_values.iter().copied(); + + for symbol in imported_values { import_variable_for_symbol( subs, constraints, diff --git a/crates/compiler/solve/src/specialize.rs b/crates/compiler/solve/src/specialize.rs index 54b6fd358a..cfde2e45e3 100644 --- a/crates/compiler/solve/src/specialize.rs +++ b/crates/compiler/solve/src/specialize.rs @@ -723,115 +723,155 @@ fn get_specialization_lambda_set_ambient_function( phase: &P, ability_member: Symbol, lset_region: u8, - specialization_key: SpecializationTypeKey, + mut specialization_key: SpecializationTypeKey, target_rank: Rank, ) -> Result { - match specialization_key { - SpecializationTypeKey::Opaque(opaque) => { - let opaque_home = opaque.module_id(); - let external_specialized_lset = - phase.with_module_abilities_store(opaque_home, |abilities_store| { - let impl_key = roc_can::abilities::ImplKey { + loop { + match specialization_key { + SpecializationTypeKey::Opaque(opaque) => { + let opaque_home = opaque.module_id(); + let found = phase.with_module_abilities_store(opaque_home, |abilities_store| { + find_opaque_specialization_ambient_function( + abilities_store, opaque, ability_member, - }; + lset_region, + ) + }); - let opt_specialization = - abilities_store.get_implementation(impl_key); - match opt_specialization { - None => { - if P::IS_LATE { - internal_error!( - "expected to know a specialization for {:?}#{:?}, but it wasn't found", - opaque, - ability_member - ); - } else { - // doesn't specialize, we'll have reported an error for this - Err(()) - } - } - Some(member_impl) => match member_impl { - MemberImpl::Impl(spec_symbol) => { - let specialization = - abilities_store.specialization_info(*spec_symbol).expect("expected custom implementations to always have complete specialization info by this point"); - - let specialized_lambda_set = *specialization - .specialization_lambda_sets - .get(&lset_region) - .unwrap_or_else(|| panic!("lambda set region not resolved: {:?}", (spec_symbol, specialization))); - Ok(specialized_lambda_set) - } - MemberImpl::Error => todo_abilities!(), - }, + let external_specialized_lset = match found { + FoundOpaqueSpecialization::UpdatedSpecializationKey(key) => { + specialization_key = key; + continue; } - })?; + FoundOpaqueSpecialization::AmbientFunction(lset) => lset, + FoundOpaqueSpecialization::NotFound => { + if P::IS_LATE { + internal_error!( + "expected to know a specialization for {:?}#{:?}, but it wasn't found", + opaque, + ability_member + ); + } else { + // We'll have reported an error for this. + return Err(()); + } + } + }; - let specialized_ambient = phase.copy_lambda_set_ambient_function_to_home_subs( - external_specialized_lset, - opaque_home, - subs, - ); + let specialized_ambient = phase.copy_lambda_set_ambient_function_to_home_subs( + external_specialized_lset, + opaque_home, + subs, + ); - Ok(specialized_ambient) - } + return Ok(specialized_ambient); + } - SpecializationTypeKey::Derived(derive_key) => { - let mut derived_module = derived_env.derived_module.lock().unwrap(); + SpecializationTypeKey::Derived(derive_key) => { + let mut derived_module = derived_env.derived_module.lock().unwrap(); - let (_, _, specialization_lambda_sets) = - derived_module.get_or_insert(derived_env.exposed_types, derive_key); + let (_, _, specialization_lambda_sets) = + derived_module.get_or_insert(derived_env.exposed_types, derive_key); - let specialized_lambda_set = *specialization_lambda_sets - .get(&lset_region) - .expect("lambda set region not resolved"); + let specialized_lambda_set = *specialization_lambda_sets + .get(&lset_region) + .expect("lambda set region not resolved"); - let specialized_ambient = derived_module.copy_lambda_set_ambient_function_to_subs( - specialized_lambda_set, - subs, - target_rank, - ); + let specialized_ambient = derived_module.copy_lambda_set_ambient_function_to_subs( + specialized_lambda_set, + subs, + target_rank, + ); - Ok(specialized_ambient) - } + return Ok(specialized_ambient); + } - SpecializationTypeKey::Immediate(imm) => { - // Immediates are like opaques in that we can simply look up their type definition in - // the ability store, there is nothing new to synthesize. - // - // THEORY: if something can become an immediate, it will always be available in the - // local ability store, because the transformation is local (?) - // - // TODO: I actually think we can get what we need here by examining `derived_env.exposed_types`, - // since immediates can only refer to builtins - and in userspace, all builtin types - // are available in `exposed_types`. - let immediate_lambda_set_at_region = - phase.get_and_copy_ability_member_ambient_function(imm, lset_region, subs); + SpecializationTypeKey::Immediate(imm) => { + // Immediates are like opaques in that we can simply look up their type definition in + // the ability store, there is nothing new to synthesize. + // + // THEORY: if something can become an immediate, it will always be available in the + // local ability store, because the transformation is local (?) + // + // TODO: I actually think we can get what we need here by examining `derived_env.exposed_types`, + // since immediates can only refer to builtins - and in userspace, all builtin types + // are available in `exposed_types`. + let immediate_lambda_set_at_region = + phase.get_and_copy_ability_member_ambient_function(imm, lset_region, subs); - Ok(immediate_lambda_set_at_region) - } + return Ok(immediate_lambda_set_at_region); + } - SpecializationTypeKey::SingleLambdaSetImmediate(imm) => { - let module_id = imm.module_id(); - debug_assert!(module_id.is_builtin()); + SpecializationTypeKey::SingleLambdaSetImmediate(imm) => { + let module_id = imm.module_id(); + debug_assert!(module_id.is_builtin()); - let module_types = &derived_env - .exposed_types - .get(&module_id) - .unwrap() - .exposed_types_storage_subs; + let module_types = &derived_env + .exposed_types + .get(&module_id) + .unwrap() + .exposed_types_storage_subs; - // Since this immediate has only one lambda set, the region must be pointing to 1, and - // moreover the imported function type is the ambient function of the single lset. - debug_assert_eq!(lset_region, 1); - let storage_var = module_types.stored_vars_by_symbol.get(&imm).unwrap(); - let imported = module_types - .storage_subs - .export_variable_to(subs, *storage_var); + // Since this immediate has only one lambda set, the region must be pointing to 1, and + // moreover the imported function type is the ambient function of the single lset. + debug_assert_eq!(lset_region, 1); + let storage_var = module_types.stored_vars_by_symbol.get(&imm).unwrap(); + let imported = module_types + .storage_subs + .export_variable_to(subs, *storage_var); - roc_types::subs::instantiate_rigids(subs, imported.variable); + roc_types::subs::instantiate_rigids(subs, imported.variable); - Ok(imported.variable) + return Ok(imported.variable); + } } } } + +enum FoundOpaqueSpecialization { + UpdatedSpecializationKey(SpecializationTypeKey), + AmbientFunction(Variable), + NotFound, +} + +fn find_opaque_specialization_ambient_function( + abilities_store: &AbilitiesStore, + opaque: Symbol, + ability_member: Symbol, + lset_region: u8, +) -> FoundOpaqueSpecialization { + let impl_key = roc_can::abilities::ImplKey { + opaque, + ability_member, + }; + + let opt_specialization = abilities_store.get_implementation(impl_key); + match opt_specialization { + None => match ability_member { + Symbol::INSPECT_TO_INSPECTOR => FoundOpaqueSpecialization::UpdatedSpecializationKey( + SpecializationTypeKey::Immediate(Symbol::INSPECT_OPAQUE), + ), + _ => FoundOpaqueSpecialization::NotFound, + }, + Some(member_impl) => match member_impl { + MemberImpl::Impl(spec_symbol) => { + let specialization = + abilities_store.specialization_info(*spec_symbol).expect("expected custom implementations to always have complete specialization info by this point"); + + let specialized_lambda_set = *specialization + .specialization_lambda_sets + .get(&lset_region) + .unwrap_or_else(|| { + panic!( + "lambda set region not resolved: {:?}", + (spec_symbol, specialization) + ) + }); + + FoundOpaqueSpecialization::AmbientFunction(specialized_lambda_set) + } + MemberImpl::Error => todo_abilities!(), + }, + } +} diff --git a/crates/compiler/test_gen/src/gen_abilities.rs b/crates/compiler/test_gen/src/gen_abilities.rs index 2bc4791b75..7c96408390 100644 --- a/crates/compiler/test_gen/src/gen_abilities.rs +++ b/crates/compiler/test_gen/src/gen_abilities.rs @@ -2288,4 +2288,42 @@ mod inspect { RocStr ); } + + #[test] + #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] + fn opaque_automatic() { + assert_evals_to!( + indoc!( + r#" + app "test" provides [main] to "./platform" + + Op := {} + + main = Inspect.toDbgStr (Inspect.inspect (@Op {})) + "# + ), + RocStr::from(r#""#), + RocStr + ); + } + + #[test] + #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] + fn opaque_automatic_with_polymorphic_call() { + assert_evals_to!( + indoc!( + r#" + app "test" provides [main] to "./platform" + + Op := {} + + late = \a -> Inspect.toDbgStr (Inspect.inspect a) + + main = late (@Op {}) + "# + ), + RocStr::from(r#""#), + RocStr + ); + } } diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_automatic.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_automatic.txt new file mode 100644 index 0000000000..ffe19f6da3 --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_automatic.txt @@ -0,0 +1,54 @@ +# +emit:mono +app "test" provides [main] to "./platform" + +Op := {} + +main = + dbg (@Op {}) + 1 + +# -emit:mono +procedure Inspect.251 (Inspect.252): + let Inspect.317 : Str = ""; + let Inspect.316 : Str = CallByName Inspect.61 Inspect.252 Inspect.317; + ret Inspect.316; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.45 (Inspect.302): + let Inspect.314 : {} = Struct {}; + let Inspect.313 : {} = CallByName Inspect.30 Inspect.314; + ret Inspect.313; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : {} = CallByName Inspect.45 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName Inspect.251 Inspect.308; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.319 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.319; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.0 (): + let Test.5 : {} = Struct {}; + let Test.4 : Str = CallByName Inspect.5 Test.5; + let Test.2 : Str = CallByName Inspect.35 Test.4; + dbg Test.2; + dec Test.2; + let Test.3 : I64 = 1i64; + ret Test.3; diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_automatic_late.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_automatic_late.txt new file mode 100644 index 0000000000..198b0d15dc --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_automatic_late.txt @@ -0,0 +1,61 @@ +# +emit:mono +app "test" provides [main] to "./platform" + +Op := {} + +late = \a -> + dbg a + 1 + +main = + late (@Op {}) + +# -emit:mono +procedure Inspect.251 (Inspect.252): + let Inspect.317 : Str = ""; + let Inspect.316 : Str = CallByName Inspect.61 Inspect.252 Inspect.317; + ret Inspect.316; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.45 (Inspect.302): + let Inspect.314 : {} = Struct {}; + let Inspect.313 : {} = CallByName Inspect.30 Inspect.314; + ret Inspect.313; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : {} = CallByName Inspect.45 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName Inspect.251 Inspect.308; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.319 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.319; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.2 (Test.3): + let Test.8 : Str = CallByName Inspect.5 Test.3; + let Test.4 : Str = CallByName Inspect.35 Test.8; + dbg Test.4; + dec Test.4; + let Test.7 : I64 = 1i64; + ret Test.7; + +procedure Test.0 (): + let Test.6 : {} = Struct {}; + let Test.5 : I64 = CallByName Test.2 Test.6; + ret Test.5; From a0509339554585135e674344fa5fa1179723e704 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Fri, 1 Dec 2023 12:33:09 +0100 Subject: [PATCH 103/105] use latest basic-cli --- crates/cli/tests/cli_run.rs | 2 +- .../tests/snapshots/pass/newline_in_packages.full.formatted.roc | 2 +- .../tests/snapshots/pass/newline_in_packages.full.result-ast | 2 +- .../tests/snapshots/pass/newline_in_packages.full.roc | 2 +- examples/cli/argsBROKEN.roc | 2 +- examples/cli/countdown.roc | 2 +- examples/cli/echo.roc | 2 +- examples/cli/env.roc | 2 +- examples/cli/fileBROKEN.roc | 2 +- examples/cli/form.roc | 2 +- examples/cli/http-get.roc | 2 +- examples/cli/ingested-file-bytes.roc | 2 +- examples/cli/ingested-file.roc | 2 +- examples/helloWorld.roc | 2 +- examples/inspect-logging.roc | 2 +- examples/parser/examples/letter-counts.roc | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index 8aefda9c70..7b403c4951 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -873,7 +873,7 @@ mod cli_run { This roc file can print it's own source code. The source is: app "ingested-file" - packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } + packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br" } imports [ pf.Stdout, "ingested-file.roc" as ownCode : Str, diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_packages.full.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_packages.full.formatted.roc index cba8a15175..156b704272 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_packages.full.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_packages.full.formatted.roc @@ -1,7 +1,7 @@ app "hello" packages { pf: - "https://github.com/roc-lang/basic-cli/releases/download/0.5.0/Cufzl36_SnJ4QbOoEmiJ5dIpUxBvdB3NEySvuH82Wio.tar.br", + "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br", } imports [pf.Stdout] provides [main] to pf diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_packages.full.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_packages.full.result-ast index 975efca1c3..d06a77cd4c 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_packages.full.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_packages.full.result-ast @@ -24,7 +24,7 @@ Full { Newline, ], package_name: @31-145 PackageName( - "https://github.com/roc-lang/basic-cli/releases/download/0.5.0/Cufzl36_SnJ4QbOoEmiJ5dIpUxBvdB3NEySvuH82Wio.tar.br", + "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br", ), }, [ diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_packages.full.roc b/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_packages.full.roc index 58dcb520fc..3fb360020d 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_packages.full.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_packages.full.roc @@ -1,6 +1,6 @@ app "hello" packages { pf: -"https://github.com/roc-lang/basic-cli/releases/download/0.5.0/Cufzl36_SnJ4QbOoEmiJ5dIpUxBvdB3NEySvuH82Wio.tar.br" +"https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br" } imports [pf.Stdout] provides [main] to pf diff --git a/examples/cli/argsBROKEN.roc b/examples/cli/argsBROKEN.roc index e5dc6ac8eb..c2fe7b1d4c 100644 --- a/examples/cli/argsBROKEN.roc +++ b/examples/cli/argsBROKEN.roc @@ -1,5 +1,5 @@ app "args" - packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } + packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br" } imports [pf.Stdout, pf.Arg, pf.Task.{ Task }] provides [main] to pf diff --git a/examples/cli/countdown.roc b/examples/cli/countdown.roc index f96624b40e..917c30fda8 100644 --- a/examples/cli/countdown.roc +++ b/examples/cli/countdown.roc @@ -1,5 +1,5 @@ app "countdown" - packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } + packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br" } imports [pf.Stdin, pf.Stdout, pf.Task.{ await, loop }] provides [main] to pf diff --git a/examples/cli/echo.roc b/examples/cli/echo.roc index 5e744a9bac..88737ea6cc 100644 --- a/examples/cli/echo.roc +++ b/examples/cli/echo.roc @@ -1,5 +1,5 @@ app "echo" - packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } + packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br" } imports [pf.Stdin, pf.Stdout, pf.Task.{ Task }] provides [main] to pf diff --git a/examples/cli/env.roc b/examples/cli/env.roc index 73e9061e66..eb2a6184c9 100644 --- a/examples/cli/env.roc +++ b/examples/cli/env.roc @@ -1,5 +1,5 @@ app "env" - packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } + packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br" } imports [pf.Stdout, pf.Stderr, pf.Env, pf.Task.{ Task }] provides [main] to pf diff --git a/examples/cli/fileBROKEN.roc b/examples/cli/fileBROKEN.roc index 172ef73d9f..bc63e5655a 100644 --- a/examples/cli/fileBROKEN.roc +++ b/examples/cli/fileBROKEN.roc @@ -1,5 +1,5 @@ app "file-io" - packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } + packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br" } imports [ pf.Stdout, pf.Stderr, diff --git a/examples/cli/form.roc b/examples/cli/form.roc index 48603a9136..3df5cd2d12 100644 --- a/examples/cli/form.roc +++ b/examples/cli/form.roc @@ -1,5 +1,5 @@ app "form" - packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } + packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br" } imports [pf.Stdin, pf.Stdout, pf.Task.{ await, Task }] provides [main] to pf diff --git a/examples/cli/http-get.roc b/examples/cli/http-get.roc index 0030c14cf1..a1890bbc27 100644 --- a/examples/cli/http-get.roc +++ b/examples/cli/http-get.roc @@ -1,5 +1,5 @@ app "http-get" - packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } + packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br" } imports [pf.Http, pf.Task.{ Task }, pf.Stdin, pf.Stdout] provides [main] to pf diff --git a/examples/cli/ingested-file-bytes.roc b/examples/cli/ingested-file-bytes.roc index 49898c84e1..5f89b21bfa 100644 --- a/examples/cli/ingested-file-bytes.roc +++ b/examples/cli/ingested-file-bytes.roc @@ -1,5 +1,5 @@ app "ingested-file-bytes" - packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } + packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br" } imports [ pf.Stdout, "ingested-file.roc" as ownCode : _, # A type hole can also be used here. diff --git a/examples/cli/ingested-file.roc b/examples/cli/ingested-file.roc index 58e1cb2ca8..8c79c1e22c 100644 --- a/examples/cli/ingested-file.roc +++ b/examples/cli/ingested-file.roc @@ -1,5 +1,5 @@ app "ingested-file" - packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } + packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br" } imports [ pf.Stdout, "ingested-file.roc" as ownCode : Str, diff --git a/examples/helloWorld.roc b/examples/helloWorld.roc index 50e600dd4e..7a30101ef2 100644 --- a/examples/helloWorld.roc +++ b/examples/helloWorld.roc @@ -1,5 +1,5 @@ app "helloWorld" - packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } + packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br" } imports [pf.Stdout] provides [main] to pf diff --git a/examples/inspect-logging.roc b/examples/inspect-logging.roc index 1054c68171..f9b9c10c91 100644 --- a/examples/inspect-logging.roc +++ b/examples/inspect-logging.roc @@ -2,7 +2,7 @@ # Shows how Roc values can be logged # app "inspect-logging" - packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } + packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br" } imports [ pf.Stdout, Community, diff --git a/examples/parser/examples/letter-counts.roc b/examples/parser/examples/letter-counts.roc index 23a28cfb27..22ed5b3956 100644 --- a/examples/parser/examples/letter-counts.roc +++ b/examples/parser/examples/letter-counts.roc @@ -1,6 +1,6 @@ app "example" packages { - cli: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br", + cli: "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br", parser: "../package/main.roc", } imports [ From cc8966e37d83aa179cd8955f4a9b1b023586279d Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Fri, 1 Dec 2023 12:49:31 +0100 Subject: [PATCH 104/105] Update ingested_file_bytes test Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com> --- crates/cli/tests/cli_run.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index 7b403c4951..80cf5548fd 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -900,7 +900,7 @@ mod cli_run { &[], &[], &[], - "30256\n", + "30461\n", UseValgrind::No, TestCliCommands::Run, ) From 590140f182878f342eb4b4ef919efd40c1d12590 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Fri, 1 Dec 2023 18:48:12 +0100 Subject: [PATCH 105/105] Revert "Merge pull request #6113 from JRMurr/nix-build-file-sets" This reverts commit f7841f0d1c74e24b4c35c4751c3fad63a7928b73, reversing changes made to b4506a4dac588461135d3f7ae6786b250b68d769. --- crates/wasm_interp/src/lib.rs | 1 + flake.lock | 8 ++-- flake.nix | 5 ++- nix/builder.nix | 4 +- nix/fileFilter.nix | 80 ----------------------------------- 5 files changed, 9 insertions(+), 89 deletions(-) delete mode 100644 nix/fileFilter.nix diff --git a/crates/wasm_interp/src/lib.rs b/crates/wasm_interp/src/lib.rs index c3add8e661..8cc98d3e39 100644 --- a/crates/wasm_interp/src/lib.rs +++ b/crates/wasm_interp/src/lib.rs @@ -1,5 +1,6 @@ mod frame; mod instance; +mod tests; mod value_store; pub mod wasi; diff --git a/flake.lock b/flake.lock index 15d775de42..e0c185ee01 100644 --- a/flake.lock +++ b/flake.lock @@ -59,17 +59,17 @@ }, "nixpkgs": { "locked": { - "lastModified": 1701068326, - "narHash": "sha256-vmMceA+q6hG1yrjb+MP8T0YFDQIrW3bl45e7z24IEts=", + "lastModified": 1693140250, + "narHash": "sha256-URyIDETtu1bbxcSl83xp7irEV04dPEgj7O3LjHcD1Sk=", "owner": "nixos", "repo": "nixpkgs", - "rev": "8cfef6986adfb599ba379ae53c9f5631ecd2fd9c", + "rev": "676fe5e01b9a41fa14aaa48d87685677664104b1", "type": "github" }, "original": { "owner": "nixos", - "ref": "nixos-unstable", "repo": "nixpkgs", + "rev": "676fe5e01b9a41fa14aaa48d87685677664104b1", "type": "github" } }, diff --git a/flake.nix b/flake.nix index 6d58d7f498..cfb5b92855 100644 --- a/flake.nix +++ b/flake.nix @@ -2,7 +2,8 @@ description = "Roc flake"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + nixpkgs.url = "github:nixos/nixpkgs?rev=676fe5e01b9a41fa14aaa48d87685677664104b1"; + # rust from nixpkgs has some libc problems, this is patched in the rust-overlay rust-overlay = { url = "github:oxalica/rust-overlay"; @@ -159,7 +160,7 @@ # You can build this package (the roc CLI) with the `nix build` command. packages = { default = rocBuild.roc-cli; - + # all rust crates in workspace.members of Cargo.toml full = rocBuild.roc-full; # only the CLI crate = executable provided in nightly releases diff --git a/nix/builder.nix b/nix/builder.nix index 6439bc62b8..4038a1bfbe 100644 --- a/nix/builder.nix +++ b/nix/builder.nix @@ -3,8 +3,6 @@ let inherit (compile-deps) zigPkg llvmPkgs llvmVersion llvmMajorMinorStr glibcPath libGccSPath; subPackagePath = if subPackage != null then "crates/${subPackage}" else null; - - filteredSource = pkgs.callPackage ./fileFilter.nix { }; in rustPlatform.buildRustPackage { pname = "roc" + lib.optionalString (subPackage != null) "_${subPackage}"; @@ -12,7 +10,7 @@ rustPlatform.buildRustPackage { buildAndTestSubdir = subPackagePath; - src = filteredSource; + src = pkgs.nix-gitignore.gitignoreSource [ ] ../.; cargoLock = { lockFile = ../Cargo.lock; diff --git a/nix/fileFilter.nix b/nix/fileFilter.nix deleted file mode 100644 index 8f974f85b2..0000000000 --- a/nix/fileFilter.nix +++ /dev/null @@ -1,80 +0,0 @@ -{ lib, nix-gitignore }: -let - # See https://nix.dev/tutorials/file-sets for a guide on how the file set api works - - fs = lib.fileset; - - fileDoesNotHaveExt = fileExts: file: (!lib.lists.any (ext: file.hasExt ext) fileExts); - - repoRoot = ../.; - - # The file set api does not currently have a way to easily remove folders dynamically. - # The nix build does not run tests, so we try to remove any folders with only tests. - removedTests = - let - dirFilter = pathStr: ( - let dirName = baseNameOf pathStr; in !( - # remove any folder whos name is `tests` or starts with `test_` - dirName == "tests" - ) - ); - removeTestFilter = - path: type: - # only do a "real" check on directory, allow everything else through - (type == "directory" && dirFilter path) - || type != "directory"; - in - lib.sources.cleanSourceWith { src = repoRoot; filter = removeTestFilter; }; - fsBase = fs.fromSource removedTests; - - # fsBase = fs.fromSource repoRoot; - - # only look at files in the crates folder - onlyCratesFolder = fs.intersection ../crates fsBase; - - # the above filter only has the subfolder, put some needed files from the root back in - includeCargoRootFiles = fs.unions [ - ../Cargo.toml - ../Cargo.lock - ../version.txt - onlyCratesFolder - ]; - - # Remove any "simple" files like markdown/pictures since they probably wont be used in the actual code - removedSimpleFiles = - let - extensionsToRemove = [ "md" "svg" "png" ]; - in - fs.intersection - includeCargoRootFiles - (fs.fileFilter (fileDoesNotHaveExt extensionsToRemove) repoRoot); - - # the above filter can make the doc crate sad since it has pictures - docsAddedBack = fs.unions [ - ../crates/docs - removedSimpleFiles - ]; - - # =============================== - # If you are trying to see what is ok to exclude from the "main" builds (cli/lang_server) - # use `cargo tree` https://doc.rust-lang.org/cargo/commands/cargo-tree.html - # - # Ex: `cargo tree -i roc_build` will show all deps of the `roc_build` crate - # if only the package passed with `-i` is shown, nothing depends on it - # =============================== - - # remove www folder from checkmate crate since it's not built with nix - removedWWW = fs.difference docsAddedBack ../crates/compiler/checkmate/www; - - # potential packages/folders that could be removed - # repl_* -> I don't think nix will build those - - filteredSrc = fs.toSource { - root = repoRoot; - # to debug you can switch to - # fileset = fs.traceVal - fileset = removedWWW; - }; - -in -filteredSrc